diff --git a/.cargo/config.toml b/.cargo/config.toml index 4796a2c26965c1021d14c6acc854bca1aea76941..bd46659f7991a95d853711672a6a4eed9222c5a1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,9 @@ -# +[build] +rustdocflags = [ + "-Dwarnings", + "-Arustdoc::redundant_explicit_links", # stylistic +] + # An auto defined `clippy` feature was introduced, # but it was found to clash with user defined features, # so was renamed to `cargo-clippy`. @@ -10,7 +15,7 @@ rustflags = [ "-Aclippy::all", "-Dclippy::correctness", "-Aclippy::if-same-then-else", - "-Aclippy::clone-double-ref", + "-Asuspicious_double_ref_op", "-Dclippy::complexity", "-Aclippy::zero-prefixed-literal", # 00_1000_000 "-Aclippy::type_complexity", # raison d'etre @@ -30,4 +35,10 @@ rustflags = [ "-Aclippy::derivable_impls", # false positives "-Aclippy::stable_sort_primitive", # prefer stable sort "-Aclippy::extra-unused-type-parameters", # stylistic + "-Aclippy::default_constructed_unit_structs", # stylistic ] + +[env] +# Needed for musl builds so user doesn't have to install musl-tools. +CC_x86_64_unknown_linux_musl = { value = ".cargo/musl-gcc", force = true, relative = true } +CXX_x86_64_unknown_linux_musl = { value = ".cargo/musl-g++", force = true, relative = true } diff --git a/.cargo/musl-g++ b/.cargo/musl-g++ new file mode 100755 index 0000000000000000000000000000000000000000..656adcc2ac1b6785b708d8828b29d93e03a77272 --- /dev/null +++ b/.cargo/musl-g++ @@ -0,0 +1,7 @@ +#!/bin/sh + +# Wrapper for building with musl. +# +# See comments for musl-gcc in this repo. + +g++ "$@" diff --git a/.cargo/musl-gcc b/.cargo/musl-gcc new file mode 100755 index 0000000000000000000000000000000000000000..5bc7852dbc6ec25f51403ae58fedc7ba094f78b7 --- /dev/null +++ b/.cargo/musl-gcc @@ -0,0 +1,13 @@ +#!/bin/sh + +# Wrapper for building with musl. +# +# musl unfortunately requires a musl-enabled C compiler (musl-gcc) to be +# installed, which can be kind of a pain to get installed depending on the +# distro. That's not a very good user experience. +# +# The real musl-gcc wrapper sets the correct system include paths for linking +# with musl libc library. Since this is not actually used to link any binaries +# it should most likely work just fine. + +gcc "$@" diff --git a/.config/lychee.toml b/.config/lychee.toml new file mode 100644 index 0000000000000000000000000000000000000000..9b2ae069931769251fc26b57686fd1dbc5ff0b83 --- /dev/null +++ b/.config/lychee.toml @@ -0,0 +1,50 @@ +# Config file for lychee link checker: +# Run with `lychee -c .config/lychee.toml ./**/*.rs ./**/*.prdoc` + +cache = true +max_cache_age = "1d" +max_redirects = 10 +max_retries = 6 + +# Exclude localhost et.al. +exclude_all_private = true + +# Treat these codes as success condition: +accept = [ + # Ok + 200, + + # Rate limited - GitHub likes to throw this. + 429 +] + +exclude_path = [ "./target" ] + +exclude = [ + # Place holders (no need to fix these): + "http://visitme/", + "https://visitme/", + + # TODO + "https://docs.substrate.io/main-docs/build/custom-rpc/#public-rpcs", + "https://docs.substrate.io/rustdocs/latest/sp_api/macro.decl_runtime_apis.html", + "https://github.com/ipfs/js-ipfs-bitswap/blob/", + "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.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/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/NPoS/3.%20Balancing.html", + "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", + "https://research.web3.foundation/en/latest/polkadot/slashing/npos.html", + "https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model", + "https://rpc.polkadot.io/", + "https://w3f.github.io/parachain-implementers-guide/node/approval/approval-distribution.html", + "https://w3f.github.io/parachain-implementers-guide/node/index.html", + "https://w3f.github.io/parachain-implementers-guide/protocol-chain-selection.html", + "https://w3f.github.io/parachain-implementers-guide/runtime/session_info.html", +] diff --git a/.github/review-bot.yml b/.github/review-bot.yml new file mode 100644 index 0000000000000000000000000000000000000000..581e33762608a298fdb0c251fa3414b06ea01de6 --- /dev/null +++ b/.github/review-bot.yml @@ -0,0 +1,120 @@ +rules: + - name: CI files + condition: + include: + - ^\.gitlab-ci\.yml + - ^docker/.* + - ^\.github/.* + - ^\.gitlab/.* + - ^\.config/nextest.toml + - ^\.cargo/.* + exclude: + - ^./gitlab/pipeline/zombienet.* + minApprovals: 2 + type: basic + teams: + - ci + - release-engineering + + - name: Audit rules + type: basic + condition: + include: + - ^polkadot/runtime\/(kusama|polkadot|common)\/.* + - ^polkadot/primitives/src\/.+\.rs$ + - ^substrate/primitives/.* + - ^substrate/frame/.* + exclude: + - ^polkadot/runtime\/(kusama|polkadot)\/src\/weights\/.+\.rs$ + - ^substrate\/frame\/.+\.md$ + minApprovals: 1 + allowedToSkipRule: + teams: + - core-devs + teams: + - srlabs + + - name: Core developers + countAuthor: true + condition: + include: + - .* + # excluding files from 'Runtime files' and 'CI files' rules + exclude: + - ^polkadot/runtime/(kusama|polkadot)/src/[^/]+\.rs$ + - ^cumulus/parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$ + - ^cumulus/parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$ + - ^cumulus/parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$ + - ^cumulus/parachains/common/src/[^/]+\.rs$ + - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) + - ^polkadot/runtime/(kusama|polkadot)/src/[^/]+\.rs$ + - ^\.gitlab-ci\.yml + - ^docker/.* + - ^\.github/.* + - ^\.gitlab/.* + - ^\.config/nextest.toml + - ^\.cargo/.* + minApprovals: 2 + type: basic + teams: + - core-devs + + # cumulus + - name: Runtime files cumulus + countAuthor: true + condition: + include: + - ^cumulus/parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$ + - ^cumulus/parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$ + - ^cumulus/parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$ + - ^cumulus/parachains/common/src/[^/]+\.rs$ + type: and-distinct + reviewers: + - minApprovals: 1 + teams: + - locks-review + - minApprovals: 1 + teams: + - polkadot-review + + # if there are any changes in the bridges subtree (in case of backport changes back to bridges repo) + - name: Bridges subtree files + type: basic + condition: + include: + - ^bridges/.* + minApprovals: 1 + teams: + - bridges-core + + # substrate + + - name: FRAME coders substrate + condition: + include: + - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) + type: "and" + reviewers: + - minApprovals: 2 + teams: + - core-devs + - minApprovals: 1 + teams: + - frame-coders + + # Protection of THIS file + - name: Review Bot + condition: + include: + - review-bot\.yml + type: "and" + reviewers: + - minApprovals: 1 + teams: + - opstooling + - minApprovals: 1 + teams: + - locks-review + - minApprovals: 1 + teams: + - ci diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 4d0afefc47aace08bff9af796f9fb9c30dee99a7..fab788c8057aab578118bb42de179a287e2d9e37 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -14,7 +14,7 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/setup-node@v3.8.1 with: node-version: "18.x" diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 0000000000000000000000000000000000000000..3ed6ba84b82f14e2b20cb4ab4553bcef4a11283d --- /dev/null +++ b/.github/workflows/check-links.yml @@ -0,0 +1,40 @@ +name: Check links + +on: + pull_request: + paths: + - "*.rs" + - "*.prdoc" + - ".github/workflows/check-links.yml" + - ".config/lychee.toml" + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + packages: read + +jobs: + link-checker: + runs-on: ubuntu-latest + steps: + - name: Restore lychee cache + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 (7. Sep 2023) + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + # This should restore from the most recent one: + restore-keys: cache-lychee- + + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) + + - name: Lychee link checker + uses: lycheeverse/lychee-action@2ac9f030ccdea0033e2510a23a67da2a2da98492 # for v1.8.0 (15. May 2023) + with: + args: >- + --config .config/lychee.toml + --no-progress + './**/*.rs' + './**/*.prdoc' + fail: true + env: + # To bypass GitHub rate-limit: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml index f1e46ca273515d9081f9c5a7f6b8b4ff902c444a..991fdd171ce6d5d09618e666ce697dd17f4ba43d 100644 --- a/.github/workflows/check-markdown.yml +++ b/.github/workflows/check-markdown.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/setup-node@v3.8.1 with: diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index d153184941ac1e05f341ae49c4c8d4e212c0d85b..3bb9a4fcabf8dc8198a18d8eef9cb06dc2d2bc58 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -40,7 +40,7 @@ jobs: - name: Checkout repo if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 - name: PRdoc check for PR#${{ github.event.pull_request.number }} if: ${{ !contains(steps.get-labels.outputs.labels, 'R0') }} diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index df785404036e138c78cf1818620dd9db8c30a243..55e67f2799b8f2363ca3d310b5130a610a7c0727 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -16,7 +16,7 @@ jobs: container: image: paritytech/ci-unified:bullseye-1.70.0-2023-05-23-v20230706 steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Cargo fmt run: cargo +nightly fmt --all -- --check diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index d01d78631e19b71cef7f450808ea707b061b8d82..414cc8b07cd4cec146170b298cf733a62d55567b 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -79,7 +79,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 #TODO: this step will be needed when automated triggering will work #this step runs only if the workflow is triggered automatically when new release is published @@ -114,10 +114,11 @@ jobs: if: ${{ inputs.binary == 'polkadot-parachain' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest needs: fetch-artifacts + environment: master steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Get artifacts from cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -237,9 +238,10 @@ jobs: if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} runs-on: ubuntu-latest needs: fetch-latest-debian-package-version + environment: master steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml new file mode 100644 index 0000000000000000000000000000000000000000..dd0783c4e214219166accf840d288a32f0cef7a0 --- /dev/null +++ b/.github/workflows/review-bot.yml @@ -0,0 +1,31 @@ +name: Review PR +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - review_requested + - review_request_removed + - ready_for_review + pull_request_review: + +permissions: + contents: read + +jobs: + review-approvals: + runs-on: ubuntu-latest + steps: + - name: Generate token + id: team_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.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + team-token: ${{ steps.team_token.outputs.token }} + checks-token: ${{ steps.team_token.outputs.token }} diff --git a/.gitignore b/.gitignore index 35e02e706b4261dcac2a3f9c6686245a01de9a8a..7feea8ada5c58d6ae92bafaa8740bca7a448e434 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .env* .idea .local +.lycheecache .vscode .wasm-binaries *.adoc diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10dd69f12a77c27a7d3de083f5063bd9f6a0e931..61451a9c462011369bc7ade4b593347f4a92f9f0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,7 +30,7 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.67" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.69" DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" default: diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 5b53798c403dd3ad82d908f7d7fe32956bcd6838..fefa3739a9ff41bb412379dcf99a8e12033fc994 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -19,12 +19,18 @@ build-linux-stable: RUN_UI_TESTS: 1 script: - time cargo build --locked --profile testnet --features pyroscope,fast-runtime --bin polkadot --bin polkadot-prepare-worker --bin polkadot-execute-worker + - time ROCOCO_EPOCH_DURATION=10 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-10/ + - time ROCOCO_EPOCH_DURATION=100 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-100/ + - time ROCOCO_EPOCH_DURATION=600 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-600/ + - pwd + - ls -alR runtimes # pack artifacts - mkdir -p ./artifacts - VERSION="${CI_COMMIT_REF_NAME}" # will be tag or branch name - mv ./target/testnet/polkadot ./artifacts/. - mv ./target/testnet/polkadot-prepare-worker ./artifacts/. - mv ./target/testnet/polkadot-execute-worker ./artifacts/. + - mv ./runtimes/ ./artifacts/. - pushd artifacts - sha256sum polkadot | tee polkadot.sha256 - shasum -c polkadot.sha256 @@ -85,6 +91,7 @@ build-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -93,7 +100,6 @@ build-rustdoc: - ./crate-docs/ script: # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"` and `--all-features` - # FIXME: return to stable when https://github.com/rust-lang/rust/issues/96937 gets into stable - time cargo doc --features try-runtime,experimental --workspace --no-deps - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 5cc2337bf40978ea704aed262ca2f296e028f645..559ce093cf67a79680a5f0d4711e68c9252ed485 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -30,7 +30,6 @@ cargo-fmt-manifest: - cargo install zepter --locked --version 0.11.0 -q -f --no-default-features && zepter --version - echo "👉 Hello developer! If you see this CI check failing then it means that one of the your changes in a Cargo.toml file introduced ill-formatted or unsorted features. Please take a look at 'docs/STYLE_GUIDE.md#manifest-formatting' to find out more." - zepter format features --check - allow_failure: true # Experimental # FIXME .cargo-deny-licenses: @@ -113,13 +112,16 @@ test-rust-feature-propagation: script: - | export RUST_LOG=remote-ext=debug,runtime=debug - echo "---------- Running try-runtime for ${NETWORK} ----------" - time cargo install --locked --git https://github.com/paritytech/try-runtime-cli --rev a93c9b5abe5d31a4cf1936204f7e5c489184b521 - time cargo build --release --locked -p "$NETWORK"-runtime --features try-runtime + echo "---------- Installing try-runtime-cli ----------" + time cargo install --locked --git https://github.com/paritytech/try-runtime-cli --tag v0.3.0 + echo "---------- Building ${PACKAGE} runtime ----------" + time cargo build --release --locked -p "$PACKAGE" --features try-runtime + echo "---------- Executing `on-runtime-upgrade` for ${NETWORK} ----------" time try-runtime \ - --runtime ./target/release/wbuild/"$NETWORK"-runtime/target/wasm32-unknown-unknown/release/"$NETWORK"_runtime.wasm \ - on-runtime-upgrade --checks=pre-and-post live --uri wss://${NETWORK}-try-runtime-node.parity-chains.parity.io:443 + --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ + on-runtime-upgrade --checks=pre-and-post ${EXTRA_ARGS} live --uri ${URI} +# Check runtime migrations for Parity managed relay chains check-runtime-migration-westend: stage: check extends: @@ -128,19 +130,61 @@ check-runtime-migration-westend: - .check-runtime-migration variables: NETWORK: "westend" + PACKAGE: "westend-runtime" + WASM: "westend_runtime.compact.compressed.wasm" + URI: "wss://westend-try-runtime-node.parity-chains.parity.io:443" + EXTRA_ARGS: "--no-weight-warnings" check-runtime-migration-rococo: stage: check - # DAG - needs: - - job: check-runtime-migration-westend - artifacts: false extends: - .docker-env - .test-pr-refs - .check-runtime-migration variables: NETWORK: "rococo" + PACKAGE: "rococo-runtime" + WASM: "rococo_runtime.compact.compressed.wasm" + URI: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" + 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-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" find-fail-ci-phrase: stage: check diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index 7b7704ee66d8c95248dc2c0e5c432e58c48fee14..6d060077a7c7334ca6d3e50309bfe0d28ca6f9e3 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -5,7 +5,7 @@ # run short-benchmarks for relay chain runtimes from polkadot -short-benchmark-polkadot: &short-bench +short-benchmark-westend: &short-bench stage: short-benchmarks extends: - .docker-env @@ -14,22 +14,18 @@ short-benchmark-polkadot: &short-bench - job: build-short-benchmark artifacts: true variables: - RUNTIME: polkadot + RUNTIME: westend + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" tags: - benchmark script: - ./artifacts/polkadot benchmark pallet --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 -short-benchmark-kusama: - <<: *short-bench - variables: - RUNTIME: kusama - -short-benchmark-westend: - <<: *short-bench - variables: - RUNTIME: westend - # run short-benchmarks for system parachain runtimes from cumulus .short-benchmark-cumulus: &short-bench-cumulus @@ -42,6 +38,12 @@ short-benchmark-westend: artifacts: true variables: RUNTIME_CHAIN: benchmarked-runtime-chain + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" tags: - benchmark script: @@ -57,6 +59,11 @@ short-benchmark-asset-hub-kusama: variables: RUNTIME_CHAIN: asset-hub-kusama-dev +short-benchmark-asset-hub-rococo: + <<: *short-bench-cumulus + variables: + RUNTIME_CHAIN: asset-hub-rococo-dev + short-benchmark-asset-hub-westend: <<: *short-bench-cumulus variables: diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 3a4f5e71247ca33fa1d3655d1f1a01fd0dffb3bf..7d7007acd8a8bba2a266422a096a1901734771f2 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -181,10 +181,8 @@ test-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" script: - time cargo doc --workspace --all-features --no-deps - allow_failure: true cargo-check-all-benches: stage: test @@ -229,12 +227,12 @@ test-deterministic-wasm: artifacts: false script: # build runtime - - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-runtime + - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p westend-runtime -p rococo-runtime # make checksum - sha256sum target/release/wbuild/*-runtime/target/wasm32-unknown-unknown/release/*.wasm > checksum.sha256 - cargo clean # build again - - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p staging-kusama-runtime -p polkadot-runtime -p westend-runtime + - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p westend-runtime -p rococo-runtime # confirm checksum - sha256sum -c checksum.sha256 @@ -314,8 +312,8 @@ node-bench-regression-guard: --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" after_script: [""] -# if this fails (especially after rust version upgrade) run -# ./substrate/.maintain/update-rust-stable.sh +# if this fails run `bot update-ui` in the Pull Request or "./scripts/update-ui-tests.sh" locally +# see ./docs/CONTRIBUTING.md#ui-tests test-frame-ui: stage: test extends: @@ -505,3 +503,23 @@ cargo-hfuzz: - cargo hfuzz build - 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: true # TODO: remove this once we have an idea how often the syscall lists will change diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index c17b7fb58b932e144c0dc6c0216b21ec69c845db..8373331b3d7de14d045df5cdd0b71a1794a58349 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -5,7 +5,7 @@ before_script: - echo "Zombie-net Tests Config" - echo "${ZOMBIENET_IMAGE}" - - echo "${RELAY_IMAGE}" + - echo "${POLKADOT_IMAGE}" - echo "${COL_IMAGE}" - echo "${GH_DIR}" - echo "${LOCAL_DIR}" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index e420baf486aa9bd3fa22c4127f1d773e44b98d8c..0402c194134b78256aaee00999e87c7a18397bf0 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -110,7 +110,7 @@ zombienet-polkadot-smoke-0001-parachains-smoke-test: - .zombienet-polkadot-common before_script: - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - - export COL_IMAGE="docker.io/paritypr/colander:4519" # The collator image is fixed + - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" - echo "local-dir ${LOCAL_DIR}" @@ -127,12 +127,12 @@ zombienet-polkadot-smoke-0002-parachains-parachains-upgrade-smoke: - .zombienet-polkadot-common before_script: - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - - export COL_IMAGE="docker.io/parity/polkadot-collator:latest" # Use cumulus lastest image + - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" - echo "Zombienet Tests Config" - echo "gh-dir ${GH_DIR}" - echo "local-dir ${LOCAL_DIR}" - echo "polkadot image ${ZOMBIENET_INTEGRATION_TEST_IMAGE}" - - echo "colander image ${COL_IMAGE}" + - echo "polkadot-parachain image ${CUMULUS_IMAGE}" - echo "malus image ${MALUS_IMAGE}" script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh @@ -193,27 +193,3 @@ zombienet-polkadot-malus-0001-dispute-valid: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/integrationtests" --test="0001-dispute-valid-block.zndsl" - -zombienet-polkadot-async-backing-compatibility: - extends: - - .zombienet-polkadot-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh - --local-dir="${LOCAL_DIR}/async_backing" - --test="001-async-backing-compatibility.zndsl" - -zombienet-polkadot-async-backing-runtime-upgrade: - extends: - - .zombienet-polkadot-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh - --local-dir="${LOCAL_DIR}/async_backing" - --test="002-async-backing-runtime-upgrade.zndsl" - -zombienet-polkadot-async-backing-collator-mix: - extends: - - .zombienet-polkadot-common - script: - - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh - --local-dir="${LOCAL_DIR}/async_backing" - --test="003-async-backing-collator-mix.zndsl" diff --git a/Cargo.lock b/Cargo.lock index 670d9c9e771c827fb5659a2f53606b7cb2a68910..40b11be0c24e4d898f9f3cc6ee2f0be422532337 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,7 +116,7 @@ dependencies = [ "cipher 0.3.0", "ctr 0.8.0", "ghash 0.4.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -130,7 +130,7 @@ dependencies = [ "cipher 0.4.4", "ctr 0.9.2", "ghash 0.5.0", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", @@ -267,9 +267,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -316,26 +316,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" -[[package]] -name = "ark-algebra-test-templates" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "400bd3a79c741b1832f1416d4373ae077ef82ca14a8b4cee1248a2f11c8b9172" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", - "hex", - "num-bigint", - "num-integer", - "num-traits", - "serde", - "serde_derive", - "serde_json", - "sha2 0.10.7", -] - [[package]] name = "ark-bls12-377" version = "0.4.0" @@ -468,52 +448,24 @@ dependencies = [ "hashbrown 0.13.2", ] -[[package]] -name = "ark-r1cs-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1d1472e5cb020cb3405ce2567c91c8d43f21b674aef37b0202f5c3304761db" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-relations", - "ark-std", - "derivative", - "num-bigint", - "num-integer", - "num-traits", - "tracing", -] - -[[package]] -name = "ark-relations" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" -dependencies = [ - "ark-ff", - "ark-std", - "tracing", - "tracing-subscriber", -] - [[package]] name = "ark-scale" -version = "0.0.10" +version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b08346a3e38e2be792ef53ee168623c9244d968ff00cd70fb9932f6fe36393" +checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" dependencies = [ "ark-ec", "ark-ff", "ark-serialize", "ark-std", "parity-scale-codec", + "scale-info", ] [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" +source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-ec", "ark-ff", @@ -561,7 +513,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" +source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-ff", "ark-serialize", @@ -571,6 +523,12 @@ dependencies = [ "sha3", ] +[[package]] +name = "array-bytes" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" + [[package]] name = "array-bytes" version = "6.1.0" @@ -693,31 +651,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] -name = "asset-hub-kusama-integration-tests" -version = "1.0.0" +name = "asset-hub-kusama-runtime" +version = "0.9.420" dependencies = [ - "assert_matches", - "asset-hub-kusama-runtime", + "asset-test-utils", + "assets-common", + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-benchmarking", + "frame-executive", "frame-support", "frame-system", - "integration-tests-common", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal", + "log", "pallet-asset-conversion", + "pallet-asset-conversion-tx-payment", "pallet-assets", + "pallet-aura", + "pallet-authorship", "pallet-balances", + "pallet-collator-selection", + "pallet-multisig", + "pallet-nft-fractionalization", + "pallet-nfts", + "pallet-nfts-runtime-api", + "pallet-proxy", + "pallet-session", + "pallet-state-trie-migration", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-uniques", + "pallet-utility", "pallet-xcm", + "pallet-xcm-benchmarks", + "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", - "polkadot-runtime-parachains", + "polkadot-runtime-common", + "primitive-types", + "scale-info", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-offchain", "sp-runtime", + "sp-session", + "sp-std", + "sp-storage", + "sp-transaction-pool", + "sp-version", + "sp-weights", "staging-xcm", - "xcm-emulator", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", ] [[package]] -name = "asset-hub-kusama-runtime" +name = "asset-hub-polkadot-runtime" version = "0.9.420" dependencies = [ "asset-test-utils", @@ -738,22 +745,18 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", - "pallet-asset-conversion", - "pallet-asset-conversion-tx-payment", + "pallet-asset-tx-payment", "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collator-selection", "pallet-multisig", - "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-proxy", "pallet-session", - "pallet-state-trie-migration", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -767,13 +770,13 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "primitive-types", "scale-info", "smallvec", "sp-api", "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -790,10 +793,11 @@ dependencies = [ ] [[package]] -name = "asset-hub-polkadot-integration-tests" +name = "asset-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ - "asset-hub-kusama-runtime", + "assert_matches", + "asset-hub-rococo-runtime", "frame-support", "frame-system", "integration-tests-common", @@ -805,7 +809,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", @@ -813,11 +816,15 @@ dependencies = [ ] [[package]] -name = "asset-hub-polkadot-runtime" +name = "asset-hub-rococo-runtime" version = "0.9.420" dependencies = [ "asset-test-utils", "assets-common", + "bp-asset-hub-rococo", + "bp-asset-hub-wococo", + "bp-bridge-hub-rococo", + "bp-bridge-hub-wococo", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -835,17 +842,20 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", - "pallet-asset-tx-payment", + "pallet-asset-conversion", + "pallet-asset-conversion-tx-payment", "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collator-selection", "pallet-multisig", + "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-proxy", "pallet-session", + "pallet-state-trie-migration", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -853,13 +863,15 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub-router", "parachain-info", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", + "primitive-types", + "rococo-runtime-constants", "scale-info", "smallvec", "sp-api", @@ -887,21 +899,27 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-westend-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", "frame-support", "frame-system", "integration-tests-common", "pallet-asset-conversion", + "pallet-asset-rate", "pallet-assets", "pallet-balances", + "pallet-treasury", "pallet-xcm", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", + "polkadot-runtime-common", "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "xcm-emulator", ] @@ -961,6 +979,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -996,6 +1015,7 @@ dependencies = [ "pallet-collator-selection", "pallet-session", "pallet-xcm", + "pallet-xcm-bridge-hub-router", "parachain-info", "parachains-common", "parachains-runtimes-test-utils", @@ -1007,6 +1027,7 @@ dependencies = [ "sp-runtime", "sp-std", "staging-xcm", + "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", ] @@ -1130,17 +1151,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "async-recursion" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.36", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -1160,7 +1170,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -1177,7 +1187,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -1240,7 +1250,7 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" version = "0.0.1" -source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" +source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1316,7 +1326,7 @@ dependencies = [ name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "env_logger 0.9.3", "hash-db", "log", @@ -1351,7 +1361,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -1393,6 +1403,18 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +dependencies = [ + "byte-tools", + "crypto-mac 0.7.0", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + [[package]] name = "blake2" version = "0.10.6" @@ -1560,6 +1582,26 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "bp-asset-hub-rococo" +version = "0.1.0" +dependencies = [ + "bp-xcm-bridge-hub-router", + "frame-support", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "bp-asset-hub-wococo" +version = "0.1.0" +dependencies = [ + "bp-xcm-bridge-hub-router", + "frame-support", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "bp-bridge-hub-cumulus" version = "0.1.0" @@ -1701,6 +1743,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "bp-polkadot-bulletin" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-messages", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + [[package]] name = "bp-polkadot-core" version = "0.1.0" @@ -1832,7 +1891,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-aura", "pallet-authorship", @@ -1859,6 +1917,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -1914,7 +1973,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", "scale-info", "serde", "smallvec", @@ -1922,6 +1980,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -1952,7 +2011,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", - "polkadot-runtime", "polkadot-runtime-parachains", "staging-xcm", "xcm-emulator", @@ -1962,6 +2020,8 @@ dependencies = [ name = "bridge-hub-rococo-runtime" version = "0.1.0" dependencies = [ + "bp-asset-hub-rococo", + "bp-asset-hub-wococo", "bp-bridge-hub-rococo", "bp-bridge-hub-wococo", "bp-header-chain", @@ -2021,6 +2081,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -2042,7 +2103,6 @@ dependencies = [ name = "bridge-hub-test-utils" version = "0.1.0" dependencies = [ - "assert_matches", "asset-test-utils", "bp-bridge-hub-rococo", "bp-bridge-hub-wococo", @@ -2080,6 +2140,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", + "sp-tracing", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2203,6 +2264,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "c2-chacha" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80" +dependencies = [ + "cipher 0.2.5", + "ppv-lite86", +] + [[package]] name = "camino" version = "1.1.6" @@ -2259,7 +2330,7 @@ checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" dependencies = [ "aead 0.3.2", "cipher 0.2.5", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -2292,6 +2363,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862" +dependencies = [ + "byteorder", + "keystream", +] + [[package]] name = "chacha20" version = "0.8.2" @@ -2333,7 +2414,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.4.3", + "clap 4.4.6", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -2463,9 +2544,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.3" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", "clap_derive 4.4.2", @@ -2473,9 +2554,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", @@ -2489,7 +2570,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", ] [[package]] @@ -2514,7 +2595,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -2554,31 +2635,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "collectives-polkadot-integration-tests" -version = "0.1.0" -dependencies = [ - "collectives-polkadot-runtime", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "frame-support", - "integration-tests-common", - "pallet-assets", - "pallet-core-fellowship", - "pallet-salary", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime", - "polkadot-runtime-parachains", - "sp-core", - "sp-runtime", - "staging-xcm", - "xcm-emulator", -] - [[package]] name = "collectives-polkadot-runtime" version = "1.0.0" @@ -2606,6 +2662,7 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "pallet-collective", + "pallet-collective-content", "pallet-core-fellowship", "pallet-multisig", "pallet-preimage", @@ -2626,7 +2683,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-common", - "polkadot-runtime-constants", "scale-info", "smallvec", "sp-api", @@ -2634,6 +2690,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-offchain", @@ -2703,7 +2760,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895" +source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" dependencies = [ "ark-ec", "ark-ff", @@ -2815,7 +2872,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-aura", "pallet-authorship", @@ -2844,6 +2900,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -3085,7 +3142,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.3", + "clap 4.4.6", "criterion-plot", "futures", "is-terminal", @@ -3181,7 +3238,7 @@ checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3193,7 +3250,7 @@ checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -3208,6 +3265,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array 0.12.4", + "subtle 1.0.0", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -3215,7 +3282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -3225,7 +3292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ "generic-array 0.14.7", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -3250,7 +3317,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3574,7 +3641,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -3624,6 +3691,7 @@ dependencies = [ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" dependencies = [ + "bp-xcm-bridge-hub-router", "cumulus-pallet-parachain-system", "cumulus-primitives-core", "frame-benchmarking", @@ -3788,7 +3856,7 @@ dependencies = [ name = "cumulus-relay-chain-minimal-node" version = "0.1.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-trait", "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -3935,7 +4003,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.3", + "clap 4.4.6", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4015,7 +4083,7 @@ dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4028,7 +4096,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4045,7 +4113,7 @@ dependencies = [ "fiat-crypto", "platforms", "rustc_version 0.4.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4057,7 +4125,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4097,7 +4165,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4114,7 +4182,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4360,14 +4428,14 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle", + "subtle 2.4.1", ] [[package]] name = "directories" -version = "4.0.1" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ "dirs-sys", ] @@ -4384,13 +4452,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -4412,7 +4481,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4424,7 +4493,7 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=f4fe253#f4fe2534ccc6d916cd10d9c16891e673728ec8b4" +source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-ec", "ark-ff", @@ -4455,18 +4524,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff509d6aa8e7ca86b36eb3d593132e64204597de3ccb763ffd8bfd2264d54cf3" +checksum = "76ee528c501ddd15d5181997e9518e59024844eac44fd1e40cb20ddb2a8562fa" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b135598b950330937f3a0ddfbe908106ee2ecd5fa95d8ae7952a3c3863efe8da" +checksum = "0ca01728ab2679c464242eca99f94e2ce0514b52ac9ad950e2ed03fca991231c" dependencies = [ "common-path", "derive-syn-parse", @@ -4474,7 +4543,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.36", + "syn 2.0.38", "termcolor", "toml 0.7.6", "walkdir", @@ -4628,7 +4697,7 @@ dependencies = [ "pkcs8 0.9.0", "rand_core 0.6.4", "sec1 0.3.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4647,7 +4716,7 @@ dependencies = [ "pkcs8 0.10.2", "rand_core 0.6.4", "sec1 0.7.3", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -4695,7 +4764,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4706,7 +4775,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4847,11 +4916,11 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" dependencies = [ - "blake2", + "blake2 0.10.6", "fs-err", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -4948,7 +5017,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -4958,7 +5027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -5107,11 +5176,19 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +[[package]] +name = "frame" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", +] + [[package]] name = "frame-benchmarking" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-support", "frame-support-procedural", "frame-system", @@ -5139,9 +5216,9 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" dependencies = [ "Inflector", - "array-bytes", + "array-bytes 6.1.0", "chrono", - "clap 4.4.3", + "clap 4.4.6", "comfy-table", "frame-benchmarking", "frame-support", @@ -5207,7 +5284,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.36", + "syn 2.0.38", "trybuild", ] @@ -5233,7 +5310,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5250,7 +5327,7 @@ dependencies = [ name = "frame-executive" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-support", "frame-system", "frame-try-runtime", @@ -5284,7 +5361,6 @@ dependencies = [ name = "frame-remote-externalities" version = "0.10.0-dev" dependencies = [ - "async-recursion", "futures", "indicatif", "jsonrpsee", @@ -5307,7 +5383,7 @@ name = "frame-support" version = "4.0.0-dev" dependencies = [ "aquamarine", - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", "docify", @@ -5359,7 +5435,8 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.36", + "sp-core-hashing", + "syn 2.0.38", ] [[package]] @@ -5370,7 +5447,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -5379,7 +5456,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -5435,6 +5512,15 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "frame-support-test-stg-frame-crate" +version = "0.1.0" +dependencies = [ + "frame", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "frame-system" version = "4.0.0-dev" @@ -5602,7 +5688,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -5722,10 +5808,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -5791,6 +5875,7 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-timestamp", "frame-benchmarking", @@ -5812,6 +5897,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -5834,7 +5920,7 @@ checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -5845,7 +5931,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", "rand_core 0.6.4", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -5931,6 +6017,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.0", +] + [[package]] name = "heck" version = "0.4.1" @@ -6355,6 +6450,7 @@ version = "1.0.0" dependencies = [ "asset-hub-kusama-runtime", "asset-hub-polkadot-runtime", + "asset-hub-rococo-runtime", "asset-hub-westend-runtime", "bp-messages", "bridge-hub-kusama-runtime", @@ -6367,8 +6463,8 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "frame-support", - "kusama-runtime-constants", "pallet-assets", + "pallet-balances", "pallet-bridge-messages", "pallet-im-online", "pallet-message-queue", @@ -6381,8 +6477,6 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", - "polkadot-runtime", - "polkadot-runtime-constants", "polkadot-runtime-parachains", "polkadot-service", "rococo-runtime", @@ -6393,7 +6487,6 @@ dependencies = [ "sp-consensus-beefy", "sp-core", "sp-runtime", - "staging-kusama-runtime", "staging-xcm", "westend-runtime", "westend-runtime-constants", @@ -6710,6 +6803,12 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "keystream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" + [[package]] name = "kitchensink-runtime" version = "3.0.0-dev" @@ -6758,6 +6857,7 @@ dependencies = [ "pallet-lottery", "pallet-membership", "pallet-message-queue", + "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", @@ -6808,8 +6908,10 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-grandpa", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", + "sp-mixnet", "sp-offchain", "sp-runtime", "sp-session", @@ -6823,19 +6925,6 @@ dependencies = [ "substrate-wasm-builder", ] -[[package]] -name = "kusama-runtime-constants" -version = "1.0.0" -dependencies = [ - "frame-support", - "polkadot-primitives", - "polkadot-runtime-common", - "smallvec", - "sp-core", - "sp-runtime", - "sp-weights", -] - [[package]] name = "kvdb" version = "0.13.0" @@ -6880,9 +6969,9 @@ dependencies = [ [[package]] name = "landlock" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520baa32708c4e957d2fc3a186bc5bd8d26637c33137f399ddfc202adb240068" +checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc" dependencies = [ "enumflags2", "libc", @@ -7425,7 +7514,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -7508,6 +7597,18 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +[[package]] +name = "lioness" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9" +dependencies = [ + "arrayref", + "blake2 0.8.1", + "chacha", + "keystream", +] + [[package]] name = "lite-json" version = "0.2.0" @@ -7610,50 +7711,50 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee866bfee30d2d7e83835a4574aad5b45adba4cc807f2a3bbba974e5d4383c9" +checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d" dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "macro_magic_core" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e766a20fd9c72bab3e1e64ed63f36bd08410e75803813df210d1ce297d7ad00" +checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "macro_magic_core_macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" +checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "macro_magic_macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" +checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -7838,6 +7939,31 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mixnet" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "bitflags 1.3.2", + "blake2 0.10.6", + "c2-chacha", + "curve25519-dalek 4.0.0", + "either", + "hashlink", + "lioness", + "log", + "parking_lot 0.12.1", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_distr", + "subtle 2.4.1", + "thiserror", + "zeroize", +] + [[package]] name = "mmr-gadget" version = "4.0.0-dev" @@ -8139,8 +8265,8 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes", - "clap 4.4.3", + "array-bytes 6.1.0", + "clap 4.4.6", "derive_more", "fs_extra", "futures", @@ -8175,9 +8301,9 @@ dependencies = [ name = "node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_cmd", - "clap 4.4.3", + "clap 4.4.6", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -8216,6 +8342,7 @@ dependencies = [ "sc-consensus-slots", "sc-executor", "sc-keystore", + "sc-mixnet", "sc-network", "sc-network-common", "sc-network-statement", @@ -8245,6 +8372,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-keystore", + "sp-mixnet", "sp-runtime", "sp-statement-store", "sp-timestamp", @@ -8303,7 +8431,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -8336,6 +8464,7 @@ dependencies = [ "sc-consensus-babe-rpc", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", + "sc-mixnet", "sc-rpc", "sc-rpc-api", "sc-rpc-spec-v2", @@ -8357,7 +8486,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "generate-bags", "kitchensink-runtime", ] @@ -8366,7 +8495,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8409,7 +8538,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "flate2", "fs_extra", "glob", @@ -8445,6 +8574,7 @@ dependencies = [ "sp-consensus-aura", "sp-consensus-grandpa", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -8692,6 +8822,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orchestra" version = "0.3.3" @@ -8775,7 +8911,7 @@ dependencies = [ name = "pallet-alliance" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-benchmarking", "frame-support", "frame-system", @@ -9078,7 +9214,7 @@ dependencies = [ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "binary-merkle-tree", "frame-support", "frame-system", @@ -9282,11 +9418,26 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-collective-content" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-contracts" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", "env_logger 0.9.3", @@ -9339,7 +9490,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -9620,7 +9771,7 @@ dependencies = [ name = "pallet-glutton" version = "4.0.0-dev" dependencies = [ - "blake2", + "blake2 0.10.6", "frame-benchmarking", "frame-support", "frame-system", @@ -9788,11 +9939,30 @@ dependencies = [ "sp-weights", ] +[[package]] +name = "pallet-mixnet" +version = "0.1.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-io", + "sp-mixnet", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "env_logger 0.9.3", "frame-benchmarking", "frame-support", @@ -10410,7 +10580,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -10590,7 +10760,7 @@ dependencies = [ name = "pallet-transaction-storage" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-benchmarking", "frame-support", "frame-system", @@ -10611,6 +10781,7 @@ dependencies = [ name = "pallet-treasury" version = "4.0.0-dev" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10800,7 +10971,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -10895,6 +11066,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -10916,7 +11088,6 @@ dependencies = [ "cumulus-primitives-utility", "frame-support", "frame-system", - "kusama-runtime-constants", "log", "num-traits", "pallet-asset-tx-payment", @@ -10927,7 +11098,6 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", - "polkadot-runtime-constants", "rococo-runtime-constants", "scale-info", "smallvec", @@ -10938,7 +11108,6 @@ dependencies = [ "sp-std", "staging-xcm", "staging-xcm-builder", - "staging-xcm-executor", "substrate-wasm-builder", "westend-runtime-constants", ] @@ -10983,7 +11152,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78f19d20a0d2cc52327a88d131fa1c4ea81ea4a04714aedcfeca2dd410049cf8" dependencies = [ - "blake2", + "blake2 0.10.6", "crc32fast", "fs2", "hex", @@ -11227,6 +11396,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -11277,7 +11447,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -11318,7 +11488,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -11508,6 +11678,7 @@ name = "polkadot-availability-recovery" version = "1.0.0" dependencies = [ "assert_matches", + "async-trait", "env_logger 0.9.3", "fatality", "futures", @@ -11536,12 +11707,12 @@ dependencies = [ name = "polkadot-cli" version = "1.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "frame-benchmarking-cli", "futures", "log", "polkadot-node-metrics", - "polkadot-performance-test", + "polkadot-node-primitives", "polkadot-service", "pyroscope", "pyroscope_pprofrs", @@ -11997,6 +12168,7 @@ version = "1.0.0" dependencies = [ "always-assert", "assert_matches", + "cfg-if", "futures", "futures-timer", "hex-literal", @@ -12053,6 +12225,7 @@ name = "polkadot-node-core-pvf-common" version = "1.0.0" dependencies = [ "assert_matches", + "cfg-if", "cpu-time", "futures", "landlock", @@ -12094,6 +12267,7 @@ dependencies = [ name = "polkadot-node-core-pvf-prepare-worker" version = "1.0.0" dependencies = [ + "cfg-if", "futures", "libc", "parity-scale-codec", @@ -12351,12 +12525,13 @@ dependencies = [ "assert_cmd", "asset-hub-kusama-runtime", "asset-hub-polkadot-runtime", + "asset-hub-rococo-runtime", "asset-hub-westend-runtime", "async-trait", "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.4.3", + "clap 4.4.6", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -12367,6 +12542,7 @@ dependencies = [ "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-service", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-relay-chain-interface", @@ -12443,23 +12619,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "polkadot-performance-test" -version = "1.0.0" -dependencies = [ - "env_logger 0.9.3", - "log", - "polkadot-erasure-coding", - "polkadot-node-core-pvf-prepare-worker", - "polkadot-node-primitives", - "polkadot-primitives", - "quote", - "sc-executor-common", - "sp-maybe-compressed-blob", - "staging-kusama-runtime", - "thiserror", -] - [[package]] name = "polkadot-primitives" version = "1.0.0" @@ -12528,110 +12687,6 @@ dependencies = [ "substrate-state-trie-migration-rpc", ] -[[package]] -name = "polkadot-runtime" -version = "1.0.0" -dependencies = [ - "bitvec", - "frame-benchmarking", - "frame-election-provider-support", - "frame-executive", - "frame-remote-externalities", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-bounties", - "pallet-child-bounties", - "pallet-collective", - "pallet-conviction-voting", - "pallet-democracy", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-fast-unstake", - "pallet-grandpa", - "pallet-identity", - "pallet-im-online", - "pallet-indices", - "pallet-membership", - "pallet-message-queue", - "pallet-multisig", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-preimage", - "pallet-proxy", - "pallet-referenda", - "pallet-scheduler", - "pallet-session", - "pallet-session-benchmarking", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-staking-runtime-api", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parity-scale-codec", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-constants", - "polkadot-runtime-parachains", - "rustc-hex", - "scale-info", - "separator", - "serde", - "serde_derive", - "serde_json", - "smallvec", - "sp-api", - "sp-arithmetic", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core", - "sp-inherents", - "sp-io", - "sp-keyring", - "sp-mmr-primitives", - "sp-npos-elections", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-staking", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-transaction-pool", - "sp-trie", - "sp-version", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "static_assertions", - "substrate-wasm-builder", - "tiny-keccak", - "tokio", -] - [[package]] name = "polkadot-runtime-common" version = "1.0.0" @@ -12646,6 +12701,7 @@ dependencies = [ "impl-trait-for-tuples", "libsecp256k1", "log", + "pallet-asset-rate", "pallet-authorship", "pallet-babe", "pallet-balances", @@ -12679,21 +12735,9 @@ dependencies = [ "sp-session", "sp-staking", "sp-std", - "staging-xcm", - "static_assertions", -] - -[[package]] -name = "polkadot-runtime-constants" -version = "1.0.0" -dependencies = [ - "frame-support", - "polkadot-primitives", - "polkadot-runtime-common", - "smallvec", - "sp-core", - "sp-runtime", - "sp-weights", + "staging-xcm", + "staging-xcm-builder", + "static_assertions", ] [[package]] @@ -12779,7 +12823,6 @@ dependencies = [ "futures", "hex-literal", "is_executable", - "kusama-runtime-constants", "kvdb", "kvdb-rocksdb", "log", @@ -12825,9 +12868,6 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-rpc", - "polkadot-runtime", - "polkadot-runtime-common", - "polkadot-runtime-constants", "polkadot-runtime-parachains", "polkadot-statement-distribution", "polkadot-test-client", @@ -12883,7 +12923,6 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", - "staging-kusama-runtime", "substrate-prometheus-endpoint", "tempfile", "thiserror", @@ -12971,7 +13010,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.3", + "clap 4.4.6", "color-eyre", "futures", "futures-timer", @@ -13041,6 +13080,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -13117,11 +13157,9 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "generate-bags", - "polkadot-runtime", "sp-io", - "staging-kusama-runtime", "westend-runtime", ] @@ -13297,7 +13335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -13373,20 +13411,20 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro-warning" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" +checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" dependencies = [ "unicode-ident", ] @@ -13425,7 +13463,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -13816,7 +13854,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -13879,16 +13917,12 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "frame-system", - "kusama-runtime-constants", "log", "pallet-bags-list-remote-tests", - "polkadot-runtime", - "polkadot-runtime-constants", "sp-core", "sp-tracing", - "staging-kusama-runtime", "tokio", "westend-runtime", "westend-runtime-constants", @@ -13961,20 +13995,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle", + "subtle 2.4.1", ] [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof?rev=8657210#86572101f4210647984ab4efedba6b3fcc890895" +source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" dependencies = [ "ark-ec", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "blake2", + "blake2 0.10.6", "common", "fflonk", "merlin 3.0.0", @@ -14055,6 +14089,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -14083,6 +14118,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-rate", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", @@ -14092,6 +14128,7 @@ dependencies = [ "pallet-bounties", "pallet-child-bounties", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-elections-phragmen", "pallet-grandpa", @@ -14106,7 +14143,9 @@ dependencies = [ "pallet-offences", "pallet-preimage", "pallet-proxy", + "pallet-ranked-collective", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-society", @@ -14120,6 +14159,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", @@ -14135,11 +14175,13 @@ dependencies = [ "serde_json", "smallvec", "sp-api", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -14579,16 +14621,16 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "sc-cli" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "chrono", - "clap 4.4.3", + "clap 4.4.6", "fdlimit", "futures", "futures-timer", @@ -14602,6 +14644,7 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-keystore", + "sc-mixnet", "sc-network", "sc-service", "sc-telemetry", @@ -14656,7 +14699,7 @@ dependencies = [ name = "sc-client-db" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", "kitchensink-runtime", @@ -14821,7 +14864,7 @@ dependencies = [ name = "sc-consensus-beefy" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "async-trait", "fnv", @@ -14897,7 +14940,7 @@ name = "sc-consensus-grandpa" version = "0.10.0-dev" dependencies = [ "ahash 0.8.3", - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "async-trait", "dyn-clone", @@ -15052,7 +15095,7 @@ dependencies = [ name = "sc-executor" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "criterion 0.4.0", "env_logger 0.9.3", @@ -15139,7 +15182,7 @@ dependencies = [ name = "sc-keystore" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "parking_lot 0.12.1", "serde_json", "sp-application-crypto", @@ -15149,11 +15192,38 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sc-mixnet" +version = "0.1.0-dev" +dependencies = [ + "array-bytes 4.2.0", + "arrayvec 0.7.4", + "blake2 0.10.6", + "futures", + "futures-timer", + "libp2p-identity", + "log", + "mixnet", + "multiaddr", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-network", + "sc-transaction-pool-api", + "sp-api", + "sp-consensus", + "sp-core", + "sp-keystore", + "sp-mixnet", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-network" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "async-channel", "async-trait", @@ -15268,7 +15338,7 @@ dependencies = [ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "futures", "libp2p-identity", @@ -15288,7 +15358,7 @@ dependencies = [ name = "sc-network-statement" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "futures", "libp2p", @@ -15305,7 +15375,7 @@ dependencies = [ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "async-trait", "fork-tree", @@ -15338,6 +15408,7 @@ dependencies = [ "substrate-test-runtime-client", "thiserror", "tokio", + "tokio-stream", ] [[package]] @@ -15374,7 +15445,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "futures", "libp2p", "log", @@ -15391,7 +15462,7 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "bytes", "fnv", "futures", @@ -15451,6 +15522,7 @@ dependencies = [ "sc-block-builder", "sc-chain-spec", "sc-client-api", + "sc-mixnet", "sc-network", "sc-network-common", "sc-rpc-api", @@ -15482,6 +15554,7 @@ dependencies = [ "jsonrpsee", "parity-scale-codec", "sc-chain-spec", + "sc-mixnet", "sc-transaction-pool-api", "scale-info", "serde", @@ -15511,7 +15584,7 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.10.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "futures", "futures-util", @@ -15624,7 +15697,7 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-channel", "fdlimit", "futures", @@ -15690,7 +15763,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "fs4", "log", "sc-client-db", @@ -15790,14 +15863,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "async-trait", "criterion 0.4.0", @@ -15917,7 +15990,7 @@ dependencies = [ "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -15991,7 +16064,7 @@ dependencies = [ "der 0.6.1", "generic-array 0.14.7", "pkcs8 0.9.0", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -16005,7 +16078,7 @@ dependencies = [ "der 0.7.8", "generic-array 0.14.7", "pkcs8 0.10.2", - "subtle", + "subtle 2.4.1", "zeroize", ] @@ -16083,6 +16156,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -16149,7 +16223,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -16215,7 +16289,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -16330,6 +16404,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-offchain", "sp-runtime", @@ -16568,14 +16643,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" dependencies = [ "aes-gcm 0.9.4", - "blake2", + "blake2 0.10.6", "chacha20poly1305", "curve25519-dalek 4.0.0", "rand_core 0.6.4", "ring 0.16.20", "rustc_version 0.4.0", "sha2 0.10.7", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -16642,12 +16717,12 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "assert_matches", - "blake2", + "blake2 0.10.6", "expander 2.0.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -16724,100 +16799,6 @@ dependencies = [ "sp-arithmetic", ] -[[package]] -name = "sp-ark-bls12-377" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b60ba7d8fbb82e21f5be499b02438c9a79365acb441a4dc3993179f09c4cc9" -dependencies = [ - "ark-bls12-377", - "ark-ff", - "ark-r1cs-std", - "ark-scale", - "ark-std", - "parity-scale-codec", - "sp-ark-models", -] - -[[package]] -name = "sp-ark-bls12-381" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2cd101171d2e988a4e1b2320ad3f26f8746a263110c7153213fe86293e0552b" -dependencies = [ - "ark-bls12-381", - "ark-ff", - "ark-scale", - "ark-serialize", - "ark-std", - "parity-scale-codec", - "sp-ark-models", -] - -[[package]] -name = "sp-ark-bw6-761" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d94d66ba98893cc42dfe81d5b5dee9142577176bdbdba80ec25a37d8cdffdbd5" -dependencies = [ - "ark-bw6-761", - "ark-ff", - "ark-scale", - "ark-std", - "parity-scale-codec", - "sp-ark-models", -] - -[[package]] -name = "sp-ark-ed-on-bls12-377" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37f6ea96c9b1cd4cbd05d741225ff7f6328ab035bda16cf3fac105c87ad98959" -dependencies = [ - "ark-ed-on-bls12-377", - "ark-ff", - "ark-r1cs-std", - "ark-scale", - "ark-serialize", - "ark-std", - "parity-scale-codec", - "sp-ark-models", -] - -[[package]] -name = "sp-ark-ed-on-bls12-381-bandersnatch" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db7a801260397cd58077befcee87acfdde8c189f48718bba1bc3783c799b67b" -dependencies = [ - "ark-ec", - "ark-ed-on-bls12-381-bandersnatch", - "ark-ff", - "ark-r1cs-std", - "ark-scale", - "ark-std", - "parity-scale-codec", - "sp-ark-bls12-381", - "sp-ark-models", -] - -[[package]] -name = "sp-ark-models" -version = "0.4.1-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd77599e09f12893739e1ef822ae065f2f46c3be040ba1979bb786ae21059f44" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "getrandom 0.2.10", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" @@ -16910,7 +16891,7 @@ dependencies = [ name = "sp-consensus-beefy" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "lazy_static", "parity-scale-codec", "scale-info", @@ -16984,10 +16965,10 @@ dependencies = [ name = "sp-core" version = "21.0.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "bandersnatch_vrfs", "bitflags 1.3.2", - "blake2", + "blake2 0.10.6", "bounded-collections", "bs58 0.5.0", "criterion 0.4.0", @@ -17047,32 +17028,20 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] name = "sp-crypto-ec-utils" version = "0.4.0" dependencies = [ - "ark-algebra-test-templates", "ark-bls12-377", "ark-bls12-381", "ark-bw6-761", "ark-ec", "ark-ed-on-bls12-377", "ark-ed-on-bls12-381-bandersnatch", - "ark-ff", "ark-scale", - "ark-serialize", - "ark-std", - "parity-scale-codec", - "sp-ark-bls12-377", - "sp-ark-bls12-381", - "sp-ark-bw6-761", - "sp-ark-ed-on-bls12-377", - "sp-ark-ed-on-bls12-381-bandersnatch", - "sp-ark-models", - "sp-io", "sp-runtime-interface", "sp-std", ] @@ -17091,7 +17060,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -17192,11 +17161,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-mixnet" +version = "0.1.0-dev" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-std", +] + [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "ckb-merkle-mountain-range", "log", "parity-scale-codec", @@ -17229,7 +17209,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17322,7 +17302,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -17394,7 +17374,7 @@ dependencies = [ name = "sp-state-machine" version = "0.28.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "assert_matches", "hash-db", "log", @@ -17516,7 +17496,7 @@ name = "sp-trie" version = "22.0.0" dependencies = [ "ahash 0.8.3", - "array-bytes", + "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", "hashbrown 0.13.2", @@ -17562,7 +17542,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -17655,119 +17635,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "staging-kusama-runtime" -version = "1.0.0" -dependencies = [ - "binary-merkle-tree", - "bitvec", - "frame-benchmarking", - "frame-election-provider-support", - "frame-executive", - "frame-remote-externalities", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "kusama-runtime-constants", - "log", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-beefy", - "pallet-beefy-mmr", - "pallet-bounties", - "pallet-child-bounties", - "pallet-collective", - "pallet-conviction-voting", - "pallet-democracy", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-fast-unstake", - "pallet-grandpa", - "pallet-identity", - "pallet-im-online", - "pallet-indices", - "pallet-membership", - "pallet-message-queue", - "pallet-mmr", - "pallet-multisig", - "pallet-nis", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-recovery", - "pallet-referenda", - "pallet-scheduler", - "pallet-session", - "pallet-session-benchmarking", - "pallet-society", - "pallet-staking", - "pallet-staking-runtime-api", - "pallet-state-trie-migration", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parity-scale-codec", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-parachains", - "rustc-hex", - "scale-info", - "separator", - "serde", - "serde_derive", - "serde_json", - "smallvec", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core", - "sp-inherents", - "sp-io", - "sp-keyring", - "sp-mmr-primitives", - "sp-npos-elections", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-staking", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-transaction-pool", - "sp-trie", - "sp-version", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "static_assertions", - "substrate-wasm-builder", - "tiny-keccak", - "tokio", -] - [[package]] name = "staging-xcm" version = "1.0.0" @@ -17935,7 +17802,7 @@ dependencies = [ "md-5", "rand 0.8.5", "ring 0.16.20", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "url", @@ -17946,8 +17813,27 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", + "sc-cli", +] + +[[package]] +name = "substrate" +version = "1.0.0" +dependencies = [ + "aquamarine", + "chain-spec-builder", + "frame-support", "sc-cli", + "sc-consensus-aura", + "sc-consensus-babe", + "sc-consensus-beefy", + "sc-consensus-grandpa", + "sc-consensus-manual-seal", + "sc-consensus-pow", + "sc-service", + "sp-runtime", + "subkey", ] [[package]] @@ -17988,7 +17874,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "frame-support", "frame-system", "sc-cli", @@ -18082,7 +17968,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "async-trait", "futures", "parity-scale-codec", @@ -18107,7 +17993,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes", + "array-bytes 6.1.0", "frame-executive", "frame-support", "frame-system", @@ -18221,6 +18107,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + [[package]] name = "subtle" version = "2.4.1" @@ -18337,9 +18229,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.36" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -18447,7 +18339,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -18495,7 +18387,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.3", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -18584,7 +18476,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -18764,7 +18656,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -18945,7 +18837,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -18988,7 +18880,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -19141,7 +19033,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.3", + "clap 4.4.6", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -19312,7 +19204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array 0.14.7", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -19322,7 +19214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle", + "subtle 2.4.1", ] [[package]] @@ -19537,7 +19429,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -19571,7 +19463,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -20071,7 +19963,7 @@ dependencies = [ "sha1", "sha2 0.10.7", "signature 1.6.4", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "webpki 0.21.4", @@ -20165,7 +20057,7 @@ dependencies = [ "rtcp", "rtp", "sha-1 0.9.8", - "subtle", + "subtle 2.4.1", "thiserror", "tokio", "webrtc-util", @@ -20209,6 +20101,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-rate", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", @@ -20217,6 +20110,7 @@ dependencies = [ "pallet-beefy", "pallet-beefy-mmr", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", @@ -20238,6 +20132,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -20253,6 +20148,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec", @@ -20268,11 +20164,13 @@ dependencies = [ "smallvec", "sp-api", "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", "sp-core", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", @@ -20707,7 +20605,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] @@ -20826,7 +20724,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.36", + "syn 2.0.38", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d1078e3c86a82a3129e2d8cb2bf965fdbf0f36d5..c98fe6d1a3acf82794792ddd321ac1745229cfa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ members = [ "bridges/modules/xcm-bridge-hub-router", "bridges/primitives/chain-asset-hub-kusama", "bridges/primitives/chain-asset-hub-polkadot", + "bridges/primitives/chain-asset-hub-rococo", + "bridges/primitives/chain-asset-hub-wococo", "bridges/primitives/chain-bridge-hub-cumulus", "bridges/primitives/chain-bridge-hub-kusama", "bridges/primitives/chain-bridge-hub-polkadot", @@ -23,6 +25,7 @@ members = [ "bridges/primitives/chain-bridge-hub-wococo", "bridges/primitives/chain-kusama", "bridges/primitives/chain-polkadot", + "bridges/primitives/chain-polkadot-bulletin", "bridges/primitives/chain-rococo", "bridges/primitives/chain-wococo", "bridges/primitives/header-chain", @@ -59,16 +62,16 @@ members = [ "cumulus/parachain-template/pallets/template", "cumulus/parachain-template/runtime", "cumulus/parachains/common", - "cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama", - "cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot", + "cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo", "cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo", - "cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot", "cumulus/parachains/integration-tests/emulated/common", + "cumulus/parachains/pallets/collective-content", "cumulus/parachains/pallets/parachain-info", "cumulus/parachains/pallets/ping", "cumulus/parachains/runtimes/assets/asset-hub-kusama", "cumulus/parachains/runtimes/assets/asset-hub-polkadot", + "cumulus/parachains/runtimes/assets/asset-hub-rococo", "cumulus/parachains/runtimes/assets/asset-hub-westend", "cumulus/parachains/runtimes/assets/common", "cumulus/parachains/runtimes/assets/test-utils", @@ -112,11 +115,11 @@ members = [ "polkadot/node/core/parachains-inherent", "polkadot/node/core/prospective-parachains", "polkadot/node/core/provisioner", + "polkadot/node/core/pvf-checker", "polkadot/node/core/pvf", "polkadot/node/core/pvf/common", "polkadot/node/core/pvf/execute-worker", "polkadot/node/core/pvf/prepare-worker", - "polkadot/node/core/pvf-checker", "polkadot/node/core/runtime-api", "polkadot/node/gum", "polkadot/node/gum/proc-macro", @@ -136,12 +139,11 @@ members = [ "polkadot/node/overseer", "polkadot/node/primitives", "polkadot/node/service", - "polkadot/node/subsystem", "polkadot/node/subsystem-test-helpers", "polkadot/node/subsystem-types", "polkadot/node/subsystem-util", + "polkadot/node/subsystem", "polkadot/node/test/client", - "polkadot/node/test/performance-test", "polkadot/node/test/service", "polkadot/node/zombienet-backchannel", "polkadot/parachain", @@ -156,12 +158,8 @@ members = [ "polkadot/rpc", "polkadot/runtime/common", "polkadot/runtime/common/slot_range_helper", - "polkadot/runtime/kusama", - "polkadot/runtime/kusama/constants", "polkadot/runtime/metrics", "polkadot/runtime/parachains", - "polkadot/runtime/polkadot", - "polkadot/runtime/polkadot/constants", "polkadot/runtime/rococo", "polkadot/runtime/rococo/constants", "polkadot/runtime/test-runtime", @@ -172,8 +170,8 @@ members = [ "polkadot/utils/generate-bags", "polkadot/utils/remote-ext-tests/bags-list", "polkadot/xcm", - "polkadot/xcm/pallet-xcm", "polkadot/xcm/pallet-xcm-benchmarks", + "polkadot/xcm/pallet-xcm", "polkadot/xcm/procedural", "polkadot/xcm/xcm-builder", "polkadot/xcm/xcm-executor", @@ -181,6 +179,10 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", + "substrate", + "substrate/bin/node-template/node", + "substrate/bin/node-template/pallets/template", + "substrate/bin/node-template/runtime", "substrate/bin/node/bench", "substrate/bin/node/cli", "substrate/bin/node/executor", @@ -189,9 +191,6 @@ members = [ "substrate/bin/node/rpc", "substrate/bin/node/runtime", "substrate/bin/node/testing", - "substrate/bin/node-template/node", - "substrate/bin/node-template/pallets/template", - "substrate/bin/node-template/runtime", "substrate/bin/utils/chain-spec-builder", "substrate/bin/utils/subkey", "substrate/client/allocator", @@ -223,6 +222,8 @@ members = [ "substrate/client/keystore", "substrate/client/merkle-mountain-range", "substrate/client/merkle-mountain-range/rpc", + "substrate/client/mixnet", + "substrate/client/network-gossip", "substrate/client/network", "substrate/client/network/bitswap", "substrate/client/network/common", @@ -231,13 +232,12 @@ members = [ "substrate/client/network/sync", "substrate/client/network/test", "substrate/client/network/transactions", - "substrate/client/network-gossip", "substrate/client/offchain", "substrate/client/proposer-metrics", - "substrate/client/rpc", "substrate/client/rpc-api", "substrate/client/rpc-servers", "substrate/client/rpc-spec-v2", + "substrate/client/rpc", "substrate/client/service", "substrate/client/service/test", "substrate/client/state-db", @@ -264,8 +264,8 @@ members = [ "substrate/frame/bags-list/fuzzer", "substrate/frame/bags-list/remote-tests", "substrate/frame/balances", - "substrate/frame/beefy", "substrate/frame/beefy-mmr", + "substrate/frame/beefy", "substrate/frame/benchmarking", "substrate/frame/benchmarking/pov", "substrate/frame/bounties", @@ -304,6 +304,7 @@ members = [ "substrate/frame/membership", "substrate/frame/merkle-mountain-range", "substrate/frame/message-queue", + "substrate/frame/mixnet", "substrate/frame/multisig", "substrate/frame/nft-fractionalization", "substrate/frame/nfts", @@ -349,6 +350,8 @@ members = [ "substrate/frame/support/test", "substrate/frame/support/test/compile_pass", "substrate/frame/support/test/pallet", + "substrate/frame/support/test/stg_frame_crate/frame", + "substrate/frame/support/test/stg_frame_crate", "substrate/frame/system", "substrate/frame/system/benchmarking", "substrate/frame/system/rpc/runtime-api", @@ -400,17 +403,18 @@ members = [ "substrate/primitives/maybe-compressed-blob", "substrate/primitives/merkle-mountain-range", "substrate/primitives/metadata-ir", + "substrate/primitives/mixnet", "substrate/primitives/npos-elections", "substrate/primitives/npos-elections/fuzzer", "substrate/primitives/offchain", "substrate/primitives/panic-handler", "substrate/primitives/rpc", - "substrate/primitives/runtime", "substrate/primitives/runtime-interface", "substrate/primitives/runtime-interface/proc-macro", - "substrate/primitives/runtime-interface/test", - "substrate/primitives/runtime-interface/test-wasm", "substrate/primitives/runtime-interface/test-wasm-deprecated", + "substrate/primitives/runtime-interface/test-wasm", + "substrate/primitives/runtime-interface/test", + "substrate/primitives/runtime", "substrate/primitives/session", "substrate/primitives/staking", "substrate/primitives/state-machine", diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 5c3fefc69ce710b1af10721ad41d1e5144b00f5a..d001e96efe8f2cdd6c8dbb51b4427cddb35091e9 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bridge-runtime-common" version = "0.1.0" +description = "Common types and functions that may be used by substrate-based runtimes of all bridged chains" authors.workspace = true edition.workspace = true repository.workspace = true diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index 07a99d2c0a16c381799c02e58cb9c4b574e2ad1c..5303fcb7ba030fa3f00a74c817d97537243f0e24 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -18,6 +18,7 @@ use crate::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; use bp_messages::{target_chain::MessageDispatch, InboundLaneData, LaneId, MessageNonce}; +use bp_runtime::OwnedBridgeModule; use frame_support::{ dispatch::CallableCallFor, traits::{Get, IsSubType}, @@ -187,8 +188,22 @@ pub trait MessagesCallSubType, I: 'static>: /// or a `ReceiveMessagesDeliveryProof` call, if the call is for the provided lane. fn call_info_for(&self, lane_id: LaneId) -> Option; - /// Check that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call is trying - /// to deliver/confirm at least some messages that are better than the ones we know of. + /// Ensures that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call: + /// + /// - does not deliver already delivered messages. We require all messages in the + /// `ReceiveMessagesProof` call to be undelivered; + /// + /// - does not submit empty `ReceiveMessagesProof` call with zero messages, unless the lane + /// needs to be unblocked by providing relayer rewards proof; + /// + /// - brings no new delivery confirmations in a `ReceiveMessagesDeliveryProof` call. We require + /// at least one new delivery confirmation in the unrewarded relayers set; + /// + /// - does not violate some basic (easy verifiable) messages pallet rules obsolete (like + /// submitting a call when a pallet is halted or delivering messages when a dispatcher is + /// inactive). + /// + /// If one of above rules is violated, the transaction is treated as invalid. fn check_obsolete_call(&self) -> TransactionValidity; } @@ -278,7 +293,17 @@ impl< } fn check_obsolete_call(&self) -> TransactionValidity { + let is_pallet_halted = Pallet::::ensure_not_halted().is_err(); match self.call_info() { + Some(proof_info) if is_pallet_halted => { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting messages transaction on halted pallet: {:?}", + proof_info + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Call.into() + }, Some(CallInfo::ReceiveMessagesProof(proof_info)) if proof_info.is_obsolete(T::MessageDispatch::is_active()) => { diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index 3d53f9da8c20e9503959b2aa8dc97807eacd5c67..fd10344812517bab17ad33e5d276a5627e01c0c0 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -38,7 +38,7 @@ where PriorityBoostPerMessage: Get, { // we don't want any boost for transaction with single message => minus one - PriorityBoostPerMessage::get().saturating_mul(messages - 1) + PriorityBoostPerMessage::get().saturating_mul(messages.saturating_sub(1)) } #[cfg(not(feature = "integrity-test"))] diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index f0c2cbf44509b3340028927a5b374461c2e94d12..6d8b2114808588a83571de6dc02a141cc146d2e3 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -24,8 +24,8 @@ use crate::messages_call_ext::{ }; use bp_messages::{LaneId, MessageNonce}; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{Parachain, ParachainIdOf, RangeInclusiveExt, StaticStrProvider}; -use codec::{Decode, Encode}; +use bp_runtime::{Chain, Parachain, ParachainIdOf, RangeInclusiveExt, StaticStrProvider}; +use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, traits::IsSubType, @@ -33,7 +33,8 @@ use frame_support::{ CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use pallet_bridge_grandpa::{ - CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, + CallSubType as GrandpaCallSubType, Config as GrandpaConfig, SubmitFinalityProofHelper, + SubmitFinalityProofInfo, }; use pallet_bridge_messages::Config as MessagesConfig; use pallet_bridge_parachains::{ @@ -96,7 +97,7 @@ where /// coming from this lane. pub trait RefundableMessagesLaneId { /// The instance of the bridge messages pallet. - type Instance; + type Instance: 'static; /// The messages lane id. type Id: Get; } @@ -106,6 +107,7 @@ pub struct RefundableMessagesLane(PhantomData<(Instance, Id)>); impl RefundableMessagesLaneId for RefundableMessagesLane where + Instance: 'static, Id: Get, { type Instance = Instance; @@ -165,7 +167,11 @@ pub enum CallInfo { SubmitParachainHeadsInfo, MessagesCallInfo, ), + /// Relay chain finality + message delivery/confirmation calls. + RelayFinalityAndMsgs(SubmitFinalityProofInfo, MessagesCallInfo), /// Parachain finality + message delivery/confirmation calls. + /// + /// This variant is used only when bridging with parachain. ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), /// Standalone message delivery/confirmation call. Msgs(MessagesCallInfo), @@ -184,6 +190,7 @@ impl CallInfo { fn submit_finality_proof_info(&self) -> Option> { match *self { Self::AllFinalityAndMsgs(info, _, _) => Some(info), + Self::RelayFinalityAndMsgs(info, _) => Some(info), _ => None, } } @@ -201,6 +208,7 @@ impl CallInfo { fn messages_call_info(&self) -> &MessagesCallInfo { match self { Self::AllFinalityAndMsgs(_, _, info) => info, + Self::RelayFinalityAndMsgs(_, info) => info, Self::ParachainFinalityAndMsgs(_, info) => info, Self::Msgs(info) => info, } @@ -209,7 +217,7 @@ impl CallInfo { /// The actions on relayer account that need to be performed because of his actions. #[derive(RuntimeDebug, PartialEq)] -enum RelayerAccountAction { +pub enum RelayerAccountAction { /// Do nothing with relayer account. None, /// Reward the relayer. @@ -218,121 +226,60 @@ enum RelayerAccountAction { Slash(AccountId, RewardsAccountParams), } -/// Signed extension that refunds a relayer for new messages coming from a parachain. -/// -/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) -/// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. -/// -/// Extension does not refund transaction tip due to security reasons. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedParachainMessages( - PhantomData<( - // runtime with `frame-utility`, `pallet-bridge-grandpa`, `pallet-bridge-parachains`, - // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // implementation of `RefundableParachainId` trait, which specifies the instance of - // the used `pallet-bridge-parachains` pallet and the bridged parachain id - Para, - // 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 - RefundBridgedParachainMessages +/// Everything common among our refund signed extensions. +pub trait RefundSignedExtension: + 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo where - Self: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + ParachainsConfig - + MessagesConfig - + RelayersConfig, - Para: RefundableParachainId, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + ParachainsCallSubType - + MessagesCallSubType, + >::BridgedChain: + Chain, { - fn expand_call<'a>(&self, call: &'a CallOf) -> Vec<&'a CallOf> { - match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 3 => - calls.iter().collect(), - Some(_) => vec![], - None => vec![call], - } - } - + /// This chain runtime. + type Runtime: UtilityConfig> + + GrandpaConfig + + MessagesConfig<::Instance> + + RelayersConfig; + /// Grandpa pallet reference. + type GrandpaInstance: 'static; + /// Messages pallet and lane reference. + type Msgs: RefundableMessagesLaneId; + /// Refund amount calculator. + type Refund: RefundCalculator::Reward>; + /// Priority boost calculator. + type Priority: Get; + /// Signed extension unique identifier. + type Id: StaticStrProvider; + + /// Unpack batch runtime call. + fn expand_call(call: &CallOf) -> Vec<&CallOf>; + + /// Given runtime call, check if it has supported format. Additionally, check if any of + /// (optionally batched) calls are obsolete and we shall reject the transaction. fn parse_and_check_for_obsolete_call( - &self, - call: &CallOf, - ) -> Result, TransactionValidityError> { - let calls = self.expand_call(call); - let total_calls = calls.len(); - let mut calls = calls.into_iter().map(Self::check_obsolete_call).rev(); - - let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); - let para_finality_call = calls - .next() - .transpose()? - .and_then(|c| c.submit_parachain_heads_info_for(Para::Id::get())); - let relay_finality_call = - calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + call: &CallOf, + ) -> Result, TransactionValidityError>; - Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { - (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => Some( - CallInfo::AllFinalityAndMsgs(relay_finality_call, para_finality_call, msgs_call), - ), - (2, None, Some(para_finality_call), Some(msgs_call)) => - Some(CallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), - (1, None, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), - _ => None, - }) - } + /// Check if parsed call is already obsolete. + fn check_obsolete_parsed_call( + call: &CallOf, + ) -> Result<&CallOf, TransactionValidityError>; - fn check_obsolete_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_submit_finality_proof()?; - call.check_obsolete_submit_parachain_heads()?; - call.check_obsolete_call()?; - Ok(call) - } + /// Called from post-dispatch and shall perform additional checks (apart from relay + /// chain finality and messages transaction finality) of given call result. + fn additional_call_result_check( + relayer: &AccountIdOf, + call_info: &CallInfo, + ) -> bool; /// Given post-dispatch information, analyze the outcome of relayer call and return /// actions that need to be performed on relayer account. fn analyze_call_result( - pre: Option>>, + pre: Option>>>, info: &DispatchInfo, post_info: &PostDispatchInfo, len: usize, result: &DispatchResult, - ) -> RelayerAccountAction, Runtime::Reward> { + ) -> RelayerAccountAction, ::Reward> + { let mut extra_weight = Weight::zero(); let mut extra_size = 0; @@ -344,15 +291,18 @@ where // now we know that the relayer either needs to be rewarded, or slashed // => let's prepare the correspondent account that pays reward/receives slashed amount - let reward_account_params = RewardsAccountParams::new( - Msgs::Id::get(), - Runtime::BridgedChainId::get(), - if call_info.is_receive_messages_proof_call() { - RewardsAccountOwner::ThisChain - } else { - RewardsAccountOwner::BridgedChain - }, - ); + let reward_account_params = + RewardsAccountParams::new( + ::Id::get(), + ::Instance, + >>::BridgedChainId::get(), + if call_info.is_receive_messages_proof_call() { + RewardsAccountOwner::ThisChain + } else { + RewardsAccountOwner::BridgedChain + }, + ); // prepare return value for the case if the call has failed or it has not caused // expected side effects (e.g. not all messages have been accepted) @@ -376,10 +326,9 @@ where if let Err(e) = result { log::trace!( target: "runtime::bridge", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid messages transaction: {:?}", - Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + "{} via {:?}: relayer {:?} has submitted invalid messages transaction: {:?}", + Self::Id::STR, + ::Id::get(), relayer, e, ); @@ -388,19 +337,18 @@ where // check if relay chain state has been updated if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { - if !SubmitFinalityProofHelper::::was_successful( + 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", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", - Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + "{} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", + Self::Id::STR, + ::Id::get(), relayer, ); - return slash_relayer_if_delivery_result; + return slash_relayer_if_delivery_result } // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` @@ -416,39 +364,25 @@ where extra_size = finality_proof_info.extra_size; } - // check if parachain state has been updated - if let Some(para_proof_info) = call_info.submit_parachain_heads_info() { - if !SubmitParachainHeadsHelper::::was_successful( - para_proof_info, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid parachain finality proof", - Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), - relayer, - ); - return slash_relayer_if_delivery_result - } - } - // 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(); - if !MessagesCallHelper::::was_successful(msgs_call_info) { + if !MessagesCallHelper::::Instance>::was_successful(msgs_call_info) { log::trace!( target: "runtime::bridge", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid messages call", - Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + "{} via {:?}: relayer {:?} has submitted invalid messages call", + Self::Id::STR, + ::Id::get(), relayer, ); return slash_relayer_if_delivery_result } + // do additional check + if !Self::additional_call_result_check(&relayer, &call_info) { + return slash_relayer_if_delivery_result + } + // regarding the tip - refund that happens here (at this side of the bridge) isn't the whole // relayer compensation. He'll receive some amount at the other side of the bridge. It shall // (in theory) cover the tip there. Otherwise, if we'll be compensating tip here, some @@ -464,14 +398,14 @@ where // let's also replace the weight of slashing relayer with the weight of rewarding relayer if call_info.is_receive_messages_proof_call() { post_info_weight = post_info_weight.saturating_sub( - ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), + ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), ); } // compute the relayer refund let mut post_info = *post_info; post_info.actual_weight = Some(post_info_weight); - let refund = Refund::compute_refund(info, &post_info, post_info_len, tip); + let refund = Self::Refund::compute_refund(info, &post_info, post_info_len, tip); // we can finally reward relayer RelayerAccountAction::Reward(relayer, reward_account_params, refund) @@ -497,7 +431,11 @@ where let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); // a quick check to avoid invalid high-priority transactions - if bundled_messages > Runtime::MaxUnconfirmedMessagesAtInboundLane::get() { + let max_unconfirmed_messages_in_confirmation_tx = ::Instance, + >>::MaxUnconfirmedMessagesAtInboundLane::get( + ); + if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { return None } @@ -505,31 +443,37 @@ where } } -impl SignedExtension - for RefundBridgedParachainMessages +/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any +/// `RefundSignedExtension`. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +pub struct RefundSignedExtensionAdapter(T) where - Self: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + ParachainsConfig - + MessagesConfig - + RelayersConfig, - Para: RefundableParachainId, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + ParachainsCallSubType - + MessagesCallSubType, + >::BridgedChain: + Chain; + +impl SignedExtension for RefundSignedExtensionAdapter +where + >::BridgedChain: + Chain, + CallOf: Dispatchable + + IsSubType, T::Runtime>> + + GrandpaCallSubType + + MessagesCallSubType::Instance>, { - const IDENTIFIER: &'static str = Id::STR; - type AccountId = Runtime::AccountId; - type Call = CallOf; + const IDENTIFIER: &'static str = T::Id::STR; + type AccountId = AccountIdOf; + type Call = CallOf; type AdditionalSigned = (); - type Pre = Option>; + type Pre = Option>>; fn additional_signed(&self) -> Result<(), TransactionValidityError> { Ok(()) @@ -547,34 +491,32 @@ where // we're not calling `validate` from `pre_dispatch` directly because of performance // reasons, so if you're adding some code that may fail here, please check if it needs // to be added to the `pre_dispatch` as well - let parsed_call = self.parse_and_check_for_obsolete_call(call)?; + let parsed_call = T::parse_and_check_for_obsolete_call(call)?; // the following code just plays with transaction priority and never returns an error // we only boost priority of presumably correct message delivery transactions - let bundled_messages = match Self::bundled_messages_for_priority_boost(parsed_call.as_ref()) - { + let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { Some(bundled_messages) => bundled_messages, None => return Ok(Default::default()), }; // we only boost priority if relayer has staked required balance - if !RelayersPallet::::is_registration_active(who) { + if !RelayersPallet::::is_registration_active(who) { return Ok(Default::default()) } // compute priority boost let priority_boost = - crate::priority_calculator::compute_priority_boost::(bundled_messages); + crate::priority_calculator::compute_priority_boost::(bundled_messages); let valid_transaction = ValidTransactionBuilder::default().priority(priority_boost); log::trace!( target: "runtime::bridge", - "{} from parachain {} via {:?} has boosted priority of message delivery transaction \ + "{} via {:?} has boosted priority of message delivery transaction \ of relayer {:?}: {} messages -> {} priority", Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + ::Id::get(), who, bundled_messages, priority_boost, @@ -591,15 +533,14 @@ where _len: usize, ) -> Result { // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) - let parsed_call = self.parse_and_check_for_obsolete_call(call)?; + let parsed_call = T::parse_and_check_for_obsolete_call(call)?; Ok(parsed_call.map(|call_info| { log::trace!( target: "runtime::bridge", - "{} from parachain {} via {:?} parsed bridge transaction in pre-dispatch: {:?}", + "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + ::Id::get(), call_info, ); PreDispatchData { relayer: who.clone(), call_info } @@ -613,12 +554,12 @@ where len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let call_result = Self::analyze_call_result(pre, info, post_info, len, result); + let call_result = T::analyze_call_result(pre, info, post_info, len, result); match call_result { RelayerAccountAction::None => (), RelayerAccountAction::Reward(relayer, reward_account, reward) => { - RelayersPallet::::register_relayer_reward( + RelayersPallet::::register_relayer_reward( reward_account, &relayer, reward, @@ -626,22 +567,263 @@ where log::trace!( target: "runtime::bridge", - "{} from parachain {} via {:?} has registered reward: {:?} for {:?}", + "{} via {:?} has registered reward: {:?} for {:?}", Self::IDENTIFIER, - Para::Id::get(), - Msgs::Id::get(), + ::Id::get(), reward, relayer, ); }, RelayerAccountAction::Slash(relayer, slash_account) => - RelayersPallet::::slash_and_deregister(&relayer, slash_account), + RelayersPallet::::slash_and_deregister(&relayer, slash_account), } Ok(()) } } +/// Signed extension that refunds a relayer for new messages coming from a parachain. +/// +/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) +/// with message delivery transaction. Batch may deliver either both relay chain header and +/// parachain head, or just parachain head. Corresponding headers must be used in messages +/// proof verification. +/// +/// Extension does not refund transaction tip due to security reasons. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Priority, Id))] +pub struct RefundBridgedParachainMessages( + PhantomData<( + // runtime with `frame-utility`, `pallet-bridge-grandpa`, `pallet-bridge-parachains`, + // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed + Runtime, + // implementation of `RefundableParachainId` trait, which specifies the instance of + // the used `pallet-bridge-parachains` pallet and the bridged parachain id + Para, + // 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 RefundBridgedParachainMessages +where + Self: 'static + Send + Sync, + Runtime: UtilityConfig> + + BoundedBridgeGrandpaConfig + + ParachainsConfig + + MessagesConfig + + RelayersConfig, + Para: RefundableParachainId, + Msgs: RefundableMessagesLaneId, + Refund: RefundCalculator, + Priority: Get, + Id: StaticStrProvider, + CallOf: Dispatchable + + IsSubType, Runtime>> + + GrandpaCallSubType + + ParachainsCallSubType + + MessagesCallSubType, +{ + type Runtime = Runtime; + type GrandpaInstance = Runtime::BridgesGrandpaPalletInstance; + type Msgs = Msgs; + type Refund = Refund; + type Priority = Priority; + type Id = Id; + + fn expand_call(call: &CallOf) -> Vec<&CallOf> { + match call.is_sub_type() { + Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 3 => + calls.iter().collect(), + Some(_) => vec![], + None => vec![call], + } + } + + fn parse_and_check_for_obsolete_call( + call: &CallOf, + ) -> Result, TransactionValidityError> { + let calls = Self::expand_call(call); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); + let para_finality_call = calls + .next() + .transpose()? + .and_then(|c| c.submit_parachain_heads_info_for(Para::Id::get())); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { + (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => Some( + CallInfo::AllFinalityAndMsgs(relay_finality_call, para_finality_call, msgs_call), + ), + (2, None, Some(para_finality_call), Some(msgs_call)) => + Some(CallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), + (1, None, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &CallOf, + ) -> Result<&CallOf, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_submit_parachain_heads()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn additional_call_result_check(relayer: &Runtime::AccountId, call_info: &CallInfo) -> bool { + // check if parachain state has been updated + if let Some(para_proof_info) = call_info.submit_parachain_heads_info() { + if !SubmitParachainHeadsHelper::::was_successful( + para_proof_info, + ) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: relayer {:?} has submitted invalid parachain finality proof", + Id::STR, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + return false + } + } + + true + } +} + +/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) +/// chain. +/// +/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) +/// with message delivery transaction. Batch may deliver either both relay chain header and +/// parachain head, or just parachain head. Corresponding headers must be used in messages +/// proof verification. +/// +/// Extension does not refund transaction tip due to security reasons. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] +pub struct RefundBridgedGrandpaMessages( + PhantomData<( + // runtime with `frame-utility`, `pallet-bridge-grandpa`, + // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed + Runtime, + // bridge GRANDPA pallet instance, used to track bridged chain state + GrandpaInstance, + // 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 RefundBridgedGrandpaMessages +where + Self: 'static + Send + Sync, + Runtime: UtilityConfig> + + BoundedBridgeGrandpaConfig + + MessagesConfig + + RelayersConfig, + GrandpaInstance: 'static, + Msgs: RefundableMessagesLaneId, + Refund: RefundCalculator, + Priority: Get, + Id: StaticStrProvider, + CallOf: Dispatchable + + IsSubType, Runtime>> + + GrandpaCallSubType + + MessagesCallSubType, +{ + type Runtime = Runtime; + type GrandpaInstance = GrandpaInstance; + type Msgs = Msgs; + type Refund = Refund; + type Priority = Priority; + type Id = Id; + + fn expand_call(call: &CallOf) -> Vec<&CallOf> { + match call.is_sub_type() { + Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 2 => + calls.iter().collect(), + Some(_) => vec![], + None => vec![call], + } + } + + fn parse_and_check_for_obsolete_call( + call: &CallOf, + ) -> Result, TransactionValidityError> { + let calls = Self::expand_call(call); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + Ok(match (total_calls, relay_finality_call, msgs_call) { + (2, Some(relay_finality_call), Some(msgs_call)) => + Some(CallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)), + (1, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &CallOf, + ) -> Result<&CallOf, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn additional_call_result_check(_relayer: &Runtime::AccountId, _call_info: &CallInfo) -> bool { + true + } +} + #[cfg(test)] mod tests { use super::*; @@ -655,19 +837,24 @@ mod tests { }, mock::*, }; - use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayersState}; + use bp_messages::{ + DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData, + UnrewardedRelayer, UnrewardedRelayersState, + }; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; - use bp_runtime::HeaderId; + use bp_runtime::{BasicOperatingMode, HeaderId}; use bp_test_utils::{make_default_justification, test_keyring}; use frame_support::{ assert_storage_noop, parameter_types, traits::{fungible::Mutate, ReservableCurrency}, weights::Weight, }; - use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet}; - use pallet_bridge_messages::Call as MessagesCall; - use pallet_bridge_parachains::{Call as ParachainsCall, RelayBlockHash}; + use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet}; + use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet}; + use pallet_bridge_parachains::{ + Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, + }; use sp_runtime::{ traits::{ConstU64, Header as HeaderT}, transaction_validity::{InvalidTransaction, ValidTransaction}, @@ -690,7 +877,17 @@ mod tests { } bp_runtime::generate_static_str_provider!(TestExtension); - type TestExtension = RefundBridgedParachainMessages< + + type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< + TestRuntime, + (), + RefundableMessagesLane<(), TestLaneId>, + ActualFeeRefund, + ConstU64<1>, + StrTestExtension, + >; + type TestGrandpaExtension = RefundSignedExtensionAdapter; + type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, DefaultRefundableParachainId<(), TestParachain>, RefundableMessagesLane<(), TestLaneId>, @@ -698,6 +895,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; + type TestExtension = RefundSignedExtensionAdapter; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = TestStake::get(); @@ -825,25 +1023,49 @@ mod tests { }) } - fn parachain_finality_and_delivery_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + fn parachain_finality_and_delivery_batch_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_delivery_call(best_message), + ], + }) + } + + fn parachain_finality_and_confirmation_batch_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + + fn relay_finality_and_delivery_batch_call( + relay_header_number: RelayBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ - submit_parachain_head_call(parachain_head_at_relay_header_number), + submit_relay_header_call(relay_header_number), message_delivery_call(best_message), ], }) } - fn parachain_finality_and_confirmation_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + fn relay_finality_and_confirmation_batch_call( + relay_header_number: RelayBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ - submit_parachain_head_call(parachain_head_at_relay_header_number), + submit_relay_header_call(relay_header_number), message_confirmation_call(best_message), ], }) @@ -931,6 +1153,50 @@ mod tests { } } + fn relay_finality_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::RelayFinalityAndMsgs( + SubmitFinalityProofInfo { + block_number: 200, + extra_weight: Weight::zero(), + extra_size: 0, + }, + MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + bundled_range: 101..=200, + best_stored_nonce: 100, + }, + unrewarded_relayers: UnrewardedRelayerOccupation { + free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), + free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + }, + }), + ), + } + } + + fn relay_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::RelayFinalityAndMsgs( + SubmitFinalityProofInfo { + block_number: 200, + extra_weight: Weight::zero(), + extra_size: 0, + }, + MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + bundled_range: 101..=200, + best_stored_nonce: 100, + }, + )), + ), + } + } + fn parachain_finality_pre_dispatch_data() -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), @@ -1013,6 +1279,7 @@ mod tests { ) -> PreDispatchData { let msg_info = match pre_dispatch_data.call_info { CallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, + CallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, CallInfo::ParachainFinalityAndMsgs(_, ref mut info) => info, CallInfo::Msgs(ref mut info) => info, }; @@ -1025,7 +1292,14 @@ mod tests { } fn run_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestExtension = RefundBridgedParachainMessages(PhantomData); + let extension: TestExtension = + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + + fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { + let extension: TestGrandpaExtension = + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } @@ -1039,7 +1313,16 @@ mod tests { fn run_pre_dispatch( call: RuntimeCall, ) -> Result>, TransactionValidityError> { - let extension: TestExtension = RefundBridgedParachainMessages(PhantomData); + let extension: TestExtension = + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + + fn run_grandpa_pre_dispatch( + call: RuntimeCall, + ) -> Result>, TransactionValidityError> { + let extension: TestGrandpaExtension = + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } @@ -1311,6 +1594,99 @@ mod tests { }); } + #[test] + fn ext_rejects_batch_with_grandpa_finality_proof_when_grandpa_pallet_is_halted() { + run_test(|| { + initialize_environment(100, 100, 100); + + GrandpaPallet::::set_operating_mode( + RuntimeOrigin::root(), + BasicOperatingMode::Halted, + ) + .unwrap(); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + }); + } + + #[test] + fn ext_rejects_batch_with_parachain_finality_proof_when_parachains_pallet_is_halted() { + run_test(|| { + initialize_environment(100, 100, 100); + + ParachainsPallet::::set_operating_mode( + RuntimeOrigin::root(), + BasicOperatingMode::Halted, + ) + .unwrap(); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + }); + } + + #[test] + fn ext_rejects_transaction_when_messages_pallet_is_halted() { + run_test(|| { + initialize_environment(100, 100, 100); + + MessagesPallet::::set_operating_mode( + RuntimeOrigin::root(), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted), + ) + .unwrap(); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + + assert_eq!( + run_pre_dispatch(message_delivery_call(200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + assert_eq!( + run_pre_dispatch(message_confirmation_call(200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + }); + } + #[test] fn pre_dispatch_parses_batch_with_relay_chain_and_parachain_headers() { run_test(|| { @@ -1674,7 +2050,7 @@ mod tests { pre_dispatch_data: PreDispatchData, dispatch_result: DispatchResult, ) -> RelayerAccountAction { - TestExtension::analyze_call_result( + TestExtensionProvider::analyze_call_result( Some(Some(pre_dispatch_data)), &dispatch_info(), &post_dispatch_info(), @@ -1737,4 +2113,209 @@ mod tests { ); }); } + + #[test] + fn grandpa_ext_only_parses_valid_batches() { + run_test(|| { + initialize_environment(100, 100, 100); + + // relay + parachain + message delivery calls batch is ignored + assert_eq!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_delivery_batch_call(200, 200, 200) + ), + Ok(None), + ); + + // relay + parachain + message confirmation calls batch is ignored + assert_eq!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_confirmation_batch_call(200, 200, 200) + ), + Ok(None), + ); + + // parachain + message delivery call batch is ignored + assert_eq!( + TestGrandpaExtensionProvider::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!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + ¶chain_finality_and_confirmation_batch_call(200, 200) + ), + Ok(None), + ); + + // relay + message delivery call batch is accepted + assert_eq!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_delivery_batch_call(200, 200) + ), + Ok(Some(relay_finality_pre_dispatch_data().call_info)), + ); + + // relay + message confirmation call batch is accepted + assert_eq!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_confirmation_batch_call(200, 200) + ), + Ok(Some(relay_finality_confirmation_pre_dispatch_data().call_info)), + ); + + // message delivery call batch is accepted + assert_eq!( + TestGrandpaExtensionProvider::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!( + TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + &message_confirmation_call(200) + ), + Ok(Some(confirmation_pre_dispatch_data().call_info)), + ); + }); + } + + #[test] + fn grandpa_ext_rejects_batch_with_obsolete_relay_chain_header() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_grandpa_pre_dispatch(relay_finality_and_delivery_batch_call(100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_grandpa_validate(relay_finality_and_delivery_batch_call(100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn grandpa_ext_rejects_calls_with_obsolete_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_grandpa_pre_dispatch(relay_finality_and_delivery_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_grandpa_pre_dispatch(relay_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_grandpa_validate(relay_finality_and_delivery_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_grandpa_validate(relay_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_grandpa_pre_dispatch(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_grandpa_pre_dispatch(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_grandpa_validate(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_grandpa_validate(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn grandpa_ext_accepts_calls_with_new_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_grandpa_pre_dispatch(relay_finality_and_delivery_batch_call(200, 200)), + Ok(Some(relay_finality_pre_dispatch_data()),) + ); + assert_eq!( + run_grandpa_pre_dispatch(relay_finality_and_confirmation_batch_call(200, 200)), + Ok(Some(relay_finality_confirmation_pre_dispatch_data())), + ); + + assert_eq!( + run_grandpa_validate(relay_finality_and_delivery_batch_call(200, 200)), + Ok(Default::default()), + ); + assert_eq!( + run_grandpa_validate(relay_finality_and_confirmation_batch_call(200, 200)), + Ok(Default::default()), + ); + + assert_eq!( + run_grandpa_pre_dispatch(message_delivery_call(200)), + Ok(Some(delivery_pre_dispatch_data())), + ); + assert_eq!( + run_grandpa_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); + + assert_eq!(run_grandpa_validate(message_delivery_call(200)), Ok(Default::default()),); + assert_eq!( + run_grandpa_validate(message_confirmation_call(200)), + Ok(Default::default()), + ); + }); + } + + #[test] + fn does_not_panic_on_boosting_priority_of_empty_message_delivery_transaction() { + run_test(|| { + let best_delivered_message = MaxUnconfirmedMessagesAtInboundLane::get(); + initialize_environment(100, 100, best_delivered_message); + + // register relayer so it gets priority boost + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + // allow empty message delivery transactions + let lane_id = TestLaneId::get(); + let in_lane_data = InboundLaneData { + last_confirmed_nonce: 0, + relayers: vec![UnrewardedRelayer { + relayer: relayer_account_at_bridged_chain(), + messages: DeliveredMessages { begin: 1, end: best_delivered_message }, + }] + .into(), + }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + // now check that the priority of empty tx is the same as priority of 1-message tx + let priority_of_zero_messages_delivery = + run_validate(message_delivery_call(best_delivered_message)).unwrap().priority; + let priority_of_one_messages_delivery = + run_validate(message_delivery_call(best_delivered_message + 1)) + .unwrap() + .priority; + + assert_eq!(priority_of_zero_messages_delivery, priority_of_one_messages_delivery); + }); + } } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 05d6a8e5c26b0d82f5dc80ce5be21d9a53b46d33..45adf09af276e477a185765152ed49470869ccf6 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "pallet-bridge-grandpa" version = "0.1.0" +description = "Module implementing GRANDPA on-chain light client used for bridging consensus of substrate-based chains." authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index e0648d5dd0f1d9cd26b2d9cdcc6dc983ef082bb2..f238064f92bcacde89971479a501b60469f01691 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -16,7 +16,7 @@ use crate::{weights::WeightInfo, BridgedBlockNumber, BridgedHeader, Config, Error, Pallet}; use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; -use bp_runtime::BlockNumberOf; +use bp_runtime::{BlockNumberOf, OwnedBridgeModule}; use codec::Encode; use frame_support::{dispatch::CallableCallFor, traits::IsSubType, weights::Weight}; use sp_runtime::{ @@ -126,6 +126,10 @@ pub trait CallSubType, I: 'static>: _ => return Ok(ValidTransaction::default()), }; + if Pallet::::ensure_not_halted().is_err() { + return InvalidTransaction::Call.into() + } + match SubmitFinalityProofHelper::::check_obsolete(finality_target.block_number) { Ok(_) => Ok(ValidTransaction::default()), Err(Error::::OldHeader) => InvalidTransaction::Stale.into(), @@ -192,10 +196,10 @@ mod tests { use crate::{ call_ext::CallSubType, mock::{run_test, test_header, RuntimeCall, TestBridgedChain, TestNumber, TestRuntime}, - BestFinalized, Config, WeightInfo, + BestFinalized, Config, PalletOperatingMode, WeightInfo, }; use bp_header_chain::ChainWithGrandpa; - use bp_runtime::HeaderId; + use bp_runtime::{BasicOperatingMode, HeaderId}; use bp_test_utils::{ make_default_justification, make_justification_for_header, JustificationGeneratorParams, }; @@ -238,6 +242,17 @@ mod tests { }); } + #[test] + fn extension_rejects_new_header_if_pallet_is_halted() { + run_test(|| { + // when pallet is halted => tx is rejected + sync_to_header_10(); + PalletOperatingMode::::put(BasicOperatingMode::Halted); + + assert!(!validate_block_submit(15)); + }); + } + #[test] fn extension_accepts_new_header() { run_test(|| { diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 4eb09ed78d17f3b4da620ac6b28645bdaab88c12..6e9ca870ce5225b500c941676d649e5a03d79663 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "pallet-bridge-parachains" version = "0.1.0" +description = "Module that allows bridged relay chains to exchange information on their parachains' heads." authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/bridges/modules/parachains/README.md b/bridges/modules/parachains/README.md index d3f52c791ab5899c438bf902acd85d3e8a96153a..9ca6080383443df2a72041e9089c0eb5c861fbc0 100644 --- a/bridges/modules/parachains/README.md +++ b/bridges/modules/parachains/README.md @@ -9,15 +9,15 @@ to verify storage proofs, generated at the bridged relay chain. ## A Brief Introduction into Parachains Finality -You can find detailed information on parachains finality in the [Polkadot](https://github.com/paritytech/polkadot) -and [Cumulus](https://github.com/paritytech/cumulus) repositories. This section gives a brief overview of how -the parachain finality works and how to build a light client for a parachain. +You can find detailed information on parachains finality in the +[Polkadot-SDK](https://github.com/paritytech/polkadot-sdk) repository. This section gives a brief overview of how the +parachain finality works and how to build a light client for a parachain. The main thing there is that the parachain generates blocks on its own, but it can't achieve finality without help of its relay chain. Instead, the parachain collators create a block and hand it over to the relay chain validators. Validators validate the block and register the new parachain head in the -[`Heads` map](https://github.com/paritytech/polkadot/blob/88013730166ba90745ae7c9eb3e0c1be1513c7cc/runtime/parachains/src/paras/mod.rs#L645) -of the [`paras`](https://github.com/paritytech/polkadot/tree/master/runtime/parachains/src/paras) pallet, +[`Heads` map](https://github.com/paritytech/polkadot-sdk/blob/bc5005217a8c2e7c95b9011c96d7e619879b1200/polkadot/runtime/parachains/src/paras/mod.rs#L683-L686) +of the [`paras`](https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/runtime/parachains/src/paras) pallet, deployed at the relay chain. Keep in mind that this pallet, deployed at a relay chain, is **NOT** a bridge pallet, even though the names are similar. diff --git a/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index 99640dadc61f4a422ec41db4fe196f752b206d06..198ff11be49512ef90ab38a093e6889a3d8f0702 100644 --- a/bridges/modules/parachains/src/call_ext.rs +++ b/bridges/modules/parachains/src/call_ext.rs @@ -17,6 +17,7 @@ use crate::{Config, Pallet, RelayBlockNumber}; use bp_parachains::BestParaHeadHash; use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use bp_runtime::OwnedBridgeModule; use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, @@ -141,6 +142,10 @@ pub trait CallSubType, I: 'static>: None => return Ok(ValidTransaction::default()), }; + if Pallet::::ensure_not_halted().is_err() { + return InvalidTransaction::Call.into() + } + if SubmitParachainHeadsHelper::::is_obsolete(&update) { return InvalidTransaction::Stale.into() } @@ -160,10 +165,11 @@ where mod tests { use crate::{ mock::{run_test, RuntimeCall, TestRuntime}, - CallSubType, ParaInfo, ParasInfo, RelayBlockNumber, + CallSubType, PalletOperatingMode, ParaInfo, ParasInfo, RelayBlockNumber, }; use bp_parachains::BestParaHeadHash; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; + use bp_runtime::BasicOperatingMode; fn validate_submit_parachain_heads( num: RelayBlockNumber, @@ -221,6 +227,17 @@ mod tests { }); } + #[test] + fn extension_rejects_header_if_pallet_is_halted() { + run_test(|| { + // when pallet is halted => tx is rejected + sync_to_relay_header_10(); + PalletOperatingMode::::put(BasicOperatingMode::Halted); + + assert!(!validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); + }); + } + #[test] fn extension_accepts_new_header() { run_test(|| { diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index 4bbe414f66355bfb2fc866cc74b89f7b97988837..c4d1e3971e74777668b8bfa4dbcfdb88fbac3779 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -60,6 +60,8 @@ benchmarks_instance_pallet! { is_congested: false, delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, }); + + let _ = T::ensure_bridged_target_destination(); T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) @@ -79,11 +81,11 @@ benchmarks_instance_pallet! { } send_message { - // make local queue congested, because it means additional db write - T::make_congested(); - let dest = T::ensure_bridged_target_destination(); let xcm = sp_std::vec![].into(); + + // make local queue congested, because it means additional db write + T::make_congested(); }: { send_xcm::>(dest, xcm).expect("message is sent") } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 58df21a6d9016a70a8414b884ccedf33d7ae1524..2152b4eb28f336d86fcd531077c8ea65a3138fe5 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -27,7 +27,7 @@ use sp_runtime::{ BuildStorage, }; use xcm::prelude::*; -use xcm_builder::NetworkExportTable; +use xcm_builder::{NetworkExportTable, NetworkExportTableItem}; pub type AccountId = u64; type Block = frame_system::mocking::MockBlock; @@ -53,8 +53,15 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ThisNetworkId::get()), Parachain(1000)); pub SiblingBridgeHubLocation: MultiLocation = ParentThen(X1(Parachain(1002))).into(); pub BridgeFeeAsset: AssetId = MultiLocation::parent().into(); - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(BridgedNetworkId::get(), SiblingBridgeHubLocation::get(), Some((BridgeFeeAsset::get(), BASE_FEE).into()))]; + pub BridgeTable: Vec + = vec![ + NetworkExportTableItem::new( + BridgedNetworkId::get(), + None, + SiblingBridgeHubLocation::get(), + Some((BridgeFeeAsset::get(), BASE_FEE).into()) + ) + ]; } impl frame_system::Config for TestRuntime { diff --git a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..a888700a0601c9c34692f5785020bc1ad522b848 --- /dev/null +++ b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "bp-asset-hub-rococo" +description = "Primitives of AssetHubRococo parachain runtime." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } + +# Substrate Dependencies +frame-support = { path = "../../../substrate/frame/support", default-features = false } + +# Bridge Dependencies +bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } + +[features] +default = [ "std" ] +std = [ + "bp-xcm-bridge-hub-router/std", + "codec/std", + "frame-support/std", + "scale-info/std", +] diff --git a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..f1ea1e9c88c9ad5285d9c4561e372956638e4111 --- /dev/null +++ b/bridges/primitives/chain-asset-hub-rococo/src/lib.rs @@ -0,0 +1,52 @@ +// 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 . + +//! Module with configuration which reflects AssetHubRococo runtime setup. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; + +/// `AssetHubRococo` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `AssetHubRococo` chain. +/// Ideally this code would be auto-generated from metadata, because we want to +/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. +/// +/// All entries here (like pretty much in the entire file) must be kept in sync with +/// `AssetHubRococo` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + /// `ToWococoXcmRouter` bridge pallet. + #[codec(index = 43)] + ToWococoXcmRouter(XcmBridgeHubRouterCall), +} + +frame_support::parameter_types! { + /// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`. + pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); + + /// Base delivery fee to `BridgeHubRococo`. + /// (initially was calculated by test `BridgeHubRococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer`) + pub const BridgeHubRococoBaseFeeInRocs: u128 = 1214739988; +} + +/// Identifier of AssetHubRococo in the Rococo relay chain. +pub const ASSET_HUB_ROCOCO_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/primitives/chain-asset-hub-wococo/Cargo.toml b/bridges/primitives/chain-asset-hub-wococo/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..872732283858ee1168648d2912b6fd22bab6ccf2 --- /dev/null +++ b/bridges/primitives/chain-asset-hub-wococo/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "bp-asset-hub-wococo" +description = "Primitives of AssetHubWococo parachain runtime." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } + +# Substrate Dependencies +frame-support = { path = "../../../substrate/frame/support", default-features = false } + +# Bridge Dependencies +bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } + +[features] +default = [ "std" ] +std = [ + "bp-xcm-bridge-hub-router/std", + "codec/std", + "frame-support/std", + "scale-info/std", +] diff --git a/bridges/primitives/chain-asset-hub-wococo/src/lib.rs b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..5ce66054d64aa8b0f2503c4be19895937cf7ac0e --- /dev/null +++ b/bridges/primitives/chain-asset-hub-wococo/src/lib.rs @@ -0,0 +1,52 @@ +// 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 . + +//! Module with configuration which reflects AssetHubWococo runtime setup. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; + +/// `AssetHubWococo` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `AssetHubWococo` chain. +/// Ideally this code would be auto-generated from metadata, because we want to +/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. +/// +/// All entries here (like pretty much in the entire file) must be kept in sync with +/// `AssetHubWococo` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + /// `ToRococoXcmRouter` bridge pallet. + #[codec(index = 44)] + ToRococoXcmRouter(XcmBridgeHubRouterCall), +} + +frame_support::parameter_types! { + /// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`. + pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); + + /// Base delivery fee to `BridgeHubWococo`. + /// (initially was calculated by test `BridgeHubWococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer`) + pub const BridgeHubWococoBaseFeeInWocs: u128 = 1214739988; +} + +/// Identifier of AssetHubWococo in the Wococo relay chain. +pub const ASSET_HUB_WOCOCO_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index c1dbc6db36f644c3d123a8c3c5930fce31973146..cd281324ee55fa9a0c4bfcfe454b34ecba9bfd07 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -52,7 +52,7 @@ pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// This is a copy-paste from the cumulus repo's `parachains-common` crate. const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(constants::WEIGHT_REF_TIME_PER_SECOND, 0) .saturating_div(2) - .set_proof_size(polkadot_primitives::v5::MAX_POV_SIZE as u64); + .set_proof_size(polkadot_primitives::MAX_POV_SIZE as u64); /// All cumulus bridge hubs assume that about 5 percent of the block weight is consumed by /// `on_initialize` handlers. This is used to limit the maximal weight of a single extrinsic. diff --git a/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs b/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs index 3a919648df47f091b76f0e16b9cd98b22f1970ff..66e0dad05895c7df72cda7158c39e589b78ada73 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs @@ -29,7 +29,6 @@ use frame_support::{ sp_runtime::{MultiAddress, MultiSigner}, }; use sp_runtime::RuntimeDebug; -use sp_std::prelude::Vec; /// BridgeHubKusama parachain. #[derive(RuntimeDebug)] diff --git a/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs b/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs index bf8d8e07c3a61c83a8f1f0cc253c45557dd1b703..c3661c1adcada619bb319ae8853c20623565c0c9 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs @@ -26,7 +26,6 @@ use bp_runtime::{ }; use frame_support::dispatch::DispatchClass; use sp_runtime::RuntimeDebug; -use sp_std::prelude::Vec; /// BridgeHubPolkadot parachain. #[derive(RuntimeDebug)] diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index b726c62ac42b3270d72c7eebc6d3f5faff54c166..6da5cd3818fe48706521fba5e5d7eda890a197f4 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -26,7 +26,7 @@ use bp_runtime::{ }; use frame_support::dispatch::DispatchClass; use sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug}; -use sp_std::prelude::Vec; + /// BridgeHubRococo parachain. #[derive(RuntimeDebug)] pub struct BridgeHubRococo; @@ -74,5 +74,8 @@ pub const WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessa /// chains. pub const WITH_BRIDGE_HUB_ROCOCO_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; +/// Pallet index of `BridgeWococoMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX: u8 = 46; + decl_bridge_finality_runtime_apis!(bridge_hub_rococo); decl_bridge_messages_runtime_apis!(bridge_hub_rococo); diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs index 5e4758645d9ea63fedbd17b39c88ee208e725f96..0c7717368042a1c92efd8cae42a883890e3fdf9a 100644 --- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -26,7 +26,6 @@ use bp_runtime::{ }; use frame_support::dispatch::DispatchClass; use sp_runtime::RuntimeDebug; -use sp_std::prelude::Vec; /// BridgeHubWococo parachain. #[derive(RuntimeDebug)] @@ -69,5 +68,8 @@ pub const WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessa /// chains. pub const WITH_BRIDGE_HUB_WOCOCO_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; +/// Pallet index of `BridgeRococoMessages: pallet_bridge_messages::`. +pub const WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 45; + decl_bridge_finality_runtime_apis!(bridge_hub_wococo); decl_bridge_messages_runtime_apis!(bridge_hub_wococo); diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 8c3fbd9c203e5e81ebfc248259cd823255d826f2..d5748aa132cea6caddeabd102b62345bbdc6153f 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -23,7 +23,6 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain}; use frame_support::weights::Weight; -use sp_std::prelude::Vec; /// Kusama Chain pub struct Kusama; diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4311aec47276e5144ddc56074cda205a1ec454da --- /dev/null +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "bp-polkadot-bulletin" +description = "Primitives of Polkadot Bulletin chain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } + +# Bridge Dependencies + +bp-header-chain = { path = "../header-chain", default-features = false } +bp-messages = { path = "../messages", default-features = false } +bp-polkadot-core = { path = "../polkadot-core", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Based Dependencies + +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } + +[features] +default = [ "std" ] +std = [ + "bp-header-chain/std", + "bp-messages/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "sp-api/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..fcc6e90eb1b298e703b7c4b1a83c914f0a018031 --- /dev/null +++ b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs @@ -0,0 +1,215 @@ +// 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 . + +//! Polkadot Bulletin Chain primitives. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_header_chain::ChainWithGrandpa; +use bp_messages::MessageNonce; +use bp_runtime::{ + decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, + extensions::{ + CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, + CheckWeight, GenericSignedExtension, GenericSignedExtensionSchema, + }, + Chain, TransactionEra, +}; +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::DispatchClass, + parameter_types, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; +use frame_system::limits; +use scale_info::TypeInfo; +use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; + +// This chain reuses most of Polkadot primitives. +pub use bp_polkadot_core::{ + AccountAddress, AccountId, Balance, Block, BlockNumber, Hash, Hasher, Header, Nonce, Signature, + SignedBlock, UncheckedExtrinsic, AVERAGE_HEADER_SIZE_IN_JUSTIFICATION, + EXTRA_STORAGE_PROOF_SIZE, MAX_HEADER_SIZE, REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, +}; + +/// Maximal number of GRANDPA authorities at Polkadot Bulletin chain. +pub const MAX_AUTHORITIES_COUNT: u32 = 100; + +/// Name of the With-Polkadot Bulletin chain GRANDPA pallet instance that is deployed at bridged +/// chains. +pub const WITH_POLKADOT_BULLETIN_GRANDPA_PALLET_NAME: &str = "BridgePolkadotBulletinGrandpa"; +/// Name of the With-Polkadot Bulletin chain messages pallet instance that is deployed at bridged +/// chains. +pub const WITH_POLKADOT_BULLETIN_MESSAGES_PALLET_NAME: &str = "BridgePolkadotBulletinMessages"; + +// There are fewer system operations on this chain (e.g. staking, governance, etc.). Use a higher +// percentage of the block for data storage. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(90); + +// Re following constants - we are using the same values at Cumulus parachains. They are limited +// by the maximal transaction weight/size. Since block limits at Bulletin Chain are larger than +// at the Cumulus Bridgeg Hubs, we could reuse the same values. + +/// Maximal number of unrewarded relayer entries at inbound lane for Cumulus-based parachains. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Maximal number of unconfirmed messages at inbound lane for Cumulus-based parachains. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; + +/// This signed extension is used to ensure that the chain transactions are signed by proper +pub type ValidateSigned = GenericSignedExtensionSchema<(), ()>; + +/// Signed extension schema, used by Polkadot Bulletin. +pub type SignedExtensionSchema = GenericSignedExtension<( + ( + CheckNonZeroSender, + CheckSpecVersion, + CheckTxVersion, + CheckGenesis, + CheckEra, + CheckNonce, + CheckWeight, + ), + ValidateSigned, +)>; + +/// Signed extension, used by Polkadot Bulletin. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub struct SignedExtension(SignedExtensionSchema); + +impl sp_runtime::traits::SignedExtension for SignedExtension { + const IDENTIFIER: &'static str = "Not needed."; + type AccountId = (); + type Call = (); + type AdditionalSigned = + ::AdditionalSigned; + type Pre = (); + + fn additional_signed(&self) -> Result { + self.0.additional_signed() + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } +} + +impl SignedExtension { + /// Create signed extension from its components. + pub fn from_params( + spec_version: u32, + transaction_version: u32, + era: TransactionEra, + genesis_hash: Hash, + nonce: Nonce, + ) -> Self { + Self(GenericSignedExtension::new( + ( + ( + (), // non-zero sender + (), // spec version + (), // tx version + (), // genesis + era.frame_era(), // era + nonce.into(), // nonce (compact encoding) + (), // Check weight + ), + (), + ), + Some(( + ( + (), + spec_version, + transaction_version, + genesis_hash, + era.signed_payload(genesis_hash), + (), + (), + ), + (), + )), + )) + } + + /// Return transaction nonce. + pub fn nonce(&self) -> Nonce { + let common_payload = self.0.payload.0; + common_payload.5 .0 + } +} + +parameter_types! { + /// We allow for 2 seconds of compute with a 6 second average block time. + pub BlockWeights: limits::BlockWeights = limits::BlockWeights::with_sensible_defaults( + Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + NORMAL_DISPATCH_RATIO, + ); + // Note: Max transaction size is 8 MB. Set max block size to 10 MB to facilitate data storage. + // This is double the "normal" Relay Chain block length limit. + /// Maximal block length at Polkadot Bulletin chain. + pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio( + 10 * 1024 * 1024, + NORMAL_DISPATCH_RATIO, + ); +} + +/// Polkadot Bulletin Chain declaration. +pub struct PolkadotBulletin; + +impl Chain for PolkadotBulletin { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + // The Bulletin Chain is a permissioned blockchain without any balances. Our `Chain` trait + // requires balance type, which is then used by various bridge infrastructure code. However + // this code is optional and we are not planning to use it in our bridge. + type Balance = Balance; + type Nonce = Nonce; + type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) + } + + fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) + } +} + +impl ChainWithGrandpa for PolkadotBulletin { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_POLKADOT_BULLETIN_GRANDPA_PALLET_NAME; + const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; +} + +decl_bridge_finality_runtime_apis!(polkadot_bulletin, grandpa); +decl_bridge_messages_runtime_apis!(polkadot_bulletin); diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index d1d6f74543121afb47c5fdc423fd29aae5e2615e..61c8ca927d807ac6c169bb30d324f9720118e010 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -23,7 +23,6 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, extensions::PrevalidateAttests, Chain}; use frame_support::weights::Weight; -use sp_std::prelude::Vec; /// Polkadot Chain pub struct Polkadot; diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index 1589d14ea5143da0bc0244b23f502a2b99cf9233..5436ad846468cda632aab9ffcf46748f4c1546f8 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -23,7 +23,6 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain}; use frame_support::{parameter_types, weights::Weight}; -use sp_std::prelude::Vec; /// Rococo Chain pub struct Rococo; diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs index 5b5bde82690442c3a2c26b424163eeb58b5892e9..b1df65630beffdaad80ce8f22ba357dbf766ea0f 100644 --- a/bridges/primitives/chain-wococo/src/lib.rs +++ b/bridges/primitives/chain-wococo/src/lib.rs @@ -26,7 +26,6 @@ pub use bp_rococo::{ use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain}; use frame_support::weights::Weight; -use sp_std::prelude::Vec; /// Wococo Chain pub struct Wococo; diff --git a/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs index bb8aaadf327ecccde64365ce5860c5b3095079e7..a66fc1e0d91d1fe45ca747a0060abdb87f9d0e44 100644 --- a/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -143,6 +143,7 @@ pub enum PrecommitError { } /// The context needed for validating GRANDPA finality proofs. +#[derive(RuntimeDebug)] pub struct JustificationVerificationContext { /// The authority set used to verify the justification. pub voter_set: VoterSet, diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 5caaebd42babc32124ec724f10129f84f39423f7..e1809e145248f1cb37022ed4c2bb29d1547b2b2a 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -311,7 +311,7 @@ macro_rules! decl_bridge_finality_runtime_apis { $( /// Returns the justifications accepted in the current block. fn []( - ) -> Vec<$justification_type>; + ) -> sp_std::vec::Vec<$justification_type>; )? } } @@ -360,10 +360,10 @@ macro_rules! decl_bridge_messages_runtime_apis { /// If some (or all) messages are missing from the storage, they'll also will /// be missing from the resulting vector. The vector is ordered by the nonce. fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec; + lane: bp_messages::LaneId, + begin: bp_messages::MessageNonce, + end: bp_messages::MessageNonce, + ) -> sp_std::vec::Vec; } /// Inbound message lane API for messages sent by this chain. @@ -376,9 +376,9 @@ macro_rules! decl_bridge_messages_runtime_apis { pub trait [] { /// Return details of given inbound messages. fn message_details( - lane: LaneId, - messages: Vec<(MessagePayload, OutboundMessageDetails)>, - ) -> Vec; + lane: bp_messages::LaneId, + messages: sp_std::vec::Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> sp_std::vec::Vec; } } } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index ece782e352bc21e6044cd93191957ac25a040b2a..7f4a1a030b14562e17e9938ddffa1293cfcda204 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -74,6 +74,9 @@ pub const MILLAU_CHAIN_ID: ChainId = *b"mlau"; /// Polkadot chain id. pub const POLKADOT_CHAIN_ID: ChainId = *b"pdot"; +/// Polkadot Bulletin chain id. +pub const POLKADOT_BULLETIN_CHAIN_ID: ChainId = *b"pdbc"; + /// Kusama chain id. pub const KUSAMA_CHAIN_ID: ChainId = *b"ksma"; diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 7081ce90f97b90c3eb437d297fae5cc9f65cfe61..9836c1877f00239f72dd97c74b6b5fa8698b12e6 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bp-test-utils" version = "0.1.0" +description = "Utilities for testing substrate-based runtime bridge code" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/cumulus/.gitattributes b/cumulus/.gitattributes deleted file mode 100644 index 2ea1ab2d6b9cff5f075666eb5a780575870c221e..0000000000000000000000000000000000000000 --- a/cumulus/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -/.gitlab-ci.yml filter=ci-prettier -/scripts/ci/gitlab/pipeline/*.yml filter=ci-prettier diff --git a/cumulus/.github/dependabot.yml b/cumulus/.github/dependabot.yml deleted file mode 100644 index 349a34690d4eb6ad43a21f215e165d2ba44b09fc..0000000000000000000000000000000000000000 --- a/cumulus/.github/dependabot.yml +++ /dev/null @@ -1,31 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "cargo" - directory: "/" - labels: ["A2-insubstantial", "B0-silent", "C1-low"] - # Handle updates for crates from github.com/paritytech/substrate manually. - ignore: - - dependency-name: "substrate-*" - - dependency-name: "sc-*" - - dependency-name: "sp-*" - - dependency-name: "frame-*" - - dependency-name: "fork-tree" - - dependency-name: "frame-remote-externalities" - - dependency-name: "pallet-*" - - dependency-name: "beefy-*" - - dependency-name: "try-runtime-*" - - dependency-name: "test-runner" - - dependency-name: "generate-bags" - - dependency-name: "sub-tokens" - - dependency-name: "polkadot-*" - - dependency-name: "xcm*" - - dependency-name: "kusama-*" - - dependency-name: "westend-*" - - dependency-name: "rococo-*" - schedule: - interval: "daily" - - package-ecosystem: github-actions - directory: '/' - labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] - schedule: - interval: daily diff --git a/cumulus/.github/pr-custom-review.yml b/cumulus/.github/pr-custom-review.yml deleted file mode 100644 index fc26ee677f065089eda5a490e52d9ce0705a3558..0000000000000000000000000000000000000000 --- a/cumulus/.github/pr-custom-review.yml +++ /dev/null @@ -1,48 +0,0 @@ -# 🔒 PROTECTED: Changes to locks-review-team should be approved by the current locks-review-team -locks-review-team: cumulus-locks-review -team-leads-team: polkadot-review -action-review-team: ci - -rules: - - name: Runtime files - check_type: changed_files - condition: ^parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$|^parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$|^parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$|^parachains/common/src/[^/]+\.rs$ - all_distinct: - - min_approvals: 1 - teams: - - cumulus-locks-review - - min_approvals: 1 - teams: - - polkadot-review - - - name: Core developers - check_type: changed_files - condition: - include: .* - # excluding files from 'Runtime files' and 'CI files' rules and `Bridges subtree files` - exclude: ^parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$|^parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$|^parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$|^parachains/common/src/[^/]+\.rs$|^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* - min_approvals: 2 - teams: - - core-devs - - # if there are any changes in the bridges subtree (in case of backport changes back to bridges repo) - - name: Bridges subtree files - check_type: changed_files - condition: ^bridges/.* - min_approvals: 1 - teams: - - bridges-core - - - name: CI files - check_type: changed_files - condition: - include: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* - exclude: ^scripts/ci/gitlab/pipeline/zombienet.yml$ - min_approvals: 2 - teams: - - ci - - release-engineering - -prevent-review-request: - teams: - - core-devs diff --git a/cumulus/.github/workflows/check-D-labels.yml b/cumulus/.github/workflows/check-D-labels.yml deleted file mode 100644 index 91062720931078730a43390f0b36edf964628472..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/check-D-labels.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Check D labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - paths: - - primitives/** - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - env: - IMAGE: paritytech/ruled_labels:0.4.0 - run: docker pull $IMAGE - - - name: Check labels - env: - IMAGE: paritytech/ruled_labels:0.4.0 - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_cumulus.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags audit --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags audit diff --git a/cumulus/.github/workflows/check-labels.yml b/cumulus/.github/workflows/check-labels.yml deleted file mode 100644 index 004271d7788ad48336544d851bd7802e4dd201e6..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/check-labels.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Check labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - env: - IMAGE: paritytech/ruled_labels:0.4.0 - run: docker pull $IMAGE - - - name: Check labels - env: - IMAGE: paritytech/ruled_labels:0.4.0 - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_cumulus.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags audit --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags PR diff --git a/cumulus/.github/workflows/docs.yml b/cumulus/.github/workflows/docs.yml deleted file mode 100644 index 6aab3f27be6b4256e2e3cfd6db58d54a7f952d50..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/docs.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Publish Rust Docs - -on: - push: - branches: - - master - -jobs: - deploy-docs: - name: Deploy docs - runs-on: ubuntu-latest - - steps: - - name: Install tooling - run: | - sudo apt-get install -y protobuf-compiler - protoc --version - - - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - - name: Rust versions - run: rustup show - - - name: Rust cache - uses: Swatinem/rust-cache@e207df5d269b42b69c8bc5101da26f7d31feddb4 # v2.6.2 - - - name: Build rustdocs - run: SKIP_WASM_BUILD=1 cargo doc --all --no-deps - - - name: Make index.html - run: echo "" > ./target/doc/index.html - - - name: Deploy documentation - uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3.9.3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: ./target/doc diff --git a/cumulus/.github/workflows/fmt-check.yml b/cumulus/.github/workflows/fmt-check.yml deleted file mode 100644 index 7571c51116be8bd5f6a4225fb90a24c4109ef1fc..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/fmt-check.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Rustfmt check - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -jobs: - quick_check: - strategy: - matrix: - os: ["ubuntu-latest"] - runs-on: ${{ matrix.os }} - container: - image: paritytech/ci-linux:production - steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - - name: Cargo fmt - run: cargo +nightly fmt --all -- --check diff --git a/cumulus/.github/workflows/pr-custom-review.yml b/cumulus/.github/workflows/pr-custom-review.yml deleted file mode 100644 index 8e40c9ee72989d9ef244247456aa578d3836f8c6..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/pr-custom-review.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Assign reviewers - -on: - pull_request: - branches: - - master - - main - types: - - opened - - reopened - - synchronize - - review_requested - - review_request_removed - - ready_for_review - - converted_to_draft - pull_request_review: - -jobs: - pr-custom-review: - runs-on: ubuntu-latest - steps: - - name: Skip if pull request is in Draft - # `if: github.event.pull_request.draft == true` should be kept here, at - # the step level, rather than at the job level. The latter is not - # recommended because when the PR is moved from "Draft" to "Ready to - # review" the workflow will immediately be passing (since it was skipped), - # even though it hasn't actually ran, since it takes a few seconds for - # the workflow to start. This is also disclosed in: - # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17 - # That scenario would open an opportunity for the check to be bypassed: - # 1. Get your PR approved - # 2. Move it to Draft - # 3. Push whatever commits you want - # 4. Move it to "Ready for review"; now the workflow is passing (it was - # skipped) and "Check reviews" is also passing (it won't be updated - # until the workflow is finished) - if: github.event.pull_request.draft == true - run: exit 1 - - name: pr-custom-review - uses: paritytech/pr-custom-review@action-v3 - with: - checks-reviews-api: http://pcr.parity-prod.parity.io/api/v1/check_reviews diff --git a/cumulus/.github/workflows/release-01_branch-check.yml b/cumulus/.github/workflows/release-01_branch-check.yml deleted file mode 100644 index afcd4580f176fd31dcf007d99ece9db00e39f45e..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-01_branch-check.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Release branch check -on: - push: - branches: - - release-**v[0-9]+.[0-9]+.[0-9]+ # client - - release-**v[0-9]+ # runtimes - - polkadot-v[0-9]+.[0-9]+.[0-9]+ # cumulus code - - workflow_dispatch: - -jobs: - check_branch: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - fetch-depth: 0 - - - name: Run check - shell: bash - run: ./scripts/ci/github/check-rel-br diff --git a/cumulus/.github/workflows/release-10_rc-automation.yml b/cumulus/.github/workflows/release-10_rc-automation.yml deleted file mode 100644 index d1795faef096e36ffc6e0050802704d3c5ffbe48..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-10_rc-automation.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Release - RC automation -on: - push: - branches: - - release-v[0-9]+.[0-9]+.[0-9]+ - - release-parachains-v[0-9]+ - workflow_dispatch: - -jobs: - tag_rc: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: 'RelEng: Cumulus Release Coordination' - room: '!NAEMyPAHWOiOQHsvus:parity.io' - pre-releases: true - steps: - - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - fetch-depth: 0 - - id: compute_tag - name: Compute next rc tag - shell: bash - run: | - # Get last rc tag if exists, else set it to {version}-rc1 - version=${GITHUB_REF#refs/heads/release-} - echo "$version" - echo "version=$version" >> $GITHUB_OUTPUT - git tag -l - last_rc=$(git tag -l "$version-rc*" | sort -V | tail -n 1) - if [ -n "$last_rc" ]; then - suffix=$(echo "$last_rc" | grep -Eo '[0-9]+$') - echo $suffix - ((suffix++)) - echo $suffix - echo "new_tag=$version-rc$suffix" >> $GITHUB_OUTPUT - echo "first_rc=false" >> $GITHUB_OUTPUT - else - echo "new_tag=$version-rc1" >> $GITHUB_OUTPUT - echo "first_rc=true" >> $GITHUB_OUTPUT - fi - - - name: Apply new tag - uses: tvdias/github-tagger@ed7350546e3e503b5e942dffd65bc8751a95e49d # v0.0.2 - with: - # We can't use the normal GITHUB_TOKEN for the following reason: - # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token - # RELEASE_BRANCH_TOKEN requires public_repo OAuth scope - repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}" - tag: ${{ steps.compute_tag.outputs.new_tag }} - - - id: create-issue-checklist-client - uses: JasonEtco/create-an-issue@e27dddc79c92bc6e4562f268fffa5ed752639abd # v2.9.1 - # Only create the issue if it's the first release candidate - if: steps.compute_tag.outputs.first_rc == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.compute_tag.outputs.version }} - with: - assignees: EgorPopelyaev, coderobe, chevdor - filename: .github/ISSUE_TEMPLATE/release-client.md - - - id: create-issue-checklist-runtime - uses: JasonEtco/create-an-issue@e27dddc79c92bc6e4562f268fffa5ed752639abd # v2.9.1 - # Only create the issue if it's the first release candidate - if: steps.compute_tag.outputs.first_rc == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.compute_tag.outputs.version }} - with: - assignees: EgorPopelyaev, coderobe, chevdor - filename: .github/ISSUE_TEMPLATE/release-runtime.md - - - name: Matrix notification to ${{ matrix.channel.name }} - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - if: steps.create-issue-checklist-client.outputs.url != '' && steps.create-issue-checklist-runtime.outputs.url != '' - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: "m.parity.io" - message: | - The Release Process for Cumulus ${{ steps.compute_tag.outputs.version }} has been started.
- Tracking issues: - - client: ${{ steps.create-issue-checklist-client.outputs.url }}" - - runtime: ${{ steps.create-issue-checklist-runtime.outputs.url }}" diff --git a/cumulus/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml b/cumulus/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml deleted file mode 100644 index d902e57ac9e7f2d95b9f7a8eb96fb7febe2da887..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml +++ /dev/null @@ -1,86 +0,0 @@ -# This workflow performs the Extrinsic Ordering Check on demand using a binary - -name: Release - Extrinsic Ordering Check from Binary -on: - workflow_dispatch: - inputs: - reference_url: - description: The WebSocket url of the reference node - default: wss://kusama-asset-hub-rpc.polkadot.io - required: true - binary_url: - description: A url to a Linux binary for the node containing the runtime to test - default: https://releases.parity.io/cumulus/polkadot-v0.9.21/polkadot-parachain - required: true - chain: - description: The name of the chain under test. Usually, you would pass a local chain - default: asset-hub-kusama-local - required: true - -jobs: - check: - name: Run check - runs-on: ubuntu-latest - env: - CHAIN: ${{github.event.inputs.chain}} - BIN: node-bin - BIN_PATH: ./tmp/$BIN - BIN_URL: ${{github.event.inputs.binary_url}} - REF_URL: ${{github.event.inputs.reference_url}} - - steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - - name: Fetch binary - run: | - echo Creating a temp dir to download and run binary - mkdir -p tmp - echo Fetching $BIN_URL - wget $BIN_URL -O $BIN_PATH - chmod a+x $BIN_PATH - $BIN_PATH --version - - - name: Start local node - run: | - echo Running on $CHAIN - $BIN_PATH --chain=$CHAIN -- --chain polkadot-local & - - - name: Prepare output - run: | - VERSION=$($BIN_PATH --version) - echo "Metadata comparison:" >> output.txt - echo "Date: $(date)" >> output.txt - echo "Reference: $REF_URL" >> output.txt - echo "Target version: $VERSION" >> output.txt - echo "Chain: $CHAIN" >> output.txt - echo "----------------------------------------------------------------------" >> output.txt - - - name: Pull polkadot-js-tools image - run: docker pull jacogr/polkadot-js-tools - - - name: Compare the metadata - run: | - CMD="docker run --pull always --network host jacogr/polkadot-js-tools metadata $REF_URL ws://localhost:9944" - echo -e "Running:\n$CMD" - $CMD >> output.txt - sed -z -i 's/\n\n/\n/g' output.txt - cat output.txt | egrep -n -i '' - SUMMARY=$(./scripts/ci/github/extrinsic-ordering-filter.sh output.txt) - echo -e $SUMMARY - echo -e $SUMMARY >> output.txt - - - name: Show result - run: | - cat output.txt - - - name: Stop our local node - run: | - pkill $BIN - continue-on-error: true - - - name: Save output as artifact - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ env.CHAIN }} - path: | - output.txt diff --git a/cumulus/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml b/cumulus/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml deleted file mode 100644 index 93c0050ff6f2500237e6461160d769caadfe2225..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml +++ /dev/null @@ -1,120 +0,0 @@ -# This workflow performs the Extrinsic Ordering Check on demand using two reference binaries - -name: Release - Extrinsic API Check with reference bins -on: - workflow_dispatch: - inputs: - reference_binary_url: - description: A url to a Linux binary for the node containing the reference runtime to test against - default: https://releases.parity.io/cumulus/v0.9.230/polkadot-parachain - required: true - binary_url: - description: A url to a Linux binary for the node containing the runtime to test - default: https://releases.parity.io/cumulus/v0.9.270-rc7/polkadot-parachain - required: true - -jobs: - check: - name: Run check - runs-on: ubuntu-latest - timeout-minutes: 10 - env: - REF_URL: ${{github.event.inputs.reference_binary_url}} - BIN_REF: polkadot-parachain-ref - BIN_URL: ${{github.event.inputs.binary_url}} - BIN_BASE: polkadot-parachain - TMP: ./tmp - strategy: - fail-fast: false - matrix: - include: - - runtime: asset-hub-kusama - local: asset-hub-kusama-local - relay: kusama-local - - runtime: asset-hub-polkadot - local: asset-hub-polkadot-local - relay: polkadot-local - - runtime: asset-hub-westend - local: asset-hub-westend-local - relay: polkadot-local - - runtime: contracts-rococo - local: contracts-rococo-local - relay: polkadot-local - - steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - - name: Create tmp dir - run: | - mkdir -p $TMP - pwd - - - name: Fetch reference binary for ${{ matrix.runtime }} - run: | - echo Fetching $REF_URL - curl $REF_URL -o $TMP/$BIN_REF - chmod a+x $TMP/$BIN_REF - $TMP/$BIN_REF --version - - - name: Fetch test binary for ${{ matrix.runtime }} - run: | - echo Fetching $BIN_URL - curl $BIN_URL -o $TMP/$BIN_BASE - chmod a+x $TMP/$BIN_BASE - $TMP/$BIN_BASE --version - - - name: Start local reference node for ${{ matrix.runtime }} - run: | - echo Running reference on ${{ matrix.local }} - $TMP/$BIN_REF --chain=${{ matrix.local }} --ws-port=9954 --tmp -- --chain ${{ matrix.relay }} & - sleep 15 - - - name: Start local test node for ${{ matrix.runtime }} - run: | - echo Running test on ${{ matrix.local }} - $TMP/$BIN_BASE --chain=${{ matrix.local }} --ws-port=9944 --tmp -- --chain ${{ matrix.relay }} & - sleep 15 - - - name: Prepare output - run: | - REF_VERSION=$($TMP/$BIN_REF --version) - BIN_VERSION=$($TMP/$BIN_BASE --version) - echo "Metadata comparison:" >> output.txt - echo "Date: $(date)" >> output.txt - echo "Ref. binary: $REF_URL" >> output.txt - echo "Test binary: $BIN_URL" >> output.txt - echo "Ref. version: $REF_VERSION" >> output.txt - echo "Test version: $BIN_VERSION" >> output.txt - echo "Chain: ${{ matrix.local }}" >> output.txt - echo "Relay: ${{ matrix.relay }}" >> output.txt - echo "----------------------------------------------------------------------" >> output.txt - - - name: Pull polkadot-js-tools image - run: docker pull jacogr/polkadot-js-tools - - - name: Compare the metadata - run: | - CMD="docker run --pull always --network host jacogr/polkadot-js-tools metadata ws://localhost:9954 ws://localhost:9944" - echo -e "Running:\n$CMD" - $CMD >> output.txt - sed -z -i 's/\n\n/\n/g' output.txt - cat output.txt | egrep -n -i '' - SUMMARY=$(./scripts/ci/github/extrinsic-ordering-filter.sh output.txt) - echo -e $SUMMARY - echo -e $SUMMARY >> output.txt - - - name: Show result - run: | - cat output.txt - - - name: Save output as artifact - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ matrix.runtime }} - path: | - output.txt - - - name: Stop our local nodes - run: | - pkill $BIN_REF || true - pkill $BIN_BASE || true diff --git a/cumulus/.github/workflows/release-30_create-draft.yml b/cumulus/.github/workflows/release-30_create-draft.yml deleted file mode 100644 index 2d11dfe18cec86883ad53cda1389a30d6b40f1d2..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-30_create-draft.yml +++ /dev/null @@ -1,311 +0,0 @@ -name: Release - Create draft - -on: - workflow_dispatch: - inputs: - ref1: - description: The 'from' tag to use for the diff - default: parachains-v9.0.0 - required: true - ref2: - description: The 'to' tag to use for the diff - default: release-parachains-v10.0.0 - required: true - release_type: - description: Pass "client" for client releases, leave empty otherwise - required: false - pre_release: - description: For pre-releases - default: "true" - required: true - notification: - description: Whether or not to notify over Matrix - default: "true" - required: true - -jobs: - get-rust-versions: - runs-on: ubuntu-latest - container: - image: paritytech/ci-linux:production - outputs: - rustc-stable: ${{ steps.get-rust-versions.outputs.stable }} - rustc-nightly: ${{ steps.get-rust-versions.outputs.nightly }} - steps: - - id: get-rust-versions - run: | - echo "stable=$(rustc +stable --version)" >> $GITHUB_OUTPUT - echo "nightly=$(rustc +nightly --version)" >> $GITHUB_OUTPUT - - # We do not skip the entire job for client builds (although we don't need it) - # because it is a dep of the next job. However we skip the time consuming steps. - build-runtimes: - runs-on: ubuntu-latest - strategy: - matrix: - include: - - category: assets - runtime: asset-hub-kusama - - category: assets - runtime: asset-hub-polkadot - - category: assets - runtime: asset-hub-westend - - category: bridge-hubs - runtime: bridge-hub-polkadot - - category: bridge-hubs - runtime: bridge-hub-kusama - - category: bridge-hubs - runtime: bridge-hub-rococo - - category: collectives - runtime: collectives-polkadot - - category: contracts - runtime: contracts-rococo - - category: starters - runtime: seedling - - category: starters - runtime: shell - - category: testing - runtime: rococo-parachain - steps: - - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - ref: ${{ github.event.inputs.ref2 }} - - - name: Cache target dir - if: ${{ github.event.inputs.release_type != 'client' }} - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 - with: - path: "${{ github.workspace }}/runtime/${{ matrix.runtime }}/target" - key: srtool-target-${{ matrix.runtime }}-${{ github.sha }} - restore-keys: | - srtool-target-${{ matrix.runtime }}- - srtool-target- - - - name: Build ${{ matrix.runtime }} runtime - if: ${{ github.event.inputs.release_type != 'client' }} - id: srtool_build - uses: chevdor/srtool-actions@v0.7.0 - with: - image: paritytech/srtool - chain: ${{ matrix.runtime }} - runtime_dir: parachains/runtimes/${{ matrix.category }}/${{ matrix.runtime }} - - - name: Store srtool digest to disk - if: ${{ github.event.inputs.release_type != 'client' }} - run: | - echo '${{ steps.srtool_build.outputs.json }}' | \ - jq > ${{ matrix.runtime }}-srtool-digest.json - - - name: Upload ${{ matrix.runtime }} srtool json - if: ${{ github.event.inputs.release_type != 'client' }} - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ matrix.runtime }}-srtool-json - path: ${{ matrix.runtime }}-srtool-digest.json - - - name: Upload ${{ matrix.runtime }} runtime - if: ${{ github.event.inputs.release_type != 'client' }} - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ matrix.runtime }}-runtime - path: | - ${{ steps.srtool_build.outputs.wasm_compressed }} - - publish-draft-release: - runs-on: ubuntu-latest - needs: ["get-rust-versions", "build-runtimes"] - outputs: - release_url: ${{ steps.create-release.outputs.html_url }} - asset_upload_url: ${{ steps.create-release.outputs.upload_url }} - steps: - - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - fetch-depth: 0 - path: cumulus - ref: ${{ github.event.inputs.ref2 }} - - - uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0 - with: - ruby-version: 3.0.0 - - - name: Download srtool json output - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - - - name: Prepare tooling - run: | - cd cumulus/scripts/ci/changelog - gem install bundler changelogerator:0.9.1 - bundle install - changelogerator --help - - URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.1/tera-cli_linux_amd64.deb - wget $URL -O tera.deb - sudo dpkg -i tera.deb - tera --version - - - name: Generate release notes - env: - RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }} - RUSTC_NIGHTLY: ${{ needs.get-rust-versions.outputs.rustc-nightly }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NO_CACHE: 1 - DEBUG: 1 - SHELL_DIGEST: ${{ github.workspace}}/shell-srtool-json/shell-srtool-digest.json - ASSET_HUB_WESTEND_DIGEST: ${{ github.workspace}}/asset-hub-westend-srtool-json/asset-hub-westend-srtool-digest.json - ASSET_HUB_KUSAMA_DIGEST: ${{ github.workspace}}/asset-hub-kusama-srtool-json/asset-hub-kusama-srtool-digest.json - ASSET_HUB_POLKADOT_DIGEST: ${{ github.workspace}}/asset-hub-polkadot-srtool-json/asset-hub-polkadot-srtool-digest.json - BRIDGE_HUB_ROCOCO_DIGEST: ${{ github.workspace}}/bridge-hub-rococo-srtool-json/bridge-hub-rococo-srtool-digest.json - BRIDGE_HUB_KUSAMA_DIGEST: ${{ github.workspace}}/bridge-hub-kusama-srtool-json/bridge-hub-kusama-srtool-digest.json - BRIDGE_HUB_POLKADOT_DIGEST: ${{ github.workspace}}/bridge-hub-polkadot-srtool-json/bridge-hub-polkadot-srtool-digest.json - COLLECTIVES_POLKADOT_DIGEST: ${{ github.workspace}}/collectives-polkadot-srtool-json/collectives-polkadot-srtool-digest.json - ROCOCO_PARA_DIGEST: ${{ github.workspace}}/rococo-parachain-srtool-json/rococo-parachain-srtool-digest.json - CANVAS_KUSAMA_DIGEST: ${{ github.workspace}}/contracts-rococo-srtool-json/contracts-rococo-srtool-digest.json - REF1: ${{ github.event.inputs.ref1 }} - REF2: ${{ github.event.inputs.ref2 }} - PRE_RELEASE: ${{ github.event.inputs.pre_release }} - RELEASE_TYPE: ${{ github.event.inputs.release_type }} - run: | - find ${{env.GITHUB_WORKSPACE}} -type f -name "*-srtool-digest.json" - - if [ "$RELEASE_TYPE" != "client" ]; then - ls -al $SHELL_DIGEST || true - ls -al $ASSET_HUB_WESTEND_DIGEST || true - ls -al $ASSET_HUB_KUSAMA_DIGEST || true - ls -al $ASSET_HUB_POLKADOT_DIGEST || true - ls -al $BRIDGE_HUB_ROCOCO_DIGEST || true - ls -al $BRIDGE_HUB_KUSAMA_DIGEST || true - ls -al $BRIDGE_HUB_POLKADOT_DIGEST || true - ls -al $COLLECTIVES_POLKADOT_DIGEST || true - ls -al $ROCOCO_PARA_DIGEST || true - ls -al $CANVAS_KUSAMA_DIGEST || true - fi - - echo "The diff will be computed from $REF1 to $REF2" - cd cumulus/scripts/ci/changelog - ./bin/changelog $REF1 $REF2 release-notes.md - ls -al {release-notes.md,context.json} || true - - - name: Archive srtool json - if: ${{ github.event.inputs.release_type != 'client' }} - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: srtool-json - path: | - **/*-srtool-digest.json - - - name: Archive context artifact - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: release-notes-context - path: | - cumulus/scripts/ci/changelog/context.json - - - name: Create draft release - id: create-release - uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - body_path: ./cumulus/scripts/ci/changelog/release-notes.md - tag_name: ${{ github.event.inputs.ref2 }} - release_name: ${{ github.event.inputs.ref2 }} - draft: true - - publish-runtimes: - if: ${{ github.event.inputs.release_type != 'client' }} - runs-on: ubuntu-latest - needs: ["publish-draft-release"] - env: - RUNTIME_DIR: parachains/runtimes - strategy: - matrix: - include: - - category: assets - runtime: asset-hub-kusama - - category: assets - runtime: asset-hub-polkadot - - category: assets - runtime: asset-hub-westend - - category: bridge-hubs - runtime: bridge-hub-polkadot - - category: bridge-hubs - runtime: bridge-hub-kusama - - category: bridge-hubs - runtime: bridge-hub-rococo - - category: collectives - runtime: collectives-polkadot - - category: contracts - runtime: contracts-rococo - - category: starters - runtime: seedling - - category: starters - runtime: shell - - category: testing - runtime: rococo-parachain - steps: - - name: Checkout sources - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - ref: ${{ github.event.inputs.ref2 }} - - - name: Download artifacts - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - - - uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0 - with: - ruby-version: 3.0.0 - - - name: Get runtime version for ${{ matrix.runtime }} - id: get-runtime-ver - run: | - echo "require './scripts/ci/github/runtime-version.rb'" > script.rb - echo "puts get_runtime(runtime: \"${{ matrix.runtime }}\", runtime_dir: \"$RUNTIME_DIR/${{ matrix.category }}\")" >> script.rb - - echo "Current folder: $PWD" - ls "$RUNTIME_DIR/${{ matrix.category }}/${{ matrix.runtime }}" - runtime_ver=$(ruby script.rb) - echo "Found version: >$runtime_ver<" - echo "runtime_ver=$runtime_ver" >> $GITHUB_OUTPUT - - - name: Fix runtime name - id: fix-runtime-path - run: | - cd "${{ matrix.runtime }}-runtime/" - mv "$(sed -E 's/- */_/g' <<< ${{ matrix.runtime }})_runtime.compact.compressed.wasm" "${{ matrix.runtime }}_runtime.compact.compressed.wasm" || true - - - name: Upload compressed ${{ matrix.runtime }} wasm - uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.publish-draft-release.outputs.asset_upload_url }} - asset_path: "${{ matrix.runtime }}-runtime/${{ matrix.runtime }}_runtime.compact.compressed.wasm" - asset_name: ${{ matrix.runtime }}_runtime-v${{ steps.get-runtime-ver.outputs.runtime_ver }}.compact.compressed.wasm - asset_content_type: application/wasm - - post_to_matrix: - if: ${{ github.event.inputs.notification == 'true' }} - runs-on: ubuntu-latest - needs: publish-draft-release - strategy: - matrix: - channel: - - name: 'RelEng: Cumulus Release Coordination' - room: '!NAEMyPAHWOiOQHsvus:parity.io' - pre-releases: true - steps: - - name: Matrix notification to ${{ matrix.channel.name }} - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: "m.parity.io" - message: | - **New draft for ${{ github.repository }}**: ${{ github.event.inputs.ref2 }}
- - Draft release created: [draft](${{ needs.publish-draft-release.outputs.release_url }}) - - NOTE: The link above will no longer be valid if the draft is edited. You can then use the following link: - [${{ github.server_url }}/${{ github.repository }}/releases](${{ github.server_url }}/${{ github.repository }}/releases) diff --git a/cumulus/.github/workflows/release-99_bot-announce.yml b/cumulus/.github/workflows/release-99_bot-announce.yml deleted file mode 100644 index 5c2604924c4c0d25216986265ca70c3c81d423f9..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/release-99_bot-announce.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Release - Pushes release notes to a Matrix room -on: - release: - types: - - published - -jobs: - ping_matrix: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: 'RelEng: Cumulus Release Coordination' - room: '!NAEMyPAHWOiOQHsvus:parity.io' - pre-releases: true - - name: 'Ledger <> Polkadot Coordination' - room: '!EoIhaKfGPmFOBrNSHT:web3.foundation' - pre-release: true - - name: 'General: Rust, Polkadot, Substrate' - room: '!aJymqQYtCjjqImFLSb:parity.io' - pre-release: false - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - pre-release: true - - steps: - - name: Matrix notification to ${{ matrix.channel.name }} - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: "m.parity.io" - message: | - A (pre)release has been ${{github.event.action}} in **${{github.event.repository.full_name}}:**
- Release version: [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) - - ----- - - ${{github.event.release.body}} diff --git a/cumulus/.github/workflows/srtool.yml b/cumulus/.github/workflows/srtool.yml deleted file mode 100644 index ae473b4813709f5f75244e07b770f43654881647..0000000000000000000000000000000000000000 --- a/cumulus/.github/workflows/srtool.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Srtool build - -env: - SUBWASM_VERSION: 0.20.0 - -on: - push: - tags: - - "*" - - # paths-ignore: - # - "docker" - # - "docs" - # - "scripts" - # - "test" - # - "client" - paths: - - parachains/runtimes/**/* - - branches: - - "release*" - - schedule: - - cron: "00 02 * * 1" # 2AM weekly on monday - - workflow_dispatch: - -jobs: - srtool: - runs-on: ubuntu-latest - strategy: - matrix: - include: - - category: assets - runtime: asset-hub-kusama - - category: assets - runtime: asset-hub-polkadot - - category: assets - runtime: asset-hub-westend - - category: bridge-hubs - runtime: bridge-hub-polkadot - - category: bridge-hubs - runtime: bridge-hub-kusama - - category: bridge-hubs - runtime: bridge-hub-rococo - - category: collectives - runtime: collectives-polkadot - - category: contracts - runtime: contracts-rococo - - category: starters - runtime: seedling - - category: starters - runtime: shell - - category: testing - runtime: rococo-parachain - steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - fetch-depth: 0 - - - name: Srtool build - id: srtool_build - uses: chevdor/srtool-actions@v0.7.0 - with: - chain: ${{ matrix.runtime }} - runtime_dir: parachains/runtimes/${{ matrix.category }}/${{ matrix.runtime }} - - - name: Summary - run: | - echo '${{ steps.srtool_build.outputs.json }}' | jq > ${{ matrix.runtime }}-srtool-digest.json - cat ${{ matrix.runtime }}-srtool-digest.json - echo "Compact Runtime: ${{ steps.srtool_build.outputs.wasm }}" - echo "Compressed Runtime: ${{ steps.srtool_build.outputs.wasm_compressed }}" - - # it takes a while to build the runtime, so let's save the artifact as soon as we have it - - name: Archive Artifacts for ${{ matrix.runtime }} - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ matrix.runtime }}-runtime - path: | - ${{ steps.srtool_build.outputs.wasm }} - ${{ steps.srtool_build.outputs.wasm_compressed }} - ${{ matrix.runtime }}-srtool-digest.json - - # We now get extra information thanks to subwasm - - name: Install subwasm - run: | - wget https://github.com/chevdor/subwasm/releases/download/v${{ env.SUBWASM_VERSION }}/subwasm_linux_amd64_v${{ env.SUBWASM_VERSION }}.deb - sudo dpkg -i subwasm_linux_amd64_v${{ env.SUBWASM_VERSION }}.deb - subwasm --version - - - name: Show Runtime information - shell: bash - run: | - subwasm info ${{ steps.srtool_build.outputs.wasm }} - subwasm info ${{ steps.srtool_build.outputs.wasm_compressed }} - subwasm --json info ${{ steps.srtool_build.outputs.wasm }} > ${{ matrix.runtime }}-info.json - subwasm --json info ${{ steps.srtool_build.outputs.wasm_compressed }} > ${{ matrix.runtime }}-compressed-info.json - - - name: Extract the metadata - shell: bash - run: | - subwasm meta ${{ steps.srtool_build.outputs.wasm }} - subwasm --json meta ${{ steps.srtool_build.outputs.wasm }} > ${{ matrix.runtime }}-metadata.json - - - name: Check the metadata diff - shell: bash - # the following subwasm call will error for chains that are not known and/or live, that includes shell for instance - run: | - subwasm diff ${{ steps.srtool_build.outputs.wasm }} --chain-b ${{ matrix.runtime }} || \ - echo "Subwasm call failed, check the logs. This is likely because ${{ matrix.runtime }} is not known by subwasm" | \ - tee ${{ matrix.runtime }}-diff.txt - - - name: Archive Subwasm results - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: ${{ matrix.runtime }}-runtime - path: | - ${{ matrix.runtime }}-info.json - ${{ matrix.runtime }}-compressed-info.json - ${{ matrix.runtime }}-metadata.json - ${{ matrix.runtime }}-diff.txt diff --git a/cumulus/.gitlab-ci.yml b/cumulus/.gitlab-ci.yml deleted file mode 100644 index f032901c6f47123954187e400467d2d88396eac0..0000000000000000000000000000000000000000 --- a/cumulus/.gitlab-ci.yml +++ /dev/null @@ -1,201 +0,0 @@ -# .gitlab-ci.yml -# -# cumulus -# -# pipelines can be triggered manually in the web - -stages: - - test - - build - # used for manual job run for regenerate weights for release-* branches (not needed anymore, just leave it here for a while as PlanB) - - benchmarks-build - # used for manual job run for regenerate weights for release-* branches (not needed anymore, just leave it here for a while as PlanB) - - benchmarks-run - - publish - - integration-tests - - zombienet - - short-benchmarks - -default: - interruptible: true - retry: - max: 2 - when: - - runner_system_failure - - unknown_failure - - api_failure - -variables: - GIT_STRATEGY: fetch - GIT_DEPTH: 100 - CARGO_INCREMENTAL: 0 - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] - DOCKER_OS: "debian:stretch" - ARCH: "x86_64" - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.55" - BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" - BUILDAH_COMMAND: "buildah --storage-driver overlay2" - -.common-before-script: - before_script: - - !reference [.job-switcher, before_script] - - !reference [.timestamp, before_script] - -.collect-artifacts: - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 1 days - paths: - - ./artifacts/ - -# collecting vars for pipeline stopper -# they will be used if the job fails -.pipeline-stopper-vars: - before_script: - - echo "FAILED_JOB_URL=${CI_JOB_URL}" > pipeline-stopper.env - - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env - - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env - - echo "PR_NUM=${CI_COMMIT_REF_NAME}" >> pipeline-stopper.env - -.pipeline-stopper-artifacts: - artifacts: - reports: - dotenv: pipeline-stopper.env - -.common-refs: - # these jobs run always* - rules: - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^release-parachains-v[0-9].*$/ # i.e. release-parachains-v1.0, release-parachains-v2.1rc1, release-parachains-v3000 - - if: $CI_COMMIT_REF_NAME =~ /^polkadot-v[0-9]+\.[0-9]+.*$/ # i.e. polkadot-v1.0.99, polkadot-v2.1rc1 - -.pr-refs: - # these jobs run always* - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.publish-refs: - rules: - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - -# run benchmarks manually only on release-parachains-v* branch -.benchmarks-manual-refs: - rules: - - if: $CI_COMMIT_REF_NAME =~ /^release-parachains-v[0-9].*$/ # i.e. release-parachains-v1.0, release-parachains-v2.1rc1, release-parachains-v3000 - when: manual - -# run benchmarks only on release-parachains-v* branch -.benchmarks-refs: - rules: - - if: $CI_COMMIT_REF_NAME =~ /^release-parachains-v[0-9].*$/ # i.e. release-parachains-v1.0, release-parachains-v2.1rc1, release-parachains-v3000 - -.zombienet-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "schedule" - when: never - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.job-switcher: - before_script: - - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi - -.docker-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.common-before-script, before_script] - - rustup show - - cargo --version - - bash --version - tags: - - linux-docker-vm-c2 - -.kubernetes-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.common-before-script, before_script] - tags: - - kubernetes-parity-build - -.git-commit-push: - script: - - git status - # Set git config - - rm -rf .git/config - - git config --global user.email "${GITHUB_EMAIL}" - - git config --global user.name "${GITHUB_USER}" - - git config remote.origin.url "https://${GITHUB_USER}:${GITHUB_TOKEN}@github.com/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - # push results to github - - git checkout -b $BRANCHNAME - - git add parachains/* - - git commit -m "[benchmarks] pr with weights" - - git push origin $BRANCHNAME - -include: - # test jobs - - scripts/ci/gitlab/pipeline/test.yml - # # build jobs - - scripts/ci/gitlab/pipeline/build.yml - # short-benchmarks jobs - - scripts/ci/gitlab/pipeline/short-benchmarks.yml - # # benchmarks jobs - # # used for manual job run for regenerate weights for release-* branches (not needed anymore, just leave it here for a while as PlanB) - - scripts/ci/gitlab/pipeline/benchmarks.yml - # # publish jobs - - scripts/ci/gitlab/pipeline/publish.yml - # zombienet jobs - - scripts/ci/gitlab/pipeline/zombienet.yml - # timestamp handler - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/timestamp.yml - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/ci-unified.yml - - -#### stage: .post - -# This job cancels the whole pipeline if any of provided jobs fail. -# In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests -# to fail the pipeline as soon as possible to shorten the feedback loop. -cancel-pipeline: - stage: .post - needs: - - job: test-linux-stable - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - when: on_failure - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "${FAILED_JOB_URL}" - FAILED_JOB_NAME: "${FAILED_JOB_NAME}" - PR_NUM: "${PR_NUM}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" - branch: "as-improve" - -remove-cancel-pipeline-message: - stage: .post - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "https://gitlab.com" - FAILED_JOB_NAME: "nope" - PR_NUM: "${CI_COMMIT_REF_NAME}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 15f28d73b36eeeb43084589f2c233317926376e5..5dd18f0c156d1581c09d73e2ab9d6422dbe9ab4c 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true edition.workspace = true [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 22d3dd3abd49dfbe4a0bb548ce4b2c35cf5ed839..9658a0add790da01ad9fe83f11956d1fbd88523a 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -579,7 +579,7 @@ fn follow_new_best_sets_best_after_it_is_imported() { block_import_params.fork_choice = Some(ForkChoiceStrategy::Custom(false)); block_import_params.body = Some(body); - // Now import the unkown block to make it "known" + // Now import the unknown block to make it "known" client.import_block(block_import_params).await.unwrap(); loop { diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 39eda5075e29e9477ced48a37db3d45e00c67705..bc8d0d430c774bb3255f9494cd1fdced5a2d944d 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -41,6 +41,3 @@ metered = { package = "prioritized-metered-channel", version = "0.5.1", default- # Cumulus cumulus-test-service = { path = "../../test/service" } - -[features] -network-protocol-staging = [ "polkadot-service/network-protocol-staging" ] diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index a6970732447c34f485a8a066d1bec27b762352a9..3dda61635804d47440689872271751e0bba27d87 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -41,7 +41,7 @@ pub type RelayChainResult = Result; #[derive(thiserror::Error, Debug)] pub enum RelayChainError { - #[error("Error occured while calling relay chain runtime: {0}")] + #[error("Error occurred while calling relay chain runtime: {0}")] ApiError(#[from] ApiError), #[error("Timeout while waiting for relay-chain block `{0}` to be imported.")] WaitTimeout(PHash), @@ -53,7 +53,7 @@ pub enum RelayChainError { WaitBlockchainError(PHash, sp_blockchain::Error), #[error("Blockchain returned an error: {0}")] BlockchainError(#[from] sp_blockchain::Error), - #[error("State machine error occured: {0}")] + #[error("State machine error occurred: {0}")] StateMachineError(Box), #[error("Unable to call RPC method '{0}'")] RpcCallError(String), @@ -67,7 +67,7 @@ pub enum RelayChainError { Application(#[from] Box), #[error("Prometheus error: {0}")] PrometheusError(#[from] PrometheusError), - #[error("Unspecified error occured: {0}")] + #[error("Unspecified error occurred: {0}")] GenericError(String), } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 39056d6b6511666c4d71be224914ad3da6e30d5d..226474d3d38cd1b34c6d1304855338bf3c6f4ff9 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -41,7 +41,3 @@ tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" -[features] -network-protocol-staging = [ - "polkadot-node-network-protocol/network-protocol-staging", -] diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index 57e16bc4283ce00eea494fb1e4c66d08008bc73d..1e78df7115435449e6beb89224f0af32f3b3b988 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -22,8 +22,8 @@ use futures::{Stream, StreamExt}; use polkadot_core_primitives::{Block, BlockNumber, Hash, Header}; use polkadot_overseer::RuntimeApiSubsystemClient; use polkadot_primitives::{ + async_backing::{AsyncBackingParams, BackingState}, slashing, - vstaging::{AsyncBackingParams, BackingState}, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sp_api::{ApiError, RuntimeApiInfo}; @@ -346,16 +346,23 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { Ok(self.rpc_client.parachain_host_minimum_backing_votes(at, session_index).await?) } - async fn staging_async_backing_params(&self, at: Hash) -> Result { - Ok(self.rpc_client.parachain_host_staging_async_backing_params(at).await?) + async fn disabled_validators( + &self, + at: Hash, + ) -> Result, ApiError> { + Ok(self.rpc_client.parachain_host_disabled_validators(at).await?) + } + + async fn async_backing_params(&self, at: Hash) -> Result { + Ok(self.rpc_client.parachain_host_async_backing_params(at).await?) } - async fn staging_para_backing_state( + async fn para_backing_state( &self, at: Hash, para_id: cumulus_primitives_core::ParaId, ) -> Result, ApiError> { - Ok(self.rpc_client.parachain_host_staging_para_backing_state(at, para_id).await?) + Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?) } } diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index bea2fc330a24e3c9875f2359cde5f4388de0e6ae..a83a18f7cd965743cdb4490c3966b6ca8b6b7272 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -30,7 +30,7 @@ use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, request_response::{ v1::{self, AvailableDataFetchingRequest}, - vstaging, IncomingRequestReceiver, ReqProtocolNames, + v2, IncomingRequestReceiver, ReqProtocolNames, }, }; use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics}; @@ -63,9 +63,8 @@ pub(crate) struct CollatorOverseerGenArgs<'a> { pub authority_discovery_service: AuthorityDiscoveryService, /// Receiver for collation request protocol v1. pub collation_req_receiver_v1: IncomingRequestReceiver, - /// Receiver for collation request protocol vstaging. - pub collation_req_receiver_vstaging: - IncomingRequestReceiver, + /// Receiver for collation request protocol v2. + pub collation_req_receiver_v2: IncomingRequestReceiver, /// Receiver for availability request protocol pub available_data_req_receiver: IncomingRequestReceiver, /// Prometheus registry, commonly used for production systems, less so for test. @@ -88,7 +87,7 @@ fn build_overseer( sync_oracle, authority_discovery_service, collation_req_receiver_v1, - collation_req_receiver_vstaging, + collation_req_receiver_v2, available_data_req_receiver, registry, spawner, @@ -121,7 +120,7 @@ fn build_overseer( peer_id: network_service.local_peer_id(), collator_pair, request_receiver_v1: collation_req_receiver_v1, - request_receiver_vstaging: collation_req_receiver_vstaging, + request_receiver_v2: collation_req_receiver_v2, metrics: Metrics::register(registry)?, }; CollatorProtocolSubsystem::new(side) diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 366d428eda70036203f48e253c9d395c58b887ec..08e4e8e34aba4219382b4554bfb8ff97762c2009 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -23,7 +23,7 @@ use polkadot_network_bridge::{peer_sets_info, IsAuthority}; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, request_response::{ - v1, vstaging, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames, + v1, v2, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames, }, }; @@ -182,7 +182,7 @@ async fn new_minimal_relay_chain( } let request_protocol_names = ReqProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); - let (collation_req_receiver_v1, collation_req_receiver_vstaging, available_data_req_receiver) = + let (collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver) = build_request_response_protocol_receivers(&request_protocol_names, &mut net_config); let best_header = relay_chain_rpc_client @@ -212,7 +212,7 @@ async fn new_minimal_relay_chain( sync_oracle, authority_discovery_service, collation_req_receiver_v1, - collation_req_receiver_vstaging, + collation_req_receiver_v2, available_data_req_receiver, registry: prometheus_registry.as_ref(), spawner: task_manager.spawn_handle(), @@ -234,13 +234,13 @@ fn build_request_response_protocol_receivers( config: &mut FullNetworkConfiguration, ) -> ( IncomingRequestReceiver, - IncomingRequestReceiver, + IncomingRequestReceiver, IncomingRequestReceiver, ) { let (collation_req_receiver_v1, cfg) = IncomingRequest::get_config_receiver(request_protocol_names); config.add_request_response_protocol(cfg); - let (collation_req_receiver_vstaging, cfg) = + let (collation_req_receiver_v2, cfg) = IncomingRequest::get_config_receiver(request_protocol_names); config.add_request_response_protocol(cfg); let (available_data_req_receiver, cfg) = @@ -248,5 +248,5 @@ fn build_request_response_protocol_receivers( config.add_request_response_protocol(cfg); let cfg = Protocol::ChunkFetchingV1.get_outbound_only_config(request_protocol_names); config.add_request_response_protocol(cfg); - (collation_req_receiver_v1, collation_req_receiver_vstaging, available_data_req_receiver) + (collation_req_receiver_v1, collation_req_receiver_v2, available_data_req_receiver) } diff --git a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs index 84e66f95571096c319ab1aa05a12a11cdc4c1035..6fd057e170b715a1586dbd2dbf3f608268c539bd 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/light_client_worker.rs @@ -48,7 +48,7 @@ const MAX_SUBSCRIPTIONS: u32 = 64; #[derive(thiserror::Error, Debug)] enum LightClientError { - #[error("Error occured while executing smoldot request: {0}")] + #[error("Error occurred while executing smoldot request: {0}")] SmoldotError(String), #[error("Nothing returned from json_rpc_responses")] EmptyResult, diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index c1e92b249d776126f8de30db2b021898e50219fc..5924716adcb41d8b4c93b525ea4e1ae8093b413b 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -30,9 +30,8 @@ use parity_scale_codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain::{ - slashing, - vstaging::{AsyncBackingParams, BackingState}, - BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + async_backing::{AsyncBackingParams, BackingState}, + slashing, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, @@ -598,31 +597,31 @@ impl RelayChainRpcClient { .await } + pub async fn parachain_host_disabled_validators( + &self, + at: RelayHash, + ) -> Result, RelayChainError> { + self.call_remote_runtime_function("ParachainHost_disabled_validators", at, None::<()>) + .await + } + #[allow(missing_docs)] - pub async fn parachain_host_staging_async_backing_params( + pub async fn parachain_host_async_backing_params( &self, at: RelayHash, ) -> Result { - self.call_remote_runtime_function( - "ParachainHost_staging_async_backing_params", - at, - None::<()>, - ) - .await + self.call_remote_runtime_function("ParachainHost_async_backing_params", at, None::<()>) + .await } #[allow(missing_docs)] - pub async fn parachain_host_staging_para_backing_state( + pub async fn parachain_host_para_backing_state( &self, at: RelayHash, para_id: ParaId, ) -> Result, RelayChainError> { - self.call_remote_runtime_function( - "ParachainHost_staging_para_backing_state", - at, - Some(para_id), - ) - .await + self.call_remote_runtime_function("ParachainHost_para_backing_state", at, Some(para_id)) + .await } fn send_register_message_to_worker( diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index b53bdbdfc815665ea5ae193a4823c3b9f7b98874..b7c274ceecdcbb524ee57d228ef475699402ea49 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -40,8 +40,3 @@ cumulus-relay-chain-interface = { path = "../relay-chain-interface" } cumulus-relay-chain-inprocess-interface = { path = "../relay-chain-inprocess-interface" } cumulus-relay-chain-minimal-node = { path = "../relay-chain-minimal-node" } -[features] -network-protocol-staging = [ - "cumulus-relay-chain-inprocess-interface/network-protocol-staging", - "cumulus-relay-chain-minimal-node/network-protocol-staging", -] diff --git a/cumulus/docker/scripts/build_docker.sh b/cumulus/docker/scripts/build_docker.sh index ba44544930102dbdf71a9e9461b587b72c913025..752d6bd00fc86598af5bb28e38b38cf3b0fa7efd 100755 --- a/cumulus/docker/scripts/build_docker.sh +++ b/cumulus/docker/scripts/build_docker.sh @@ -6,7 +6,7 @@ cd "$(cd "$(dirname "$0")" && git rev-parse --show-toplevel)" dockerfile="$1" if [ -z "$dockerfile" ]; then - dockerfile="./docker/test-parachain-collator.dockerfile" + dockerfile="./docker/test-parachain-collator.Dockerfile" else shift 1 fi diff --git a/cumulus/docs/release.md b/cumulus/docs/release.md index 38d1915013b07d67ae074a0f7606c6fd58526e3b..8302b7b9b7fc046920a92a97894ff16e8baca214 100644 --- a/cumulus/docs/release.md +++ b/cumulus/docs/release.md @@ -79,9 +79,9 @@ Offline signing libraries depend on a consistent ordering of call indices and fu current and new runtimes and ensure that the `module index, call index` tuples map to the same set of functions. It also checks if there have been any changes in `storage`. In case of a breaking change, increase `transaction_version`. -To verify the order has not changed, manually start the following [Github -Action](https://github.com/paritytech/cumulus/actions/workflows/extrinsic-ordering-check-from-bin.yml). It takes around -a minute to run and will produce the report as artifact you need to manually check. +To verify the order has not changed, manually start the following +[Github Action](https://github.com/paritytech/polkadot-sdk/cumulus/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml). +It takes around a minute to run and will produce the report as artifact you need to manually check. To run it, in the _Run Workflow_ dropdown: 1. **Use workflow from**: to ignore, leave `master` as default diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index ee0943bb99eefeab5de946e2b23a12214587773d..cb5d9904c7cf3c37e4a0d8fe13fc175888cad20d 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -9,7 +9,7 @@ description = "Proc macros provided by the parachain-system pallet" proc-macro = true [dependencies] -syn = "2.0.36" +syn = "2.0.38" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "1.3.1" diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index a7e59a61c9be2a74025eb3014a11f1632f73ff15..eaf15768e290de18e7d7c22cb9ca8abec9afa53d 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -245,10 +245,10 @@ pub mod pallet { >::kill(); let relay_upgrade_go_ahead = >::take(); - assert!( - >::exists(), - "set_validation_data inherent needs to be present in every block!" - ); + let vfp = >::get() + .expect("set_validation_data inherent needs to be present in every block!"); + + LastRelayChainBlockNumber::::put(vfp.relay_parent_number); let host_config = match Self::host_configuration() { Some(ok) => ok, @@ -380,8 +380,7 @@ pub mod pallet { let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal); let watermark = HrmpWatermark::::get(); - let watermark_update = - HrmpWatermarkUpdate::new(watermark, LastRelayChainBlockNumber::::get()); + let watermark_update = HrmpWatermarkUpdate::new(watermark, vfp.relay_parent_number); aggregated_segment .append(&ancestor, watermark_update, &total_bandwidth_out) @@ -460,6 +459,9 @@ pub mod pallet { 4 + hrmp_max_message_num_per_candidate as u64, ); + // Weight for updating the last relay chain block number in `on_finalize`. + weight += T::DbWeight::get().reads_writes(1, 1); + // Weight for adjusting the unincluded segment in `on_finalize`. weight += T::DbWeight::get().reads_writes(6, 3); @@ -515,7 +517,6 @@ pub mod pallet { vfp.relay_parent_number, LastRelayChainBlockNumber::::get(), ); - LastRelayChainBlockNumber::::put(vfp.relay_parent_number); let relay_state_proof = RelayChainStateProof::new( T::SelfParaId::get(), @@ -756,6 +757,8 @@ pub mod pallet { pub(super) type DidSetValidationCode = StorageValue<_, bool, ValueQuery>; /// The relay chain block number associated with the last parachain block. + /// + /// This is updated in `on_finalize`. #[pallet::storage] pub(super) type LastRelayChainBlockNumber = StorageValue<_, RelayChainBlockNumber, ValueQuery>; @@ -1447,7 +1450,7 @@ impl Pallet { hrmp_max_message_num_per_candidate: 2, validation_upgrade_cooldown: 2, validation_upgrade_delay: 2, - async_backing_params: relay_chain::vstaging::AsyncBackingParams { + async_backing_params: relay_chain::AsyncBackingParams { allowed_ancestry_len: 0, max_candidate_depth: 0, }, @@ -1501,6 +1504,12 @@ impl Pallet { Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) }); Ok((0, hash)) } + + /// Get the relay chain block number which was used as an anchor for the last block in this + /// chain. + pub fn last_relay_block_number(&self) -> RelayChainBlockNumber { + LastRelayChainBlockNumber::::get() + } } impl UpwardMessageSender for Pallet { diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 5aab57da91b4f731567bd81d384cab646beb936d..77d0551b51102e51dccfebc0659b78da69254d35 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -28,6 +28,9 @@ cumulus-primitives-core = { path = "../../primitives/core", default-features = f # Optional import for benchmarking frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true} +# Bridges +bp-xcm-bridge-hub-router = { path = "../../../bridges/primitives/xcm-bridge-hub-router", default-features = false, optional = true } + [dev-dependencies] # Substrate @@ -43,6 +46,7 @@ cumulus-pallet-parachain-system = { path = "../parachain-system", features = ["p [features] default = [ "std" ] std = [ + "bp-xcm-bridge-hub-router?/std", "codec/std", "cumulus-primitives-core/std", "frame-benchmarking?/std", @@ -77,3 +81,4 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] +bridging = [ "bp-xcm-bridge-hub-router" ] diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs new file mode 100644 index 0000000000000000000000000000000000000000..0fc3f1f39ea38bfd1c86c76832cdf77cdb572363 --- /dev/null +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -0,0 +1,95 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{pallet, OutboundState}; +use cumulus_primitives_core::ParaId; +use frame_support::pallet_prelude::Get; + +/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks +/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `ParaId` if any of those is +/// suspended. +pub struct InAndOutXcmpChannelStatusProvider( + sp_std::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, +); +impl, Runtime: crate::Config> + bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for InAndOutXcmpChannelStatusProvider +{ + fn is_congested() -> bool { + // if the inbound channel with recipient is suspended, it means that we are unable to + // receive congestion reports from the bridge hub. So we assume the bridge pipeline is + // congested too + if pallet::Pallet::::is_inbound_channel_suspended(SiblingBridgeHubParaId::get()) { + return true + } + + // if the outbound channel with recipient is suspended, it means that one of further + // bridge queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall + // take larger fee for our outbound messages + OutXcmpChannelStatusProvider::::is_congested() + } +} + +/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks +/// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. +pub struct OutXcmpChannelStatusProvider( + sp_std::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, +); +impl, Runtime: crate::Config> + bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for OutXcmpChannelStatusProvider +{ + fn is_congested() -> bool { + let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); + + // let's find the channel's state with the sibling parachain, + let Some((outbound_state, queued_pages)) = pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) else { + return false + }; + // suspended channel => it is congested + if outbound_state == OutboundState::Suspended { + return true + } + + // TODO: https://github.com/paritytech/polkadot-sdk/pull/1556 - once this PR is merged, we may + // remove the following code. + // TODO: the following restriction is arguable, we may live without that, assuming that + // There can't be more than some `N` messages queued at the bridge queue (at the source BH) + // AND before accepting next (or next-after-next) delivery transaction, we'll receive the + // suspension signal from the target parachain and stop accepting delivery transactions. + + // It takes some time for target parachain to suspend inbound channel with the target BH and + // during that we will keep accepting new message delivery transactions. Let's also reject + // new deliveries if there are too many "pages" (concatenated XCM messages) in the target BH + // -> target parachain queue. + + // If the outbound channel has at least `N` pages enqueued, let's assume it is congested. + // Normally, the chain with a few opened HRMP channels, will "send" pages at every block. + // Having `N` pages means that for last `N` blocks we either have not sent any messages, + // or have sent signals. + + const MAX_QUEUED_PAGES_BEFORE_DEACTIVATION: u16 = 4; + if queued_pages > MAX_QUEUED_PAGES_BEFORE_DEACTIVATION { + return true + } + + false + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn suspend_channel_for_benchmarks(target: ParaId) { + pallet::Pallet::::suspend_channel(target) +} diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 1cb92f59518697d184ca9a6eac407ccdef86f8f2..b53eb7cc0e10e5e2eea2265f582b621b745d20e0 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -35,6 +35,8 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +#[cfg(feature = "bridging")] +pub mod bridging; pub mod weights; pub use weights::WeightInfo; @@ -947,6 +949,24 @@ impl Pallet { } }); } + + #[cfg(feature = "bridging")] + fn is_inbound_channel_suspended(sender: ParaId) -> bool { + >::get() + .iter() + .find(|c| c.sender == sender) + .map(|c| c.state == InboundState::Suspended) + .unwrap_or(false) + } + + #[cfg(feature = "bridging")] + /// Returns tuple of `OutboundState` and number of queued pages. + fn outbound_channel_state(target: ParaId) -> Option<(OutboundState, u16)> { + >::get().iter().find(|c| c.recipient == target).map(|c| { + let queued_pages = c.last_index.saturating_sub(c.first_index); + (c.state, queued_pages) + }) + } } impl XcmpMessageHandler for Pallet { @@ -1129,7 +1149,7 @@ 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() - pruned); + statuses.rotate_left(result.len().saturating_sub(pruned)); >::put(statuses); diff --git a/cumulus/parachain-template/README.md b/cumulus/parachain-template/README.md index 2d71bbd71f3615a071710d9402c83f43621893d1..01e9cc26d9af3e8c437486b6785d6f5eb8d6047c 100644 --- a/cumulus/parachain-template/README.md +++ b/cumulus/parachain-template/README.md @@ -1,6 +1,6 @@ # Substrate Cumulus Parachain Template -A new [Cumulus](https://github.com/paritytech/cumulus/)-based Substrate node, ready for hacking ☁️.. +A new [Cumulus](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus)-based Substrate node, ready for hacking ☁️.. This project is originally a fork of the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) @@ -10,7 +10,7 @@ modified to include dependencies required for registering this node as a **parat The stand-alone version of this template is hosted on the [Substrate Devhub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) for each release of Polkadot. It is generated directly to the upstream -[Parachain Template in Cumulus](https://github.com/paritytech/cumulus/tree/master/parachain-template) +[Parachain Template in Cumulus](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus/parachain-template) at each release branch using the [Substrate Template Generator](https://github.com/paritytech/substrate-template-generator/). diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 6de57b185e4a5cea2bbaaf11afdf7c0fd91534dc..e73c7b507262eca43c2e77293d0ecadd606bdc57 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -11,7 +11,7 @@ build = "build.rs" publish = false [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } @@ -89,7 +89,4 @@ try-runtime = [ "polkadot-cli/try-runtime", "sp-runtime/try-runtime", ] -network-protocol-staging = [ - "cumulus-client-service/network-protocol-staging", - "polkadot-cli/network-protocol-staging", -] + diff --git a/cumulus/parachain-template/node/src/command.rs b/cumulus/parachain-template/node/src/command.rs index 7acfb0c2035e3c1b0efcc1b28124711da114409b..4dd8463f6be67cb4d8012b8dba1f32be341dfe24 100644 --- a/cumulus/parachain-template/node/src/command.rs +++ b/cumulus/parachain-template/node/src/command.rs @@ -50,7 +50,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -86,7 +86,7 @@ impl SubstrateCli for RelayChainCli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index 4e51f16dca168fbcc94309a055e27908e1420ef7..68db2f041ddb3019b62cfbcb1478ee3ee13c6cea 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -44,6 +44,7 @@ sp-api = { path = "../../../substrate/primitives/api", default-features = false} sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} @@ -111,6 +112,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index 038597096f6a56ca7fda99b84a1d4b67e5ef4a26..b9bf97d7786f6c27736929ad5b408a57f9f64a37 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -28,6 +28,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, weights::{ @@ -742,6 +743,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 963de03fa16aeec446d9afca50bb26bcaf37a1d7..29528b169ae2ed76608d85c367f4a648344f8e56 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -29,15 +29,12 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-std = { path = "../../../substrate/primitives/std", default-features = false } # Polkadot -kusama-runtime-constants = { path = "../../../polkadot/runtime/kusama/constants", default-features = false} -polkadot-runtime-constants = { path = "../../../polkadot/runtime/polkadot/constants", default-features = false} rococo-runtime-constants = { path = "../../../polkadot/runtime/rococo/constants", default-features = false} westend-runtime-constants = { path = "../../../polkadot/runtime/westend/constants", default-features = false} polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false} polkadot-primitives = { path = "../../../polkadot/primitives", default-features = false} 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} # Cumulus pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } @@ -58,7 +55,6 @@ std = [ "cumulus-primitives-utility/std", "frame-support/std", "frame-system/std", - "kusama-runtime-constants/std", "log/std", "pallet-asset-tx-payment/std", "pallet-assets/std", @@ -67,7 +63,6 @@ std = [ "pallet-collator-selection/std", "polkadot-core-primitives/std", "polkadot-primitives/std", - "polkadot-runtime-constants/std", "rococo-runtime-constants/std", "sp-consensus-aura/std", "sp-core/std", @@ -76,7 +71,6 @@ std = [ "sp-std/std", "westend-runtime-constants/std", "xcm-builder/std", - "xcm-executor/std", "xcm/std", ] @@ -91,5 +85,4 @@ runtime-benchmarks = [ "polkadot-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", ] diff --git a/cumulus/parachains/common/src/kusama.rs b/cumulus/parachains/common/src/kusama.rs index 308f7d081cedcc90aba2d6c12ed25e13e716bbb4..073971a70750f78fb8ad86ad86b0f07bbcdd3cde 100644 --- a/cumulus/parachains/common/src/kusama.rs +++ b/cumulus/parachains/common/src/kusama.rs @@ -27,20 +27,20 @@ pub mod consensus { /// Constants relating to KSM. pub mod currency { - use kusama_runtime_constants as constants; use polkadot_core_primitives::Balance; /// The existential deposit. Set to 1/10 of its parent Relay Chain. - pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; + pub const EXISTENTIAL_DEPOSIT: Balance = 1 * CENTS / 10; - pub const UNITS: Balance = constants::currency::UNITS; - pub const CENTS: Balance = constants::currency::CENTS; - pub const GRAND: Balance = constants::currency::GRAND; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; + pub const UNITS: Balance = 1_000_000_000_000; + pub const QUID: Balance = UNITS / 30; + pub const CENTS: Balance = QUID / 100; + pub const GRAND: Balance = QUID * 1_000; + pub const MILLICENTS: Balance = CENTS / 1_000; pub const fn deposit(items: u32, bytes: u32) -> Balance { // map to 1/100 of what the kusama relay chain charges (v9020) - constants::currency::deposit(items, bytes) / 100 + (items as Balance * 2_000 * CENTS + (bytes as Balance) * 100 * MILLICENTS) / 100 } } diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index cb2ac1a1e3e45d7af1cba07c8dddbba1837cf199..89e74b2f9b745d32b34f659e30134c5023fc9e41 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -20,6 +20,7 @@ pub mod kusama; pub mod polkadot; pub mod rococo; pub mod westend; +pub mod wococo; pub mod xcm_config; pub use constants::*; pub use opaque::*; diff --git a/cumulus/parachains/common/src/polkadot.rs b/cumulus/parachains/common/src/polkadot.rs index 52cee939224cc0f276bf9f92aa896a2469346256..744108bce2e5f539e17dc71725a7c1dd7af52675 100644 --- a/cumulus/parachains/common/src/polkadot.rs +++ b/cumulus/parachains/common/src/polkadot.rs @@ -27,6 +27,10 @@ pub mod account { /// It is used as a temporarily place to deposit a slashed imbalance /// before the teleport to the Treasury. pub const REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/refer"); + /// Ambassador Referenda pallet ID. + /// It is used as a temporarily place to deposit a slashed imbalance + /// before the teleport to the Treasury. + pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); } /// Consensus-related. @@ -44,19 +48,19 @@ pub mod consensus { /// Constants relating to DOT. pub mod currency { use polkadot_core_primitives::Balance; - use polkadot_runtime_constants as constants; /// The existential deposit. Set to 1/10 of its parent Relay Chain. - pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; + pub const EXISTENTIAL_DEPOSIT: Balance = 100 * CENTS / 10; - pub const UNITS: Balance = constants::currency::UNITS; - pub const DOLLARS: Balance = constants::currency::DOLLARS; - pub const CENTS: Balance = constants::currency::CENTS; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; + pub const UNITS: Balance = 10_000_000_000; + pub const DOLLARS: Balance = UNITS; // 10_000_000_000 + pub const GRAND: Balance = DOLLARS * 1_000; // 10_000_000_000_000 + pub const CENTS: Balance = DOLLARS / 100; // 100_000_000 + pub const MILLICENTS: Balance = CENTS / 1_000; // 100_000 pub const fn deposit(items: u32, bytes: u32) -> Balance { // 1/100 of Polkadot - constants::currency::deposit(items, bytes) / 100 + (items as Balance * 20 * DOLLARS + (bytes as Balance) * 100 * MILLICENTS) / 100 } } diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs b/cumulus/parachains/common/src/wococo.rs similarity index 90% rename from cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs rename to cumulus/parachains/common/src/wococo.rs index fb3e235a25cd48602975355abb713e39297b5aab..5cd6121135a3321369fee2132b696aef8a2bae81 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/common/src/wococo.rs @@ -13,4 +13,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod fellowship; +// re-export rococo +pub use crate::rococo::{consensus, currency, fee}; diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 146671441453df76c48776e0b202166aca37361b..91ad7d902bda9e86d554f68192b08719f236f801 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -14,13 +14,14 @@ // limitations under the License. use crate::impls::AccountIdOf; -use core::marker::PhantomData; +use cumulus_primitives_core::{IsSystem, ParaId}; use frame_support::{ traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair}, weights::Weight, }; use log; use sp_runtime::traits::Get; +use sp_std::marker::PhantomData; use xcm::latest::prelude::*; /// A `ChargeFeeInFungibles` implementation that converts the output of @@ -78,3 +79,85 @@ impl> ContainsPair matches!(asset.id, Concrete(ref id) if id == origin && origin == &Location::get()) } } + +/// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain). +pub struct ConcreteAssetFromSystem(PhantomData); +impl> ContainsPair + for ConcreteAssetFromSystem +{ + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + log::trace!(target: "xcm::contains", "ConcreteAssetFromSystem asset: {:?}, origin: {:?}", asset, origin); + let is_system = match origin { + // The Relay Chain + MultiLocation { parents: 1, interior: Here } => true, + // System parachain + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => + ParaId::from(*id).is_system(), + // Others + _ => false, + }; + matches!(asset.id, Concrete(id) if id == AssetLocation::get()) && is_system + } +} + +#[cfg(test)] +mod tests { + use frame_support::parameter_types; + + use super::{ + ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, MultiAsset, MultiLocation, + PalletInstance, Parachain, Parent, + }; + + parameter_types! { + pub const RelayLocation: MultiLocation = MultiLocation::parent(); + } + + #[test] + fn concrete_asset_from_relay_works() { + let expected_asset: MultiAsset = (Parent, 1000000).into(); + let expected_origin: MultiLocation = (Parent, Here).into(); + + assert!(>::contains( + &expected_asset, + &expected_origin + )); + } + + #[test] + fn concrete_asset_from_sibling_system_para_fails_for_wrong_asset() { + let unexpected_assets: Vec = vec![ + (Here, 1000000).into(), + ((PalletInstance(50), GeneralIndex(1)), 1000000).into(), + ((Parent, Parachain(1000), PalletInstance(50), GeneralIndex(1)), 1000000).into(), + ]; + let expected_origin: MultiLocation = (Parent, Parachain(1000)).into(); + + unexpected_assets.iter().for_each(|asset| { + assert!(!>::contains(asset, &expected_origin)); + }); + } + + #[test] + fn concrete_asset_from_sibling_system_para_works_for_correct_asset() { + // (para_id, expected_result) + let test_data = vec![ + (0, true), + (1, true), + (1000, true), + (1999, true), + (2000, false), // Not a System Parachain + (2001, false), // Not a System Parachain + ]; + + let expected_asset: MultiAsset = (Parent, 1000000).into(); + + for (para_id, expected_result) in test_data { + let origin: MultiLocation = (Parent, Parachain(para_id)).into(); + assert_eq!( + expected_result, + >::contains(&expected_asset, &origin) + ); + } + } +} diff --git a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml index 1038ec8dc42b314e4d46d744aeba9afde5de38a4..17a16d9ccd7da8e0d7fc53973987bb0ed117705b 100644 --- a/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml +++ b/cumulus/parachains/integration-tests/e2e/collectives/collectives-polkadot/0_xcm/3_hrmp-open-channels.yml @@ -37,7 +37,12 @@ tests: ] events: - name: hrmp.HrmpChannelForceOpened - result: [*cp_id, *sp_id, *hrmp_proposed_max_capacity, *hrmp_proposed_max_message_size] + result: { + sender: *cp_id, + recipient: *sp_id, + proposed_max_capacity: *hrmp_proposed_max_capacity, + proposed_max_message_size: *hrmp_proposed_max_message_size + } - name: Force Open HRMP Channel From AssetHub Parachain → Collectives Parachain its: - name: Alice calls hrmp.forceOpenHrmpChannel @@ -56,4 +61,9 @@ tests: ] events: - name: hrmp.HrmpChannelForceOpened - result: [*sp_id, *cp_id, *hrmp_proposed_max_capacity, *hrmp_proposed_max_message_size] + result: { + sender: *sp_id, + recipient: *cp_id, + proposed_max_capacity: *hrmp_proposed_max_capacity, + proposed_max_message_size: *hrmp_proposed_max_message_size + } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs deleted file mode 100644 index 623b3ff599c8eb85e7f7561eb415296b186bde7f..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -const MAX_CAPACITY: u32 = 8; -const MAX_MESSAGE_SIZE: u32 = 8192; - -/// Opening HRMP channels between Parachains should work -#[test] -fn open_hrmp_channel_between_paras_works() { - // Parchain A init values - let para_a_id = PenpalKusamaA::para_id(); - let para_a_root_origin = ::RuntimeOrigin::root(); - - // Parachain B init values - let para_b_id = PenpalKusamaB::para_id(); - let para_b_root_origin = ::RuntimeOrigin::root(); - - let fee_amount = KUSAMA_ED * 1000; - let fund_amount = KUSAMA_ED * 1000_000_000; - - // Fund Parachain's Sovereign accounts to be able to reserve the deposit - let para_a_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_a_id); - let para_b_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_b_id); - - let relay_destination: VersionedMultiLocation = PenpalKusamaA::parent_location().into(); - - // ---- Init Open channel from Parachain to System Parachain - let mut call = Kusama::init_open_channel_call(para_b_id, MAX_CAPACITY, MAX_MESSAGE_SIZE); - let origin_kind = OriginKind::Native; - let native_asset: MultiAsset = (Here, fee_amount).into(); - let beneficiary = Kusama::sovereign_account_id_of_child_para(para_a_id); - - let mut xcm = xcm_transact_paid_execution(call, origin_kind, native_asset.clone(), beneficiary); - - PenpalKusamaA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - para_a_root_origin, - bx!(relay_destination.clone()), - bx!(xcm), - )); - - PenpalKusamaA::assert_xcm_pallet_sent(); - }); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - Kusama::assert_ump_queue_processed( - true, - Some(para_a_id), - Some(Weight::from_parts(1_312_558_000, 200000)), - ); - - assert_expected_events!( - Kusama, - vec![ - // Parachain's Sovereign account balance is withdrawn to pay XCM fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == para_a_sovereign_account.clone(), - amount: *amount == fee_amount, - }, - // Sender deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_a_sovereign_account, - }, - // Open channel requested from Para A to Para B - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( - sender, recipient, max_capacity, max_message_size - ) - ) => { - sender: *sender == para_a_id.into(), - recipient: *recipient == para_b_id.into(), - max_capacity: *max_capacity == MAX_CAPACITY, - max_message_size: *max_message_size == MAX_MESSAGE_SIZE, - }, - ] - ); - }); - - // ---- Accept Open channel from Parachain to System Parachain - call = Kusama::accept_open_channel_call(para_a_id); - let beneficiary = Kusama::sovereign_account_id_of_child_para(para_b_id); - - xcm = xcm_transact_paid_execution(call, origin_kind, native_asset, beneficiary); - - PenpalKusamaB::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - para_b_root_origin, - bx!(relay_destination), - bx!(xcm), - )); - - PenpalKusamaB::assert_xcm_pallet_sent(); - }); - - PenpalKusamaB::execute_with(|| {}); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - Kusama::assert_ump_queue_processed( - true, - Some(para_b_id), - Some(Weight::from_parts(1_312_558_000, 200_000)), - ); - - assert_expected_events!( - Kusama, - vec![ - // Parachain's Sovereign account balance is withdrawn to pay XCM fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == para_b_sovereign_account.clone(), - amount: *amount == fee_amount, - }, - // Sender deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_b_sovereign_account, - }, - // Open channel accepted for Para A to Para B - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( - sender, recipient - ) - ) => { - sender: *sender == para_a_id.into(), - recipient: *recipient == para_b_id.into(), - }, - ] - ); - }); - - Kusama::force_process_hrmp_open(para_a_id, para_b_id); -} - -/// Opening HRMP channels between System Parachains and Parachains should work -#[test] -fn force_open_hrmp_channel_for_system_para_works() { - // Relay Chain init values - let relay_root_origin = ::RuntimeOrigin::root(); - - // System Para init values - let system_para_id = AssetHubKusama::para_id(); - - // Parachain A init values - let para_a_id = PenpalKusamaA::para_id(); - - let fund_amount = KUSAMA_ED * 1000_000_000; - - // Fund Parachain's Sovereign accounts to be able to reserve the deposit - let para_a_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_a_id); - let system_para_sovereign_account = Kusama::fund_para_sovereign(fund_amount, system_para_id); - - Kusama::execute_with(|| { - assert_ok!(::Hrmp::force_open_hrmp_channel( - relay_root_origin, - system_para_id, - para_a_id, - MAX_CAPACITY, - MAX_MESSAGE_SIZE - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - // Sender deposit is reserved for System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == system_para_sovereign_account, - }, - // Recipient deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_a_sovereign_account, - }, - // HRMP channel forced opened - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( - sender, recipient, max_capacity, max_message_size - ) - ) => { - sender: *sender == system_para_id.into(), - recipient: *recipient == para_a_id.into(), - max_capacity: *max_capacity == MAX_CAPACITY, - max_message_size: *max_message_size == MAX_MESSAGE_SIZE, - }, - ] - ); - }); - - Kusama::force_process_hrmp_open(system_para_id, para_a_id); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs deleted file mode 100644 index 5891b694c8e436104b508cce7b67b8266460cc3e..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -/// Relay Chain should be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Superuser` and signer is `sudo` -#[test] -fn send_transact_sudo_from_relay_to_system_para_works() { - // Init tests variables - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = Kusama::child_location_of(AssetHubKusama::para_id()).into(); - let asset_owner: AccountId = AssetHubKusamaSender::get().into(); - let xcm = AssetHubKusama::force_create_asset_xcm( - OriginKind::Superuser, - ASSET_ID, - asset_owner.clone(), - true, - 1000, - ); - // Send XCM message from Relay Chain - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - Kusama::assert_xcm_pallet_sent(); - }); - - // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_445_000, 200_000))); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == asset_owner, - }, - ] - ); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); -} - -/// Relay Chain shouldn't be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Native` -#[test] -fn send_transact_native_from_relay_to_system_para_fails() { - // Init tests variables - let signed_origin = ::RuntimeOrigin::signed(KusamaSender::get().into()); - let system_para_destination = Kusama::child_location_of(AssetHubKusama::para_id()).into(); - let asset_owner = AssetHubKusamaSender::get().into(); - let xcm = AssetHubKusama::force_create_asset_xcm( - OriginKind::Native, - ASSET_ID, - asset_owner, - true, - 1000, - ); - - // Send XCM message from Relay Chain - Kusama::execute_with(|| { - assert_err!( - ::XcmPallet::send( - signed_origin, - bx!(system_para_destination), - bx!(xcm) - ), - DispatchError::BadOrigin - ); - }); -} - -/// System Parachain shouldn't be able to execute `Transact` instructions in Relay Chain -/// when `OriginKind::Native` -#[test] -fn send_transact_native_from_system_para_to_relay_fails() { - // Init tests variables - let signed_origin = - ::RuntimeOrigin::signed(AssetHubKusamaSender::get().into()); - let relay_destination = AssetHubKusama::parent_location().into(); - let call = ::RuntimeCall::System(frame_system::Call::< - ::Runtime, - >::remark_with_event { - remark: vec![0, 1, 2, 3], - }) - .encode() - .into(); - let origin_kind = OriginKind::Native; - - let xcm = xcm_transact_unpaid_execution(call, origin_kind); - - // Send XCM message from Relay Chain - AssetHubKusama::execute_with(|| { - assert_err!( - ::PolkadotXcm::send( - signed_origin, - bx!(relay_destination), - bx!(xcm) - ), - DispatchError::BadOrigin - ); - }); -} - -/// Parachain should be able to send XCM paying its fee with sufficient asset -/// in the System Parachain -#[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { - let para_sovereign_account = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()), - ); - - // Force create and mint assets for Parachain's sovereign account - AssetHubKusama::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - para_sovereign_account.clone(), - ASSET_MIN_BALANCE * 1000000000, - ); - - // We just need a call that can pass the `SafeCallFilter` - // Call values are not relevant - let call = AssetHubKusama::force_create_asset_call( - ASSET_ID, - para_sovereign_account.clone(), - true, - ASSET_MIN_BALANCE, - ); - - let origin_kind = OriginKind::SovereignAccount; - let fee_amount = ASSET_MIN_BALANCE * 1000000; - let native_asset = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = - PenpalKusamaA::sibling_location_of(AssetHubKusama::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - native_asset, - para_sovereign_account.clone(), - ); - - PenpalKusamaA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalKusamaA::assert_xcm_pallet_sent(); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593))); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == para_sovereign_account, - balance: *balance == fee_amount, - }, - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { - asset_id: *asset_id == ASSET_ID, - }, - ] - ); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml deleted file mode 100644 index 023e8b84f11b4a9e8330b12f6cec0c60967e9cae..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,52 +0,0 @@ -[package] -name = "asset-hub-polkadot-integration-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } - -# Substrate -sp-runtime = { path = "../../../../../../substrate/primitives/runtime", 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} - -# Polkadot -polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false} -polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} - -# Cumulus -parachains-common = { path = "../../../../common" } -asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusama" } - -# Local -xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} -integration-tests-common = { path = "../../common", default-features = false} - -[features] -runtime-benchmarks = [ - "asset-hub-kusama-runtime/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "integration-tests-common/runtime-benchmarks", - "pallet-asset-conversion/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-runtime/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs deleted file mode 100644 index e8ba8e44f25c529f17cae594008d2f3e3fb2e80c..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; -pub use integration_tests_common::{ - constants::{ - asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, polkadot::ED as POLKADOT_ED, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, - PenpalPolkadotA, PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotB, - PenpalPolkadotBPallet, Polkadot, PolkadotPallet, PolkadotReceiver, PolkadotSender, -}; -pub use parachains_common::{AccountId, Balance}; -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Polkadot as PolkadotId}, -}; -pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, -}; - -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; - -pub type RelayToSystemParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; - -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests -pub fn relay_test_args(amount: Balance) -> TestArgs { - TestArgs { - dest: Polkadot::child_location_of(AssetHubPolkadot::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubPolkadotReceiver::get().into(), - } - .into(), - amount, - assets: (Here, amount).into(), - asset_id: None, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests -pub fn system_para_test_args( - dest: MultiLocation, - beneficiary_id: AccountId32, - amount: Balance, - assets: MultiAssets, - asset_id: Option, -) -> TestArgs { - TestArgs { - dest, - beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), - amount, - assets, - asset_id, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -#[cfg(test)] -#[cfg(not(feature = "runtime-benchmarks"))] -mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs deleted file mode 100644 index a1423f2ea90b60a7c7b2136ed9301a0c34dc6666..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -const MAX_CAPACITY: u32 = 8; -const MAX_MESSAGE_SIZE: u32 = 8192; - -/// Opening HRMP channels between Parachains should work -#[test] -fn open_hrmp_channel_between_paras_works() { - // Parchain A init values - let para_a_id = PenpalPolkadotA::para_id(); - let para_a_root_origin = ::RuntimeOrigin::root(); - - // Parachain B init values - let para_b_id = PenpalPolkadotB::para_id(); - let para_b_root_origin = ::RuntimeOrigin::root(); - - let fee_amount = POLKADOT_ED * 1000; - let fund_amount = POLKADOT_ED * 1000_000_000; - - // Fund Parachain's Sovereign accounts to be able to reserve the deposit - let para_a_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_a_id); - let para_b_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_b_id); - - let relay_destination: VersionedMultiLocation = PenpalPolkadotA::parent_location().into(); - - // ---- Init Open channel from Parachain to System Parachain - let mut call = Polkadot::init_open_channel_call(para_b_id, MAX_CAPACITY, MAX_MESSAGE_SIZE); - let origin_kind = OriginKind::Native; - let native_asset: MultiAsset = (Here, fee_amount).into(); - let beneficiary = Polkadot::sovereign_account_id_of_child_para(para_a_id); - - let mut xcm = xcm_transact_paid_execution(call, origin_kind, native_asset.clone(), beneficiary); - - PenpalPolkadotA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - para_a_root_origin, - bx!(relay_destination.clone()), - bx!(xcm), - )); - - PenpalPolkadotA::assert_xcm_pallet_sent(); - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_ump_queue_processed( - true, - Some(para_a_id), - Some(Weight::from_parts(1_282_426_000, 207_186)), - ); - - assert_expected_events!( - Polkadot, - vec![ - // Parachain's Sovereign account balance is withdrawn to pay XCM fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == para_a_sovereign_account.clone(), - amount: *amount == fee_amount, - }, - // Sender deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_a_sovereign_account, - }, - // Open channel requested from Para A to Para B - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( - sender, recipient, max_capacity, max_message_size - ) - ) => { - sender: *sender == para_a_id.into(), - recipient: *recipient == para_b_id.into(), - max_capacity: *max_capacity == MAX_CAPACITY, - max_message_size: *max_message_size == MAX_MESSAGE_SIZE, - }, - ] - ); - }); - - // ---- Accept Open channel from Parachain to System Parachain - call = Polkadot::accept_open_channel_call(para_a_id); - let beneficiary = Polkadot::sovereign_account_id_of_child_para(para_b_id); - - xcm = xcm_transact_paid_execution(call, origin_kind, native_asset, beneficiary); - - PenpalPolkadotB::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - para_b_root_origin, - bx!(relay_destination), - bx!(xcm), - )); - - PenpalPolkadotB::assert_xcm_pallet_sent(); - }); - - PenpalPolkadotB::execute_with(|| {}); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_ump_queue_processed( - true, - Some(para_b_id), - Some(Weight::from_parts(1_282_426_000, 207_186)), - ); - - assert_expected_events!( - Polkadot, - vec![ - // Parachain's Sovereign account balance is withdrawn to pay XCM fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == para_b_sovereign_account.clone(), - amount: *amount == fee_amount, - }, - // Sender deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_b_sovereign_account, - }, - // Open channel accepted for Para A to Para B - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( - sender, recipient - ) - ) => { - sender: *sender == para_a_id.into(), - recipient: *recipient == para_b_id.into(), - }, - ] - ); - }); - - Polkadot::force_process_hrmp_open(para_a_id, para_b_id); -} - -/// Opening HRMP channels between System Parachains and Parachains should work -#[test] -fn force_open_hrmp_channel_for_system_para_works() { - // Relay Chain init values - let relay_root_origin = ::RuntimeOrigin::root(); - - // System Para init values - let system_para_id = AssetHubPolkadot::para_id(); - - // Parachain A init values - let para_a_id = PenpalPolkadotA::para_id(); - - let fund_amount = POLKADOT_ED * 1000_000_000; - - // Fund Parachain's Sovereign accounts to be able to reserve the deposit - let system_para_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, system_para_id); - let para_a_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_a_id); - - Polkadot::execute_with(|| { - assert_ok!(::Hrmp::force_open_hrmp_channel( - relay_root_origin, - system_para_id, - para_a_id, - MAX_CAPACITY, - MAX_MESSAGE_SIZE - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - // Sender deposit is reserved for System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == system_para_sovereign_account, - }, - // Recipient deposit is reserved for Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ - who: *who == para_a_sovereign_account, - }, - // HRMP channel forced opened - RuntimeEvent::Hrmp( - polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( - sender, recipient, max_capacity, max_message_size - ) - ) => { - sender: *sender == system_para_id.into(), - recipient: *recipient == para_a_id.into(), - max_capacity: *max_capacity == MAX_CAPACITY, - max_message_size: *max_message_size == MAX_MESSAGE_SIZE, - }, - ] - ); - }); - - Polkadot::force_process_hrmp_open(system_para_id, para_a_id); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs deleted file mode 100644 index e53693d85d2bbc48ae9fc5ee473c55613cc76d63..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196))); - - assert_expected_events!( - Polkadot, - vec![ - // Amount to reserve transfer is transferred to System Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { - from: *from == t.sender.account_id, - to: *to == Polkadot::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubPolkadot::assert_dmp_queue_incomplete( - Some(Weight::from_parts(1_000_000_000, 0)), - Some(Error::UntrustedReserveLocation), - ); -} - -fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubPolkadot::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) -} - -fn system_para_to_para_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubPolkadot::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereing account - RuntimeEvent::Assets( - pallet_assets::Event::Transferred { asset_id, from, to, amount } - ) => { - asset_id: *asset_id == ASSET_ID, - from: *from == t.sender.account_id, - to: *to == AssetHubPolkadot::sovereign_account_id_of( - t.args.dest - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't -/// work -#[test] -fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: AssetHubPolkadotReceiver::get(), - args: relay_test_args(amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work -#[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: AssetHubPolkadotReceiver::get(), - args: relay_test_args(amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { - // Init values for System Parachain - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - assert_eq!(sender_balance_before, sender_balance_after); - assert_eq!(receiver_balance_before, receiver_balance_after); -} - -/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work -#[test] -fn limited_reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain - let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); - let beneficiary_id = PenpalPolkadotAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalPolkadotAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers -} - -/// Reserve Transfers of native asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_native_asset_from_system_para_to_para() { - // Init values for System Parachain - let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); - let beneficiary_id = PenpalPolkadotAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalPolkadotAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - - test.set_assertion::(system_para_to_para_assertions); - // TODO: Add assertion for Penpal runtime. Right now message is failing with - // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve - // transfers -} - -/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work -#[test] -fn limited_reserve_transfer_asset_from_system_para_to_para() { - // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubPolkadot::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubPolkadotSender::get(), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); - let beneficiary_id = PenpalPolkadotAReceiver::get(); - let amount_to_send = ASSET_MIN_BALANCE * 1000; - let assets = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) - .into(); - - let system_para_test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalPolkadotAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - - system_para_test.set_assertion::(system_para_to_para_assets_assertions); - // TODO: Add assertions when Penpal is able to manage assets - system_para_test - .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); - system_para_test.assert(); -} - -/// Reserve Transfers of a local asset from System Parachain to Parachain should work -#[test] -fn reserve_transfer_asset_from_system_para_to_para() { - // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubPolkadot::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubPolkadotSender::get(), - ASSET_MIN_BALANCE * 1000000, - ); - - // Init values for System Parachain - let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); - let beneficiary_id = PenpalPolkadotAReceiver::get(); - let amount_to_send = ASSET_MIN_BALANCE * 1000; - let assets = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) - .into(); - - let system_para_test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalPolkadotAReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - - system_para_test.set_assertion::(system_para_to_para_assets_assertions); - // TODO: Add assertions when Penpal is able to manage assets - system_para_test - .set_dispatchable::(system_para_to_para_reserve_transfer_assets); - system_para_test.assert(); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs deleted file mode 100644 index 244b428a7523b36680e08696ca28f69cef8a2fc4..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -/// Relay Chain should be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Superuser` and signer is `sudo` -#[test] -fn send_transact_sudo_from_relay_to_system_para_works() { - // Init tests variables - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - let asset_owner: AccountId = AssetHubPolkadotSender::get().into(); - let xcm = AssetHubPolkadot::force_create_asset_xcm( - OriginKind::Superuser, - ASSET_ID, - asset_owner.clone(), - true, - 1000, - ); - // Send XCM message from Relay Chain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - Polkadot::assert_xcm_pallet_sent(); - }); - - // Receive XCM message in Assets Parachain - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts( - 1_019_445_000, - 200_000, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == asset_owner, - }, - ] - ); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); -} - -/// Relay Chain shouldn't be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Native` -#[test] -fn send_transact_native_from_relay_to_system_para_fails() { - // Init tests variables - let signed_origin = ::RuntimeOrigin::signed(PolkadotSender::get().into()); - let system_para_destination = Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - let asset_owner = AssetHubPolkadotSender::get().into(); - let xcm = AssetHubPolkadot::force_create_asset_xcm( - OriginKind::Native, - ASSET_ID, - asset_owner, - true, - 1000, - ); - - // Send XCM message from Relay Chain - Polkadot::execute_with(|| { - assert_err!( - ::XcmPallet::send( - signed_origin, - bx!(system_para_destination), - bx!(xcm) - ), - DispatchError::BadOrigin - ); - }); -} - -/// System Parachain shouldn't be able to execute `Transact` instructions in Relay Chain -/// when `OriginKind::Native` -#[test] -fn send_transact_native_from_system_para_to_relay_fails() { - // Init tests variables - let signed_origin = - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get().into()); - let relay_destination = AssetHubPolkadot::parent_location().into(); - let call = ::RuntimeCall::System(frame_system::Call::< - ::Runtime, - >::remark_with_event { - remark: vec![0, 1, 2, 3], - }) - .encode() - .into(); - let origin_kind = OriginKind::Native; - - let xcm = xcm_transact_unpaid_execution(call, origin_kind); - - // Send XCM message from Relay Chain - AssetHubPolkadot::execute_with(|| { - assert_err!( - ::PolkadotXcm::send( - signed_origin, - bx!(relay_destination), - bx!(xcm) - ), - DispatchError::BadOrigin - ); - }); -} - -/// Parachain should be able to send XCM paying its fee with sufficient asset -/// in the System Parachain -#[test] -fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { - let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()), - ); - - // Force create and mint assets for Parachain's sovereign account - AssetHubPolkadot::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - para_sovereign_account.clone(), - ASSET_MIN_BALANCE * 1000000000, - ); - - // We just need a call that can pass the `SafeCallFilter` - // Call values are not relevant - let call = AssetHubPolkadot::force_create_asset_call( - ASSET_ID, - para_sovereign_account.clone(), - true, - ASSET_MIN_BALANCE, - ); - - let origin_kind = OriginKind::SovereignAccount; - let fee_amount = ASSET_MIN_BALANCE * 1000000; - let native_asset = - (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = - PenpalPolkadotA::sibling_location_of(AssetHubPolkadot::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - native_asset, - para_sovereign_account.clone(), - ); - - PenpalPolkadotA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalPolkadotA::assert_xcm_pallet_sent(); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcmp_queue_success(Some(Weight::from_parts( - 2_176_414_000, - 203_593, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == para_sovereign_account, - balance: *balance == fee_amount, - }, - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { - asset_id: *asset_id == ASSET_ID, - }, - ] - ); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs deleted file mode 100644 index e121c4167993fbfedfd6ba8f7cbe51417e212591..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -#[test] -fn relay_sets_system_para_xcm_supported_version() { - // Init tests variables - let sudo_origin = ::RuntimeOrigin::root(); - let system_para_destination: MultiLocation = - Polkadot::child_location_of(AssetHubPolkadot::para_id()); - - // Relay Chain sets supported version for Asset Parachain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::force_xcm_version( - sudo_origin, - bx!(system_para_destination), - XCM_V3 - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V3 - }) => { location: *location == system_para_destination, }, - ] - ); - }); -} - -#[test] -fn system_para_sets_relay_xcm_supported_version() { - // Init test variables - let sudo_origin = ::RuntimeOrigin::root(); - let parent_location = AssetHubPolkadot::parent_location(); - let system_para_destination: VersionedMultiLocation = - Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - let call = ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< - ::Runtime, - >::force_xcm_version { - location: bx!(parent_location), - version: XCM_V3, - }) - .encode() - .into(); - let origin_kind = OriginKind::Superuser; - - let xcm = xcm_transact_unpaid_execution(call, origin_kind); - - // System Parachain sets supported version for Relay Chain throught it - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - Polkadot::assert_xcm_pallet_sent(); - }); - - // System Parachain receive the XCM message - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts( - 1_019_210_000, - 200_000, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V3 - }) => { location: *location == parent_location, }, - ] - ); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs deleted file mode 100644 index 644c51d75b6620429ebdbcab1a1bdc8b37cce410..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(dead_code)] // - -use crate::*; - -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(632_207_000, 7_186))); - - assert_expected_events!( - Polkadot, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_ump_queue_processed( - true, - Some(AssetHubPolkadot::para_id()), - Some(Weight::from_parts(368_931_000, 7_186)), - ); - - assert_expected_events!( - Polkadot, - vec![ - // Amount is witdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Polkadot::assert_ump_queue_processed( - false, - Some(AssetHubPolkadot::para_id()), - Some(Weight::from_parts(232_982_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 632_207_000, - 7_186, - ))); - - AssetHubPolkadot::assert_parachain_system_ump_sent(); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts(161_196_000, 0))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - -fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged -// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { -// ::PolkadotXcm::teleport_assets( -// t.signed_origin, -// bx!(t.args.dest), -// bx!(t.args.beneficiary), -// bx!(t.args.assets), -// t.args.fee_asset_item, -// ) -// } - -/// Limited Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn limited_teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: AssetHubPolkadotReceiver::get(), - args: relay_test_args(amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let destination = AssetHubPolkadot::parent_location().into(); - let beneficiary_id = PolkadotReceiver::get().into(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: AssetHubPolkadotReceiver::get(), - args: relay_test_args(amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged - -// Right now it is failing in the Relay Chain with a -// `messageQueue.ProcessingFailed` event `error: Unsupported`. -// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` -// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier - -// /// Teleport of native asset from System Parachains to the Relay Chain -// /// should work when there is enough balance in Relay Chain's `CheckAccount` -// #[test] -// fn teleport_native_assets_back_from_system_para_to_relay_works() { -// // Dependency - Relay Chain's `CheckAccount` should have enough balance -// teleport_native_assets_from_relay_to_system_para_works(); - -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; -// let test_args = TestContext { -// sender: AssetHubPolkadotSender::get(), -// receiver: PolkadotReceiver::get(), -// args: get_para_dispatch_args(amount_to_send), -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance is increased -// assert!(receiver_balance_after > receiver_balance_before); -// } - -// /// Teleport of native asset from System Parachain to Relay Chain -// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -// #[test] -// fn teleport_native_assets_from_system_para_to_relay_fails() { -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; -// let assets = (Parent, amount_to_send).into(); -// -// let test_args = TestContext { -// sender: AssetHubPolkadotSender::get(), -// receiver: PolkadotReceiver::get(), -// args: system_para_test_args(amount_to_send), -// assets, -// None -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance does not change -// assert_eq!(receiver_balance_after, receiver_balance_before); -// } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml similarity index 85% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml index 788b2482be877e424052a563a86885b34fb1ead7..52682c6eefd61e8da8ce85cf96c9f7a4d0eeb3ad 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "asset-hub-kusama-integration-tests" +name = "asset-hub-rococo-integration-tests" version = "1.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" -description = "Asset Hub Kusama runtime integration tests with xcm-emulator" +description = "Asset Hub Rococo runtime integration tests with xcm-emulator" publish = false [dependencies] @@ -23,13 +23,12 @@ pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conv polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } -asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusama" } +asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} @@ -37,7 +36,7 @@ integration-tests-common = { path = "../../common", default-features = false} [features] runtime-benchmarks = [ - "asset-hub-kusama-runtime/runtime-benchmarks", + "asset-hub-rococo-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "integration-tests-common/runtime-benchmarks", @@ -48,6 +47,5 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs similarity index 74% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs index ad74aa2301fc34d478b9f719f9ccfddb44b79fc8..e0e9dcbdce7467dc0aa3359d570265f893fd950d 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/lib.rs @@ -22,18 +22,20 @@ pub use frame_support::{ }; pub use integration_tests_common::{ constants::{ - asset_hub_kusama::ED as ASSET_HUB_KUSAMA_ED, kusama::ED as KUSAMA_ED, PROOF_SIZE_THRESHOLD, + asset_hub_rococo::ED as ASSET_HUB_ROCOCO_ED, rococo::ED as ROCOCO_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, + test_parachain_is_trusted_teleporter, xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, Kusama, - KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, - PenpalKusamaAReceiver, PenpalKusamaASender, PenpalKusamaB, PenpalKusamaBPallet, + AssetHubRococo, AssetHubRococoPallet, AssetHubRococoReceiver, AssetHubRococoSender, + BridgeHubRococo, BridgeHubRococoReceiver, PenpalRococoA, PenpalRococoAPallet, + PenpalRococoAReceiver, PenpalRococoASender, PenpalRococoB, PenpalRococoBPallet, Rococo, + RococoPallet, RococoReceiver, RococoSender, }; pub use parachains_common::{AccountId, Balance}; pub use xcm::{ prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Kusama as KusamaId}, + v3::{Error, NetworkId::Rococo as RococoId}, }; pub use xcm_emulator::{ assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, @@ -45,17 +47,17 @@ pub const ASSET_MIN_BALANCE: u128 = 1000; // `Assets` pallet index pub const ASSETS_PALLET_ID: u8 = 50; -pub type RelayToSystemParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; +pub type RelayToSystemParaTest = Test; +pub type SystemParaToRelayTest = Test; +pub type SystemParaToParaTest = Test; /// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests pub fn relay_test_args(amount: Balance) -> TestArgs { TestArgs { - dest: Kusama::child_location_of(AssetHubKusama::para_id()), + dest: Rococo::child_location_of(AssetHubRococo::para_id()), beneficiary: AccountId32Junction { network: None, - id: AssetHubKusamaReceiver::get().into(), + id: AssetHubRococoReceiver::get().into(), } .into(), amount, @@ -86,5 +88,4 @@ pub fn system_para_test_args( } #[cfg(test)] -#[cfg(not(feature = "runtime-benchmarks"))] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs similarity index 97% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs index b3089a3b38269bfbb6d6377099ea4acae4a034b1..b3841af0e6c38372b8fb621fac468b25bdec63a1 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/mod.rs @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod hrmp_channels; mod reserve_transfer; mod send; mod set_xcm_versions; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs similarity index 71% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 645dca5035b1d8d385d9e01c31c2570dae14c2a4..0c136e2789f51c59455e349291c6d01215927b8d 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -16,17 +16,17 @@ use crate::*; fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); assert_expected_events!( - Kusama, + Rococo, vec![ // Amount to reserve transfer is transferred to System Parachain's Sovereign account RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { from: *from == t.sender.account_id, - to: *to == Kusama::sovereign_account_id_of( + to: *to == Rococo::sovereign_account_id_of( t.args.dest ), amount: *amount == t.args.amount, @@ -36,33 +36,33 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { } fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubKusama::assert_dmp_queue_incomplete( + AssetHubRococo::assert_dmp_queue_incomplete( Some(Weight::from_parts(1_000_000_000, 0)), Some(Error::UntrustedReserveLocation), ); } fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { - AssetHubKusama::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) + AssetHubRococo::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) } fn system_para_to_para_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 630_092_000, 6_196, ))); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereing account RuntimeEvent::Balances( pallet_balances::Event::Transfer { from, to, amount } ) => { from: *from == t.sender.account_id, - to: *to == AssetHubKusama::sovereign_account_id_of( + to: *to == AssetHubRococo::sovereign_account_id_of( t.args.dest ), amount: *amount == t.args.amount, @@ -72,15 +72,15 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) { } fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 676_119_000, 6196, ))); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereing account RuntimeEvent::Assets( @@ -88,7 +88,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { ) => { asset_id: *asset_id == ASSET_ID, from: *from == t.sender.account_id, - to: *to == AssetHubKusama::sovereign_account_id_of( + to: *to == AssetHubRococo::sovereign_account_id_of( t.args.dest ), amount: *amount == t.args.amount, @@ -98,7 +98,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { } fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( + ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -109,7 +109,7 @@ fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchRe } fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::reserve_transfer_assets( + ::XcmPallet::reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -119,7 +119,7 @@ fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { } fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -130,7 +130,7 @@ fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> Disp } fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -140,7 +140,7 @@ fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResu } fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -151,7 +151,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) } fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -165,10 +165,10 @@ fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> Dispa #[test] fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; + let amount_to_send: Balance = ROCOCO_ED * 1000; let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::get(), + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::get(), args: relay_test_args(amount_to_send), }; @@ -177,9 +177,9 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_limited_reserve_transfer_assets); + test.set_assertion::(relay_origin_assertions); + test.set_assertion::(system_para_dest_assertions_incomplete); + test.set_dispatchable::(relay_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -193,14 +193,14 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubRococo::parent_location(); + let beneficiary_id = RococoReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -209,8 +209,8 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_limited_reserve_transfer_assets); + test.set_assertion::(system_para_to_relay_assertions); + test.set_dispatchable::(system_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -224,10 +224,10 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; + let amount_to_send: Balance = ROCOCO_ED * 1000; let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::get(), + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::get(), args: relay_test_args(amount_to_send), }; @@ -236,9 +236,9 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); - test.set_dispatchable::(relay_reserve_transfer_assets); + test.set_assertion::(relay_origin_assertions); + test.set_assertion::(system_para_dest_assertions_incomplete); + test.set_dispatchable::(relay_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -252,14 +252,14 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { #[test] fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { // Init values for System Parachain - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubRococo::parent_location(); + let beneficiary_id = RococoReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -268,8 +268,8 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(system_para_to_relay_assertions); - test.set_dispatchable::(system_para_reserve_transfer_assets); + test.set_assertion::(system_para_to_relay_assertions); + test.set_dispatchable::(system_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -283,14 +283,14 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { #[test] fn limited_reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let beneficiary_id = PenpalRococoAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: PenpalKusamaAReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -298,10 +298,10 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_before = test.sender.balance; - test.set_assertion::(system_para_to_para_assertions); + test.set_assertion::(system_para_to_para_assertions); // TODO: Add assertion for Penpal runtime. Right now message is failing with // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -315,14 +315,14 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() { #[test] fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let beneficiary_id = PenpalRococoAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: PenpalKusamaAReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -330,10 +330,10 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { let sender_balance_before = test.sender.balance; - test.set_assertion::(system_para_to_para_assertions); + test.set_assertion::(system_para_to_para_assertions); // TODO: Add assertion for Penpal runtime. Right now message is failing with // `UntrustedReserveLocation` - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -347,34 +347,35 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { #[test] fn limited_reserve_transfer_asset_from_system_para_to_para() { // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubKusama::force_create_and_mint_asset( + AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, true, - AssetHubKusamaSender::get(), + AssetHubRococoSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1000000, ); // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let beneficiary_id = PenpalRococoAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) .into(); let system_para_test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: PenpalKusamaAReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - system_para_test.set_assertion::(system_para_to_para_assets_assertions); + system_para_test.set_assertion::(system_para_to_para_assets_assertions); // TODO: Add assertions when Penpal is able to manage assets system_para_test - .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + .set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); system_para_test.assert(); } @@ -382,33 +383,34 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { #[test] fn reserve_transfer_asset_from_system_para_to_para() { // Force create asset from Relay Chain and mint assets for System Parachain's sender account - AssetHubKusama::force_create_and_mint_asset( + AssetHubRococo::force_create_and_mint_asset( ASSET_ID, ASSET_MIN_BALANCE, true, - AssetHubKusamaSender::get(), + AssetHubRococoSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1000000, ); // Init values for System Parachain - let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); - let beneficiary_id = PenpalKusamaAReceiver::get(); + let destination = AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()); + let beneficiary_id = PenpalRococoAReceiver::get(); let amount_to_send = ASSET_MIN_BALANCE * 1000; let assets = (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) .into(); let system_para_test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: PenpalKusamaAReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: PenpalRococoAReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); - system_para_test.set_assertion::(system_para_to_para_assets_assertions); + system_para_test.set_assertion::(system_para_to_para_assets_assertions); // TODO: Add assertions when Penpal is able to manage assets system_para_test - .set_dispatchable::(system_para_to_para_reserve_transfer_assets); + .set_dispatchable::(system_para_to_para_reserve_transfer_assets); system_para_test.assert(); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs new file mode 100644 index 0000000000000000000000000000000000000000..b8ec370e3f8db347bb3394467a5b01efc684aba8 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/send.rs @@ -0,0 +1,102 @@ +// 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::*; + +/// Relay Chain should be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Superuser`. +#[test] +fn send_transact_as_superuser_from_relay_to_system_para_works() { + AssetHubRococo::force_create_asset_from_relay_as_root( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubRococoSender::get().into(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + ) +} + +/// Parachain should be able to send XCM paying its fee with sufficient asset +/// in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { + let para_sovereign_account = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalRococoA::para_id()), + ); + + // Force create and mint assets for Parachain's sovereign account + AssetHubRococo::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + para_sovereign_account.clone(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + ASSET_MIN_BALANCE * 1000000000, + ); + + // We just need a call that can pass the `SafeCallFilter` + // Call values are not relevant + let call = AssetHubRococo::force_create_asset_call( + ASSET_ID, + para_sovereign_account.clone(), + true, + ASSET_MIN_BALANCE, + ); + + let origin_kind = OriginKind::SovereignAccount; + let fee_amount = ASSET_MIN_BALANCE * 1000000; + let native_asset = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); + + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = + PenpalRococoA::sibling_location_of(AssetHubRococo::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + native_asset, + para_sovereign_account.clone(), + ); + + PenpalRococoA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + PenpalRococoA::assert_xcm_pallet_sent(); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593))); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == para_sovereign_account, + balance: *balance == fee_amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { + asset_id: *asset_id == ASSET_ID, + }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs similarity index 56% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs index a7af96096cdde4a9fc6bddb86874c02ca65a1c97..8faba50fc888b2155836d54c8e111146bc85c218 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs @@ -18,22 +18,22 @@ use crate::*; #[test] fn relay_sets_system_para_xcm_supported_version() { // Init tests variables - let sudo_origin = ::RuntimeOrigin::root(); + let sudo_origin = ::RuntimeOrigin::root(); let system_para_destination: MultiLocation = - Kusama::child_location_of(AssetHubKusama::para_id()); + Rococo::child_location_of(AssetHubRococo::para_id()); // Relay Chain sets supported version for Asset Parachain - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::force_xcm_version( + Rococo::execute_with(|| { + assert_ok!(::XcmPallet::force_xcm_version( sudo_origin, bx!(system_para_destination), XCM_V3 )); - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - Kusama, + Rococo, vec![ RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { location, @@ -47,41 +47,31 @@ fn relay_sets_system_para_xcm_supported_version() { #[test] fn system_para_sets_relay_xcm_supported_version() { // Init test variables - let sudo_origin = ::RuntimeOrigin::root(); - let parent_location = AssetHubKusama::parent_location(); - let system_para_destination: VersionedMultiLocation = - Kusama::child_location_of(AssetHubKusama::para_id()).into(); - let call = ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< - ::Runtime, - >::force_xcm_version { - location: bx!(parent_location), - version: XCM_V3, - }) - .encode() - .into(); - let origin_kind = OriginKind::Superuser; + let parent_location = AssetHubRococo::parent_location(); + let force_xcm_version_call = + ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< + ::Runtime, + >::force_xcm_version { + location: bx!(parent_location), + version: XCM_V3, + }) + .encode() + .into(); - let xcm = xcm_transact_unpaid_execution(call, origin_kind); - - // System Parachain sets supported version for Relay Chain throught it - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - Kusama::assert_xcm_pallet_sent(); - }); + // System Parachain sets supported version for Relay Chain through it + Rococo::send_unpaid_transact_to_parachain_as_root( + AssetHubRococo::para_id(), + force_xcm_version_call, + ); // System Parachain receive the XCM message - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { location, diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs similarity index 52% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs index 3a67b5435828184eb49c9ffbda814803d4115048..f9da0bf946ed5f1c6c838f617cdb7796638142e8 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs @@ -15,67 +15,67 @@ use crate::*; use frame_support::{instances::Instance2, BoundedVec}; -use parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; +use parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; use sp_runtime::{DispatchError, ModuleError}; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()); + let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); let asset_one = Box::new(MultiLocation { parents: 0, interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), }); - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), ASSET_ID.into(), - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), 1000, )); - assert!(::Assets::asset_exists(ASSET_ID)); + assert!(::Assets::asset_exists(ASSET_ID)); - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::Assets::mint( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), ASSET_ID.into(), - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), 100_000_000_000_000, )); - assert_ok!(::Balances::force_set_balance( - ::RuntimeOrigin::root(), - AssetHubKusamaSender::get().into(), + assert_ok!(::Balances::force_set_balance( + ::RuntimeOrigin::root(), + AssetHubRococoSender::get().into(), 100_000_000_000_000, )); - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), asset_one.clone(), )); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, ] ); - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), asset_one.clone(), 1_000_000_000_000, 2_000_000_000_000, 0, 0, - AssetHubKusamaSender::get().into() + AssetHubRococoSender::get().into() )); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, ] @@ -84,18 +84,18 @@ fn swap_locally_on_chain_using_local_assets() { let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + ::AssetConversion::swap_exact_tokens_for_tokens( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), path, 100, 1, - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), true ) ); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => { amount_in: *amount_in == 100, @@ -104,14 +104,14 @@ fn swap_locally_on_chain_using_local_assets() { ] ); - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::AssetConversion::remove_liquidity( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native, asset_one, 1414213562273 - EXISTENTIAL_DEPOSIT * 2, // all but the 2 EDs can't be retrieved. 0, 0, - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), )); }); } @@ -120,69 +120,69 @@ fn swap_locally_on_chain_using_local_assets() { fn swap_locally_on_chain_using_foreign_assets() { use frame_support::weights::WeightToFee; - let asset_native = Box::new(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()); + let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); - let foreign_asset1_at_asset_hub_kusama = Box::new(MultiLocation { + let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation { parents: 1, interior: X3( - Parachain(PenpalKusamaA::para_id().into()), + Parachain(PenpalRococoA::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), }); let assets_para_destination: VersionedMultiLocation = - MultiLocation { parents: 1, interior: X1(Parachain(AssetHubKusama::para_id().into())) } + MultiLocation { parents: 1, interior: X1(Parachain(AssetHubRococo::para_id().into())) } .into(); let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalKusamaA::para_id().into())) }; + MultiLocation { parents: 1, interior: X1(Parachain(PenpalRococoA::para_id().into())) }; // 1. Create asset on penpal: - PenpalKusamaA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalKusamaASender::get()), + PenpalRococoA::execute_with(|| { + assert_ok!(::Assets::create( + ::RuntimeOrigin::signed(PenpalRococoASender::get()), ASSET_ID.into(), - PenpalKusamaASender::get().into(), + PenpalRococoASender::get().into(), 1000, )); - assert!(::Assets::asset_exists(ASSET_ID)); + assert!(::Assets::asset_exists(ASSET_ID)); }); - // 2. Create foreign asset on asset_hub_kusama: + // 2. Create foreign asset on asset_hub_rococo: let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000); let origin_kind = OriginKind::Xcm; - let sov_penpal_on_asset_hub_kusama = AssetHubKusama::sovereign_account_id_of(penpal_location); + let sov_penpal_on_asset_hub_rococo = AssetHubRococo::sovereign_account_id_of(penpal_location); - AssetHubKusama::fund_accounts(vec![ - (AssetHubKusamaSender::get().into(), 5_000_000 * KUSAMA_ED), /* An account to swap dot + AssetHubRococo::fund_accounts(vec![ + (AssetHubRococoSender::get().into(), 5_000_000 * ROCOCO_ED), /* An account to swap dot * for something else. */ - (sov_penpal_on_asset_hub_kusama.clone().into(), 1000_000_000_000_000_000 * KUSAMA_ED), + (sov_penpal_on_asset_hub_rococo.clone().into(), 1000_000_000_000_000_000 * ROCOCO_ED), ]); - let sov_penpal_on_asset_hub_kusama_as_location: MultiLocation = MultiLocation { + let sov_penpal_on_asset_hub_rococo_as_location: MultiLocation = MultiLocation { parents: 0, interior: X1(AccountId32Junction { network: None, - id: sov_penpal_on_asset_hub_kusama.clone().into(), + id: sov_penpal_on_asset_hub_rococo.clone().into(), }), }; let call_foreign_assets_create = - ::RuntimeCall::ForeignAssets(pallet_assets::Call::< - ::Runtime, + ::RuntimeCall::ForeignAssets(pallet_assets::Call::< + ::Runtime, Instance2, >::create { - id: *foreign_asset1_at_asset_hub_kusama, + id: *foreign_asset1_at_asset_hub_rococo, min_balance: 1000, - admin: sov_penpal_on_asset_hub_kusama.clone().into(), + admin: sov_penpal_on_asset_hub_rococo.clone().into(), }) .encode() .into(); - let buy_execution_fee_amount = parachains_common::kusama::fee::WeightToFee::weight_to_fee( + let buy_execution_fee_amount = parachains_common::rococo::fee::WeightToFee::weight_to_fee( &Weight::from_parts(10_100_000_000_000, 300_000), ); let buy_execution_fee = MultiAsset { @@ -197,23 +197,23 @@ fn swap_locally_on_chain_using_foreign_assets() { RefundSurplus, DepositAsset { assets: All.into(), - beneficiary: sov_penpal_on_asset_hub_kusama_as_location, + beneficiary: sov_penpal_on_asset_hub_rococo_as_location, }, ])); - // Send XCM message from penpal => asset_hub_kusama - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalKusamaA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + // Send XCM message from penpal => asset_hub_rococo + let sudo_penpal_origin = ::RuntimeOrigin::root(); + PenpalRococoA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( sudo_penpal_origin.clone(), bx!(assets_para_destination.clone()), bx!(xcm), )); - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - PenpalKusamaA, + PenpalRococoA, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, ] @@ -221,64 +221,64 @@ fn swap_locally_on_chain_using_foreign_assets() { }); // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_kusama + AssetHubRococo::execute_with(|| { + assert!(::ForeignAssets::asset_exists( + *foreign_asset1_at_asset_hub_rococo )); - // 3: Mint foreign asset on asset_hub_kusama: + // 3: Mint foreign asset on asset_hub_rococo: // // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; // 3. Mint foreign asset (in reality this should be a teleport or some such) - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_kusama.clone().into() + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed( + sov_penpal_on_asset_hub_rococo.clone().into() ), - *foreign_asset1_at_asset_hub_kusama, - sov_penpal_on_asset_hub_kusama.clone().into(), + *foreign_asset1_at_asset_hub_rococo, + sov_penpal_on_asset_hub_rococo.clone().into(), 3_000_000_000_000, )); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, ] ); // 4. Create pool: - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), + foreign_asset1_at_asset_hub_rococo.clone(), )); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, ] ); // 5. Add liquidity: - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_kusama.clone() + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed( + sov_penpal_on_asset_hub_rococo.clone() ), asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), + foreign_asset1_at_asset_hub_rococo.clone(), 1_000_000_000_000, 2_000_000_000_000, 0, 0, - sov_penpal_on_asset_hub_kusama.clone().into() + sov_penpal_on_asset_hub_rococo.clone().into() )); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, @@ -289,22 +289,22 @@ fn swap_locally_on_chain_using_foreign_assets() { // 6. Swap! let path = BoundedVec::<_, _>::truncate_from(vec![ asset_native.clone(), - foreign_asset1_at_asset_hub_kusama.clone(), + foreign_asset1_at_asset_hub_rococo.clone(), ]); assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + ::AssetConversion::swap_exact_tokens_for_tokens( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), path, 100000, 1000, - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), true ) ); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { amount_in: *amount_in == 100000, @@ -314,47 +314,47 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 7. Remove liquidity - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_kusama.clone() + assert_ok!(::AssetConversion::remove_liquidity( + ::RuntimeOrigin::signed( + sov_penpal_on_asset_hub_rococo.clone() ), asset_native, - foreign_asset1_at_asset_hub_kusama, + foreign_asset1_at_asset_hub_rococo, 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, - sov_penpal_on_asset_hub_kusama.clone().into(), + sov_penpal_on_asset_hub_rococo.clone().into(), )); }); } #[test] fn cannot_create_pool_from_pool_assets() { - let asset_native = Box::new(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()); - let mut asset_one = asset_hub_kusama_runtime::xcm_config::PoolAssetsPalletLocation::get(); + let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); + let mut asset_one = asset_hub_rococo_runtime::xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); - AssetHubKusama::execute_with(|| { - let pool_owner_account_id = asset_hub_kusama_runtime::AssetConversionOrigin::get(); + AssetHubRococo::execute_with(|| { + let pool_owner_account_id = asset_hub_rococo_runtime::AssetConversionOrigin::get(); - assert_ok!(::PoolAssets::create( - ::RuntimeOrigin::signed(pool_owner_account_id.clone()), + assert_ok!(::PoolAssets::create( + ::RuntimeOrigin::signed(pool_owner_account_id.clone()), ASSET_ID.into(), pool_owner_account_id.clone().into(), 1000, )); - assert!(::PoolAssets::asset_exists(ASSET_ID)); + assert!(::PoolAssets::asset_exists(ASSET_ID)); - assert_ok!(::PoolAssets::mint( - ::RuntimeOrigin::signed(pool_owner_account_id), + assert_ok!(::PoolAssets::mint( + ::RuntimeOrigin::signed(pool_owner_account_id), ASSET_ID.into(), - AssetHubKusamaSender::get().into(), + AssetHubRococoSender::get().into(), 3_000_000_000_000, )); assert_matches::assert_matches!( - ::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), + ::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), Box::new(asset_one), ), diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs similarity index 53% rename from cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs rename to cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs index f69878f35435ded3da456756328350a1c286a471..21afed179184e6cebdd00ab87e33327337ea4059 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/teleport.rs @@ -13,17 +13,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(dead_code)] // - use crate::*; fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); assert_expected_events!( - Kusama, + Rococo, vec![ // Amount to teleport is withdrawn from Sender RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { @@ -32,7 +30,7 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { }, // Amount to teleport is deposited in Relay's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { - who: *who == ::XcmPallet::check_account(), + who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, ] @@ -40,20 +38,20 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { } fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_ump_queue_processed( + Rococo::assert_ump_queue_processed( true, - Some(AssetHubKusama::para_id()), + Some(AssetHubRococo::para_id()), Some(Weight::from_parts(307_225_000, 7_186)), ); assert_expected_events!( - Kusama, + Rococo, vec![ // Amount is witdrawn from Relay Chain's `CheckAccount` RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { - who: *who == ::XcmPallet::check_account(), + who: *who == ::XcmPallet::check_account(), amount: *amount == t.args.amount, }, // Amount minus fees are deposited in Receiver's account @@ -65,25 +63,25 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { } fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Kusama::assert_ump_queue_processed( + Rococo::assert_ump_queue_processed( false, - Some(AssetHubKusama::para_id()), + Some(AssetHubRococo::para_id()), Some(Weight::from_parts(148_433_000, 3_593)), ); } fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 534_872_000, 7_133, ))); - AssetHubKusama::assert_parachain_system_ump_sent(); + AssetHubRococo::assert_parachain_system_ump_sent(); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ // Amount is withdrawn from Sender's account RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { @@ -95,12 +93,12 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { } fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); assert_expected_events!( - AssetHubKusama, + AssetHubRococo, vec![ // Amount minus fees are deposited in Receiver's account RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { @@ -111,7 +109,7 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { } fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_assets( + ::XcmPallet::limited_teleport_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -122,7 +120,7 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { } fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( + ::XcmPallet::teleport_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -132,7 +130,7 @@ fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { } fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( + ::PolkadotXcm::limited_teleport_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -142,25 +140,24 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged -// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { -// ::PolkadotXcm::teleport_assets( -// t.signed_origin, -// bx!(t.args.dest), -// bx!(t.args.beneficiary), -// bx!(t.args.assets), -// t.args.fee_asset_item, -// ) -// } +fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { + ::PolkadotXcm::teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} /// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] fn limited_teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; + let amount_to_send: Balance = ROCOCO_ED * 1000; let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::get(), + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::get(), args: relay_test_args(amount_to_send), }; @@ -169,9 +166,9 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); + test.set_assertion::(relay_origin_assertions); + test.set_assertion::(para_dest_assertions); + test.set_dispatchable::(relay_limited_teleport_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -191,14 +188,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { limited_teleport_native_assets_from_relay_to_system_para_works(); // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let destination = AssetHubRococo::parent_location(); + let beneficiary_id = RococoReceiver::get(); let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -207,9 +204,9 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions); + test.set_dispatchable::(system_para_limited_teleport_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -226,14 +223,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { #[test] fn limited_teleport_native_assets_from_system_para_to_relay_fails() { // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location().into(); - let beneficiary_id = KusamaReceiver::get().into(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let destination = AssetHubRococo::parent_location().into(); + let beneficiary_id = RococoReceiver::get().into(); let assets = (Parent, amount_to_send).into(); let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), }; @@ -242,9 +239,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions_fail); + test.set_dispatchable::(system_para_limited_teleport_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -260,10 +257,10 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { #[test] fn teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; + let amount_to_send: Balance = ROCOCO_ED * 1000; let test_args = TestContext { - sender: KusamaSender::get(), - receiver: AssetHubKusamaReceiver::get(), + sender: RococoSender::get(), + receiver: AssetHubRococoReceiver::get(), args: relay_test_args(amount_to_send), }; @@ -272,9 +269,9 @@ fn teleport_native_assets_from_relay_to_system_para_works() { let sender_balance_before = test.sender.balance; let receiver_balance_before = test.receiver.balance; - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); + test.set_assertion::(relay_origin_assertions); + test.set_assertion::(para_dest_assertions); + test.set_dispatchable::(relay_teleport_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -286,78 +283,87 @@ fn teleport_native_assets_from_relay_to_system_para_works() { assert!(receiver_balance_after > receiver_balance_before); } -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged - -// Right now it is failing in the Relay Chain with a -// `messageQueue.ProcessingFailed` event `error: Unsupported`. -// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` -// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier - -// /// Teleport of native asset from System Parachains to the Relay Chain -// /// should work when there is enough balance in Relay Chain's `CheckAccount` -// #[test] -// fn teleport_native_assets_back_from_system_para_to_relay_works() { -// // Dependency - Relay Chain's `CheckAccount` should have enough balance -// teleport_native_assets_from_relay_to_system_para_works(); - -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; -// let test_args = TestContext { -// sender: AssetHubKusamaSender::get(), -// receiver: KusamaReceiver::get(), -// args: get_para_dispatch_args(amount_to_send), -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance is increased -// assert!(receiver_balance_after > receiver_balance_before); -// } - -// /// Teleport of native asset from System Parachain to Relay Chain -// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -// #[test] -// fn teleport_native_assets_from_system_para_to_relay_fails() { -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; -// let assets = (Parent, amount_to_send).into(); -// -// let test_args = TestContext { -// sender: AssetHubKusamaSender::get(), -// receiver: KusamaReceiver::get(), -// args: system_para_test_args(amount_to_send), -// assets, -// None -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance does not change -// assert_eq!(receiver_balance_after, receiver_balance_before); -// } +/// Teleport of native asset from System Parachains to the Relay Chain +/// should work when there is enough balance in Relay Chain's `CheckAccount` +#[test] +fn teleport_native_assets_back_from_system_para_to_relay_works() { + // Dependency - Relay Chain's `CheckAccount` should have enough balance + teleport_native_assets_from_relay_to_system_para_works(); + + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let destination = AssetHubRococo::parent_location(); + let beneficiary_id = RococoReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions); + test.set_dispatchable::(system_para_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +/// Teleport of native asset from System Parachain to Relay Chain +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` +#[test] +fn teleport_native_assets_from_system_para_to_relay_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let destination = AssetHubRococo::parent_location(); + let beneficiary_id = RococoReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubRococoSender::get(), + receiver: RococoReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions_fail); + test.set_dispatchable::(system_para_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance does not change + assert_eq!(receiver_balance_after, receiver_balance_before); +} + +#[test] +fn teleport_to_other_system_parachains_works() { + let amount = ASSET_HUB_ROCOCO_ED * 100; + let native_asset: VersionedMultiAssets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + AssetHubRococo, // Origin + vec![BridgeHubRococo], // Destinations + (native_asset, amount) + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index 80c41c24aa75ef4c166bd778935e2178b9529484..bf141dafebf2cde02f3eeda6b71841b02ae62282 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml @@ -18,18 +18,24 @@ frame-system = { path = "../../../../../../substrate/frame/system", default-feat 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-asset-rate = { path = "../../../../../../substrate/frame/asset-rate", default-features = false} # Polkadot polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false} +polkadot-runtime-common = { path = "../../../../../../polkadot/runtime/common" } polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } 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} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} # Cumulus parachains-common = { path = "../../../../common" } asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } +cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" } +cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} @@ -38,16 +44,21 @@ integration-tests-common = { path = "../../common", default-features = false} [features] runtime-benchmarks = [ "asset-hub-westend-runtime/runtime-benchmarks", + "cumulus-pallet-parachain-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "integration-tests-common/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", + "pallet-asset-rate/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index 6e0f3434aedf3dd7a5f630ad40729e6a61e9ba47..c25cc601fbefb978c8d041c8fda8e60594749df8 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs @@ -27,6 +27,7 @@ pub use integration_tests_common::{ asset_hub_westend::ED as ASSET_HUB_WESTEND_ED, westend::ED as WESTEND_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, + test_parachain_is_trusted_teleporter, xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, AssetHubWestend, AssetHubWestendPallet, AssetHubWestendReceiver, AssetHubWestendSender, PenpalWestendA, PenpalWestendAPallet, PenpalWestendAReceiver, PenpalWestendASender, Westend, @@ -88,5 +89,4 @@ pub fn system_para_test_args( } #[cfg(test)] -#[cfg(not(feature = "runtime-benchmarks"))] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs index b3841af0e6c38372b8fb621fac468b25bdec63a1..0c9de89c5f98f04a8a8f79048faf260c7bae27d5 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs @@ -18,3 +18,4 @@ mod send; mod set_xcm_versions; mod swap; mod teleport; +mod treasury; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 51fac43be1255948a9ae72044bececa3d907f2c5..8f8b7a7dde77723d70b845210740cb88e36fac09 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -35,11 +35,8 @@ fn relay_origin_assertions(t: RelayToSystemParaTest) { ); } -fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { - AssetHubWestend::assert_dmp_queue_incomplete( - Some(Weight::from_parts(1_000_000_000, 0)), - Some(Error::UntrustedReserveLocation), - ); +fn system_para_dest_assertions(_t: RelayToSystemParaTest) { + AssetHubWestend::assert_dmp_queue_error(Error::WeightNotComputable); } fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { @@ -178,7 +175,7 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); + test.set_assertion::(system_para_dest_assertions); test.set_dispatchable::(relay_limited_reserve_transfer_assets); test.assert(); @@ -237,7 +234,7 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { let receiver_balance_before = test.receiver.balance; test.set_assertion::(relay_origin_assertions); - test.set_assertion::(system_para_dest_assertions_incomplete); + test.set_assertion::(system_para_dest_assertions); test.set_dispatchable::(relay_reserve_transfer_assets); test.assert(); @@ -352,6 +349,7 @@ fn limited_reserve_transfer_asset_from_system_para_to_para() { ASSET_MIN_BALANCE, true, AssetHubWestendSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1000000, ); @@ -387,6 +385,7 @@ fn reserve_transfer_asset_from_system_para_to_para() { ASSET_MIN_BALANCE, true, AssetHubWestendSender::get(), + Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1000000, ); diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs index 424d222bef3811966f55d8fbac954f33f065ffc7..e603af685bb5c50ca4ab695ab8ccb588bb52edfd 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs @@ -16,52 +16,16 @@ use crate::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Superuser` and signer is `sudo` +/// when `OriginKind::Superuser`. #[test] -fn send_transact_sudo_from_relay_to_system_para_works() { - // Init tests variables - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = Westend::child_location_of(AssetHubWestend::para_id()).into(); - let asset_owner: AccountId = AssetHubWestendSender::get().into(); - let xcm = AssetHubWestend::force_create_asset_xcm( - OriginKind::Superuser, +fn send_transact_as_superuser_from_relay_to_system_para_works() { + AssetHubWestend::force_create_asset_from_relay_as_root( ASSET_ID, - asset_owner.clone(), + ASSET_MIN_BALANCE, true, - 1000, - ); - // Send XCM message from Relay Chain - Westend::execute_with(|| { - assert_ok!(::XcmPallet::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - Westend::assert_xcm_pallet_sent(); - }); - - // Receive XCM message in Assets Parachain - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts( - 1_019_445_000, - 200_000, - ))); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == asset_owner, - }, - ] - ); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); + AssetHubWestendSender::get().into(), + Some(Weight::from_parts(1_019_445_000, 200_000)), + ) } /// Parachain should be able to send XCM paying its fee with sufficient asset @@ -78,6 +42,7 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { ASSET_MIN_BALANCE, true, para_sovereign_account.clone(), + Some(Weight::from_parts(1_019_445_000, 200_000)), ASSET_MIN_BALANCE * 1000000000, ); @@ -119,8 +84,8 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( - 2_176_414_000, - 203_593, + 16_290_336_000, + 562_893, ))); assert_expected_events!( diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs index 2720095aac00d5d15c43e77224b30b7387079897..2133d5e5fb7c7537ae757c30a8c6ba3b96cc9c00 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs @@ -47,32 +47,22 @@ fn relay_sets_system_para_xcm_supported_version() { #[test] fn system_para_sets_relay_xcm_supported_version() { // Init test variables - let sudo_origin = ::RuntimeOrigin::root(); let parent_location = AssetHubWestend::parent_location(); - let system_para_destination: VersionedMultiLocation = - Westend::child_location_of(AssetHubWestend::para_id()).into(); - let call = ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< - ::Runtime, - >::force_xcm_version { - location: bx!(parent_location), - version: XCM_V3, - }) - .encode() - .into(); - let origin_kind = OriginKind::Superuser; - - let xcm = xcm_transact_unpaid_execution(call, origin_kind); - - // System Parachain sets supported version for Relay Chain throught it - Westend::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(system_para_destination), - bx!(xcm), - )); + let force_xcm_version_call = + ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< + ::Runtime, + >::force_xcm_version { + location: bx!(parent_location), + version: XCM_V3, + }) + .encode() + .into(); - Westend::assert_xcm_pallet_sent(); - }); + // System Parachain sets supported version for Relay Chain through it + Westend::send_unpaid_transact_to_parachain_as_root( + AssetHubWestend::para_id(), + force_xcm_version_call, + ); // System Parachain receive the XCM message AssetHubWestend::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index 8de73a7420c6b69954b2fe295a3b5f6bf4e7219c..81471c401f39637c7d53f95465f7e95ecf4bf8ba 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs @@ -97,7 +97,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { fn para_dest_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(164_733_000, 0))); + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(164_793_000, 3593))); assert_expected_events!( AssetHubWestend, @@ -142,16 +142,15 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged -// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { -// ::PolkadotXcm::teleport_assets( -// t.signed_origin, -// bx!(t.args.dest), -// bx!(t.args.beneficiary), -// bx!(t.args.assets), -// t.args.fee_asset_item, -// ) -// } +fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { + ::PolkadotXcm::teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} /// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] @@ -286,78 +285,89 @@ fn teleport_native_assets_from_relay_to_system_para_works() { assert!(receiver_balance_after > receiver_balance_before); } -// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged +/// Teleport of native asset from System Parachains to the Relay Chain +/// should work when there is enough balance in Relay Chain's `CheckAccount` +#[test] +fn teleport_native_assets_back_from_system_para_to_relay_works() { + // Dependency - Relay Chain's `CheckAccount` should have enough balance + teleport_native_assets_from_relay_to_system_para_works(); -// Right now it is failing in the Relay Chain with a -// `messageQueue.ProcessingFailed` event `error: Unsupported`. -// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` -// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let destination = AssetHubWestend::parent_location(); + let beneficiary_id = WestendReceiver::get(); + let assets = (Parent, amount_to_send).into(); -// /// Teleport of native asset from System Parachains to the Relay Chain -// /// should work when there is enough balance in Relay Chain's `CheckAccount` -// #[test] -// fn teleport_native_assets_back_from_system_para_to_relay_works() { -// // Dependency - Relay Chain's `CheckAccount` should have enough balance -// teleport_native_assets_from_relay_to_system_para_works(); - -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; -// let test_args = TestContext { -// sender: AssetHubWestendSender::get(), -// receiver: WestendReceiver::get(), -// args: get_para_dispatch_args(amount_to_send), -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance is increased -// assert!(receiver_balance_after > receiver_balance_before); -// } + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; -// /// Teleport of native asset from System Parachain to Relay Chain -// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions); + test.set_dispatchable::(system_para_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +/// Teleport of native asset from System Parachain to Relay Chain +/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` +#[test] +fn teleport_native_assets_from_system_para_to_relay_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let destination = AssetHubWestend::parent_location(); + let beneficiary_id = WestendReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::(para_origin_assertions); + test.set_assertion::(relay_dest_assertions_fail); + test.set_dispatchable::(system_para_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance does not change + assert_eq!(receiver_balance_after, receiver_balance_before); +} + +// TODO: uncomment when CollectivesWestend and BridgeHubWestend are implemented +// https://github.com/paritytech/polkadot-sdk/pull/1737 (CollectivesWestend) // #[test] -// fn teleport_native_assets_from_system_para_to_relay_fails() { -// // Init values for Relay Chain -// let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; -// let assets = (Parent, amount_to_send).into(); -// -// let test_args = TestContext { -// sender: AssetHubWestendSender::get(), -// receiver: WestendReceiver::get(), -// args: system_para_test_args(amount_to_send), -// assets, -// None -// }; - -// let mut test = SystemParaToRelayTest::new(test_args); - -// let sender_balance_before = test.sender.balance; -// let receiver_balance_before = test.receiver.balance; - -// test.set_assertion::(para_origin_assertions); -// test.set_assertion::(relay_dest_assertions); -// test.set_dispatchable::(system_para_teleport_assets); -// test.assert(); - -// let sender_balance_after = test.sender.balance; -// let receiver_balance_after = test.receiver.balance; - -// // Sender's balance is reduced -// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); -// // Receiver's balance does not change -// assert_eq!(receiver_balance_after, receiver_balance_before); +// fn teleport_to_other_system_parachains_works() { +// let amount = ASSET_HUB_WESTEND_ED * 100; +// let native_asset: VersionedMultiAssets = (Parent, amount).into(); + +// test_parachain_is_trusted_teleporter!( +// AssetHubWestend, // Origin +// vec![CollectivesWestend, BridgeHubWestend], // Destinations +// (native_asset, amount) +// ); // } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs new file mode 100644 index 0000000000000000000000000000000000000000..cf06f58682da2d8dfb626305a9e8f0aff7b48804 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/treasury.rs @@ -0,0 +1,126 @@ +// 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 frame_support::traits::fungibles::{Create, Inspect, Mutate}; +use integration_tests_common::constants::accounts::{ALICE, BOB}; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use xcm_executor::traits::ConvertLocation; + +#[test] +fn create_and_claim_treasury_spend() { + const ASSET_ID: u32 = 1984; + const SPEND_AMOUNT: u128 = 1_000_000; + // treasury location from a sibling parachain. + let treasury_location: MultiLocation = MultiLocation::new(1, PalletInstance(37)); + // treasury account on a sibling parachain. + let treasury_account = + asset_hub_westend_runtime::xcm_config::LocationToAccountId::convert_location( + &treasury_location, + ) + .unwrap(); + let asset_hub_location = MultiLocation::new(0, Parachain(AssetHubWestend::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: AssetId::Concrete((PalletInstance(50), GeneralIndex(ASSET_ID.into())).into()), + }; + // treasury spend beneficiary. + let alice: AccountId = Westend::account_id_of(ALICE); + let bob: AccountId = Westend::account_id_of(BOB); + let bob_signed = ::RuntimeOrigin::signed(bob.clone()); + + AssetHubWestend::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,); + }); + + Westend::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(MultiLocation::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), + None, + )); + // claim the spend. + assert_ok!(Treasury::payout(bob_signed.clone(), 0)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubWestend::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!( + AssetHubWestend, + 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::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { outcome: Outcome::Complete(..) ,.. }) => {}, + ] + ); + // beneficiary received the assets from the treasury. + assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + }); + + Westend::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!( + Westend, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml index c02c96255e1837bcdbd0755b669e5985721e0c16..7ecf87158241d443c9592e9da85a82dd6eb26729 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml @@ -17,7 +17,6 @@ frame-support = { path = "../../../../../../substrate/frame/support", default-fe polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false} polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs index 122d65461159d90a84888b792f35e89decf7c5be..3c4dbe18a9ac42d126efb3c999645f926a521483 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs @@ -17,12 +17,13 @@ pub use bp_messages::LaneId; pub use frame_support::assert_ok; pub use integration_tests_common::{ constants::{ - asset_hub_kusama::ED as ASSET_HUB_ROCOCO_ED, kusama::ED as ROCOCO_ED, PROOF_SIZE_THRESHOLD, - REF_TIME_THRESHOLD, XCM_V3, + bridge_hub_rococo::ED as BRIDGE_HUB_ROCOCO_ED, rococo::ED as ROCOCO_ED, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, + test_parachain_is_trusted_teleporter, xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - AssetHubRococo, AssetHubRococoReceiver, AssetHubWococo, BridgeHubRococo, BridgeHubWococo, - PenpalRococoA, Rococo, RococoPallet, + AssetHubRococo, AssetHubRococoReceiver, AssetHubWococo, BridgeHubRococo, BridgeHubRococoPallet, + BridgeHubRococoSender, BridgeHubWococo, PenpalRococoA, Rococo, RococoPallet, }; pub use parachains_common::{AccountId, Balance}; pub use xcm::{ @@ -63,5 +64,4 @@ pub fn relay_test_args(amount: Balance) -> TestArgs { } #[cfg(test)] -#[cfg(not(feature = "runtime-benchmarks"))] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs index 48347557ae77df661d8c41726cb3fe7f24738678..1eef05c6b9281e26d3e412f4aac8b9e265d2d5c0 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -14,3 +14,4 @@ // limitations under the License. mod example; +mod teleport; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs new file mode 100644 index 0000000000000000000000000000000000000000..4c7e37fab6230acaae461da20fda9c4d1a9bcefd --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/teleport.rs @@ -0,0 +1,28 @@ +// 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::*; + +#[test] +fn teleport_to_other_system_parachains_works() { + let amount = BRIDGE_HUB_ROCOCO_ED * 100; + let native_asset: VersionedMultiAssets = (Parent, amount).into(); + + test_parachain_is_trusted_teleporter!( + BridgeHubRococo, // Origin + vec![AssetHubRococo], // Destinations + (native_asset, amount) + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml deleted file mode 100644 index 5a28b12741512be22a6f29c4d6a57bebf7656567..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "collectives-polkadot-integration-tests" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Polkadot Collectives parachain runtime integration tests based on xcm-emulator" -publish = false - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } - -# Substrate -sp-runtime = { path = "../../../../../../substrate/primitives/runtime", default-features = false} -frame-support = { path = "../../../../../../substrate/frame/support", default-features = false} -sp-core = { path = "../../../../../../substrate/primitives/core", default-features = false} -pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false} -pallet-core-fellowship = { path = "../../../../../../substrate/frame/core-fellowship", default-features = false} -pallet-salary = { path = "../../../../../../substrate/frame/salary", default-features = false} - -# Polkadot -polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false} -polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false} -polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../../polkadot/runtime/polkadot" } -xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} -pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} - -# Cumulus -parachains-common = { path = "../../../../common" } -cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} -cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } -collectives-polkadot-runtime = { path = "../../../../runtimes/collectives/collectives-polkadot" } - -# Local -xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} -integration-tests-common = { path = "../../common", default-features = false} diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs deleted file mode 100644 index aa716c7c94855acb016056733bcd6111fa8b5599..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; -pub use frame_support::{assert_ok, sp_runtime::AccountId32}; -pub use integration_tests_common::{ - constants::{ - accounts::ALICE, asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, - polkadot::ED as POLKADOT_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, Collectives, - PenpalPolkadotA, Polkadot, -}; -pub use parachains_common::{AccountId, Balance}; -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Polkadot as PolkadotId}, -}; -pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, ParaId, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, TestExternalities, -}; - -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -pub const ASSETS_PALLET_ID: u8 = 50; - -pub type RelayToSystemParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; - -/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests -pub fn relay_test_args(amount: Balance) -> TestArgs { - TestArgs { - dest: Polkadot::child_location_of(AssetHubPolkadot::para_id()), - beneficiary: AccountId32Junction { - network: None, - id: AssetHubPolkadotReceiver::get().into(), - } - .into(), - amount, - assets: (Here, amount).into(), - asset_id: None, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests -pub fn system_para_test_args( - dest: MultiLocation, - beneficiary_id: AccountId32, - amount: Balance, - assets: MultiAssets, - asset_id: Option, -) -> TestArgs { - TestArgs { - dest, - beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), - amount, - assets, - asset_id, - fee_asset_item: 0, - weight_limit: WeightLimit::Unlimited, - } -} - -#[cfg(test)] -#[cfg(not(feature = "runtime-benchmarks"))] -mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs deleted file mode 100644 index c08a660205f6829ed50b5643ab191b4c3005ce73..0000000000000000000000000000000000000000 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Integration tests concerning the Fellowship. - -use crate::*; -use collectives_polkadot_runtime::fellowship::FellowshipSalaryPaymaster; -use frame_support::traits::{ - fungibles::{Create, Mutate}, - tokens::Pay, -}; -use sp_core::crypto::Ss58Codec; -use xcm_emulator::TestExt; - -#[test] -fn pay_salary() { - let asset_id: u32 = 1984; - let pay_from: AccountId = - ::from_string("13w7NdvSR1Af8xsQTArDtZmVvjE8XhWNdL4yed3iFHrUNCnS") - .unwrap(); - let pay_to = Polkadot::account_id_of(ALICE); - let pay_amount = 9000; - - AssetHubPolkadot::execute_with(|| { - type AssetHubAssets = ::Assets; - - assert_ok!(>::create( - asset_id, - pay_to.clone(), - true, - pay_amount / 2 - )); - assert_ok!(>::mint_into(asset_id, &pay_from, pay_amount * 2)); - }); - - Collectives::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount)); - assert_expected_events!( - Collectives, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => - { asset_id: id == &asset_id, - from: from == &pay_from, - to: to == &pay_to, - amount: amount == &pay_amount, - }, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {}, - ] - ); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index f1db26c2a540d4d7c2ca29e0c68860d12b2cf8b5..1691d21e173d2f038bc492b93e1a390f2ec6a1dd 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -19,6 +19,7 @@ frame-support = { path = "../../../../../substrate/frame/support", default-featu sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} sp-consensus-babe = { path = "../../../../../substrate/primitives/consensus/babe", default-features = false} pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false} +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-staking = { path = "../../../../../substrate/frame/staking", default-features = false} pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false} pallet-im-online = { path = "../../../../../substrate/frame/im-online", default-features = false} @@ -30,10 +31,6 @@ polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", de polkadot-service = { path = "../../../../../polkadot/node/service", default-features = false, features = ["full-node"] } polkadot-primitives = { path = "../../../../../polkadot/primitives", default-features = false} polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } -polkadot-runtime = { path = "../../../../../polkadot/runtime/polkadot" } -polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/constants" } -kusama-runtime = { package = "staging-kusama-runtime", path = "../../../../../polkadot/runtime/kusama" } -kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/constants" } rococo-runtime = { path = "../../../../../polkadot/runtime/rococo" } rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants" } westend-runtime = { path = "../../../../../polkadot/runtime/westend" } @@ -47,6 +44,7 @@ cumulus-primitives-core = { path = "../../../../primitives/core" } penpal-runtime = { path = "../../../runtimes/testing/penpal" } asset-hub-polkadot-runtime = { path = "../../../runtimes/assets/asset-hub-polkadot" } asset-hub-kusama-runtime = { path = "../../../runtimes/assets/asset-hub-kusama" } +asset-hub-rococo-runtime = { path = "../../../runtimes/assets/asset-hub-rococo" } asset-hub-westend-runtime = { path = "../../../runtimes/assets/asset-hub-westend" } collectives-polkadot-runtime = { path = "../../../runtimes/collectives/collectives-polkadot" } bridge-hub-kusama-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-kusama" } @@ -64,6 +62,7 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common" } runtime-benchmarks = [ "asset-hub-kusama-runtime/runtime-benchmarks", "asset-hub-polkadot-runtime/runtime-benchmarks", + "asset-hub-rococo-runtime/runtime-benchmarks", "asset-hub-westend-runtime/runtime-benchmarks", "bridge-hub-kusama-runtime/runtime-benchmarks", "bridge-hub-polkadot-runtime/runtime-benchmarks", @@ -73,8 +72,8 @@ runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", "frame-support/runtime-benchmarks", - "kusama-runtime/runtime-benchmarks", "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", @@ -85,7 +84,6 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-runtime/runtime-benchmarks", "polkadot-service/runtime-benchmarks", "rococo-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 8725ebd140b97272630430de324177bf5cae1484..592269e9aa388d921e4253c562e954779460adf2 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -138,144 +138,6 @@ pub mod validators { /// The default XCM version to set in genesis config. const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -// Polkadot -pub mod polkadot { - use super::*; - pub const ED: Balance = polkadot_runtime_constants::currency::EXISTENTIAL_DEPOSIT; - const STASH: u128 = 100 * polkadot_runtime_constants::currency::UNITS; - - pub fn get_host_config() -> HostConfiguration { - HostConfiguration { - max_upward_queue_count: 10, - max_upward_queue_size: 51200, - max_upward_message_size: 51200, - max_upward_message_num_per_candidate: 10, - max_downward_message_size: 51200, - hrmp_sender_deposit: 100_000_000_000, - hrmp_recipient_deposit: 100_000_000_000, - hrmp_channel_max_capacity: 1000, - hrmp_channel_max_message_size: 102400, - hrmp_channel_max_total_size: 102400, - hrmp_max_parachain_outbound_channels: 30, - hrmp_max_parachain_inbound_channels: 30, - ..Default::default() - } - } - - fn session_keys( - babe: BabeId, - grandpa: GrandpaId, - im_online: ImOnlineId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - ) -> polkadot_runtime::SessionKeys { - polkadot_runtime::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - } - } - - pub fn genesis() -> Storage { - let genesis_config = polkadot_runtime::RuntimeGenesisConfig { - system: polkadot_runtime::SystemConfig { - code: polkadot_runtime::WASM_BINARY.unwrap().to_vec(), - ..Default::default() - }, - balances: polkadot_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - session: polkadot_runtime::SessionConfig { - keys: validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - polkadot::session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - }, - staking: polkadot_runtime::StakingConfig { - validator_count: validators::initial_authorities().len() as u32, - minimum_validator_count: 1, - stakers: validators::initial_authorities() - .iter() - .map(|x| { - (x.0.clone(), x.1.clone(), STASH, polkadot_runtime::StakerStatus::Validator) - }) - .collect(), - invulnerables: validators::initial_authorities() - .iter() - .map(|x| x.0.clone()) - .collect(), - force_era: pallet_staking::Forcing::ForceNone, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: polkadot_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(polkadot_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - configuration: polkadot_runtime::ConfigurationConfig { config: get_host_config() }, - paras: polkadot_runtime::ParasConfig { - paras: vec![ - ( - asset_hub_polkadot::PARA_ID.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - asset_hub_polkadot_runtime::WASM_BINARY.unwrap().to_vec(), - ), - para_kind: ParaKind::Parachain, - }, - ), - ( - penpal::PARA_ID_A.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - penpal_runtime::WASM_BINARY.unwrap().to_vec(), - ), - para_kind: ParaKind::Parachain, - }, - ), - ( - penpal::PARA_ID_B.into(), - ParaGenesisArgs { - genesis_head: HeadData::default(), - validation_code: ValidationCode( - penpal_runtime::WASM_BINARY.unwrap().to_vec(), - ), - para_kind: ParaKind::Parachain, - }, - ), - ], - ..Default::default() - }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} // Westend pub mod westend { @@ -386,13 +248,12 @@ pub mod westend { } } -// Kusama -pub mod kusama { +// Rococo +pub mod rococo { use super::*; - pub const ED: Balance = kusama_runtime_constants::currency::EXISTENTIAL_DEPOSIT; - use kusama_runtime_constants::currency::UNITS as KSM; - const ENDOWMENT: u128 = 1_000_000 * KSM; - const STASH: u128 = 100 * KSM; + pub const ED: Balance = rococo_runtime_constants::currency::EXISTENTIAL_DEPOSIT; + use rococo_runtime_constants::currency::UNITS as ROC; + const ENDOWMENT: u128 = 1_000_000 * ROC; pub fn get_host_config() -> HostConfiguration { HostConfiguration { @@ -401,8 +262,8 @@ pub mod kusama { max_upward_message_size: 51200, max_upward_message_num_per_candidate: 10, max_downward_message_size: 51200, - hrmp_sender_deposit: 5_000_000_000_000, - hrmp_recipient_deposit: 5_000_000_000_000, + hrmp_sender_deposit: 0, + hrmp_recipient_deposit: 0, hrmp_channel_max_capacity: 1000, hrmp_channel_max_message_size: 102400, hrmp_channel_max_total_size: 102400, @@ -420,8 +281,8 @@ pub mod kusama { para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, beefy: BeefyId, - ) -> kusama_runtime::SessionKeys { - kusama_runtime::SessionKeys { + ) -> rococo_runtime::SessionKeys { + rococo_runtime::SessionKeys { babe, grandpa, im_online, @@ -433,25 +294,26 @@ pub mod kusama { } pub fn genesis() -> Storage { - let genesis_config = kusama_runtime::RuntimeGenesisConfig { - system: kusama_runtime::SystemConfig { - code: kusama_runtime::WASM_BINARY.unwrap().to_vec(), + let genesis_config = rococo_runtime::RuntimeGenesisConfig { + system: rococo_runtime::SystemConfig { + code: rococo_runtime::WASM_BINARY.unwrap().to_vec(), ..Default::default() }, - balances: kusama_runtime::BalancesConfig { + balances: rococo_runtime::BalancesConfig { balances: accounts::init_balances() .iter() - .map(|k: &AccountId| (k.clone(), ENDOWMENT)) + .map(|k| (k.clone(), ENDOWMENT)) .collect(), }, - session: kusama_runtime::SessionConfig { + // indices: rococo_runtime::IndicesConfig { indices: vec![] }, + session: rococo_runtime::SessionConfig { keys: validators::initial_authorities() .iter() .map(|x| { ( x.0.clone(), x.0.clone(), - kusama::session_keys( + session_keys( x.2.clone(), x.3.clone(), x.4.clone(), @@ -464,37 +326,23 @@ pub mod kusama { }) .collect::>(), }, - staking: kusama_runtime::StakingConfig { - validator_count: validators::initial_authorities().len() as u32, - minimum_validator_count: 1, - stakers: validators::initial_authorities() - .iter() - .map(|x| { - (x.0.clone(), x.1.clone(), STASH, kusama_runtime::StakerStatus::Validator) - }) - .collect(), - invulnerables: validators::initial_authorities() - .iter() - .map(|x| x.0.clone()) - .collect(), - force_era: pallet_staking::Forcing::NotForcing, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: kusama_runtime::BabeConfig { + babe: rococo_runtime::BabeConfig { authorities: Default::default(), - epoch_config: Some(kusama_runtime::BABE_GENESIS_EPOCH_CONFIG), + epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), ..Default::default() }, - configuration: kusama_runtime::ConfigurationConfig { config: get_host_config() }, - paras: kusama_runtime::ParasConfig { + sudo: rococo_runtime::SudoConfig { + key: Some(get_account_id_from_seed::("Alice")), + }, + configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, + paras: rococo_runtime::ParasConfig { paras: vec![ ( - asset_hub_kusama::PARA_ID.into(), + asset_hub_rococo::PARA_ID.into(), ParaGenesisArgs { genesis_head: HeadData::default(), validation_code: ValidationCode( - asset_hub_kusama_runtime::WASM_BINARY.unwrap().to_vec(), + asset_hub_rococo_runtime::WASM_BINARY.unwrap().to_vec(), ), para_kind: ParaKind::Parachain, }, @@ -522,100 +370,6 @@ pub mod kusama { ], ..Default::default() }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} - -// Rococo -pub mod rococo { - use super::*; - pub const ED: Balance = rococo_runtime_constants::currency::EXISTENTIAL_DEPOSIT; - use rococo_runtime_constants::currency::UNITS as ROC; - const ENDOWMENT: u128 = 1_000_000 * ROC; - - pub fn get_host_config() -> HostConfiguration { - HostConfiguration { - max_upward_queue_count: 10, - max_upward_queue_size: 51200, - max_upward_message_size: 51200, - max_upward_message_num_per_candidate: 10, - max_downward_message_size: 51200, - hrmp_sender_deposit: 0, - hrmp_recipient_deposit: 0, - hrmp_channel_max_capacity: 1000, - hrmp_channel_max_message_size: 102400, - hrmp_channel_max_total_size: 102400, - hrmp_max_parachain_outbound_channels: 30, - hrmp_max_parachain_inbound_channels: 30, - ..Default::default() - } - } - - fn session_keys( - babe: BabeId, - grandpa: GrandpaId, - im_online: ImOnlineId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - beefy: BeefyId, - ) -> rococo_runtime::SessionKeys { - rococo_runtime::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - beefy, - } - } - - pub fn genesis() -> Storage { - let genesis_config = rococo_runtime::RuntimeGenesisConfig { - system: rococo_runtime::SystemConfig { - code: rococo_runtime::WASM_BINARY.unwrap().to_vec(), - ..Default::default() - }, - balances: rococo_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .map(|k| (k.clone(), ENDOWMENT)) - .collect(), - }, - // indices: rococo_runtime::IndicesConfig { indices: vec![] }, - session: rococo_runtime::SessionConfig { - keys: validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - get_from_seed::("Alice"), - ), - ) - }) - .collect::>(), - }, - babe: rococo_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - sudo: rococo_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), - }, - configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, registrar: rococo_runtime::RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, ..Default::default() @@ -627,33 +381,33 @@ pub mod rococo { } } -// Asset Hub Polkadot -pub mod asset_hub_polkadot { +// Asset Hub Westend +pub mod asset_hub_westend { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - let genesis_config = asset_hub_polkadot_runtime::RuntimeGenesisConfig { - system: asset_hub_polkadot_runtime::SystemConfig { - code: asset_hub_polkadot_runtime::WASM_BINARY + let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { + system: asset_hub_westend_runtime::SystemConfig { + code: asset_hub_westend_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), ..Default::default() }, - balances: asset_hub_polkadot_runtime::BalancesConfig { + balances: asset_hub_westend_runtime::BalancesConfig { balances: accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) .collect(), }, - parachain_info: asset_hub_polkadot_runtime::ParachainInfoConfig { + parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() }, - collator_selection: asset_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables_asset_hub_polkadot() + collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() .iter() .cloned() .map(|(acc, _)| acc) @@ -661,19 +415,19 @@ pub mod asset_hub_polkadot { candidacy_bond: ED * 16, ..Default::default() }, - session: asset_hub_polkadot_runtime::SessionConfig { - keys: collators::invulnerables_asset_hub_polkadot() + session: asset_hub_westend_runtime::SessionConfig { + keys: collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( - acc.clone(), // account id - acc, // validator id - asset_hub_polkadot_runtime::SessionKeys { aura }, // session keys + acc.clone(), // account id + acc, // validator id + asset_hub_westend_runtime::SessionKeys { aura }, // session keys ) }) .collect(), }, - polkadot_xcm: asset_hub_polkadot_runtime::PolkadotXcmConfig { + polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, @@ -684,32 +438,31 @@ pub mod asset_hub_polkadot { } } -// Asset Hub Westend -pub mod asset_hub_westend { +pub mod asset_hub_rococo { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { - system: asset_hub_westend_runtime::SystemConfig { - code: asset_hub_westend_runtime::WASM_BINARY + let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig { + code: asset_hub_rococo_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), ..Default::default() }, - balances: asset_hub_westend_runtime::BalancesConfig { + balances: asset_hub_rococo_runtime::BalancesConfig { balances: accounts::init_balances() .iter() .cloned() - .map(|k| (k, ED * 4096)) + .map(|k| (k, ED * 4096 * 4096)) .collect(), }, - parachain_info: asset_hub_westend_runtime::ParachainInfoConfig { + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() }, - collator_selection: asset_hub_westend_runtime::CollatorSelectionConfig { + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { invulnerables: collators::invulnerables() .iter() .cloned() @@ -718,19 +471,19 @@ pub mod asset_hub_westend { candidacy_bond: ED * 16, ..Default::default() }, - session: asset_hub_westend_runtime::SessionConfig { + session: asset_hub_rococo_runtime::SessionConfig { keys: collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( - acc.clone(), // account id - acc, // validator id - asset_hub_westend_runtime::SessionKeys { aura }, // session keys + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys ) }) .collect(), }, - polkadot_xcm: asset_hub_westend_runtime::PolkadotXcmConfig { + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, @@ -741,32 +494,31 @@ pub mod asset_hub_westend { } } -// Asset Hub Kusama -pub mod asset_hub_kusama { +pub mod asset_hub_wococo { use super::*; pub const PARA_ID: u32 = 1000; - pub const ED: Balance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; + pub const ED: Balance = parachains_common::wococo::currency::EXISTENTIAL_DEPOSIT; pub fn genesis() -> Storage { - let genesis_config = asset_hub_kusama_runtime::RuntimeGenesisConfig { - system: asset_hub_kusama_runtime::SystemConfig { - code: asset_hub_kusama_runtime::WASM_BINARY + let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig { + code: asset_hub_rococo_runtime::WASM_BINARY .expect("WASM binary was not build, please build it!") .to_vec(), ..Default::default() }, - balances: asset_hub_kusama_runtime::BalancesConfig { + balances: asset_hub_rococo_runtime::BalancesConfig { balances: accounts::init_balances() .iter() .cloned() .map(|k| (k, ED * 4096)) .collect(), }, - parachain_info: asset_hub_kusama_runtime::ParachainInfoConfig { + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() }, - collator_selection: asset_hub_kusama_runtime::CollatorSelectionConfig { + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { invulnerables: collators::invulnerables() .iter() .cloned() @@ -775,19 +527,19 @@ pub mod asset_hub_kusama { candidacy_bond: ED * 16, ..Default::default() }, - session: asset_hub_kusama_runtime::SessionConfig { + session: asset_hub_rococo_runtime::SessionConfig { keys: collators::invulnerables() .into_iter() .map(|(acc, aura)| { ( acc.clone(), // account id acc, // validator id - asset_hub_kusama_runtime::SessionKeys { aura }, // session keys + asset_hub_rococo_runtime::SessionKeys { aura }, // session keys ) }) .collect(), }, - polkadot_xcm: asset_hub_kusama_runtime::PolkadotXcmConfig { + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, @@ -859,177 +611,6 @@ pub mod penpal { } } -// Collectives -pub mod collectives { - use super::*; - pub const PARA_ID: u32 = 1001; - pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = collectives_polkadot_runtime::RuntimeGenesisConfig { - system: collectives_polkadot_runtime::SystemConfig { - code: collectives_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: collectives_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: collectives_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: collectives_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: collectives_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - collectives_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: collectives_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} - -// Bridge Hub Kusama -pub mod bridge_hub_kusama { - use super::*; - pub const PARA_ID: u32 = 1002; - pub const ED: Balance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = bridge_hub_kusama_runtime::RuntimeGenesisConfig { - system: bridge_hub_kusama_runtime::SystemConfig { - code: bridge_hub_kusama_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: bridge_hub_kusama_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: bridge_hub_kusama_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: bridge_hub_kusama_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: bridge_hub_kusama_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: bridge_hub_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} - -// Bridge Hub Polkadot -pub mod bridge_hub_polkadot { - use super::*; - pub const PARA_ID: u32 = 1002; - pub const ED: Balance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; - - pub fn genesis() -> Storage { - let genesis_config = bridge_hub_polkadot_runtime::RuntimeGenesisConfig { - system: bridge_hub_polkadot_runtime::SystemConfig { - code: bridge_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - ..Default::default() - }, - balances: bridge_hub_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096)) - .collect(), - }, - parachain_info: bridge_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: bridge_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: bridge_hub_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - }, - polkadot_xcm: bridge_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - genesis_config.build_storage().unwrap() - } -} - // Bridge Hub Rococo & Bridge Hub Wococo pub mod bridge_hub_rococo { use super::*; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index eed61d94171107a278e13b8fca8ba9a94a547f21..bb4c9d102e98a928de6d721ee6fb8f1dd7abf9f4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -54,7 +54,7 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{OriginKind, Outcome, VersionedXcm, Weight}, + prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm, Weight}, v3::Error, DoubleEncoded, }; @@ -80,21 +80,11 @@ impl From for LaneIdWrapper { type BridgeHubRococoRuntime = ::Runtime; type BridgeHubWococoRuntime = ::Runtime; -// TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged -// type BridgeHubPolkadotRuntime = ::Runtime; -// type BridgeHubKusamaRuntime = ::Runtime; - pub type RococoWococoMessageHandler = BridgeHubMessageHandler; pub type WococoRococoMessageHandler = BridgeHubMessageHandler; -// TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged -// pub type PolkadotKusamaMessageHandler -// = BridgeHubMessageHandler; -// pub type KusamaPolkadotMessageHandler -// = BridgeHubMessageHandler; - impl BridgeMessageHandler for BridgeHubMessageHandler where S: Config, @@ -356,6 +346,37 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { }; } +#[macro_export] +macro_rules! impl_send_transact_helpers_for_relay_chain { + ( $chain:ident ) => { + $crate::impls::paste::paste! { + impl $chain { + /// A root origin (as governance) sends `xcm::Transact` with `UnpaidExecution` and encoded `call` to child parachain. + pub fn send_unpaid_transact_to_parachain_as_root( + recipient: $crate::impls::ParaId, + call: $crate::impls::DoubleEncoded<()> + ) { + use $crate::impls::{bx, Chain, RelayChain}; + + ::execute_with(|| { + let root_origin = ::RuntimeOrigin::root(); + let destination: $crate::impls::MultiLocation = ::child_location_of(recipient); + let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser); + + // Send XCM `Transact` + $crate::impls::assert_ok!(]>::XcmPallet::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + Self::assert_xcm_pallet_sent(); + }); + } + } + } + }; +} + #[macro_export] macro_rules! impl_accounts_helpers_for_parachain { ( $chain:ident ) => { @@ -503,6 +524,22 @@ macro_rules! impl_assert_events_helpers_for_parachain { ); } + /// Asserts a XCM from Relay Chain is executed with error + pub fn assert_dmp_queue_error( + expected_error: $crate::impls::Error, + ) { + $crate::impls::assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::DmpQueue($crate::impls::cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: $crate::impls::Outcome::Error(error), .. + }) => { + error: *error == expected_error, + }, + ] + ); + } + /// Asserts a XCM from another Parachain is completely executed pub fn assert_xcmp_queue_success(expected_weight: Option<$crate::impls::Weight>) { $crate::impls::assert_expected_events!( @@ -600,53 +637,58 @@ macro_rules! impl_assets_helpers_for_parachain { min_balance: u128, is_sufficient: bool, asset_owner: $crate::impls::AccountId, + dmp_weight_threshold: Option<$crate::impls::Weight>, amount_to_mint: u128, ) { - use $crate::impls::{bx, Chain, RelayChain, Parachain, Inspect, TestExt}; - // Init values for Relay Chain - let root_origin = <$relay_chain as Chain>::RuntimeOrigin::root(); - let destination = <$relay_chain>::child_location_of(<$chain>::para_id()); - let xcm = Self::force_create_asset_xcm( - $crate::impls::OriginKind::Superuser, + use $crate::impls::Chain; + + // Force create asset + Self::force_create_asset_from_relay_as_root( id, - asset_owner.clone(), - is_sufficient, min_balance, + is_sufficient, + asset_owner.clone(), + dmp_weight_threshold ); - <$relay_chain>::execute_with(|| { - $crate::impls::assert_ok!(<$relay_chain as [<$relay_chain Pallet>]>::XcmPallet::send( - root_origin, - bx!(destination.into()), - bx!(xcm), - )); + // Mint asset for System Parachain's sender + let signed_origin = ::RuntimeOrigin::signed(asset_owner.clone()); + Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint); + } - <$relay_chain>::assert_xcm_pallet_sent(); - }); + /// Relay Chain sends `Transact` instruction with `force_create_asset` to Parachain with `Assets` instance of `pallet_assets` . + pub fn force_create_asset_from_relay_as_root( + id: u32, + min_balance: u128, + is_sufficient: bool, + asset_owner: $crate::impls::AccountId, + dmp_weight_threshold: Option<$crate::impls::Weight>, + ) { + use $crate::impls::{Parachain, Inspect, TestExt}; - Self::execute_with(|| { - Self::assert_dmp_queue_complete(Some($crate::impls::Weight::from_parts(1_019_445_000, 200_000))); + <$relay_chain>::send_unpaid_transact_to_parachain_as_root( + Self::para_id(), + Self::force_create_asset_call(id, asset_owner.clone(), is_sufficient, min_balance), + ); + // Receive XCM message in Assets Parachain + Self::execute_with(|| { type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + Self::assert_dmp_queue_complete(dmp_weight_threshold); + $crate::impls::assert_expected_events!( Self, vec![ - // Asset has been created RuntimeEvent::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => { asset_id: *asset_id == id, - owner: *owner == asset_owner.clone(), + owner: *owner == asset_owner, }, ] ); assert!(]>::Assets::asset_exists(id.into())); }); - - let signed_origin = ::RuntimeOrigin::signed(asset_owner.clone()); - - // Mint asset for System Parachain's sender - Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint); } } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 7461165f2a198e8f8b871850545bf50f6e37e885..8a8081c9fac388c810d43f45ccbfb67a73334f0b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -15,56 +15,35 @@ pub mod constants; pub mod impls; +pub mod macros; pub mod xcm_helpers; use constants::{ accounts::{ALICE, BOB}, - asset_hub_kusama, asset_hub_polkadot, asset_hub_westend, bridge_hub_kusama, - bridge_hub_polkadot, bridge_hub_rococo, collectives, kusama, penpal, polkadot, rococo, westend, + asset_hub_rococo, asset_hub_westend, asset_hub_wococo, bridge_hub_rococo, penpal, rococo, + westend, }; use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; +pub use paste; // Substrate use frame_support::traits::OnInitialize; +pub use pallet_balances; // Cumulus +pub use cumulus_pallet_xcmp_queue; +pub use xcm_emulator::Chain; use xcm_emulator::{ decl_test_bridges, decl_test_networks, decl_test_parachains, decl_test_relay_chains, decl_test_sender_receiver_accounts_parameter_types, DefaultMessageProcessor, }; +// Polkadot +pub use pallet_xcm; +pub use xcm::prelude::{AccountId32, WeightLimit}; + decl_test_relay_chains! { - #[api_version(5)] - pub struct Polkadot { - genesis = polkadot::genesis(), - on_init = (), - runtime = polkadot_runtime, - core = { - MessageProcessor: DefaultMessageProcessor, - SovereignAccountOf: polkadot_runtime::xcm_config::SovereignAccountOf, - }, - pallets = { - XcmPallet: polkadot_runtime::XcmPallet, - Balances: polkadot_runtime::Balances, - Hrmp: polkadot_runtime::Hrmp, - } - }, - #[api_version(5)] - pub struct Kusama { - genesis = kusama::genesis(), - on_init = (), - runtime = kusama_runtime, - core = { - MessageProcessor: DefaultMessageProcessor, - SovereignAccountOf: kusama_runtime::xcm_config::SovereignAccountOf, - }, - pallets = { - XcmPallet: kusama_runtime::XcmPallet, - Balances: kusama_runtime::Balances, - Hrmp: kusama_runtime::Hrmp, - } - }, - #[api_version(6)] + #[api_version(8)] pub struct Westend { genesis = westend::genesis(), on_init = (), @@ -77,9 +56,11 @@ decl_test_relay_chains! { XcmPallet: westend_runtime::XcmPallet, Sudo: westend_runtime::Sudo, Balances: westend_runtime::Balances, + Treasury: westend_runtime::Treasury, + AssetRate: westend_runtime::AssetRate, } }, - #[api_version(5)] + #[api_version(8)] pub struct Rococo { genesis = rococo::genesis(), on_init = (), @@ -92,9 +73,10 @@ decl_test_relay_chains! { XcmPallet: rococo_runtime::XcmPallet, Sudo: rococo_runtime::Sudo, Balances: rococo_runtime::Balances, + Hrmp: rococo_runtime::Hrmp, } }, - #[api_version(5)] + #[api_version(8)] pub struct Wococo { genesis = rococo::genesis(), on_init = (), @@ -112,59 +94,29 @@ decl_test_relay_chains! { } decl_test_parachains! { - // Polkadot Parachains - pub struct AssetHubPolkadot { - genesis = asset_hub_polkadot::genesis(), - on_init = { - asset_hub_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_polkadot_runtime, - core = { - XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_polkadot_runtime::DmpQueue, - LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, - Assets: asset_hub_polkadot_runtime::Assets, - Balances: asset_hub_polkadot_runtime::Balances, - } - }, - pub struct Collectives { - genesis = collectives::genesis(), - on_init = { - collectives_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = collectives_polkadot_runtime, - core = { - XcmpMessageHandler: collectives_polkadot_runtime::XcmpQueue, - DmpMessageHandler: collectives_polkadot_runtime::DmpQueue, - LocationToAccountId: collectives_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: collectives_polkadot_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: collectives_polkadot_runtime::PolkadotXcm, - Balances: collectives_polkadot_runtime::Balances, - } - }, - pub struct BridgeHubPolkadot { - genesis = bridge_hub_polkadot::genesis(), + // Westend Parachains + pub struct AssetHubWestend { + genesis = asset_hub_westend::genesis(), on_init = { - bridge_hub_polkadot_runtime::AuraExt::on_initialize(1); + asset_hub_westend_runtime::AuraExt::on_initialize(1); }, - runtime = bridge_hub_polkadot_runtime, + runtime = asset_hub_westend_runtime, core = { - XcmpMessageHandler: bridge_hub_polkadot_runtime::XcmpQueue, - DmpMessageHandler: bridge_hub_polkadot_runtime::DmpQueue, - LocationToAccountId: bridge_hub_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_polkadot_runtime::ParachainInfo, + XcmpMessageHandler: asset_hub_westend_runtime::XcmpQueue, + DmpMessageHandler: asset_hub_westend_runtime::DmpQueue, + LocationToAccountId: asset_hub_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_westend_runtime::ParachainInfo, }, pallets = { - PolkadotXcm: bridge_hub_polkadot_runtime::PolkadotXcm, + PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm, + Balances: asset_hub_westend_runtime::Balances, + Assets: asset_hub_westend_runtime::Assets, + ForeignAssets: asset_hub_westend_runtime::ForeignAssets, + PoolAssets: asset_hub_westend_runtime::PoolAssets, + AssetConversion: asset_hub_westend_runtime::AssetConversion, } }, - pub struct PenpalPolkadotA { + pub struct PenpalWestendA { genesis = penpal::genesis(penpal::PARA_ID_A), on_init = { penpal_runtime::AuraExt::on_initialize(1); @@ -179,64 +131,50 @@ decl_test_parachains! { pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, + Balances: penpal_runtime::Balances, } }, - pub struct PenpalPolkadotB { - genesis = penpal::genesis(penpal::PARA_ID_B), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - } - }, - // Kusama Parachains - pub struct AssetHubKusama { - genesis = asset_hub_kusama::genesis(), + // Rococo Parachains + pub struct BridgeHubRococo { + genesis = bridge_hub_rococo::genesis(), on_init = { - asset_hub_kusama_runtime::AuraExt::on_initialize(1); + bridge_hub_rococo_runtime::AuraExt::on_initialize(1); }, - runtime = asset_hub_kusama_runtime, + runtime = bridge_hub_rococo_runtime, core = { - XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_kusama_runtime::DmpQueue, - LocationToAccountId: asset_hub_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_kusama_runtime::ParachainInfo, + XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, + DmpMessageHandler: bridge_hub_rococo_runtime::DmpQueue, + LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, }, pallets = { - PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, - Assets: asset_hub_kusama_runtime::Assets, - ForeignAssets: asset_hub_kusama_runtime::ForeignAssets, - PoolAssets: asset_hub_kusama_runtime::PoolAssets, - AssetConversion: asset_hub_kusama_runtime::AssetConversion, - Balances: asset_hub_kusama_runtime::Balances, + PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, + Balances: bridge_hub_rococo_runtime::Balances, } }, - pub struct BridgeHubKusama { - genesis = bridge_hub_kusama::genesis(), + // AssetHubRococo + pub struct AssetHubRococo { + genesis = asset_hub_rococo::genesis(), on_init = { - bridge_hub_kusama_runtime::AuraExt::on_initialize(1); + asset_hub_rococo_runtime::AuraExt::on_initialize(1); }, - runtime = bridge_hub_kusama_runtime, + runtime = asset_hub_rococo_runtime, core = { - XcmpMessageHandler: bridge_hub_kusama_runtime::XcmpQueue, - DmpMessageHandler: bridge_hub_kusama_runtime::DmpQueue, - LocationToAccountId: bridge_hub_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_kusama_runtime::ParachainInfo, + XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, + DmpMessageHandler: asset_hub_rococo_runtime::DmpQueue, + LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, }, pallets = { - PolkadotXcm: bridge_hub_kusama_runtime::PolkadotXcm, + PolkadotXcm: asset_hub_rococo_runtime::PolkadotXcm, + Assets: asset_hub_rococo_runtime::Assets, + ForeignAssets: asset_hub_rococo_runtime::ForeignAssets, + PoolAssets: asset_hub_rococo_runtime::PoolAssets, + AssetConversion: asset_hub_rococo_runtime::AssetConversion, + Balances: asset_hub_rococo_runtime::Balances, } }, - pub struct PenpalKusamaA { + pub struct PenpalRococoA { genesis = penpal::genesis(penpal::PARA_ID_A), on_init = { penpal_runtime::AuraExt::on_initialize(1); @@ -253,7 +191,7 @@ decl_test_parachains! { Assets: penpal_runtime::Assets, } }, - pub struct PenpalKusamaB { + pub struct PenpalRococoB { genesis = penpal::genesis(penpal::PARA_ID_B), on_init = { penpal_runtime::AuraExt::on_initialize(1); @@ -270,86 +208,12 @@ decl_test_parachains! { Assets: penpal_runtime::Assets, } }, - // Westend Parachains - pub struct AssetHubWestend { - genesis = asset_hub_westend::genesis(), - on_init = { - asset_hub_westend_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_westend_runtime, - core = { - XcmpMessageHandler: asset_hub_westend_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_westend_runtime::DmpQueue, - LocationToAccountId: asset_hub_westend_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_westend_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm, - Balances: asset_hub_westend_runtime::Balances, - Assets: asset_hub_westend_runtime::Assets, - ForeignAssets: asset_hub_westend_runtime::ForeignAssets, - PoolAssets: asset_hub_westend_runtime::PoolAssets, - AssetConversion: asset_hub_westend_runtime::AssetConversion, - } - }, - pub struct PenpalWestendA { - genesis = penpal::genesis(penpal::PARA_ID_A), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - } - }, - // Rococo Parachains - pub struct BridgeHubRococo { - genesis = bridge_hub_rococo::genesis(), - on_init = { - bridge_hub_rococo_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_rococo_runtime, - core = { - XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, - DmpMessageHandler: bridge_hub_rococo_runtime::DmpQueue, - LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, - Balances: bridge_hub_rococo_runtime::Balances, - } - }, - // AssetHubRococo (aka Rockmine/Rockmine2) mirrors AssetHubKusama - pub struct AssetHubRococo { - genesis = asset_hub_kusama::genesis(), - on_init = { - asset_hub_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_kusama_runtime, - core = { - XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_kusama_runtime::DmpQueue, - LocationToAccountId: asset_hub_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_kusama_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, - Assets: asset_hub_kusama_runtime::Assets, - } - }, // Wococo Parachains pub struct BridgeHubWococo { genesis = bridge_hub_rococo::genesis(), on_init = { bridge_hub_rococo_runtime::AuraExt::on_initialize(1); + // TODO: manage to set_wococo_flavor with `set_storage` }, runtime = bridge_hub_rococo_runtime, core = { @@ -363,67 +227,30 @@ decl_test_parachains! { } }, pub struct AssetHubWococo { - genesis = asset_hub_polkadot::genesis(), + genesis = asset_hub_wococo::genesis(), on_init = { - asset_hub_polkadot_runtime::AuraExt::on_initialize(1); + asset_hub_rococo_runtime::AuraExt::on_initialize(1); + // TODO: manage to set_wococo_flavor with `set_storage` }, - runtime = asset_hub_polkadot_runtime, - core = { - XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_polkadot_runtime::DmpQueue, - LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, - }, - pallets = { - PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, - Assets: asset_hub_polkadot_runtime::Assets, - } - }, - pub struct PenpalRococoA { - genesis = penpal::genesis(penpal::PARA_ID_A), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - }, - runtime = penpal_runtime, + runtime = asset_hub_rococo_runtime, core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - DmpMessageHandler: penpal_runtime::DmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, + XcmpMessageHandler: asset_hub_rococo_runtime::XcmpQueue, + DmpMessageHandler: asset_hub_rococo_runtime::DmpQueue, + LocationToAccountId: asset_hub_rococo_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, }, pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, + PolkadotXcm: asset_hub_rococo_runtime::PolkadotXcm, + Assets: asset_hub_rococo_runtime::Assets, + ForeignAssets: asset_hub_rococo_runtime::ForeignAssets, + PoolAssets: asset_hub_rococo_runtime::PoolAssets, + AssetConversion: asset_hub_rococo_runtime::AssetConversion, + Balances: asset_hub_rococo_runtime::Balances, } } } decl_test_networks! { - pub struct PolkadotMockNet { - relay_chain = Polkadot, - parachains = vec![ - AssetHubPolkadot, - Collectives, - BridgeHubPolkadot, - PenpalPolkadotA, - PenpalPolkadotB, - ], - // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged - // bridge = PolkadotKusamaMockBridge - bridge = () - }, - pub struct KusamaMockNet { - relay_chain = Kusama, - parachains = vec![ - AssetHubKusama, - PenpalKusamaA, - BridgeHubKusama, - PenpalKusamaB, - ], - // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged - // bridge = KusamaPolkadotMockBridge - bridge = () - }, pub struct WestendMockNet { relay_chain = Westend, parachains = vec![ @@ -438,6 +265,7 @@ decl_test_networks! { AssetHubRococo, BridgeHubRococo, PenpalRococoA, + PenpalRococoB, ], bridge = RococoWococoMockBridge }, @@ -462,100 +290,59 @@ decl_test_bridges! { target = BridgeHubRococo, handler = WococoRococoMessageHandler } - // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged - // pub struct PolkadotKusamaMockBridge { - // source = BridgeHubPolkadot, - // target = BridgeHubKusama, - // handler = PolkadotKusamaMessageHandler - // }, - // pub struct KusamaPolkadotMockBridge { - // source = BridgeHubKusama, - // target = BridgeHubPolkadot, - // handler = KusamaPolkadotMessageHandler - // } } -// Polkadot implementation -impl_accounts_helpers_for_relay_chain!(Polkadot); -impl_assert_events_helpers_for_relay_chain!(Polkadot); -impl_hrmp_channels_helpers_for_relay_chain!(Polkadot); - -// Kusama implementation -impl_accounts_helpers_for_relay_chain!(Kusama); -impl_assert_events_helpers_for_relay_chain!(Kusama); -impl_hrmp_channels_helpers_for_relay_chain!(Kusama); - // Westend implementation impl_accounts_helpers_for_relay_chain!(Westend); impl_assert_events_helpers_for_relay_chain!(Westend); +impl_send_transact_helpers_for_relay_chain!(Westend); // Rococo implementation impl_accounts_helpers_for_relay_chain!(Rococo); impl_assert_events_helpers_for_relay_chain!(Rococo); +impl_hrmp_channels_helpers_for_relay_chain!(Rococo); +impl_send_transact_helpers_for_relay_chain!(Rococo); // Wococo implementation impl_accounts_helpers_for_relay_chain!(Wococo); impl_assert_events_helpers_for_relay_chain!(Wococo); - -// AssetHubPolkadot implementation -impl_accounts_helpers_for_parachain!(AssetHubPolkadot); -impl_assets_helpers_for_parachain!(AssetHubPolkadot, Polkadot); -impl_assert_events_helpers_for_parachain!(AssetHubPolkadot); - -// AssetHubKusama implementation -impl_accounts_helpers_for_parachain!(AssetHubKusama); -impl_assets_helpers_for_parachain!(AssetHubKusama, Kusama); -impl_assert_events_helpers_for_parachain!(AssetHubKusama); +impl_send_transact_helpers_for_relay_chain!(Wococo); // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); -// PenpalPolkadot implementations -impl_assert_events_helpers_for_parachain!(PenpalPolkadotA); -impl_assert_events_helpers_for_parachain!(PenpalPolkadotB); - -// PenpalKusama implementations -impl_assert_events_helpers_for_parachain!(PenpalKusamaA); -impl_assert_events_helpers_for_parachain!(PenpalKusamaB); +// AssetHubRococo implementation +impl_accounts_helpers_for_parachain!(AssetHubRococo); +impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_assert_events_helpers_for_parachain!(AssetHubRococo); // PenpalWestendA implementation impl_assert_events_helpers_for_parachain!(PenpalWestendA); -// Collectives implementation -impl_accounts_helpers_for_parachain!(Collectives); -impl_assert_events_helpers_for_parachain!(Collectives); - // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +// PenpalRococo implementations +impl_assert_events_helpers_for_parachain!(PenpalRococoA); +impl_assert_events_helpers_for_parachain!(PenpalRococoB); + decl_test_sender_receiver_accounts_parameter_types! { // Relays - Polkadot { sender: ALICE, receiver: BOB }, - Kusama { sender: ALICE, receiver: BOB }, Westend { sender: ALICE, receiver: BOB }, Rococo { sender: ALICE, receiver: BOB }, Wococo { sender: ALICE, receiver: BOB }, // Asset Hubs - AssetHubPolkadot { sender: ALICE, receiver: BOB }, - AssetHubKusama { sender: ALICE, receiver: BOB }, AssetHubWestend { sender: ALICE, receiver: BOB }, AssetHubRococo { sender: ALICE, receiver: BOB }, AssetHubWococo { sender: ALICE, receiver: BOB }, - // Collectives - Collectives { sender: ALICE, receiver: BOB }, // Bridged Hubs - BridgeHubPolkadot { sender: ALICE, receiver: BOB }, - BridgeHubKusama { sender: ALICE, receiver: BOB }, BridgeHubRococo { sender: ALICE, receiver: BOB }, BridgeHubWococo { sender: ALICE, receiver: BOB }, // Penpals - PenpalPolkadotA { sender: ALICE, receiver: BOB }, - PenpalPolkadotB { sender: ALICE, receiver: BOB }, - PenpalKusamaA { sender: ALICE, receiver: BOB }, - PenpalKusamaB { sender: ALICE, receiver: BOB }, PenpalWestendA { sender: ALICE, receiver: BOB }, - PenpalRococoA { sender: ALICE, receiver: BOB } + PenpalRococoA { sender: ALICE, receiver: BOB }, + PenpalRococoB { sender: ALICE, receiver: BOB } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs new file mode 100644 index 0000000000000000000000000000000000000000..e87c361ebeacc611fee2861598dc1713b6ddc05d --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -0,0 +1,102 @@ +// 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. + +#[macro_export] +macro_rules! test_parachain_is_trusted_teleporter { + ( $sender_para:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { + $crate::paste::paste! { + // init Origin variables + let sender = [<$sender_para Sender>]::get(); + let mut para_sender_balance_before = + <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; + let origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); + let fee_asset_item = 0; + let weight_limit = $crate::WeightLimit::Unlimited; + + $( + { + // init Destination variables + let receiver = [<$receiver_para Receiver>]::get(); + let para_receiver_balance_before = + <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; + let para_destination = + <$sender_para>::sibling_location_of(<$receiver_para>::para_id()).into(); + let beneficiary = + $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); + + // Send XCM message from Origin Parachain + // We are only testing the limited teleport version, which should be ok since success will + // depend only on a proper `XcmConfig` at destination. + <$sender_para>::execute_with(|| { + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets( + origin.clone(), + bx!(para_destination), + bx!(beneficiary), + bx!($assets.clone()), + fee_asset_item, + weight_limit.clone(), + )); + + type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; + + assert_expected_events!( + $sender_para, + vec![ + RuntimeEvent::PolkadotXcm( + $crate::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } + ) => {}, + RuntimeEvent::XcmpQueue( + $crate::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + RuntimeEvent::Balances( + $crate::pallet_balances::Event::Withdraw { who: sender, amount } + ) => {}, + ] + ); + }); + + // Receive XCM message in Destination Parachain + <$receiver_para>::execute_with(|| { + type RuntimeEvent = <$receiver_para as $crate::Chain>::RuntimeEvent; + + assert_expected_events!( + $receiver_para, + vec![ + RuntimeEvent::Balances( + $crate::pallet_balances::Event::Deposit { who: receiver, .. } + ) => {}, + RuntimeEvent::XcmpQueue( + $crate::cumulus_pallet_xcmp_queue::Event::Success { .. } + ) => {}, + ] + ); + }); + + // Check if balances are updated accordingly in Origin and Destination Parachains + let para_sender_balance_after = + <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; + let para_receiver_balance_after = + <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; + + assert_eq!(para_sender_balance_before - $amount, para_sender_balance_after); + assert!(para_receiver_balance_after > para_receiver_balance_before); + + // Update sender balance + para_sender_balance_before = <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; + } + )+ + } + }; +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index 4096cdbba0b9154beb9f90272a459087b2443498..7c218bfbc092f319a115090a504808bcf28c1bea 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -1,18 +1,17 @@ -// Copyright Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 -// 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 . +// 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 parachains_common::AccountId; use xcm::{ diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..1c831ac7268a54533acf38188b3dcf73edcec6c1 --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "pallet-collective-content" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +description = "Managed content" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } + +frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", optional = true, default-features = false } +frame-support = { path = "../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../substrate/frame/system", default-features = false } + +sp-core = { path = "../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../../substrate/primitives/std", default-features = false } + +[dev-dependencies] +sp-io = { path = "../../../../substrate/primitives/io", default-features = false } + +[features] +default = [ "std" ] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] + +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/cumulus/parachains/pallets/collective-content/src/benchmarking.rs b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f145f725b139b4e93481a9c69b0715471f7ec0b --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs @@ -0,0 +1,88 @@ +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The pallet benchmarks. + +use super::{Pallet as CollectiveContent, *}; +use frame_benchmarking::{impl_benchmark_test_suite, v2::*}; +use frame_support::traits::EnsureOrigin; + +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +/// returns CID hash of 68 bytes of given `i`. +fn create_cid(i: u8) -> OpaqueCid { + let cid: OpaqueCid = [i; 68].to_vec().try_into().unwrap(); + cid +} + +#[instance_benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn set_charter() -> Result<(), BenchmarkError> { + let cid: OpaqueCid = create_cid(1); + let origin = + T::CharterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, cid.clone()); + + assert_eq!(Charter::::get(), Some(cid.clone())); + assert_last_event::(Event::NewCharterSet { cid }.into()); + Ok(()) + } + + #[benchmark] + fn announce() -> Result<(), BenchmarkError> { + let expire_at = DispatchTime::<_>::At(10u32.into()); + let now = frame_system::Pallet::::block_number(); + let cid: OpaqueCid = create_cid(1); + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, cid.clone(), Some(expire_at.clone())); + + assert_eq!(>::count(), 1); + assert_last_event::( + Event::AnnouncementAnnounced { cid, expire_at: expire_at.evaluate(now) }.into(), + ); + + Ok(()) + } + + #[benchmark] + fn remove_announcement() -> Result<(), BenchmarkError> { + let cid: OpaqueCid = create_cid(1); + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + CollectiveContent::::announce(origin.clone(), cid.clone(), None) + .expect("could not publish an announcement"); + assert_eq!(>::count(), 1); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, cid.clone()); + + assert_eq!(>::count(), 0); + assert_last_event::(Event::AnnouncementRemoved { cid }.into()); + + Ok(()) + } + + impl_benchmark_test_suite!(CollectiveContent, super::mock::new_bench_ext(), super::mock::Test); +} diff --git a/cumulus/parachains/pallets/collective-content/src/lib.rs b/cumulus/parachains/pallets/collective-content/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a685858accb67868837e734ba9808741a4f7ea1 --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/src/lib.rs @@ -0,0 +1,206 @@ +// Copyright (C) 2023 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. + +//! Managed Collective Content Pallet +//! +//! The pallet provides the functionality to store different types of content. This would typically +//! be used by an on-chain collective, such as the Polkadot Alliance or Ambassador Program. +//! +//! The pallet stores content as an [OpaqueCid], which should correspond to some off-chain hosting +//! service, such as IPFS, and contain any type of data. Each type of content has its own origin +//! from which it can be managed. The origins are configurable in the runtime. Storing content does +//! not require a deposit, as it is expected to be managed by a trusted collective. +//! +//! Content types: +//! +//! - Collective [charter](pallet::Charter): A single document (`OpaqueCid`) managed by +//! [CharterOrigin](pallet::Config::CharterOrigin). +//! - Collective [announcements](pallet::Announcements): A list of announcements managed by +//! [AnnouncementOrigin](pallet::Config::AnnouncementOrigin). + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +use frame_support::{traits::schedule::DispatchTime, BoundedVec}; +use sp_core::ConstU32; +use sp_std::prelude::*; + +/// IPFS compatible CID. +// Worst case 2 bytes base and codec, 2 bytes hash type and size, 64 bytes hash digest. +pub type OpaqueCid = BoundedVec>; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{ensure, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use sp_runtime::{traits::BadOrigin, Saturating}; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); + + /// The module configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// Default lifetime for an announcement before it expires. + type AnnouncementLifetime: Get>; + + /// The origin to control the collective announcements. + type AnnouncementOrigin: EnsureOrigin; + + /// Maximum number of announcements in the storage. + #[pallet::constant] + type MaxAnnouncements: Get; + + /// The origin to control the collective charter. + type CharterOrigin: EnsureOrigin; + + /// Weight information needed for the pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// The announcement is not found. + MissingAnnouncement, + /// Number of announcements exceeds `MaxAnnouncementsCount`. + TooManyAnnouncements, + /// Cannot expire in the past. + InvalidExpiration, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A new charter has been set. + NewCharterSet { cid: OpaqueCid }, + /// A new announcement has been made. + AnnouncementAnnounced { cid: OpaqueCid, expire_at: BlockNumberFor }, + /// An on-chain announcement has been removed. + AnnouncementRemoved { cid: OpaqueCid }, + } + + /// The collective charter. + #[pallet::storage] + pub type Charter, I: 'static = ()> = StorageValue<_, OpaqueCid, OptionQuery>; + + /// The collective announcements. + #[pallet::storage] + pub type Announcements, I: 'static = ()> = + CountedStorageMap<_, Blake2_128Concat, OpaqueCid, BlockNumberFor, OptionQuery>; + + #[pallet::call] + impl, I: 'static> Pallet { + /// Set the collective charter. + /// + /// Parameters: + /// - `origin`: Must be the [Config::CharterOrigin]. + /// - `cid`: [CID](super::OpaqueCid) of the IPFS document of the collective charter. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::set_charter())] + pub fn set_charter(origin: OriginFor, cid: OpaqueCid) -> DispatchResult { + T::CharterOrigin::ensure_origin(origin)?; + + Charter::::put(&cid); + + Self::deposit_event(Event::::NewCharterSet { cid }); + Ok(()) + } + + /// Publish an announcement. + /// + /// Parameters: + /// - `origin`: Must be the [Config::AnnouncementOrigin]. + /// - `cid`: [CID](super::OpaqueCid) of the IPFS document to announce. + /// - `maybe_expire`: Expiration block of the announcement. If `None` + /// [`Config::AnnouncementLifetime`] + /// used as a default. + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::announce())] + pub fn announce( + origin: OriginFor, + cid: OpaqueCid, + maybe_expire: Option>>, + ) -> DispatchResult { + T::AnnouncementOrigin::ensure_origin(origin)?; + + let now = frame_system::Pallet::::block_number(); + let expire_at = maybe_expire + .map_or(now.saturating_add(T::AnnouncementLifetime::get()), |e| e.evaluate(now)); + ensure!(expire_at > now, Error::::InvalidExpiration); + ensure!( + T::MaxAnnouncements::get() > >::count(), + Error::::TooManyAnnouncements + ); + + >::insert(cid.clone(), expire_at); + + Self::deposit_event(Event::::AnnouncementAnnounced { cid, expire_at }); + Ok(()) + } + + /// Remove an announcement. + /// + /// Transaction fee refunded for expired announcements. + /// + /// Parameters: + /// - `origin`: Must be the [Config::AnnouncementOrigin] or signed for expired + /// announcements. + /// - `cid`: [CID](super::OpaqueCid) of the IPFS document to remove. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::remove_announcement())] + pub fn remove_announcement( + origin: OriginFor, + cid: OpaqueCid, + ) -> DispatchResultWithPostInfo { + let maybe_who = match T::AnnouncementOrigin::try_origin(origin) { + Ok(_) => None, + Err(origin) => Some(ensure_signed(origin)?), + }; + let expire_at = >::get(cid.clone()) + .ok_or(Error::::MissingAnnouncement)?; + let now = frame_system::Pallet::::block_number(); + ensure!(maybe_who.is_none() || now >= expire_at, BadOrigin); + + >::remove(cid.clone()); + + Self::deposit_event(Event::::AnnouncementRemoved { cid }); + + if now >= expire_at { + return Ok(Pays::No.into()) + } + Ok(Pays::Yes.into()) + } + } +} diff --git a/cumulus/parachains/pallets/collective-content/src/mock.rs b/cumulus/parachains/pallets/collective-content/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..2ae5943f332acf61b60792563b7d3f9b1e808c70 --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/src/mock.rs @@ -0,0 +1,107 @@ +// Copyright (C) 2023 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 utilities. + +pub use crate as pallet_collective_content; +use crate::WeightInfo; +use frame_support::{ + ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64}, + weights::Weight, +}; +use frame_system::EnsureSignedBy; +use sp_runtime::{traits::IdentityLookup, BuildStorage}; + +frame_support::construct_runtime!( + pub enum Test { + System: frame_system, + CollectiveContent: pallet_collective_content, + } +); + +type AccountId = u64; +type Block = frame_system::mocking::MockBlock; + +ord_parameter_types! { + pub const CharterManager: u64 = 1; + pub const AnnouncementManager: u64 = 2; + pub const SomeAccount: u64 = 3; +} + +parameter_types! { + pub const AnnouncementLifetime: u64 = 100; + pub const MaxAnnouncements: u32 = 5; +} + +impl pallet_collective_content::Config for Test { + type RuntimeEvent = RuntimeEvent; + type AnnouncementLifetime = AnnouncementLifetime; + type AnnouncementOrigin = EnsureSignedBy; + type MaxAnnouncements = MaxAnnouncements; + type CharterOrigin = EnsureSignedBy; + type WeightInfo = CCWeightInfo; +} + +impl frame_system::Config for Test { + type BaseCallFilter = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Block = Block; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} +pub struct CCWeightInfo; +impl WeightInfo for CCWeightInfo { + fn set_charter() -> Weight { + Weight::zero() + } + fn announce() -> Weight { + Weight::zero() + } + fn remove_announcement() -> Weight { + Weight::zero() + } +} + +// Build test environment. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = RuntimeGenesisConfig::default().build_storage().unwrap().into(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_bench_ext() -> sp_io::TestExternalities { + RuntimeGenesisConfig::default().build_storage().unwrap().into() +} diff --git a/cumulus/parachains/pallets/collective-content/src/tests.rs b/cumulus/parachains/pallets/collective-content/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..4910b30b89af84430a60e2eab011ed2c5c6a3d03 --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/src/tests.rs @@ -0,0 +1,204 @@ +// Copyright (C) 2023 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. + +use super::{mock::*, *}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin, pallet_prelude::Pays}; + +/// returns CID hash of 68 bytes of given `i`. +fn create_cid(i: u8) -> OpaqueCid { + let cid: OpaqueCid = [i; 68].to_vec().try_into().unwrap(); + cid +} + +#[test] +fn set_charter_works() { + new_test_ext().execute_with(|| { + // wrong origin. + let origin = RuntimeOrigin::signed(SomeAccount::get()); + let cid = create_cid(1); + assert_noop!(CollectiveContent::set_charter(origin, cid), BadOrigin); + + // success. + let origin = RuntimeOrigin::signed(CharterManager::get()); + let cid = create_cid(2); + + assert_ok!(CollectiveContent::set_charter(origin, cid.clone())); + assert_eq!(Charter::::get(), Some(cid.clone())); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::NewCharterSet { cid })); + + // reset. success. + let origin = RuntimeOrigin::signed(CharterManager::get()); + let cid = create_cid(3); + + assert_ok!(CollectiveContent::set_charter(origin, cid.clone())); + assert_eq!(Charter::::get(), Some(cid.clone())); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::NewCharterSet { cid })); + }); +} + +#[test] +fn announce_works() { + new_test_ext().execute_with(|| { + let now = frame_system::Pallet::::block_number(); + // wrong origin. + let origin = RuntimeOrigin::signed(SomeAccount::get()); + let cid = create_cid(1); + + assert_noop!(CollectiveContent::announce(origin, cid, None), BadOrigin); + + // success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(2); + let maybe_expire_at = None; + + assert_ok!(CollectiveContent::announce(origin, cid.clone(), maybe_expire_at)); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementAnnounced { + cid, + expire_at: now.saturating_add(AnnouncementLifetime::get()), + })); + + // one more. success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(3); + let maybe_expire_at = None; + + assert_ok!(CollectiveContent::announce(origin, cid.clone(), maybe_expire_at)); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementAnnounced { + cid, + expire_at: now.saturating_add(AnnouncementLifetime::get()), + })); + + // one more with expire. success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(4); + let maybe_expire_at = DispatchTime::<_>::After(10); + + assert_ok!(CollectiveContent::announce(origin, cid.clone(), Some(maybe_expire_at))); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementAnnounced { + cid, + expire_at: maybe_expire_at.evaluate(now), + })); + + // one more with later expire. success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(5); + let maybe_expire_at = DispatchTime::<_>::At(now + 20); + + assert_ok!(CollectiveContent::announce(origin, cid.clone(), Some(maybe_expire_at))); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementAnnounced { + cid, + expire_at: maybe_expire_at.evaluate(now), + })); + + // one more with earlier expire. success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(6); + let maybe_expire_at = DispatchTime::<_>::At(now + 5); + + assert_ok!(CollectiveContent::announce(origin, cid.clone(), Some(maybe_expire_at))); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementAnnounced { + cid, + expire_at: maybe_expire_at.evaluate(now), + })); + + // one more with earlier expire. success. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(7); + let maybe_expire_at = DispatchTime::<_>::At(now + 5); + + assert_eq!(>::count(), MaxAnnouncements::get()); + assert_noop!( + CollectiveContent::announce(origin, cid.clone(), Some(maybe_expire_at)), + Error::::TooManyAnnouncements + ); + }); +} + +#[test] +fn remove_announcement_works() { + new_test_ext().execute_with(|| { + // wrong origin. + let origin = RuntimeOrigin::signed(CharterManager::get()); + let cid = create_cid(8); + + assert_noop!( + CollectiveContent::remove_announcement(origin, cid), + Error::::MissingAnnouncement + ); + + // missing announcement. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(9); + + assert_noop!( + CollectiveContent::remove_announcement(origin, cid), + Error::::MissingAnnouncement + ); + + // wrong origin. announcement not yet expired. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(10); + assert_ok!(CollectiveContent::announce(origin.clone(), cid.clone(), None)); + assert!(>::contains_key(cid.clone())); + + let origin = RuntimeOrigin::signed(SomeAccount::get()); + assert_noop!(CollectiveContent::remove_announcement(origin, cid.clone()), BadOrigin); + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + assert_ok!(CollectiveContent::remove_announcement(origin, cid)); + + // success. + + // remove first announcement and assert. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(11); + assert_ok!(CollectiveContent::announce(origin.clone(), cid.clone(), None)); + assert!(>::contains_key(cid.clone())); + + let info = CollectiveContent::remove_announcement(origin.clone(), cid.clone()).unwrap(); + assert_eq!(info.pays_fee, Pays::Yes); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementRemoved { + cid: cid.clone(), + })); + assert_noop!( + CollectiveContent::remove_announcement(origin, cid.clone()), + Error::::MissingAnnouncement + ); + assert!(!>::contains_key(cid)); + + // remove expired announcement and assert. + let origin = RuntimeOrigin::signed(AnnouncementManager::get()); + let cid = create_cid(12); + assert_ok!(CollectiveContent::announce( + origin.clone(), + cid.clone(), + Some(DispatchTime::<_>::At(10)) + )); + assert!(>::contains_key(cid.clone())); + + System::set_block_number(11); + let origin = RuntimeOrigin::signed(SomeAccount::get()); + let info = CollectiveContent::remove_announcement(origin.clone(), cid.clone()).unwrap(); + assert_eq!(info.pays_fee, Pays::No); + System::assert_last_event(RuntimeEvent::CollectiveContent(Event::AnnouncementRemoved { + cid: cid.clone(), + })); + assert_noop!( + CollectiveContent::remove_announcement(origin, cid), + Error::::MissingAnnouncement + ); + }); +} diff --git a/cumulus/parachains/pallets/collective-content/src/weights.rs b/cumulus/parachains/pallets/collective-content/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..7ebbaabb5acc2451dc9323874c4f912f98ad8fef --- /dev/null +++ b/cumulus/parachains/pallets/collective-content/src/weights.rs @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The pallet weight info trait and its unit implementation. + +use frame_support::weights::Weight; + +/// Weights information needed for the pallet. +pub trait WeightInfo { + /// Returns the weight of the set_charter extrinsic. + fn set_charter() -> Weight; + /// Returns the weight of the announce extrinsic. + fn announce() -> Weight; + /// Returns the weight of the remove_announcement extrinsic. + fn remove_announcement() -> Weight; +} + +/// Unit implementation of the [WeightInfo]. +impl WeightInfo for () { + fn set_charter() -> Weight { + Weight::zero() + } + fn announce() -> Weight { + Weight::zero() + } + fn remove_announcement() -> Weight { + Weight::zero() + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml index 1d0c7bc98563417169a3a17586de695e1ba36a3a..eb0f249aaae79307629cb0abc73826a14dcbda56 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/Cargo.toml @@ -42,6 +42,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -55,7 +56,6 @@ sp-weights = { path = "../../../../../substrate/primitives/weights", default-fea primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "scale-info", "num-traits"] } # Polkadot -kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/constants", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} @@ -176,7 +176,6 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime?/std", - "kusama-runtime-constants/std", "log/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", @@ -209,6 +208,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index 828d1b4750a3e0436bc18f7926489a04a4b2bb9e..40ce122112d296d538496cb216ad33602d58e9b9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -52,6 +52,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, ord_parameter_types, parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, @@ -1340,6 +1341,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs index 9aff4902d15baa7c8040c8d37ef747fc0c08b754..ce6e92065156ea474afcaf004798b527c1c1f7e0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for AssetHubKusamaXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -127,10 +119,7 @@ impl XcmWeightInfo for AssetHubKusamaXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 6e663039b0c2bcd2767dbd46b6e53c113b50be3d..9b8611fd6637aab79237ba23883b6497e091b53b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/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 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=asset-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=asset-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/assets/asset-hub-kusama/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: 26_104_000 picoseconds. - Weight::from_parts(26_722_000, 3593) + // Minimum execution time: 25_602_000 picoseconds. + Weight::from_parts(26_312_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: 52_259_000 picoseconds. - Weight::from_parts(53_854_000, 6196) + // Minimum execution time: 51_173_000 picoseconds. + Weight::from_parts(52_221_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,10 +86,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `210` + // Measured: `246` // Estimated: `6196` - // Minimum execution time: 77_248_000 picoseconds. - Weight::from_parts(80_354_000, 6196) + // Minimum execution time: 74_651_000 picoseconds. + Weight::from_parts(76_500_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -118,10 +116,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 482_070_000 picoseconds. - Weight::from_parts(490_269_000, 3574) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 458_666_000 picoseconds. + Weight::from_parts(470_470_000, 3610) .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_970_000 picoseconds. - Weight::from_parts(4_056_000, 0) + // Minimum execution time: 3_701_000 picoseconds. + Weight::from_parts(3_887_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 26_324_000 picoseconds. - Weight::from_parts(26_985_000, 3593) + // Minimum execution time: 25_709_000 picoseconds. + Weight::from_parts(26_320_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,10 +157,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3593` - // Minimum execution time: 52_814_000 picoseconds. - Weight::from_parts(54_666_000, 3593) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 51_663_000 picoseconds. + Weight::from_parts(52_538_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,10 +178,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 33_044_000 picoseconds. - Weight::from_parts(33_849_000, 3574) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 31_972_000 picoseconds. + Weight::from_parts(32_834_000, 3610) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 0c197598f889535ce94fe08398ded797a324ef8a..57e745d2e5edeb6b0be36b2ca29fa1056f01fd35 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -21,9 +21,7 @@ use super::{ use crate::ForeignAssets; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, - matching::{ - FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus, - }, + matching::{FromSiblingParachain, IsForeignConcreteAsset}, }; use frame_support::{ match_types, parameter_types, @@ -31,7 +29,10 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, +}; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; @@ -39,11 +40,11 @@ use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, - EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NativeAsset, - NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -448,7 +449,7 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. @@ -470,6 +471,15 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// +/// - KSM with the parent Relay Chain and sibling system parachains; and +/// - Sibling parachains' assets from where they originate (as `ForeignCreators`). +pub type TrustedTeleporters = ( + ConcreteAssetFromSystem, + IsForeignConcreteAsset>>, +); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -480,13 +490,7 @@ impl xcm_executor::Config for XcmConfig { // Asset Hub acting _as_ a reserve location for KSM and assets created under `pallet-assets`. // For KSM, users must use teleport where allowed (e.g. with the Relay Chain). type IsReserve = (); - // We allow: - // - teleportation of KSM - // - teleportation of sibling parachain's assets (as ForeignCreators) - type IsTeleporter = ( - NativeAsset, - IsForeignConcreteAsset>>, - ); + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index 4a6ce4cbf593108fdc06c81853cd1dafaa7d3fde..df38e4d9d64a9b70bfb3d09042e404221e1b430e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -39,6 +39,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -55,7 +56,6 @@ pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchma polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/constants", default-features = false} 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} @@ -184,12 +184,12 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", - "polkadot-runtime-constants/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index 0051af21f9a32b67ff87b0ca3b82373ff4778715..d4f7d6ef361674e5fa7bbd407e2eb830529a2963 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -84,6 +84,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, @@ -1218,6 +1219,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs index 55fed809e2b750d96d279c0558264918a8b60eb9..eb140c4bf32383697ca6c27c913e56edd2f100c4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for AssetHubPolkadotXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -127,10 +119,7 @@ impl XcmWeightInfo for AssetHubPolkadotXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 4f64ea3fa1bb37a4a91274de003dbf49349d6e4f..96d86ec423f20e1923cf0842830a6e12ad81d436 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/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 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=asset-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=asset-hub-polkadot-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/assets/asset-hub-polkadot/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: 26_090_000 picoseconds. - Weight::from_parts(27_006_000, 3593) + // Minimum execution time: 25_903_000 picoseconds. + Weight::from_parts(26_768_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: 50_699_000 picoseconds. - Weight::from_parts(51_888_000, 6196) + // Minimum execution time: 51_042_000 picoseconds. + Weight::from_parts(51_939_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: `176` // Estimated: `6196` - // Minimum execution time: 72_130_000 picoseconds. - Weight::from_parts(73_994_000, 6196) + // Minimum execution time: 74_626_000 picoseconds. + Weight::from_parts(75_963_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3540` - // Minimum execution time: 477_183_000 picoseconds. - Weight::from_parts(488_156_000, 3540) + // Minimum execution time: 480_030_000 picoseconds. + Weight::from_parts(486_039_000, 3540) .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_966_000 picoseconds. - Weight::from_parts(4_129_000, 0) + // Minimum execution time: 3_936_000 picoseconds. + Weight::from_parts(4_033_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 26_047_000 picoseconds. - Weight::from_parts(26_982_000, 3593) + // Minimum execution time: 26_274_000 picoseconds. + Weight::from_parts(26_609_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `3593` - // Minimum execution time: 51_076_000 picoseconds. - Weight::from_parts(51_826_000, 3593) + // Minimum execution time: 52_888_000 picoseconds. + Weight::from_parts(53_835_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: `75` // Estimated: `3540` - // Minimum execution time: 30_606_000 picoseconds. - Weight::from_parts(31_168_000, 3540) + // Minimum execution time: 33_395_000 picoseconds. + Weight::from_parts(33_827_000, 3540) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index d59507e4bd07d4f5a8953c1ad62814a2ebbc2a37..8a4b24407b53dbea3037b6ef95e9f91c8d135aa5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs @@ -18,16 +18,17 @@ use super::{ ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; -use assets_common::matching::{ - FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus, -}; +use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset}; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, +}; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; @@ -35,11 +36,11 @@ use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, - EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NativeAsset, - NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -186,6 +187,9 @@ match_types! { pub type FellowshipSalaryPallet: impl Contains = { MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(64)) } }; + pub type AmbassadorSalaryPallet: impl Contains = { + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(74)) } + }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -363,7 +367,7 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality @@ -372,6 +376,7 @@ pub type Barrier = TrailingSetTopicAsId< ParentOrParentsPlurality, FellowsPlurality, FellowshipSalaryPallet, + AmbassadorSalaryPallet, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, @@ -390,6 +395,15 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// +/// - DOT with the parent Relay Chain and sibling system parachains; and +/// - Sibling parachains' assets from where they originate (as `ForeignCreators`). +pub type TrustedTeleporters = ( + ConcreteAssetFromSystem, + IsForeignConcreteAsset>>, +); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -400,13 +414,7 @@ impl xcm_executor::Config for XcmConfig { // Asset Hub acting _as_ a reserve location for DOT and assets created under `pallet-assets`. // For DOT, users must use teleport where allowed (e.g. with the Relay Chain). type IsReserve = (); - // We allow: - // - teleportation of DOT - // - teleportation of sibling parachain's assets (as ForeignCreators) - type IsTeleporter = ( - NativeAsset, - IsForeignConcreteAsset>>, - ); + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..af0ce6d5814ef8d12aa0757250063199dc94a4e9 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -0,0 +1,241 @@ +[package] +name = "asset-hub-rococo-runtime" +version = "0.9.420" +authors.workspace = true +edition.workspace = true +description = "Rococo variant of Asset Hub parachain runtime" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +hex-literal = { version = "0.4.1" } +log = { version = "0.4.20", default-features = false } +scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +smallvec = "1.11.0" + +# Substrate +frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true} +frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false} +frame-support = { path = "../../../../../substrate/frame/support", default-features = false} +frame-system = { path = "../../../../../substrate/frame/system", default-features = false} +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-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} +pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false} +pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false} +pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} +pallet-multisig = { path = "../../../../../substrate/frame/multisig", default-features = false} +pallet-nft-fractionalization = { path = "../../../../../substrate/frame/nft-fractionalization", default-features = false} +pallet-nfts = { path = "../../../../../substrate/frame/nfts", default-features = false} +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} +pallet-uniques = { path = "../../../../../substrate/frame/uniques", default-features = false} +pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false} +sp-api = { path = "../../../../../substrate/primitives/api", default-features = false} +sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} +sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} +sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} +sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} +sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} +sp-session = { path = "../../../../../substrate/primitives/session", default-features = false} +sp-std = { path = "../../../../../substrate/primitives/std", default-features = false} +sp-storage = { path = "../../../../../substrate/primitives/storage", default-features = false} +sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction-pool", default-features = false} +sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} +sp-weights = { path = "../../../../../substrate/primitives/weights", default-features = false} +# num-traits feature needed for dex integer sq root: +primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "scale-info", "num-traits"] } + +# Polkadot +rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false} +pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} +pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } +polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} +polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} +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} + +# Cumulus +cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } +cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } +cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false} +cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } +cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } +cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } +parachain-info = { path = "../../../pallets/parachain-info", default-features = false } +parachains-common = { path = "../../../common", default-features = false } +assets-common = { path = "../common", default-features = false } + +# Bridges +pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } +bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-wococo = { path = "../../../../../bridges/primitives/chain-asset-hub-wococo", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-wococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-wococo", default-features = false } + +[dev-dependencies] +asset-test-utils = { path = "../test-utils" } + +[build-dependencies] +substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } + +[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", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-asset-conversion/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-multisig/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", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-bridge-hub-router/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] +try-runtime = [ + "cumulus-pallet-aura-ext/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-asset-conversion-tx-payment/try-runtime", + "pallet-asset-conversion/try-runtime", + "pallet-assets/try-runtime", + "pallet-aura/try-runtime", + "pallet-authorship/try-runtime", + "pallet-balances/try-runtime", + "pallet-collator-selection/try-runtime", + "pallet-multisig/try-runtime", + "pallet-nft-fractionalization/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", + "pallet-utility/try-runtime", + "pallet-xcm-bridge-hub-router/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/try-runtime", +] +std = [ + "assets-common/std", + "bp-asset-hub-rococo/std", + "bp-asset-hub-wococo/std", + "bp-bridge-hub-rococo/std", + "bp-bridge-hub-wococo/std", + "codec/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-session-benchmarking/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-utility/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", + "pallet-asset-conversion-tx-payment/std", + "pallet-asset-conversion/std", + "pallet-assets/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-multisig/std", + "pallet-nft-fractionalization/std", + "pallet-nfts-runtime-api/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", + "pallet-uniques/std", + "pallet-utility/std", + "pallet-xcm-benchmarks?/std", + "pallet-xcm-bridge-hub-router/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-core-primitives/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "rococo-runtime-constants/std", + "scale-info/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-storage/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-weights/std", + "substrate-wasm-builder", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] + +experimental = [ "pallet-aura/experimental" ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..60f8a125129ff1344a1799246e931acdb1d139d5 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs @@ -0,0 +1,26 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(feature = "std")] +fn main() { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} + +#[cfg(not(feature = "std"))] +fn main() {} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..3328ff0edaf49d1d334542f3b81775110a5eb8d5 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -0,0 +1,1566 @@ +// 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 Hub Rococo Runtime +//! +//! Asset Hub Rococo, formerly known as "Rockmine", is the test network for its Kusama cousin. +//! +//! This runtime is also used for Asset Hub Wococo. But we dont want to create another exact copy of +//! Asset Hub Rococo, so we injected some tweaks backed by `RuntimeFlavor` and `pub storage Flavor: +//! RuntimeFlavor`. (For example this is needed for successful asset transfer between Asset Hub +//! Rococo and Asset Hub Wococo, where we need to have correct `xcm_config::UniversalLocation` with +//! correct `GlobalConsensus`. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +mod weights; +pub mod xcm_config; + +use assets_common::{ + foreign_creators::ForeignCreators, + local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter}, + matching::FromSiblingParachain, + AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, +}; +use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use sp_api::impl_runtime_apis; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Verify}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, Permill, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + ord_parameter_types, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, + Equals, InstanceFilter, + }, + weights::{ConstantMultiplier, Weight}, + BoundedVec, PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, EnsureSigned, EnsureSignedBy, +}; +use pallet_asset_conversion_tx_payment::AssetConversionAdapter; +use pallet_nfts::PalletFeatures; +pub use parachains_common as common; +use parachains_common::{ + impls::DealWithFees, + rococo::{consensus::*, currency::*, fee::WeightToFee}, + AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, + Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, + NORMAL_DISPATCH_RATIO, SLOT_DURATION, +}; +use sp_runtime::RuntimeDebug; +use xcm::opaque::v3::MultiLocation; +use xcm_config::{ + ForeignAssetsConvertedConcreteId, GovernanceLocation, PoolAssetsConvertedConcreteId, + TokenLocation, TrustBackedAssetsConvertedConcreteId, XcmConfig, +}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +// Polkadot imports +use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use xcm::latest::BodyId; +use xcm_executor::XcmExecutor; + +use crate::xcm_config::{ + ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, + TrustBackedAssetsPalletLocation, +}; +use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; + +/// Enum for handling differences in the runtime configuration for `AssetHubRococo` vs. +/// `AssetHubWococo`. +#[derive(Default, Eq, PartialEq, Debug, Clone, Copy, Decode, Encode)] +pub enum RuntimeFlavor { + #[default] + Rococo, + Wococo, +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[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: 10006, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 13, + 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: 10006, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 13, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + pub const SS58Prefix: u8 = 42; +} + +// Configure FRAME pallets to include in runtime. +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = RuntimeBlockWeights; + type BlockLength = RuntimeBlockLength; + type AccountId = AccountId; + type RuntimeCall = RuntimeCall; + type Lookup = AccountIdLookup; + type Nonce = Nonce; + type Hash = Hash; + type Hashing = BlakeTwo256; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type BlockHashCount = BlockHashCount; + type DbWeight = RocksDbWeight; + type Version = Version; + type PalletInfo = PalletInfo; + type OnNewAccount = (); + type OnKilledAccount = (); + type AccountData = pallet_balances::AccountData; + type SystemWeightInfo = weights::frame_system::WeightInfo; + type SS58Prefix = SS58Prefix; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +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 WeightInfo = weights::pallet_timestamp::WeightInfo; +} + +impl pallet_authorship::Config for Runtime { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + type EventHandler = (CollatorSelection,); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = weights::pallet_balances::WeightInfo; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type FreezeIdentifier = (); + // We allow each account to have holds on it from: + // - `NftFractionalization`: 1 + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = MILLICENTS; +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = + pallet_transaction_payment::CurrencyAdapter>; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type OperationalFeeMultiplier = ConstU8<5>; +} + +parameter_types! { + pub const AssetDeposit: Balance = UNITS / 10; // 1 / 10 UNITS deposit to create asset + pub const AssetAccountDeposit: Balance = deposit(1, 16); + pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = deposit(1, 68); + pub const MetadataDepositPerByte: Balance = deposit(0, 1); +} + +/// We allow root to execute privileged asset operations. +pub type AssetsForceOrigin = EnsureRoot; + +// Called "Trust Backed" assets because these are generally registered by some account, and users of +// the asset assume it has some claimed backing. The pallet is called `Assets` in +// `construct_runtime` to avoid breaking changes on storage reads. +pub type TrustBackedAssetsInstance = pallet_assets::Instance1; +type TrustBackedAssetsCall = pallet_assets::Call; +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetIdForTrustBackedAssets; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = weights::pallet_assets_local::WeightInfo; + type CallbackHandle = (); + type AssetAccountDeposit = AssetAccountDeposit; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +parameter_types! { + pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); + pub const AllowMultiAssetPools: bool = false; + // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero + pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); +} + +ord_parameter_types! { + pub const AssetConversionOrigin: sp_runtime::AccountId32 = + AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); +} + +pub type PoolAssetsInstance = pallet_assets::Instance3; +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type RemoveItemsLimit = ConstU32<1000>; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = + AsEnsureOriginWithArg>; + type ForceOrigin = AssetsForceOrigin; + // Deposits are zero because creation/admin is limited to Asset Conversion pallet. + type AssetDeposit = ConstU128<0>; + type AssetAccountDeposit = ConstU128<0>; + type MetadataDepositBase = ConstU128<0>; + type MetadataDepositPerByte = ConstU128<0>; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = ConstU32<50>; + type Freezer = (); + type Extra = (); + type WeightInfo = weights::pallet_assets_pool::WeightInfo; + type CallbackHandle = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_asset_conversion::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type HigherPrecisionBalance = sp_core::U256; + type Currency = Balances; + type AssetBalance = Balance; + type AssetId = MultiLocation; + type Assets = LocalAndForeignAssets< + Assets, + AssetIdForTrustBackedAssetsConvert, + ForeignAssets, + >; + type PoolAssets = PoolAssets; + type PoolAssetId = u32; + type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam + type PoolSetupFeeReceiver = AssetConversionOrigin; + // should be non-zero if `AllowMultiAssetPools` is true, otherwise can be zero. + type LiquidityWithdrawalFee = LiquidityWithdrawalFee; + type LPFee = ConstU32<3>; + type PalletId = AssetConversionPalletId; + type AllowMultiAssetPools = AllowMultiAssetPools; + type MaxSwapPathLength = ConstU32<4>; + type MultiAssetId = Box; + type MultiAssetIdConverter = + MultiLocationConverter; + type MintMinLiquidity = ConstU128<100>; + type WeightInfo = weights::pallet_asset_conversion::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = + crate::xcm_config::BenchmarkMultiLocationConverter>; +} + +parameter_types! { + // we just reuse the same deposits + pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get(); + pub const ForeignAssetsAssetAccountDeposit: Balance = AssetAccountDeposit::get(); + pub const ForeignAssetsApprovalDeposit: Balance = ApprovalDeposit::get(); + pub const ForeignAssetsAssetsStringLimit: u32 = AssetsStringLimit::get(); + pub const ForeignAssetsMetadataDepositBase: Balance = MetadataDepositBase::get(); + pub const ForeignAssetsMetadataDepositPerByte: Balance = MetadataDepositPerByte::get(); +} + +/// Assets managed by some foreign location. Note: we do not declare a `ForeignAssetsCall` type, as +/// this type is used in proxy definitions. We assume that a foreign location would not want to set +/// an individual, local account as a proxy for the issuance of their assets. This issuance should +/// be managed by the foreign location's governance. +pub type ForeignAssetsInstance = pallet_assets::Instance2; +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = MultiLocationForAssetId; + type AssetIdParameter = MultiLocationForAssetId; + type Currency = Balances; + type CreateOrigin = ForeignCreators< + (FromSiblingParachain>,), + ForeignCreatorsSovereignAccountOf, + AccountId, + >; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = ForeignAssetsAssetDeposit; + type MetadataDepositBase = ForeignAssetsMetadataDepositBase; + type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte; + type ApprovalDeposit = ForeignAssetsApprovalDeposit; + type StringLimit = ForeignAssetsAssetsStringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = weights::pallet_assets_foreign::WeightInfo; + type CallbackHandle = (); + type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = xcm_config::XcmBenchmarkHelper; +} + +parameter_types! { + // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. + pub const DepositBase: Balance = deposit(1, 88); + // Additional storage item size of 32 bytes. + pub const DepositFactor: Balance = deposit(0, 32); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = weights::pallet_multisig::WeightInfo; +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = weights::pallet_utility::WeightInfo; +} + +parameter_types! { + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Assets proxy. Can execute any call from `assets`, **including asset transfers**. + Assets, + /// Owner proxy. Can execute calls related to asset ownership. + AssetOwner, + /// Asset manager. Can execute calls related to asset management. + AssetManager, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances { .. } | + RuntimeCall::Assets { .. } | + RuntimeCall::NftFractionalization { .. } | + RuntimeCall::Nfts { .. } | + RuntimeCall::Uniques { .. } + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Assets => { + matches!( + c, + RuntimeCall::Assets { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } | + RuntimeCall::NftFractionalization { .. } | + RuntimeCall::Nfts { .. } | RuntimeCall::Uniques { .. } + ) + }, + ProxyType::AssetOwner => matches!( + c, + RuntimeCall::Assets(TrustBackedAssetsCall::create { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::start_destroy { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::destroy_accounts { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::destroy_approvals { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::finish_destroy { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::transfer_ownership { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_team { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::create { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::destroy { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::redeposit { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::transfer_ownership { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_team { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_collection { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::create { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::destroy { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::transfer_ownership { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::set_team { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::set_metadata { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::set_attribute { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::set_collection_metadata { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::clear_metadata { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::clear_attribute { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::clear_collection_metadata { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::set_collection_max_supply { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::AssetManager => matches!( + c, + RuntimeCall::Assets(TrustBackedAssetsCall::mint { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::burn { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::freeze { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::block { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::thaw { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::freeze_asset { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | + RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::force_mint { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::update_mint_settings { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::mint_pre_signed { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_item_transfer { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::lock_item_properties { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::clear_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::set_collection_metadata { .. }) | + RuntimeCall::Nfts(pallet_nfts::Call::clear_collection_metadata { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::mint { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::burn { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::freeze { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::thaw { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::freeze_collection { .. }) | + RuntimeCall::Uniques(pallet_uniques::Call::thaw_collection { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Assets, ProxyType::AssetOwner) => true, + (ProxyType::Assets, ProxyType::AssetManager) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = MaxPending; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type DmpMessageHandler = DmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + 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, + >; +} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type ExecuteOverweightOrigin = EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; + type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = (); +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = EnsureRoot; +} + +parameter_types! { + pub const Period: u32 = 6 * HOURS; + pub const Offset: u32 = 0; +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = ::AccountId; + // we don't have stash and controller, thus we don't need the convert as well. + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = CollatorSelection; + // Essentially just Aura, but let's be pedantic. + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + type WeightInfo = weights::pallet_session::WeightInfo; +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<100_000>; + type AllowMultipleBlocksPerSlot = ConstBool; + #[cfg(feature = "experimental")] + type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); + pub const SessionLength: BlockNumber = 6 * HOURS; + // StakingAdmin pluralistic body. + pub const StakingAdminBodyId: BodyId = BodyId::Defense; +} + +/// We allow root and the `StakingAdmin` to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< + EnsureRoot, + EnsureXcm>, +>; + +impl pallet_collator_selection::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type UpdateOrigin = CollatorSelectionUpdateOrigin; + type PotId = PotId; + type MaxCandidates = ConstU32<100>; + type MinEligibleCollators = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; + // should be a multiple of session or things will get inconsistent + type KickThreshold = Period; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = weights::pallet_collator_selection::WeightInfo; +} + +impl pallet_asset_conversion_tx_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Fungibles = LocalAndForeignAssets< + Assets, + AssetIdForTrustBackedAssetsConvert, + ForeignAssets, + >; + type OnChargeAssetTransaction = AssetConversionAdapter; +} + +parameter_types! { + pub const UniquesCollectionDeposit: Balance = UNITS / 10; // 1 / 10 UNIT deposit to create a collection + pub const UniquesItemDeposit: Balance = UNITS / 1_000; // 1 / 1000 UNIT deposit to mint an item + pub const UniquesMetadataDepositBase: Balance = deposit(1, 129); + pub const UniquesAttributeDepositBase: Balance = deposit(1, 0); + pub const UniquesDepositPerByte: Balance = deposit(0, 1); +} + +impl pallet_uniques::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type CollectionDeposit = UniquesCollectionDeposit; + type ItemDeposit = UniquesItemDeposit; + type MetadataDepositBase = UniquesMetadataDepositBase; + type AttributeDepositBase = UniquesAttributeDepositBase; + type DepositPerByte = UniquesDepositPerByte; + type StringLimit = ConstU32<128>; + type KeyLimit = ConstU32<32>; + type ValueLimit = ConstU32<64>; + type WeightInfo = weights::pallet_uniques::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type CreateOrigin = AsEnsureOriginWithArg>; + type Locker = (); +} + +parameter_types! { + pub const NftFractionalizationPalletId: PalletId = PalletId(*b"fraction"); + pub NewAssetSymbol: BoundedVec = (*b"FRAC").to_vec().try_into().unwrap(); + pub NewAssetName: BoundedVec = (*b"Frac").to_vec().try_into().unwrap(); +} + +impl pallet_nft_fractionalization::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Deposit = AssetDeposit; + type Currency = Balances; + type NewAssetSymbol = NewAssetSymbol; + type NewAssetName = NewAssetName; + type StringLimit = AssetsStringLimit; + type NftCollectionId = ::CollectionId; + type NftId = ::ItemId; + type AssetBalance = ::Balance; + type AssetId = >::AssetId; + type Assets = Assets; + type Nfts = Nfts; + type PalletId = NftFractionalizationPalletId; + type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; + type RuntimeHoldReason = RuntimeHoldReason; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +parameter_types! { + pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; + // re-use the Uniques deposits + pub const NftsCollectionDeposit: Balance = UniquesCollectionDeposit::get(); + pub const NftsItemDeposit: Balance = UniquesItemDeposit::get(); + pub const NftsMetadataDepositBase: Balance = UniquesMetadataDepositBase::get(); + pub const NftsAttributeDepositBase: Balance = UniquesAttributeDepositBase::get(); + pub const NftsDepositPerByte: Balance = UniquesDepositPerByte::get(); +} + +impl pallet_nfts::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = AssetsForceOrigin; + type Locker = (); + type CollectionDeposit = NftsCollectionDeposit; + type ItemDeposit = NftsItemDeposit; + type MetadataDepositBase = NftsMetadataDepositBase; + type AttributeDepositBase = NftsAttributeDepositBase; + type DepositPerByte = NftsDepositPerByte; + type StringLimit = ConstU32<256>; + type KeyLimit = ConstU32<64>; + type ValueLimit = ConstU32<256>; + type ApprovalsLimit = ConstU32<20>; + type ItemAttributesApprovalsLimit = ConstU32<30>; + type MaxTips = ConstU32<10>; + type MaxDeadlineDuration = NftsMaxDeadlineDuration; + type MaxAttributesPerCall = ConstU32<10>; + type Features = NftsPalletFeatures; + type OffchainSignature = Signature; + type OffchainPublic = ::Signer; + type WeightInfo = weights::pallet_nfts::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); +} + +/// XCM router instance to BridgeHub with bridging capabilities for `Wococo` global +/// consensus with dynamic fees and back-pressure. +pub type ToWococoXcmRouterInstance = pallet_assets::Instance1; +impl pallet_xcm_bridge_hub_router::Config for Runtime { + type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_wococo::WeightInfo; + + type UniversalLocation = xcm_config::UniversalLocation; + type BridgedNetworkId = xcm_config::bridging::to_wococo::WococoNetwork; + type Bridges = xcm_config::bridging::to_wococo::NetworkExportTable; + + #[cfg(not(feature = "runtime-benchmarks"))] + type BridgeHubOrigin = EnsureXcm>; + #[cfg(feature = "runtime-benchmarks")] + type BridgeHubOrigin = EitherOfDiverse< + // for running benchmarks + EnsureRoot, + // for running tests with `--feature runtime-benchmarks` + EnsureXcm>, + >; + + type ToBridgeHubSender = XcmpQueue; + type WithBridgeHubChannel = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< + xcm_config::bridging::SiblingBridgeHubParaId, + Runtime, + >; + + type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; + type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; +} + +/// XCM router instance to BridgeHub with bridging capabilities for `Rococo` global +/// consensus with dynamic fees and back-pressure. +pub type ToRococoXcmRouterInstance = pallet_assets::Instance2; +impl pallet_xcm_bridge_hub_router::Config for Runtime { + type WeightInfo = weights::pallet_xcm_bridge_hub_router_to_rococo::WeightInfo; + + type UniversalLocation = xcm_config::UniversalLocation; + type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; + type Bridges = xcm_config::bridging::to_rococo::NetworkExportTable; + + #[cfg(not(feature = "runtime-benchmarks"))] + type BridgeHubOrigin = EnsureXcm>; + #[cfg(feature = "runtime-benchmarks")] + type BridgeHubOrigin = EitherOfDiverse< + // for running benchmarks + EnsureRoot, + // for running tests with `--feature runtime-benchmarks` + EnsureXcm>, + >; + + type ToBridgeHubSender = XcmpQueue; + type WithBridgeHubChannel = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< + xcm_config::bridging::SiblingBridgeHubParaId, + Runtime, + >; + + type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; + type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +construct_runtime!( + pub enum Runtime + { + // System support stuff. + System: frame_system::{Pallet, Call, Config, Storage, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{ + Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, + } = 1, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 11, + AssetTxPayment: pallet_asset_conversion_tx_payment::{Pallet, Event} = 13, + + // Collator support. the order of these 5 are important and shall not change. + Authorship: pallet_authorship::{Pallet, Storage} = 20, + CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, + Aura: pallet_aura::{Pallet, Storage, Config} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, + + // XCM helpers. + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 31, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 40, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, + + // Bridge utilities. + ToWococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 43, + ToRococoXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 44, + + // The main stage. + Assets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, + Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, + Nfts: pallet_nfts::{Pallet, Call, Storage, Event} = 52, + ForeignAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 53, + NftFractionalization: pallet_nft_fractionalization::{Pallet, Call, Storage, Event, HoldReason} = 54, + + PoolAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 55, + AssetConversion: pallet_asset_conversion::{Pallet, Call, Storage, Event} = 56, + + #[cfg(feature = "state-trie-version-1")] + StateTrieMigration: pallet_state_trie_migration = 70, + } +); + +/// The address format for describing accounts. +pub type Address = sp_runtime::MultiAddress; +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +/// Migrations to apply on runtime upgrade. +pub type Migrations = (pallet_collator_selection::migration::v1::MigrateToV1,); + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + Migrations, +>; + +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_system, SystemBench::] + [pallet_assets, Local] + [pallet_assets, Foreign] + [pallet_assets, Pool] + [pallet_asset_conversion, AssetConversion] + [pallet_balances, Balances] + [pallet_multisig, Multisig] + [pallet_nft_fractionalization, NftFractionalization] + [pallet_nfts, Nfts] + [pallet_proxy, Proxy] + [pallet_session, SessionBench::] + [pallet_uniques, Uniques] + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_xcm_bridge_hub_router, ToWococo] + [pallet_xcm_bridge_hub_router, ToRococo] + // XCM + [pallet_xcm, PolkadotXcm] + // NOTE: Make sure you point to the individual modules below. + [pallet_xcm_benchmarks::fungible, XcmBalances] + [pallet_xcm_benchmarks::generic, XcmGeneric] + ); +} + +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()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + impl pallet_asset_conversion::AssetConversionApi< + Block, + Balance, + u128, + Box, + > for Runtime + { + fn quote_price_exact_tokens_for_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) + } + fn quote_price_tokens_for_exact_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) + } + fn get_reserves(asset1: Box, asset2: Box) -> Option<(Balance, Balance)> { + AssetConversion::get_reserves(&asset1, &asset2).ok() + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl assets_common::runtime_api::FungiblesApi< + Block, + AccountId, + > for Runtime + { + fn query_account_balances(account: AccountId) -> Result { + use assets_common::fungible_conversion::{convert, convert_balance}; + Ok([ + // collect pallet_balance + { + let balance = Balances::free_balance(account.clone()); + if balance > 0 { + vec![convert_balance::(balance)?] + } else { + vec![] + } + }, + // collect pallet_assets (TrustBackedAssets) + convert::<_, _, _, _, TrustBackedAssetsConvertedConcreteId>( + Assets::account_balances(account.clone()) + .iter() + .filter(|(_, balance)| balance > &0) + )?, + // collect pallet_assets (ForeignAssets) + convert::<_, _, _, _, ForeignAssetsConvertedConcreteId>( + ForeignAssets::account_balances(account.clone()) + .iter() + .filter(|(_, balance)| balance > &0) + )?, + // collect pallet_assets (PoolAssets) + convert::<_, _, _, _, PoolAssetsConvertedConcreteId>( + PoolAssets::account_balances(account) + .iter() + .filter(|(_, balance)| balance > &0) + )?, + // collect ... e.g. other tokens + ].concat().into()) + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + let weight = Executive::try_runtime_upgrade(checks).unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Weight { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; + + // This is defined once again in dispatch_benchmark, because list_benchmarks! + // and add_benchmarks! are macros exported by define_benchmarks! macros and those types + // are referenced in that call. + type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; + type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; + + // Benchmark files generated for `Assets/ForeignAssets` instances are by default + // `pallet_assets_assets.rs / pallet_assets_foreign_assets`, which is not really nice, + // so with this redefinition we can change names to nicer: + // `pallet_assets_local.rs / pallet_assets_foreign.rs`. + type Local = pallet_assets::Pallet::; + type Foreign = pallet_assets::Pallet::; + type Pool = pallet_assets::Pallet::; + + type ToWococo = XcmBridgeHubRouterBench; + type ToRococo = XcmBridgeHubRouterBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; + use sp_storage::TrackedStorageKey; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime { + fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); + Ok(()) + } + + fn verify_set_code() { + System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); + } + } + + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + impl cumulus_pallet_session_benchmarking::Config for Runtime {} + + use pallet_xcm_bridge_hub_router::benchmarking::{ + Pallet as XcmBridgeHubRouterBench, + Config as XcmBridgeHubRouterConfig, + }; + + impl XcmBridgeHubRouterConfig for Runtime { + fn make_congested() { + cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( + xcm_config::bridging::SiblingBridgeHubParaId::get().into() + ); + } + fn ensure_bridged_target_destination() -> MultiLocation { + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + xcm_config::bridging::SiblingBridgeHubParaId::get().into() + ); + xcm_config::bridging::to_wococo::AssetHubWococo::get() + } + } + impl XcmBridgeHubRouterConfig for Runtime { + fn make_congested() { + cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( + xcm_config::bridging::SiblingBridgeHubParaId::get().into() + ); + } + fn ensure_bridged_target_destination() -> MultiLocation { + xcm_config::Flavor::set(&RuntimeFlavor::Wococo); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + xcm_config::bridging::SiblingBridgeHubParaId::get().into() + ); + xcm_config::bridging::to_rococo::AssetHubRococo::get() + } + } + + use xcm::latest::prelude::*; + use xcm_config::{TokenLocation, MaxAssetsIntoHolding}; + use pallet_xcm_benchmarks::asset_instance_from; + + impl pallet_xcm_benchmarks::Config for Runtime { + type XcmConfig = xcm_config::XcmConfig; + type AccountIdConverter = xcm_config::LocationToAccountId; + fn valid_destination() -> Result { + Ok(TokenLocation::get()) + } + fn worst_case_holding(depositable_count: u32) -> MultiAssets { + // 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 fungibles_amount: u128 = 100; + let mut assets = (0..holding_fungibles) + .map(|i| { + MultiAsset { + id: Concrete(GeneralIndex(i as u128).into()), + fun: Fungible(fungibles_amount * i as u128), + } + }) + .chain(core::iter::once(MultiAsset { id: Concrete(Here.into()), fun: Fungible(u128::MAX) })) + .chain((0..holding_non_fungibles).map(|i| MultiAsset { + id: Concrete(GeneralIndex(i as u128).into()), + fun: NonFungible(asset_instance_from(i)), + })) + .collect::>(); + + assets.push(MultiAsset { + id: Concrete(TokenLocation::get()), + fun: Fungible(1_000_000 * UNITS), + }); + assets.into() + } + } + + parameter_types! { + pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( + TokenLocation::get(), + MultiAsset { fun: Fungible(UNITS), id: Concrete(TokenLocation::get()) }, + )); + pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; + pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; + } + + impl pallet_xcm_benchmarks::fungible::Config for Runtime { + type TransactAsset = Balances; + + type CheckedAccount = CheckedAccount; + type TrustedTeleporter = TrustedTeleporter; + type TrustedReserve = TrustedReserve; + + fn get_multi_asset() -> MultiAsset { + MultiAsset { + id: Concrete(TokenLocation::get()), + fun: Fungible(UNITS), + } + } + } + + impl pallet_xcm_benchmarks::generic::Config for Runtime { + type RuntimeCall = RuntimeCall; + + fn worst_case_response() -> (u64, Response) { + (0u64, Response::Version(Default::default())) + } + + fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { + match xcm_config::bridging::BridgingBenchmarksHelper::prepare_universal_alias() { + Some(alias) => Ok(alias), + None => Err(BenchmarkError::Skip) + } + } + + fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { + Ok((TokenLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + } + + fn subscribe_origin() -> Result { + Ok(TokenLocation::get()) + } + + fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { + let origin = TokenLocation::get(); + let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); + let ticket = MultiLocation { parents: 0, interior: Here }; + Ok((origin, ticket, assets)) + } + + fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn export_message_origin_and_destination( + ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { + Err(BenchmarkError::Skip) + } + } + + type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; + type XcmGeneric = pallet_xcm_benchmarks::generic::Pallet::; + + type Local = pallet_assets::Pallet::; + type Foreign = pallet_assets::Pallet::; + type Pool = pallet_assets::Pallet::; + + type ToWococo = XcmBridgeHubRouterBench; + type ToRococo = XcmBridgeHubRouterBench; + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // Event Count + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + //TODO: use from relay_well_known_keys::ACTIVE_CONFIG + hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + Ok(batches) + } + } +} + +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + 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 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::*; + use crate::{CENTS, MILLICENTS}; + use parachains_common::rococo::fee; + use sp_runtime::traits::Zero; + use sp_weights::WeightToFee; + + /// We can fit at least 1000 transfers in a block. + #[test] + fn sane_block_weight() { + use pallet_balances::WeightInfo; + let block = RuntimeBlockWeights::get().max_block; + let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; + let transfer = + base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); + + let fit = block.checked_div_per_component(&transfer).unwrap_or_default(); + assert!(fit >= 1000, "{} should be at least 1000", fit); + } + + /// The fee for one transfer is at most 1 CENT. + #[test] + fn sane_transfer_fee() { + use pallet_balances::WeightInfo; + let base = RuntimeBlockWeights::get().get(DispatchClass::Normal).base_extrinsic; + let transfer = + base + weights::pallet_balances::WeightInfo::::transfer_allow_death(); + + let fee: Balance = fee::WeightToFee::weight_to_fee(&transfer); + assert!(fee <= CENTS, "{} MILLICENTS should be at most 1000", fee / MILLICENTS); + } + + /// Weight is being charged for both dimensions. + #[test] + fn weight_charged_for_both_components() { + let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(10_000, 0)); + assert!(!fee.is_zero(), "Charges for ref time"); + + let fee: Balance = fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, 10_000)); + assert_eq!(fee, CENTS, "10kb maps to CENT"); + } + + /// Filling up a block by proof size is at most 30 times more expensive than ref time. + /// + /// This is just a sanity check. + #[test] + fn full_block_fee_ratio() { + let block = RuntimeBlockWeights::get().max_block; + let time_fee: Balance = + fee::WeightToFee::weight_to_fee(&Weight::from_parts(block.ref_time(), 0)); + let proof_fee: Balance = + fee::WeightToFee::weight_to_fee(&Weight::from_parts(0, block.proof_size())); + + let proof_o_time = proof_fee.checked_div(time_fee).unwrap_or_default(); + assert!(proof_o_time <= 30, "{} should be at most 30", proof_o_time); + let time_o_proof = time_fee.checked_div(proof_fee).unwrap_or_default(); + assert!(time_o_proof <= 30, "{} should be at most 30", time_o_proof); + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..e7fdb2aae2a01ec06076de83d94817e540e205dd --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Importing a block with 0 Extrinsics. + pub const BlockExecutionWeight: Weight = + Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000), 0); + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::BlockExecutionWeight::get(); + + // At least 100 µs. + assert!( + w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, + "Weight should be at least 100 µs." + ); + // At most 50 ms. + assert!( + w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, + "Weight should be at most 50 ms." + ); + } + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..26ce4c8c9c5f6c30339f465ff96b7a9e0f8245d3 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -0,0 +1,77 @@ +// 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 `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=cumulus_pallet_xcmp_queue +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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 `cumulus_pallet_xcmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_u32() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 5_467_000 picoseconds. + Weight::from_parts(5_634_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 5_409_000 picoseconds. + Weight::from_parts(5_570_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..1a4adb968bb7195428ea00d59cd92dcd3b6eea5f --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Executing a NO-OP `System::remarks` Extrinsic. + pub const ExtrinsicBaseWeight: Weight = + Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000), 0); + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::ExtrinsicBaseWeight::get(); + + // At least 10 µs. + assert!( + w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, + "Weight should be at least 10 µs." + ); + // At most 1 ms. + assert!( + w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, + "Weight should be at most 1 ms." + ); + } + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system.rs new file mode 100644 index 0000000000000000000000000000000000000000..4f993155c19c7fc521f00f00b4841a15064d15c8 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system.rs @@ -0,0 +1,155 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `frame_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=frame_system +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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 `frame_system`. +pub struct WeightInfo(PhantomData); +impl frame_system::WeightInfo for WeightInfo { + /// The range of component `b` is `[0, 3932160]`. + fn remark(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_106_000 picoseconds. + Weight::from_parts(1_884_213, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(388, 0).saturating_mul(b.into())) + } + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_528_000 picoseconds. + Weight::from_parts(27_081_927, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_730, 0).saturating_mul(b.into())) + } + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + fn set_heap_pages() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 3_882_000 picoseconds. + Weight::from_parts(4_149_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `ParachainSystem::UpgradeRestrictionSignal` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingValidationCode` (r:1 w:1) + /// Proof: `ParachainSystem::PendingValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::NewValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::NewValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::DidSetValidationCode` (r:0 w:1) + /// Proof: `ParachainSystem::DidSetValidationCode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_code() -> Weight { + // Proof Size summary in bytes: + // Measured: `119` + // Estimated: `1604` + // Minimum execution time: 103_389_161_000 picoseconds. + Weight::from_parts(106_870_091_000, 0) + .saturating_add(Weight::from_parts(0, 1604)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn set_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_236_000 picoseconds. + Weight::from_parts(2_302_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_045 + .saturating_add(Weight::from_parts(763_456, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `i` is `[0, 1000]`. + fn kill_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_175_000 picoseconds. + Weight::from_parts(2_238_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1_040 + .saturating_add(Weight::from_parts(571_397, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[0, 1000]`. + fn kill_prefix(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `84 + p * (69 ±0)` + // Estimated: `80 + p * (70 ±0)` + // Minimum execution time: 3_843_000 picoseconds. + Weight::from_parts(3_947_000, 0) + .saturating_add(Weight::from_parts(0, 80)) + // Standard Error: 2_188 + .saturating_add(Weight::from_parts(1_212_360, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..59f97d2c8e5c3a6777c8077a1b20e75e7ca69f1a --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -0,0 +1,45 @@ +// 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 . + +pub mod block_weights; +pub mod cumulus_pallet_xcmp_queue; +pub mod extrinsic_weights; +pub mod frame_system; +pub mod pallet_asset_conversion; +pub mod pallet_assets_foreign; +pub mod pallet_assets_local; +pub mod pallet_assets_pool; +pub mod pallet_balances; +pub mod pallet_collator_selection; +pub mod pallet_multisig; +pub mod pallet_nft_fractionalization; +pub mod pallet_nfts; +pub mod pallet_proxy; +pub mod pallet_session; +pub mod pallet_timestamp; +pub mod pallet_uniques; +pub mod pallet_utility; +pub mod pallet_xcm; +pub mod pallet_xcm_bridge_hub_router_to_rococo; +pub mod pallet_xcm_bridge_hub_router_to_wococo; +pub mod paritydb_weights; +pub mod rocksdb_weights; +pub mod xcm; + +pub use block_weights::constants::BlockExecutionWeight; +pub use extrinsic_weights::constants::ExtrinsicBaseWeight; +pub use paritydb_weights::constants::ParityDbWeight; +pub use rocksdb_weights::constants::RocksDbWeight; 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 new file mode 100644 index 0000000000000000000000000000000000000000..4514fbfa8763ad40a65ad604eadde797c6f6bf9b --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs @@ -0,0 +1,155 @@ +// 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` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/cumulus/.git/.artifacts/bench.json +// --pallet=pallet_asset_conversion +// --chain=asset-hub-rococo-dev +// --header=./file_header.txt +// --output=./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`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion::WeightInfo for WeightInfo { + /// Storage: `AssetConversion::Pools` (r:1 w:1) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) + /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn create_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `480` + // Estimated: `6196` + // Minimum execution time: 88_484_000 picoseconds. + Weight::from_parts(92_964_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// 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:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn add_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1117` + // Estimated: `7404` + // Minimum execution time: 153_015_000 picoseconds. + Weight::from_parts(157_018_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// 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:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn remove_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `7404` + // Minimum execution time: 141_726_000 picoseconds. + Weight::from_parts(147_865_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn swap_exact_tokens_for_tokens() -> Weight { + // Proof Size summary in bytes: + // Measured: `1148` + // Estimated: `13818` + // Minimum execution time: 168_619_000 picoseconds. + Weight::from_parts(174_283_000, 0) + .saturating_add(Weight::from_parts(0, 13818)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn swap_tokens_for_exact_tokens() -> Weight { + // Proof Size summary in bytes: + // Measured: `1148` + // Estimated: `13818` + // Minimum execution time: 171_565_000 picoseconds. + Weight::from_parts(173_702_000, 0) + .saturating_add(Weight::from_parts(0, 13818)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs new file mode 100644 index 0000000000000000000000000000000000000000..5148edb0ee9e2c5f97c9c0afe830e0f87f2ac92f --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_foreign.rs @@ -0,0 +1,534 @@ +// 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_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/cumulus/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_assets::WeightInfo for WeightInfo { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `4273` + // Minimum execution time: 30_485_000 picoseconds. + Weight::from_parts(31_007_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `4273` + // Minimum execution time: 12_991_000 picoseconds. + Weight::from_parts(13_304_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn start_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `4273` + // Minimum execution time: 15_689_000 picoseconds. + Weight::from_parts(16_063_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: ForeignAssets Asset (r:1 w:1) + /// Proof: ForeignAssets Asset (max_values: None, max_size: Some(808), added: 3283, mode: MaxEncodedLen) + /// Storage: ForeignAssets Account (r:1001 w:1000) + /// Proof: ForeignAssets Account (max_values: None, max_size: Some(732), added: 3207, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `c` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. + fn destroy_accounts(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + c * (208 ±0)` + // Estimated: `4273 + c * (3207 ±0)` + // Minimum execution time: 18_533_000 picoseconds. + Weight::from_parts(18_791_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + // Standard Error: 5_059 + .saturating_add(Weight::from_parts(12_049_659, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 3207).saturating_mul(c.into())) + } + /// Storage: ForeignAssets Asset (r:1 w:1) + /// Proof: ForeignAssets Asset (max_values: None, max_size: Some(808), added: 3283, mode: MaxEncodedLen) + /// Storage: ForeignAssets Approvals (r:1001 w:1000) + /// Proof: ForeignAssets Approvals (max_values: None, max_size: Some(746), added: 3221, mode: MaxEncodedLen) + /// The range of component `a` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy_approvals(a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `413 + a * (86 ±0)` + // Estimated: `4273 + a * (3221 ±0)` + // Minimum execution time: 20_028_000 picoseconds. + Weight::from_parts(20_148_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + // Standard Error: 3_401 + .saturating_add(Weight::from_parts(13_897_319, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 3221).saturating_mul(a.into())) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Metadata` (r:1 w:0) + /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`) + fn finish_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 15_949_000 picoseconds. + Weight::from_parts(16_241_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 27_156_000 picoseconds. + Weight::from_parts(28_182_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `4273` + // Minimum execution time: 33_503_000 picoseconds. + Weight::from_parts(33_860_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `7404` + // Minimum execution time: 45_065_000 picoseconds. + Weight::from_parts(45_856_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r: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: `350` + // Estimated: `7404` + // Minimum execution time: 39_913_000 picoseconds. + Weight::from_parts(40_791_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `7404` + // Minimum execution time: 45_337_000 picoseconds. + Weight::from_parts(45_980_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:0) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `4273` + // Minimum execution time: 19_012_000 picoseconds. + Weight::from_parts(19_326_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:0) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `4273` + // Minimum execution time: 18_656_000 picoseconds. + Weight::from_parts(19_205_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn freeze_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `4273` + // Minimum execution time: 15_440_000 picoseconds. + Weight::from_parts(15_825_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn thaw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `4273` + // Minimum execution time: 15_465_000 picoseconds. + Weight::from_parts(15_769_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Metadata` (r:1 w:0) + /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 16_579_000 picoseconds. + Weight::from_parts(16_931_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 15_138_000 picoseconds. + Weight::from_parts(15_435_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: ForeignAssets Asset (r:1 w:0) + /// Proof: ForeignAssets Asset (max_values: None, max_size: Some(808), added: 3283, mode: MaxEncodedLen) + /// Storage: ForeignAssets Metadata (r:1 w:1) + /// Proof: ForeignAssets Metadata (max_values: None, max_size: Some(738), added: 3213, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 29_846_000 picoseconds. + Weight::from_parts(31_607_649, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:0) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Metadata` (r:1 w:1) + /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `406` + // Estimated: `4273` + // Minimum execution time: 30_582_000 picoseconds. + Weight::from_parts(31_008_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: ForeignAssets Asset (r:1 w:0) + /// Proof: ForeignAssets Asset (max_values: None, max_size: Some(808), added: 3283, mode: MaxEncodedLen) + /// Storage: ForeignAssets Metadata (r:1 w:1) + /// Proof: ForeignAssets Metadata (max_values: None, max_size: Some(738), added: 3213, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `81` + // Estimated: `4273` + // Minimum execution time: 14_186_000 picoseconds. + Weight::from_parts(14_717_332, 0) + .saturating_add(Weight::from_parts(0, 4273)) + // Standard Error: 517 + .saturating_add(Weight::from_parts(2_595, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:0) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Metadata` (r:1 w:1) + /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`) + fn force_clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `406` + // Estimated: `4273` + // Minimum execution time: 29_499_000 picoseconds. + Weight::from_parts(29_918_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn force_asset_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 13_815_000 picoseconds. + Weight::from_parts(14_138_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Approvals` (r:1 w:1) + /// Proof: `ForeignAssets::Approvals` (`max_values`: None, `max_size`: Some(746), added: 3221, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `4273` + // Minimum execution time: 33_029_000 picoseconds. + Weight::from_parts(33_524_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Approvals` (r:1 w:1) + /// Proof: `ForeignAssets::Approvals` (`max_values`: None, `max_size`: Some(746), added: 3221, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `520` + // Estimated: `7404` + // Minimum execution time: 63_205_000 picoseconds. + Weight::from_parts(64_078_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Approvals` (r:1 w:1) + /// Proof: `ForeignAssets::Approvals` (`max_values`: None, `max_size`: Some(746), added: 3221, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `446` + // Estimated: `4273` + // Minimum execution time: 34_948_000 picoseconds. + Weight::from_parts(35_484_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Approvals` (r:1 w:1) + /// Proof: `ForeignAssets::Approvals` (`max_values`: None, `max_size`: Some(746), added: 3221, mode: `MaxEncodedLen`) + fn force_cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `446` + // Estimated: `4273` + // Minimum execution time: 35_722_000 picoseconds. + Weight::from_parts(36_266_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 15_855_000 picoseconds. + Weight::from_parts(16_182_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `345` + // Estimated: `4273` + // Minimum execution time: 34_984_000 picoseconds. + Weight::from_parts(35_512_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4273` + // Minimum execution time: 33_041_000 picoseconds. + Weight::from_parts(34_124_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `471` + // Estimated: `4273` + // Minimum execution time: 31_728_000 picoseconds. + Weight::from_parts(32_012_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `401` + // Estimated: `4273` + // Minimum execution time: 29_432_000 picoseconds. + Weight::from_parts(29_968_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ForeignAssets::Asset` (r:1 w:0) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `350` + // Estimated: `4273` + // Minimum execution time: 18_827_000 picoseconds. + Weight::from_parts(19_172_000, 0) + .saturating_add(Weight::from_parts(0, 4273)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs new file mode 100644 index 0000000000000000000000000000000000000000..4ee235830aed23f9b6c6743a90aa5095bf6f9ed9 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_local.rs @@ -0,0 +1,531 @@ +// 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_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_assets +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_assets::WeightInfo for WeightInfo { + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3675` + // Minimum execution time: 26_510_000 picoseconds. + Weight::from_parts(27_332_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3675` + // Minimum execution time: 10_899_000 picoseconds. + Weight::from_parts(11_395_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn start_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 13_593_000 picoseconds. + Weight::from_parts(14_108_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1001 w:1000) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1000 w:1000) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. + fn destroy_accounts(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + c * (208 ±0)` + // Estimated: `3675 + c * (2609 ±0)` + // Minimum execution time: 16_216_000 picoseconds. + Weight::from_parts(16_636_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 9_346 + .saturating_add(Weight::from_parts(15_306_152, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1001 w:1000) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy_approvals(a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `414 + a * (86 ±0)` + // Estimated: `3675 + a * (2623 ±0)` + // Minimum execution time: 16_745_000 picoseconds. + Weight::from_parts(17_247_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(Weight::from_parts(15_634_963, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn finish_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(14_721_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 24_121_000 picoseconds. + Weight::from_parts(25_023_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 31_414_000 picoseconds. + Weight::from_parts(32_235_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `6208` + // Minimum execution time: 43_114_000 picoseconds. + Weight::from_parts(44_106_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `6208` + // Minimum execution time: 37_954_000 picoseconds. + Weight::from_parts(38_772_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `6208` + // Minimum execution time: 43_051_000 picoseconds. + Weight::from_parts(44_003_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 17_048_000 picoseconds. + Weight::from_parts(17_614_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 16_705_000 picoseconds. + Weight::from_parts(17_581_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn freeze_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 13_284_000 picoseconds. + Weight::from_parts(13_735_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn thaw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 13_030_000 picoseconds. + Weight::from_parts(13_417_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 14_174_000 picoseconds. + Weight::from_parts(14_660_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 12_737_000 picoseconds. + Weight::from_parts(13_172_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 27_707_000 picoseconds. + Weight::from_parts(29_036_880, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 688 + .saturating_add(Weight::from_parts(2_426, 0).saturating_mul(n.into())) + // Standard Error: 688 + .saturating_add(Weight::from_parts(776, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `407` + // Estimated: `3675` + // Minimum execution time: 28_514_000 picoseconds. + Weight::from_parts(29_216_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3675` + // Minimum execution time: 12_452_000 picoseconds. + Weight::from_parts(13_095_356, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 275 + .saturating_add(Weight::from_parts(826, 0).saturating_mul(n.into())) + // Standard Error: 275 + .saturating_add(Weight::from_parts(808, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn force_clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `407` + // Estimated: `3675` + // Minimum execution time: 28_181_000 picoseconds. + Weight::from_parts(29_050_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn force_asset_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 12_253_000 picoseconds. + Weight::from_parts(12_545_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 31_084_000 picoseconds. + Weight::from_parts(32_052_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `521` + // Estimated: `6208` + // Minimum execution time: 61_756_000 picoseconds. + Weight::from_parts(62_740_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `447` + // Estimated: `3675` + // Minimum execution time: 33_370_000 picoseconds. + Weight::from_parts(34_127_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn force_cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `447` + // Estimated: `3675` + // Minimum execution time: 33_753_000 picoseconds. + Weight::from_parts(34_613_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 13_508_000 picoseconds. + Weight::from_parts(13_997_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `346` + // Estimated: `3675` + // Minimum execution time: 32_578_000 picoseconds. + Weight::from_parts(33_675_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 30_768_000 picoseconds. + Weight::from_parts(31_710_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `472` + // Estimated: `3675` + // Minimum execution time: 30_028_000 picoseconds. + Weight::from_parts(30_793_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `402` + // Estimated: `3675` + // Minimum execution time: 28_354_000 picoseconds. + Weight::from_parts(29_097_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 16_607_000 picoseconds. + Weight::from_parts(17_433_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs new file mode 100644 index 0000000000000000000000000000000000000000..df7ad2c633867aaf5fea7c737ed926cccb5e2c80 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_assets_pool.rs @@ -0,0 +1,531 @@ +// 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_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/cumulus/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --chain=asset-hub-rococo-dev +// --header=./file_header.txt +// --output=./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_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_assets::WeightInfo for WeightInfo { + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3675` + // Minimum execution time: 11_591_000 picoseconds. + Weight::from_parts(11_901_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3675` + // Minimum execution time: 11_184_000 picoseconds. + Weight::from_parts(11_640_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn start_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `314` + // Estimated: `3675` + // Minimum execution time: 13_809_000 picoseconds. + Weight::from_parts(14_226_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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:1001 w:1000) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1000 w:1000) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. + fn destroy_accounts(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + c * (208 ±0)` + // Estimated: `3675 + c * (2609 ±0)` + // Minimum execution time: 16_439_000 picoseconds. + Weight::from_parts(16_743_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 4_792 + .saturating_add(Weight::from_parts(14_463_991, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Approvals` (r:1001 w:1000) + /// Proof: `PoolAssets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy_approvals(a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `451 + a * (86 ±0)` + // Estimated: `3675 + a * (2623 ±0)` + // Minimum execution time: 17_218_000 picoseconds. + Weight::from_parts(17_585_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 2_056 + .saturating_add(Weight::from_parts(5_323_866, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:0) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn finish_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 13_848_000 picoseconds. + Weight::from_parts(14_325_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 24_904_000 picoseconds. + Weight::from_parts(25_607_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// 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`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `3675` + // Minimum execution time: 31_477_000 picoseconds. + Weight::from_parts(32_338_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// 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:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `6208` + // Minimum execution time: 42_994_000 picoseconds. + Weight::from_parts(44_041_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// 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:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `6208` + // Minimum execution time: 37_551_000 picoseconds. + Weight::from_parts(38_648_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// 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:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `6208` + // Minimum execution time: 42_829_000 picoseconds. + Weight::from_parts(44_029_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// 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`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `3675` + // Minimum execution time: 17_304_000 picoseconds. + Weight::from_parts(17_782_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// 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`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `3675` + // Minimum execution time: 17_040_000 picoseconds. + Weight::from_parts(17_698_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn freeze_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `314` + // Estimated: `3675` + // Minimum execution time: 13_238_000 picoseconds. + Weight::from_parts(13_810_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn thaw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `314` + // Estimated: `3675` + // Minimum execution time: 13_034_000 picoseconds. + Weight::from_parts(13_603_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:0) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 14_357_000 picoseconds. + Weight::from_parts(14_774_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 13_040_000 picoseconds. + Weight::from_parts(13_616_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:1) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 15_274_000 picoseconds. + Weight::from_parts(16_096_881, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 239 + .saturating_add(Weight::from_parts(1_631, 0).saturating_mul(n.into())) + // Standard Error: 239 + .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:1) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `444` + // Estimated: `3675` + // Minimum execution time: 15_900_000 picoseconds. + Weight::from_parts(16_526_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:1) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119` + // Estimated: `3675` + // Minimum execution time: 13_391_000 picoseconds. + Weight::from_parts(14_047_176, 0) + .saturating_add(Weight::from_parts(0, 3675)) + // Standard Error: 172 + .saturating_add(Weight::from_parts(2_617, 0).saturating_mul(n.into())) + // Standard Error: 172 + .saturating_add(Weight::from_parts(2_081, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Metadata` (r:1 w:1) + /// Proof: `PoolAssets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + fn force_clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `444` + // Estimated: `3675` + // Minimum execution time: 15_794_000 picoseconds. + Weight::from_parts(16_279_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn force_asset_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 12_538_000 picoseconds. + Weight::from_parts(13_080_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Approvals` (r:1 w:1) + /// Proof: `PoolAssets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `314` + // Estimated: `3675` + // Minimum execution time: 18_991_000 picoseconds. + Weight::from_parts(19_812_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Approvals` (r:1 w:1) + /// Proof: `PoolAssets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `558` + // Estimated: `6208` + // Minimum execution time: 50_336_000 picoseconds. + Weight::from_parts(51_441_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Approvals` (r:1 w:1) + /// Proof: `PoolAssets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `484` + // Estimated: `3675` + // Minimum execution time: 21_195_000 picoseconds. + Weight::from_parts(21_946_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Approvals` (r:1 w:1) + /// Proof: `PoolAssets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + fn force_cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `484` + // Estimated: `3675` + // Minimum execution time: 21_568_000 picoseconds. + Weight::from_parts(22_366_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 13_690_000 picoseconds. + Weight::from_parts(14_086_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// 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`) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 18_240_000 picoseconds. + Weight::from_parts(19_000_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// 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`) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `3675` + // Minimum execution time: 18_469_000 picoseconds. + Weight::from_parts(19_040_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// 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`) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `406` + // Estimated: `3675` + // Minimum execution time: 14_633_000 picoseconds. + Weight::from_parts(15_296_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// 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`) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `439` + // Estimated: `3675` + // Minimum execution time: 14_751_000 picoseconds. + Weight::from_parts(15_312_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PoolAssets::Asset` (r:1 w:0) + /// 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`) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `3675` + // Minimum execution time: 16_930_000 picoseconds. + Weight::from_parts(17_653_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs similarity index 56% rename from polkadot/runtime/polkadot/src/weights/pallet_balances.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs index 374718082615204d49f4e06c51a7579e64326d22..d373d0f8e651137360382a995db368db8eac1fed 100644 --- a/polkadot/runtime/polkadot/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs @@ -1,43 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// 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-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/production/polkadot-parachain // benchmark // pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_balances // --no-storage-info // --no-median-slopes // --no-min-squares -// --pallet=pallet_balances // --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,102 +50,102 @@ 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: 56_740_000 picoseconds. - Weight::from_parts(57_361_000, 0) + // Minimum execution time: 55_040_000 picoseconds. + Weight::from_parts(56_106_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: 42_767_000 picoseconds. - Weight::from_parts(43_195_000, 0) + // Minimum execution time: 41_342_000 picoseconds. + Weight::from_parts(41_890_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` + // Measured: `103` // Estimated: `3593` - // Minimum execution time: 17_405_000 picoseconds. - Weight::from_parts(17_754_000, 0) + // Minimum execution time: 14_723_000 picoseconds. + Weight::from_parts(15_182_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` + // Measured: `103` // Estimated: `3593` - // Minimum execution time: 24_580_000 picoseconds. - Weight::from_parts(25_063_000, 0) + // Minimum execution time: 22_073_000 picoseconds. + Weight::from_parts(22_638_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: 59_923_000 picoseconds. - Weight::from_parts(60_797_000, 0) + // Minimum execution time: 57_265_000 picoseconds. + Weight::from_parts(58_222_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: 52_587_000 picoseconds. - Weight::from_parts(53_496_000, 0) + // Minimum execution time: 51_485_000 picoseconds. + Weight::from_parts(52_003_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` + // Measured: `103` // Estimated: `3593` - // Minimum execution time: 20_257_000 picoseconds. - Weight::from_parts(20_977_000, 0) + // Minimum execution time: 17_460_000 picoseconds. + Weight::from_parts(17_849_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) + /// 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 * (135 ±0)` + // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 19_254_000 picoseconds. - Weight::from_parts(19_508_000, 0) + // Minimum execution time: 17_259_000 picoseconds. + Weight::from_parts(17_478_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 12_504 - .saturating_add(Weight::from_parts(16_053_923, 0).saturating_mul(u.into())) + // Standard Error: 16_756 + .saturating_add(Weight::from_parts(15_291_954, 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())) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_collator_selection.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_collator_selection.rs new file mode 100644 index 0000000000000000000000000000000000000000..d98abbbc2d3db26bb757597f9e859752cfa8ed88 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_collator_selection.rs @@ -0,0 +1,225 @@ +// 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_collator_selection` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_collator_selection +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_collator_selection`. +pub struct WeightInfo(PhantomData); +impl pallet_collator_selection::WeightInfo for WeightInfo { + /// Storage: `Session::NextKeys` (r:20 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::Invulnerables` (r:0 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// The range of component `b` is `[1, 20]`. + fn set_invulnerables(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `163 + b * (79 ±0)` + // Estimated: `1154 + b * (2555 ±0)` + // Minimum execution time: 15_408_000 picoseconds. + Weight::from_parts(13_068_592, 0) + .saturating_add(Weight::from_parts(0, 1154)) + // Standard Error: 7_395 + .saturating_add(Weight::from_parts(3_219_916, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 2555).saturating_mul(b.into())) + } + /// Storage: `Session::NextKeys` (r:1 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Candidates` (r:1 w:1) + /// Proof: `CollatorSelection::Candidates` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `b` is `[1, 19]`. + /// The range of component `c` is `[1, 99]`. + fn add_invulnerable(b: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `756 + b * (32 ±0) + c * (53 ±0)` + // Estimated: `6287 + b * (37 ±0) + c * (53 ±0)` + // Minimum execution time: 49_692_000 picoseconds. + Weight::from_parts(51_768_986, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 18_404 + .saturating_add(Weight::from_parts(55_676, 0).saturating_mul(b.into())) + // Standard Error: 3_488 + .saturating_add(Weight::from_parts(184_343, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 53).saturating_mul(c.into())) + } + /// Storage: `CollatorSelection::Candidates` (r:1 w:0) + /// Proof: `CollatorSelection::Candidates` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:1) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// The range of component `b` is `[5, 20]`. + fn remove_invulnerable(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119 + b * (32 ±0)` + // Estimated: `6287` + // Minimum execution time: 16_486_000 picoseconds. + Weight::from_parts(16_646_017, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 3_230 + .saturating_add(Weight::from_parts(148_941, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CollatorSelection::DesiredCandidates` (r:0 w:1) + /// Proof: `CollatorSelection::DesiredCandidates` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_desired_candidates() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_806_000 picoseconds. + Weight::from_parts(8_002_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CollatorSelection::CandidacyBond` (r:0 w:1) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + fn set_candidacy_bond() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_937_000 picoseconds. + Weight::from_parts(8_161_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CollatorSelection::Candidates` (r:1 w:1) + /// Proof: `CollatorSelection::Candidates` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::DesiredCandidates` (r:1 w:0) + /// Proof: `CollatorSelection::DesiredCandidates` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `Session::NextKeys` (r:1 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CollatorSelection::CandidacyBond` (r:1 w:0) + /// Proof: `CollatorSelection::CandidacyBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 99]`. + fn register_as_candidate(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `736 + c * (52 ±0)` + // Estimated: `6287 + c * (54 ±0)` + // Minimum execution time: 42_805_000 picoseconds. + Weight::from_parts(45_979_502, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_336 + .saturating_add(Weight::from_parts(221_049, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 54).saturating_mul(c.into())) + } + /// Storage: `CollatorSelection::Candidates` (r:1 w:1) + /// Proof: `CollatorSelection::Candidates` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// The range of component `c` is `[4, 100]`. + fn leave_intent(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `306 + c * (50 ±0)` + // Estimated: `6287` + // Minimum execution time: 34_814_000 picoseconds. + Weight::from_parts(36_371_520, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 2_391 + .saturating_add(Weight::from_parts(201_700, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:0 w:1) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn note_author() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 46_989_000 picoseconds. + Weight::from_parts(48_151_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `CollatorSelection::Candidates` (r:1 w:0) + /// Proof: `CollatorSelection::Candidates` (`max_values`: Some(1), `max_size`: Some(4802), added: 5297, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::LastAuthoredBlock` (r:100 w:0) + /// Proof: `CollatorSelection::LastAuthoredBlock` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `CollatorSelection::Invulnerables` (r:1 w:0) + /// Proof: `CollatorSelection::Invulnerables` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:97 w:97) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 100]`. + /// The range of component `c` is `[1, 100]`. + fn new_session(r: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2243 + c * (97 ±0) + r * (112 ±0)` + // Estimated: `6287 + c * (2519 ±0) + r * (2603 ±0)` + // Minimum execution time: 17_547_000 picoseconds. + Weight::from_parts(17_854_000, 0) + .saturating_add(Weight::from_parts(0, 6287)) + // Standard Error: 370_637 + .saturating_add(Weight::from_parts(15_798_857, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 2519).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(r.into())) + } +} diff --git a/polkadot/runtime/kusama/src/weights/pallet_multisig.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs similarity index 51% rename from polkadot/runtime/kusama/src/weights/pallet_multisig.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs index 108189c6ca1db47df39a19983dfbc79079470315..cf9c523f6571f48b37a300295d162960d82528bd 100644 --- a/polkadot/runtime/kusama/src/weights/pallet_multisig.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_multisig.rs @@ -1,43 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/production/polkadot-parachain // benchmark // pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_multisig // --no-storage-info // --no-median-slopes // --no-min-squares -// --pallet=pallet_multisig // --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,110 +55,110 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_299_000 picoseconds. - Weight::from_parts(14_368_762, 0) + // Minimum execution time: 13_714_000 picoseconds. + Weight::from_parts(14_440_231, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 5 - .saturating_add(Weight::from_parts(557, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(598, 0).saturating_mul(z.into())) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `301 + s * (2 ±0)` + // Measured: `262 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 45_147_000 picoseconds. - Weight::from_parts(34_161_081, 0) + // Minimum execution time: 44_768_000 picoseconds. + Weight::from_parts(33_662_218, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_022 - .saturating_add(Weight::from_parts(127_000, 0).saturating_mul(s.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_553, 0).saturating_mul(z.into())) + // Standard Error: 1_633 + .saturating_add(Weight::from_parts(128_927, 0).saturating_mul(s.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_543, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `320` + // Measured: `282` // Estimated: `6811` - // Minimum execution time: 29_650_000 picoseconds. - Weight::from_parts(20_868_716, 0) + // Minimum execution time: 29_745_000 picoseconds. + Weight::from_parts(20_559_891, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_323 - .saturating_add(Weight::from_parts(112_380, 0).saturating_mul(s.into())) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_440, 0).saturating_mul(z.into())) + // Standard Error: 914 + .saturating_add(Weight::from_parts(103_601, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_504, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `426 + s * (33 ±0)` + // Measured: `385 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 50_649_000 picoseconds. - Weight::from_parts(34_736_758, 0) + // Minimum execution time: 51_506_000 picoseconds. + Weight::from_parts(36_510_777, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_738 - .saturating_add(Weight::from_parts(182_282, 0).saturating_mul(s.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_824, 0).saturating_mul(z.into())) + // Standard Error: 2_183 + .saturating_add(Weight::from_parts(183_764, 0).saturating_mul(s.into())) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_653, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `301 + s * (2 ±0)` + // Measured: `263 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 32_162_000 picoseconds. - Weight::from_parts(33_215_652, 0) + // Minimum execution time: 31_072_000 picoseconds. + Weight::from_parts(32_408_621, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_093 - .saturating_add(Weight::from_parts(133_715, 0).saturating_mul(s.into())) + // Standard Error: 913 + .saturating_add(Weight::from_parts(121_410, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `320` + // Measured: `282` // Estimated: `6811` - // Minimum execution time: 18_073_000 picoseconds. - Weight::from_parts(19_038_713, 0) + // Minimum execution time: 18_301_000 picoseconds. + Weight::from_parts(18_223_547, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 681 - .saturating_add(Weight::from_parts(111_279, 0).saturating_mul(s.into())) + // Standard Error: 747 + .saturating_add(Weight::from_parts(114_584, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `492 + s * (1 ±0)` + // Measured: `454 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 33_867_000 picoseconds. - Weight::from_parts(34_896_470, 0) + // Minimum execution time: 32_107_000 picoseconds. + Weight::from_parts(33_674_827, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_002 - .saturating_add(Weight::from_parts(116_935, 0).saturating_mul(s.into())) + // Standard Error: 1_220 + .saturating_add(Weight::from_parts(122_011, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nft_fractionalization.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nft_fractionalization.rs new file mode 100644 index 0000000000000000000000000000000000000000..97cec5d82ecd0635e5032f50a887c6766c80d2a2 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nft_fractionalization.rs @@ -0,0 +1,115 @@ +// 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_nft_fractionalization` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_nft_fractionalization +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_nft_fractionalization`. +pub struct WeightInfo(PhantomData); +impl pallet_nft_fractionalization::WeightInfo for WeightInfo { + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: `NftFractionalization::NftToAsset` (r:0 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn fractionalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `462` + // Estimated: `4326` + // Minimum execution time: 178_501_000 picoseconds. + Weight::from_parts(180_912_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) + /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + fn unify() -> Weight { + // Proof Size summary in bytes: + // Measured: `1275` + // Estimated: `4326` + // Minimum execution time: 125_253_000 picoseconds. + Weight::from_parts(128_238_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(10)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nfts.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nfts.rs new file mode 100644 index 0000000000000000000000000000000000000000..277cfd1747bf68a745ee2cd021be05381554ac9a --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_nfts.rs @@ -0,0 +1,773 @@ +// 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_nfts` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_nfts +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_nfts`. +pub struct WeightInfo(PhantomData); +impl pallet_nfts::WeightInfo for WeightInfo { + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `179` + // Estimated: `3549` + // Minimum execution time: 39_124_000 picoseconds. + Weight::from_parts(39_975_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:1) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3549` + // Minimum execution time: 23_444_000 picoseconds. + Weight::from_parts(23_857_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// The range of component `m` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32204 + a * (366 ±0)` + // Estimated: `2523990 + a * (2954 ±0)` + // Minimum execution time: 1_224_365_000 picoseconds. + Weight::from_parts(1_281_136_346, 0) + .saturating_add(Weight::from_parts(0, 2523990)) + // Standard Error: 10_484 + .saturating_add(Weight::from_parts(6_910_740, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1004)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1005)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) + } + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `455` + // Estimated: `4326` + // Minimum execution time: 50_489_000 picoseconds. + Weight::from_parts(51_045_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + fn force_mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `455` + // Estimated: `4326` + // Minimum execution time: 49_146_000 picoseconds. + Weight::from_parts(49_756_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `564` + // Estimated: `4326` + // Minimum execution time: 56_059_000 picoseconds. + Weight::from_parts(57_162_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `593` + // Estimated: `4326` + // Minimum execution time: 42_406_000 picoseconds. + Weight::from_parts(43_187_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:5000 w:5000) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `763 + i * (108 ±0)` + // Estimated: `3549 + i * (3336 ±0)` + // Minimum execution time: 16_960_000 picoseconds. + Weight::from_parts(17_167_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + // Standard Error: 24_110 + .saturating_add(Weight::from_parts(18_046_970, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn lock_item_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3534` + // Minimum execution time: 21_023_000 picoseconds. + Weight::from_parts(21_409_000, 0) + .saturating_add(Weight::from_parts(0, 3534)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn unlock_item_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3534` + // Minimum execution time: 20_706_000 picoseconds. + Weight::from_parts(21_030_000, 0) + .saturating_add(Weight::from_parts(0, 3534)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn lock_collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_449_000 picoseconds. + Weight::from_parts(17_804_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `388` + // Estimated: `3549` + // Minimum execution time: 22_958_000 picoseconds. + Weight::from_parts(23_499_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `369` + // Estimated: `6078` + // Minimum execution time: 40_105_000 picoseconds. + Weight::from_parts(40_800_000, 0) + .saturating_add(Weight::from_parts(0, 6078)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:2) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn force_collection_owner() -> Weight { + // Proof Size summary in bytes: + // Measured: `311` + // Estimated: `3549` + // Minimum execution time: 17_832_000 picoseconds. + Weight::from_parts(18_297_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn force_collection_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3549` + // Minimum execution time: 15_027_000 picoseconds. + Weight::from_parts(15_370_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn lock_item_properties() -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3534` + // Minimum execution time: 19_912_000 picoseconds. + Weight::from_parts(20_258_000, 0) + .saturating_add(Weight::from_parts(0, 3534)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn set_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `539` + // Estimated: `3944` + // Minimum execution time: 50_138_000 picoseconds. + Weight::from_parts(50_971_000, 0) + .saturating_add(Weight::from_parts(0, 3944)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn force_set_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `344` + // Estimated: `3944` + // Minimum execution time: 26_385_000 picoseconds. + Weight::from_parts(27_086_000, 0) + .saturating_add(Weight::from_parts(0, 3944)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn clear_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `983` + // Estimated: `3944` + // Minimum execution time: 45_687_000 picoseconds. + Weight::from_parts(47_107_000, 0) + .saturating_add(Weight::from_parts(0, 3944)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) + fn approve_item_attributes() -> Weight { + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `4466` + // Minimum execution time: 18_065_000 picoseconds. + Weight::from_parts(18_371_000, 0) + .saturating_add(Weight::from_parts(0, 4466)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1001 w:1000) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn cancel_item_attributes_approval(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `760 + n * (398 ±0)` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 26_680_000 picoseconds. + Weight::from_parts(27_010_000, 0) + .saturating_add(Weight::from_parts(0, 4466)) + // Standard Error: 6_351 + .saturating_add(Weight::from_parts(6_584_290, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn set_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `539` + // Estimated: `3812` + // Minimum execution time: 42_038_000 picoseconds. + Weight::from_parts(42_758_000, 0) + .saturating_add(Weight::from_parts(0, 3812)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `849` + // Estimated: `3812` + // Minimum execution time: 40_220_000 picoseconds. + Weight::from_parts(41_026_000, 0) + .saturating_add(Weight::from_parts(0, 3812)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + fn set_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `398` + // Estimated: `3759` + // Minimum execution time: 38_135_000 picoseconds. + Weight::from_parts(38_561_000, 0) + .saturating_add(Weight::from_parts(0, 3759)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + fn clear_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `716` + // Estimated: `3759` + // Minimum execution time: 37_583_000 picoseconds. + Weight::from_parts(38_215_000, 0) + .saturating_add(Weight::from_parts(0, 3759)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `410` + // Estimated: `4326` + // Minimum execution time: 21_405_000 picoseconds. + Weight::from_parts(21_803_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 18_713_000 picoseconds. + Weight::from_parts(19_185_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn clear_all_transfer_approvals() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 17_803_000 picoseconds. + Weight::from_parts(18_270_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_accept_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3517` + // Minimum execution time: 15_982_000 picoseconds. + Weight::from_parts(16_700_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn set_collection_max_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 19_501_000 picoseconds. + Weight::from_parts(19_785_000, 0) + .saturating_add(Weight::from_parts(0, 3549)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn update_mint_settings() -> Weight { + // Proof Size summary in bytes: + // Measured: `323` + // Estimated: `3538` + // Minimum execution time: 18_914_000 picoseconds. + Weight::from_parts(19_292_000, 0) + .saturating_add(Weight::from_parts(0, 3538)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + fn set_price() -> Weight { + // Proof Size summary in bytes: + // Measured: `518` + // Estimated: `4326` + // Minimum execution time: 24_625_000 picoseconds. + Weight::from_parts(25_257_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:2) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + fn buy_item() -> Weight { + // Proof Size summary in bytes: + // Measured: `705` + // Estimated: `4326` + // Minimum execution time: 50_833_000 picoseconds. + Weight::from_parts(52_161_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// The range of component `n` is `[0, 10]`. + fn pay_tips(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_220_000 picoseconds. + Weight::from_parts(3_476_001, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 7_084 + .saturating_add(Weight::from_parts(3_844_820, 0).saturating_mul(n.into())) + } + /// Storage: `Nfts::Item` (r:2 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + fn create_swap() -> Weight { + // Proof Size summary in bytes: + // Measured: `494` + // Estimated: `7662` + // Minimum execution time: 21_983_000 picoseconds. + Weight::from_parts(22_746_000, 0) + .saturating_add(Weight::from_parts(0, 7662)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn cancel_swap() -> Weight { + // Proof Size summary in bytes: + // Measured: `513` + // Estimated: `4326` + // Minimum execution time: 20_875_000 picoseconds. + Weight::from_parts(21_465_000, 0) + .saturating_add(Weight::from_parts(0, 4326)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Nfts::Item` (r:2 w:2) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:2 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:4) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + fn claim_swap() -> Weight { + // Proof Size summary in bytes: + // Measured: `834` + // Estimated: `7662` + // Minimum execution time: 84_771_000 picoseconds. + Weight::from_parts(86_078_000, 0) + .saturating_add(Weight::from_parts(0, 7662)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(10)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 10]`. + fn mint_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `558` + // Estimated: `6078 + n * (2954 ±0)` + // Minimum execution time: 143_265_000 picoseconds. + Weight::from_parts(150_978_773, 0) + .saturating_add(Weight::from_parts(0, 6078)) + // Standard Error: 49_443 + .saturating_add(Weight::from_parts(31_888_255, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 10]`. + fn set_attributes_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `588` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 83_754_000 picoseconds. + Weight::from_parts(96_685_026, 0) + .saturating_add(Weight::from_parts(0, 4466)) + // Standard Error: 72_592 + .saturating_add(Weight::from_parts(30_914_858, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_proxy.rs new file mode 100644 index 0000000000000000000000000000000000000000..0e680011e79b512e123c19345eec8041c87763aa --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_proxy.rs @@ -0,0 +1,226 @@ +// 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_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_283_443, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_409 + .saturating_add(Weight::from_parts(32_123, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 37_572_000 picoseconds. + Weight::from_parts(37_045_756, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_896 + .saturating_add(Weight::from_parts(139_561, 0).saturating_mul(a.into())) + // Standard Error: 2_993 + .saturating_add(Weight::from_parts(73_270, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_066_000 picoseconds. + Weight::from_parts(24_711_403, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_626 + .saturating_add(Weight::from_parts(128_391, 0).saturating_mul(a.into())) + // Standard Error: 1_680 + .saturating_add(Weight::from_parts(23_124, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_162_000 picoseconds. + Weight::from_parts(23_928_058, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(152_299, 0).saturating_mul(a.into())) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(39_775, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 33_858_000 picoseconds. + Weight::from_parts(33_568_059, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_816 + .saturating_add(Weight::from_parts(134_400, 0).saturating_mul(a.into())) + // Standard Error: 1_876 + .saturating_add(Weight::from_parts(57_028, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_235_199, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_363 + .saturating_add(Weight::from_parts(41_435, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 25_186_000 picoseconds. + Weight::from_parts(26_823_133, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_259 + .saturating_add(Weight::from_parts(34_224, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 22_156_000 picoseconds. + Weight::from_parts(23_304_060, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(39_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `4706` + // Minimum execution time: 26_914_000 picoseconds. + Weight::from_parts(28_009_062, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_978 + .saturating_add(Weight::from_parts(12_255, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_281_000 picoseconds. + Weight::from_parts(24_392_989, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_943 + .saturating_add(Weight::from_parts(30_287, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_session.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_session.rs new file mode 100644 index 0000000000000000000000000000000000000000..6cfa66a4bea61e13fb4f176327aacfff800697bb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_session.rs @@ -0,0 +1,81 @@ +// 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_session` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_session +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_session`. +pub struct WeightInfo(PhantomData); +impl pallet_session::WeightInfo for WeightInfo { + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:1 w:1) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `270` + // Estimated: `3735` + // Minimum execution time: 16_932_000 picoseconds. + Weight::from_parts(17_357_000, 0) + .saturating_add(Weight::from_parts(0, 3735)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Session::NextKeys` (r:1 w:1) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::KeyOwner` (r:0 w:1) + /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn purge_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `3707` + // Minimum execution time: 12_157_000 picoseconds. + Weight::from_parts(12_770_000, 0) + .saturating_add(Weight::from_parts(0, 3707)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_timestamp.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs similarity index 59% rename from polkadot/runtime/polkadot/src/weights/pallet_timestamp.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs index 27d92d609fd46687d269a0cf2660120b722252b7..38e1fbd822b2309ee92e57b5599adef0e79d414c 100644 --- a/polkadot/runtime/polkadot/src/weights/pallet_timestamp.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_timestamp.rs @@ -1,43 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/production/polkadot-parachain // benchmark // pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_timestamp // --no-storage-info // --no-median-slopes // --no-min-squares -// --pallet=pallet_timestamp // --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,26 +50,26 @@ use core::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: Timestamp Now (r:1 w:1) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Aura::CurrentSlot` (r:1 w:0) + /// Proof: `Aura::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `345` + // Measured: `86` // Estimated: `1493` - // Minimum execution time: 10_314_000 picoseconds. - Weight::from_parts(10_644_000, 0) + // Minimum execution time: 9_313_000 picoseconds. + Weight::from_parts(9_775_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `128` + // Measured: `57` // Estimated: `0` - // Minimum execution time: 4_852_000 picoseconds. - Weight::from_parts(5_026_000, 0) + // Minimum execution time: 3_322_000 picoseconds. + Weight::from_parts(3_577_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_uniques.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_uniques.rs new file mode 100644 index 0000000000000000000000000000000000000000..c4e220b7facb17d6b8a53a8af195f3d22f14d9ef --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_uniques.rs @@ -0,0 +1,467 @@ +// 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_uniques` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_uniques +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_uniques`. +pub struct WeightInfo(PhantomData); +impl pallet_uniques::WeightInfo for WeightInfo { + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassAccount` (r:0 w:1) + /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3643` + // Minimum execution time: 28_845_000 picoseconds. + Weight::from_parts(29_675_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassAccount` (r:0 w:1) + /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3643` + // Minimum execution time: 13_492_000 picoseconds. + Weight::from_parts(14_049_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:1001 w:1000) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::InstanceMetadataOf` (r:1000 w:1000) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Attribute` (r:1000 w:1000) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassAccount` (r:0 w:1) + /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassMetadataOf` (r:0 w:1) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Account` (r:0 w:1000) + /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Uniques::CollectionMaxSupply` (r:0 w:1) + /// Proof: `Uniques::CollectionMaxSupply` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + /// The range of component `m` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy(n: u32, m: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `257 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` + // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` + // Minimum execution time: 2_920_070_000 picoseconds. + Weight::from_parts(2_983_862_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + // Standard Error: 36_415 + .saturating_add(Weight::from_parts(7_589_778, 0).saturating_mul(n.into())) + // Standard Error: 36_415 + .saturating_add(Weight::from_parts(479_496, 0).saturating_mul(m.into())) + // Standard Error: 36_415 + .saturating_add(Weight::from_parts(562_056, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) + } + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::CollectionMaxSupply` (r:1 w:0) + /// Proof: `Uniques::CollectionMaxSupply` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Account` (r:0 w:1) + /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 35_329_000 picoseconds. + Weight::from_parts(36_019_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Account` (r:0 w:1) + /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ItemPriceOf` (r:0 w:1) + /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `3643` + // Minimum execution time: 36_474_000 picoseconds. + Weight::from_parts(37_190_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Account` (r:0 w:2) + /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ItemPriceOf` (r:0 w:1) + /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `3643` + // Minimum execution time: 26_786_000 picoseconds. + Weight::from_parts(27_400_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:5000 w:5000) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `738 + i * (76 ±0)` + // Estimated: `3643 + i * (2597 ±0)` + // Minimum execution time: 14_546_000 picoseconds. + Weight::from_parts(14_831_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + // Standard Error: 24_362 + .saturating_add(Weight::from_parts(17_972_938, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(i.into())) + } + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `3643` + // Minimum execution time: 18_919_000 picoseconds. + Weight::from_parts(19_547_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `3643` + // Minimum execution time: 18_643_000 picoseconds. + Weight::from_parts(19_000_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn freeze_collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 13_530_000 picoseconds. + Weight::from_parts(14_165_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn thaw_collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 13_523_000 picoseconds. + Weight::from_parts(14_055_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassAccount` (r:0 w:2) + /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3643` + // Minimum execution time: 22_131_000 picoseconds. + Weight::from_parts(22_628_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 13_841_000 picoseconds. + Weight::from_parts(14_408_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassAccount` (r:0 w:1) + /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn force_item_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 16_954_000 picoseconds. + Weight::from_parts(17_482_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Attribute` (r:1 w:1) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + fn set_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `3652` + // Minimum execution time: 38_493_000 picoseconds. + Weight::from_parts(39_513_000, 0) + .saturating_add(Weight::from_parts(0, 3652)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Attribute` (r:1 w:1) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + fn clear_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `756` + // Estimated: `3652` + // Minimum execution time: 37_918_000 picoseconds. + Weight::from_parts(38_666_000, 0) + .saturating_add(Weight::from_parts(0, 3652)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + fn set_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `348` + // Estimated: `3652` + // Minimum execution time: 29_810_000 picoseconds. + Weight::from_parts(30_363_000, 0) + .saturating_add(Weight::from_parts(0, 3652)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `3652` + // Minimum execution time: 30_877_000 picoseconds. + Weight::from_parts(31_430_000, 0) + .saturating_add(Weight::from_parts(0, 3652)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:1) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + fn set_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 30_478_000 picoseconds. + Weight::from_parts(31_065_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + fn clear_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `473` + // Estimated: `3643` + // Minimum execution time: 29_582_000 picoseconds. + Weight::from_parts(30_160_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `428` + // Estimated: `3643` + // Minimum execution time: 19_328_000 picoseconds. + Weight::from_parts(19_866_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `461` + // Estimated: `3643` + // Minimum execution time: 19_131_000 picoseconds. + Weight::from_parts(19_569_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::OwnershipAcceptance` (r:1 w:1) + /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_accept_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3517` + // Minimum execution time: 15_212_000 picoseconds. + Weight::from_parts(15_691_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::CollectionMaxSupply` (r:1 w:1) + /// Proof: `Uniques::CollectionMaxSupply` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + fn set_collection_max_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 16_290_000 picoseconds. + Weight::from_parts(16_654_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Asset` (r:1 w:0) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ItemPriceOf` (r:0 w:1) + /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + fn set_price() -> Weight { + // Proof Size summary in bytes: + // Measured: `259` + // Estimated: `3587` + // Minimum execution time: 16_095_000 picoseconds. + Weight::from_parts(16_555_000, 0) + .saturating_add(Weight::from_parts(0, 3587)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Uniques::Asset` (r:1 w:1) + /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Uniques::ItemPriceOf` (r:1 w:1) + /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Class` (r:1 w:0) + /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) + /// Storage: `Uniques::Account` (r:0 w:2) + /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + fn buy_item() -> Weight { + // Proof Size summary in bytes: + // Measured: `540` + // Estimated: `3643` + // Minimum execution time: 35_506_000 picoseconds. + Weight::from_parts(36_305_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/polkadot/runtime/kusama/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs similarity index 63% rename from polkadot/runtime/kusama/src/weights/pallet_utility.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs index d6843617fe32d7749f89307c023212696dc55dd5..a82115b9d0937f2d224667383569596dbe8a236d 100644 --- a/polkadot/runtime/kusama/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs @@ -1,43 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/production/polkadot-parachain // benchmark // pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_utility // --no-storage-info // --no-median-slopes // --no-min-squares -// --pallet=pallet_utility // --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,18 +55,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_750_000 picoseconds. - Weight::from_parts(7_924_668, 0) + // Minimum execution time: 7_103_000 picoseconds. + Weight::from_parts(7_226_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_937 - .saturating_add(Weight::from_parts(5_116_413, 0).saturating_mul(c.into())) + // Standard Error: 2_732 + .saturating_add(Weight::from_parts(6_560_347, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_928_000 picoseconds. - Weight::from_parts(5_208_000, 0) + // Minimum execution time: 5_208_000 picoseconds. + Weight::from_parts(5_480_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -74,18 +74,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_747_000 picoseconds. - Weight::from_parts(12_311_060, 0) + // Minimum execution time: 7_070_000 picoseconds. + Weight::from_parts(1_321_270, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 4_311 - .saturating_add(Weight::from_parts(5_344_485, 0).saturating_mul(c.into())) + // Standard Error: 3_454 + .saturating_add(Weight::from_parts(6_864_640, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_012_000 picoseconds. - Weight::from_parts(9_239_000, 0) + // Minimum execution time: 9_255_000 picoseconds. + Weight::from_parts(9_683_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -93,10 +93,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_708_000 picoseconds. - Weight::from_parts(10_795_859, 0) + // Minimum execution time: 6_852_000 picoseconds. + Weight::from_parts(7_007_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_055 - .saturating_add(Weight::from_parts(5_143_833, 0).saturating_mul(c.into())) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(6_562_902, 0).saturating_mul(c.into())) } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..909d7f2890784a0f72477c6a8d9b329a357ea3e2 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -0,0 +1,290 @@ +// 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_xcm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_xcm +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./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_xcm`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 30_015_000 picoseconds. + Weight::from_parts(30_576_000, 0) + .saturating_add(Weight::from_parts(0, 3574)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 24_785_000 picoseconds. + Weight::from_parts(25_097_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn reserve_transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 18_561_000 picoseconds. + Weight::from_parts(19_121_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_298_000 picoseconds. + Weight::from_parts(9_721_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_default_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_912_000 picoseconds. + Weight::from_parts(3_262_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_subscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 35_127_000 picoseconds. + Weight::from_parts(36_317_000, 0) + .saturating_add(Weight::from_parts(0, 3574)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_unsubscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `326` + // Estimated: `3791` + // Minimum execution time: 36_634_000 picoseconds. + Weight::from_parts(37_983_000, 0) + .saturating_add(Weight::from_parts(0, 3791)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_940_000 picoseconds. + Weight::from_parts(3_085_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:4 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_supported_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `11052` + // Minimum execution time: 17_400_000 picoseconds. + Weight::from_parts(17_759_000, 0) + .saturating_add(Weight::from_parts(0, 11052)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:4 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notifiers() -> Weight { + // Proof Size summary in bytes: + // Measured: `166` + // Estimated: `11056` + // Minimum execution time: 17_287_000 picoseconds. + Weight::from_parts(17_678_000, 0) + .saturating_add(Weight::from_parts(0, 11056)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn already_notified_target() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `13538` + // Minimum execution time: 18_941_000 picoseconds. + Weight::from_parts(19_285_000, 0) + .saturating_add(Weight::from_parts(0, 13538)) + .saturating_add(T::DbWeight::get().reads(5)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_current_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `176` + // Estimated: `6116` + // Minimum execution time: 32_668_000 picoseconds. + Weight::from_parts(33_533_000, 0) + .saturating_add(Weight::from_parts(0, 6116)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn notify_target_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `8621` + // Minimum execution time: 9_182_000 picoseconds. + Weight::from_parts(9_498_000, 0) + .saturating_add(Weight::from_parts(0, 8621)) + .saturating_add(T::DbWeight::get().reads(3)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notify_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `11063` + // Minimum execution time: 17_519_000 picoseconds. + Weight::from_parts(17_943_000, 0) + .saturating_add(Weight::from_parts(0, 11063)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn migrate_and_notify_old_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `179` + // Estimated: `11069` + // Minimum execution time: 38_680_000 picoseconds. + Weight::from_parts(39_984_000, 0) + .saturating_add(Weight::from_parts(0, 11069)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs new file mode 100644 index 0000000000000000000000000000000000000000..3ce9e4e7d319c09b74559e7e72a8b9df44bb1031 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_rococo.rs @@ -0,0 +1,124 @@ +// 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_xcm_bridge_hub_router` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-guclnr1q-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: +// target/production/polkadot-parachain +// 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_xcm_bridge_hub_router +// --chain=asset-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --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_xcm_bridge_hub_router`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn on_initialize_when_non_congested() -> Weight { + // Proof Size summary in bytes: + // Measured: `232` + // Estimated: `3697` + // Minimum execution time: 10_861_000 picoseconds. + Weight::from_parts(11_253_000, 0) + .saturating_add(Weight::from_parts(0, 3697)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_initialize_when_congested() -> Weight { + // Proof Size summary in bytes: + // Measured: `169` + // Estimated: `3634` + // Minimum execution time: 5_807_000 picoseconds. + Weight::from_parts(6_018_000, 0) + .saturating_add(Weight::from_parts(0, 3634)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `117` + // Estimated: `1502` + // Minimum execution time: 11_479_000 picoseconds. + Weight::from_parts(11_831_000, 0) + .saturating_add(Weight::from_parts(0, 1502)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) + /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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 send_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `445` + // Estimated: `3910` + // Minimum execution time: 52_670_000 picoseconds. + Weight::from_parts(54_368_000, 0) + .saturating_add(Weight::from_parts(0, 3910)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs new file mode 100644 index 0000000000000000000000000000000000000000..1ee0e93371556d09b3a4a6bbf7f3fdb721fa20eb --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router_to_wococo.rs @@ -0,0 +1,124 @@ +// 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_xcm_bridge_hub_router` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-guclnr1q-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: +// target/production/polkadot-parachain +// 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_xcm_bridge_hub_router +// --chain=asset-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --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_xcm_bridge_hub_router`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ToWococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn on_initialize_when_non_congested() -> Weight { + // Proof Size summary in bytes: + // Measured: `198` + // Estimated: `3663` + // Minimum execution time: 10_936_000 picoseconds. + Weight::from_parts(11_432_000, 0) + .saturating_add(Weight::from_parts(0, 3663)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_initialize_when_congested() -> Weight { + // Proof Size summary in bytes: + // Measured: `150` + // Estimated: `3615` + // Minimum execution time: 5_165_000 picoseconds. + Weight::from_parts(5_356_000, 0) + .saturating_add(Weight::from_parts(0, 3615)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `ToWococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `83` + // Estimated: `1502` + // Minimum execution time: 11_420_000 picoseconds. + Weight::from_parts(11_946_000, 0) + .saturating_add(Weight::from_parts(0, 1502)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) + /// Storage: `ToWococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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 send_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `392` + // Estimated: `3857` + // Minimum execution time: 52_129_000 picoseconds. + Weight::from_parts(53_552_000, 0) + .saturating_add(Weight::from_parts(0, 3857)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/polkadot/runtime/kusama/constants/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs similarity index 100% rename from polkadot/runtime/kusama/constants/src/weights/paritydb_weights.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs diff --git a/polkadot/runtime/kusama/constants/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs similarity index 100% rename from polkadot/runtime/kusama/constants/src/weights/rocksdb_weights.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs diff --git a/polkadot/runtime/kusama/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs similarity index 61% rename from polkadot/runtime/kusama/src/weights/xcm/mod.rs rename to cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs index 5958abe40df94109fb3c4ee09b70a47edccda9da..22c2f2450b29642fce8eadbbca294b4aa90b2425 100644 --- a/polkadot/runtime/kusama/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs @@ -1,101 +1,79 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . mod pallet_xcm_benchmarks_fungible; mod pallet_xcm_benchmarks_generic; -use crate::Runtime; +use crate::{xcm_config::MaxAssetsIntoHolding, Runtime}; use frame_support::weights::Weight; +use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; +use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; use sp_std::prelude::*; use xcm::{latest::prelude::*, DoubleEncoded}; -use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; -use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; - -/// Types of asset supported by the Kusama runtime. -pub enum AssetTypes { - /// An asset backed by `pallet-balances`. - Balances, - /// Unknown asset. - Unknown, -} - -impl From<&MultiAsset> for AssetTypes { - fn from(asset: &MultiAsset) -> Self { - match asset { - MultiAsset { id: Concrete(MultiLocation { parents: 0, interior: Here }), .. } => - AssetTypes::Balances, - _ => AssetTypes::Unknown, - } - } -} - trait WeighMultiAssets { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight; + fn weigh_multi_assets(&self, weight: Weight) -> Weight; } -// Kusama only knows about one asset, the balances pallet. -const MAX_ASSETS: u64 = 1; +const MAX_ASSETS: u64 = 100; impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { + fn weigh_multi_assets(&self, weight: Weight) -> Weight { match self { - Self::Definite(assets) => assets - .inner() - .into_iter() - .map(From::from) - .map(|t| match t { - AssetTypes::Balances => balances_weight, - AssetTypes::Unknown => Weight::MAX, - }) - .fold(Weight::zero(), |acc, x| acc.saturating_add(x)), - // We don't support any NFTs on Kusama, so these two variants will always match - // only 1 kind of fungible asset. - Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight, - Self::Wild(AllCounted(count)) => - balances_weight.saturating_mul(MAX_ASSETS.min(*count as u64)), - Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS), + Self::Definite(assets) => weight.saturating_mul(assets.inner().iter().count() as u64), + Self::Wild(asset) => match asset { + All => weight.saturating_mul(MAX_ASSETS), + AllOf { fun, .. } => match fun { + WildFungibility::Fungible => weight, + // Magic number 2 has to do with the fact that we could have up to 2 times + // MaxAssetsIntoHolding in the worst-case scenario. + WildFungibility::NonFungible => + weight.saturating_mul((MaxAssetsIntoHolding::get() * 2) as u64), + }, + AllCounted(count) => weight.saturating_mul(MAX_ASSETS.min(*count as u64)), + AllOfCounted { count, .. } => weight.saturating_mul(MAX_ASSETS.min(*count as u64)), + }, } } } impl WeighMultiAssets for MultiAssets { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { - self.inner() - .into_iter() - .map(|m| >::from(m)) - .map(|t| match t { - AssetTypes::Balances => balances_weight, - AssetTypes::Unknown => Weight::MAX, - }) - .fold(Weight::zero(), |acc, x| acc.saturating_add(x)) + fn weigh_multi_assets(&self, weight: Weight) -> Weight { + weight.saturating_mul(self.inner().iter().count() as u64) } } -pub struct KusamaXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for KusamaXcmWeight { +pub struct AssetHubRococoXcmWeight(core::marker::PhantomData); +impl XcmWeightInfo for AssetHubRococoXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::withdraw_asset()) - } - fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { - // Kusama doesn't support ReserveAssetDeposited, so this benchmark has a default weight - assets.weigh_multi_assets(XcmBalancesWeight::::reserve_asset_deposited()) + assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) + } + // Currently there is no trusted reserve (`IsReserve = ()`), + // but we need this hack for `pallet_xcm::reserve_transfer_assets` + // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 + // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 + fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { + // TODO: if we change `IsReserve = ...` then use this line... + // TODO: or if remote weight estimation is fixed, then remove + // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 + let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); + hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::receive_teleported_asset()) + assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) } fn query_response( _query_id: &u64, @@ -106,19 +84,19 @@ impl XcmWeightInfo for KusamaXcmWeight { XcmGeneric::::query_response() } fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::transfer_asset()) + assets.weigh_multi_assets(XcmFungibleWeight::::transfer_asset()) } fn transfer_reserve_asset( assets: &MultiAssets, _dest: &MultiLocation, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::transfer_reserve_asset()) + assets.weigh_multi_assets(XcmFungibleWeight::::transfer_reserve_asset()) } fn transact( - _origin_kind: &OriginKind, + _origin_type: &OriginKind, _require_weight_at_most: &Weight, - _call: &DoubleEncoded, + _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() } @@ -149,17 +127,19 @@ impl XcmWeightInfo for KusamaXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::deposit_asset()) + // Hardcoded till the XCM pallet is fixed + let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); + let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); + hardcoded_weight.min(weight) } fn deposit_reserve_asset( assets: &MultiAssetFilter, _dest: &MultiLocation, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::deposit_reserve_asset()) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_reserve_asset()) } fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - // Kusama does not currently support exchange asset operations Weight::MAX } fn initiate_reserve_withdraw( @@ -167,14 +147,14 @@ impl XcmWeightInfo for KusamaXcmWeight { _reserve: &MultiLocation, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::initiate_reserve_withdraw()) + assets.weigh_multi_assets(XcmFungibleWeight::::initiate_reserve_withdraw()) } fn initiate_teleport( assets: &MultiAssetFilter, _dest: &MultiLocation, _xcm: &Xcm<()>, ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::initiate_teleport()) + assets.weigh_multi_assets(XcmFungibleWeight::::initiate_teleport()) } fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight { XcmGeneric::::report_holding() @@ -185,10 +165,10 @@ impl XcmWeightInfo for KusamaXcmWeight { fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } - fn set_error_handler(_xcm: &Xcm) -> Weight { + fn set_error_handler(_xcm: &Xcm) -> Weight { XcmGeneric::::set_error_handler() } - fn set_appendix(_xcm: &Xcm) -> Weight { + fn set_appendix(_xcm: &Xcm) -> Weight { XcmGeneric::::set_appendix() } fn clear_error() -> Weight { @@ -240,27 +220,21 @@ impl XcmWeightInfo for KusamaXcmWeight { XcmGeneric::::clear_transact_status() } fn universal_origin(_: &Junction) -> Weight { - // Kusama does not currently support universal origin operations - Weight::MAX + XcmGeneric::::universal_origin() } fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - // Kusama relay should not support export message operations Weight::MAX } fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Kusama does not currently support asset locking operations Weight::MAX } fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Kusama does not currently support asset locking operations Weight::MAX } fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Kusama does not currently support asset locking operations Weight::MAX } fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Kusama does not currently support asset locking operations Weight::MAX } fn set_fees_mode(_: &bool) -> Weight { @@ -280,11 +254,3 @@ impl XcmWeightInfo for KusamaXcmWeight { XcmGeneric::::unpaid_execution() } } - -#[test] -fn all_counted_has_a_sane_weight_upper_limit() { - let assets = MultiAssetFilter::Wild(AllCounted(4294967295)); - let weight = Weight::from_parts(1000, 1000); - - assert_eq!(assets.weigh_multi_assets(weight), weight * MAX_ASSETS); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs new file mode 100644 index 0000000000000000000000000000000000000000..9d95048c0ac2d9ec2486d81db326ca47cc9b331c --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -0,0 +1,190 @@ +// 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_xcm_benchmarks::fungible` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --template=./templates/xcm-bench-template.hbs +// --chain=asset-hub-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 +// --header=./file_header.txt +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_benchmarks::fungible`. +pub struct WeightInfo(PhantomData); +impl WeightInfo { + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + pub fn withdraw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 26_104_000 picoseconds. + Weight::from_parts(26_722_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + pub fn transfer_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `6196` + // Minimum execution time: 52_259_000 picoseconds. + Weight::from_parts(53_854_000, 6196) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn transfer_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `210` + // Estimated: `6196` + // Minimum execution time: 77_248_000 picoseconds. + Weight::from_parts(80_354_000, 6196) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: `Benchmark::Override` (r:0 w:0) + // Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn reserve_asset_deposited() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 500_000_000_000 picoseconds. + Weight::from_parts(500_000_000_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 482_070_000 picoseconds. + Weight::from_parts(490_269_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + pub fn receive_teleported_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_970_000 picoseconds. + Weight::from_parts(4_056_000, 0) + } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + pub fn deposit_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 26_324_000 picoseconds. + Weight::from_parts(26_985_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) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn deposit_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3593` + // Minimum execution time: 52_814_000 picoseconds. + Weight::from_parts(54_666_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_teleport() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 33_044_000 picoseconds. + Weight::from_parts(33_849_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs new file mode 100644 index 0000000000000000000000000000000000000000..2c51afde7b34afbf689d3a66838c5f67779b0444 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,339 @@ +// 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_xcm_benchmarks::generic` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --template=./templates/xcm-bench-template.hbs +// --chain=asset-hub-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 +// --header=./file_header.txt +// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_benchmarks::generic`. +pub struct WeightInfo(PhantomData); +impl WeightInfo { + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_holding() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 432_196_000 picoseconds. + Weight::from_parts(438_017_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + pub fn buy_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_223_000 picoseconds. + Weight::from_parts(4_412_000, 0) + } + // Storage: `PolkadotXcm::Queries` (r:1 w:0) + // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn query_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3568` + // Minimum execution time: 11_582_000 picoseconds. + Weight::from_parts(11_830_000, 3568) + .saturating_add(T::DbWeight::get().reads(1)) + } + pub fn transact() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_955_000 picoseconds. + Weight::from_parts(14_320_000, 0) + } + pub fn refund_surplus() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_423_000 picoseconds. + Weight::from_parts(4_709_000, 0) + } + pub fn set_error_handler() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_028_000 picoseconds. + Weight::from_parts(3_151_000, 0) + } + pub fn set_appendix() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_966_000 picoseconds. + Weight::from_parts(3_076_000, 0) + } + pub fn clear_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_971_000 picoseconds. + Weight::from_parts(3_119_000, 0) + } + pub fn descend_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_772_000 picoseconds. + Weight::from_parts(3_853_000, 0) + } + pub fn clear_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_940_000 picoseconds. + Weight::from_parts(3_050_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 27_734_000 picoseconds. + Weight::from_parts(28_351_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn claim_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `3625` + // Minimum execution time: 16_456_000 picoseconds. + Weight::from_parts(16_846_000, 3625) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn trap() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_974_000 picoseconds. + Weight::from_parts(3_108_000, 0) + } + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn subscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 29_823_000 picoseconds. + Weight::from_parts(30_776_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: `PolkadotXcm::VersionNotifyTargets` (r:0 w:1) + // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub fn unsubscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_966_000 picoseconds. + Weight::from_parts(5_157_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: 141_875_000 picoseconds. + Weight::from_parts(144_925_000, 0) + } + pub fn expect_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_147_000 picoseconds. + Weight::from_parts(13_420_000, 0) + } + pub fn expect_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_050_000 picoseconds. + Weight::from_parts(3_161_000, 0) + } + pub fn expect_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_930_000 picoseconds. + Weight::from_parts(3_077_000, 0) + } + pub fn expect_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_188_000 picoseconds. + Weight::from_parts(3_299_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn query_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 31_678_000 picoseconds. + Weight::from_parts(32_462_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + pub fn expect_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_638_000 picoseconds. + Weight::from_parts(5_756_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn report_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 27_556_000 picoseconds. + Weight::from_parts(28_240_000, 3574) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + pub fn clear_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_932_000 picoseconds. + Weight::from_parts(3_097_000, 0) + } + pub fn set_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_860_000 picoseconds. + Weight::from_parts(2_957_000, 0) + } + pub fn clear_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_886_000 picoseconds. + Weight::from_parts(3_015_000, 0) + } + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + pub fn universal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1489` + // Minimum execution time: 5_088_000 picoseconds. + Weight::from_parts(5_253_000, 1489) + .saturating_add(T::DbWeight::get().reads(1)) + } + pub fn set_fees_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_874_000 picoseconds. + Weight::from_parts(3_060_000, 0) + } + pub fn unpaid_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_029_000 picoseconds. + Weight::from_parts(3_158_000, 0) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs new file mode 100644 index 0000000000000000000000000000000000000000..6db4a78740576bbc066ca15c6a2f76806764d48f --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -0,0 +1,942 @@ +// 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::{ + AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, + ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, + RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, ToRococoXcmRouter, ToWococoXcmRouter, + TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, +}; +use assets_common::{ + local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, + matching::{FromSiblingParachain, IsForeignConcreteAsset}, +}; +use frame_support::{ + match_types, parameter_types, + traits::{ConstU32, Contains, Equals, Everything, Get, Nothing, PalletInfoAccess}, +}; +use frame_system::EnsureRoot; +use pallet_xcm::XcmPassthrough; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, +}; +use polkadot_parachain_primitives::primitives::Sibling; +use sp_runtime::traits::ConvertInto; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, + IsConcrete, LocalMint, LocationWithAssetFilters, NetworkExportTableItem, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, +}; +use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; + +#[cfg(feature = "runtime-benchmarks")] +use cumulus_primitives_core::ParaId; + +parameter_types! { + pub storage Flavor: RuntimeFlavor = RuntimeFlavor::default(); + pub const TokenLocation: MultiLocation = MultiLocation::parent(); + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorMultiLocation = + X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); + pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); + pub TrustBackedAssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); + pub ForeignAssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); + pub PoolAssetsPalletLocation: MultiLocation = + PalletInstance(::index() as u8).into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); +} + +/// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. +pub struct RelayNetwork; +impl Get> for RelayNetwork { + fn get() -> Option { + Some(Self::get()) + } +} +impl Get for RelayNetwork { + fn get() -> NetworkId { + match Flavor::get() { + RuntimeFlavor::Rococo => NetworkId::Rococo, + RuntimeFlavor::Wococo => NetworkId::Wococo, + } + } +} + +/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the parent `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, + // Different global consensus parachain sovereign account. + // (Used for over-bridge transfers and reserve processing) + GlobalConsensusParachainConvertsFor, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = CurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// `AssetId`/`Balance` converter for `PoolAssets`. +pub type TrustBackedAssetsConvertedConcreteId = + assets_common::TrustBackedAssetsConvertedConcreteId; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + TrustBackedAssetsConvertedConcreteId, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + LocalMint>, + // The account to use for tracking teleports. + CheckingAccount, +>; + +/// `AssetId/Balance` converter for `TrustBackedAssets` +pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< + ( + // Ignore `TrustBackedAssets` explicitly + StartsWith, + // Ignore assets that start explicitly with our `GlobalConsensus(NetworkId)`, means: + // - foreign assets from our consensus should be: `MultiLocation {parents: 1, + // X*(Parachain(xyz), ..)}` + // - foreign assets outside our consensus with the same `GlobalConsensus(NetworkId)` won't + // be accepted here + StartsWithExplicitGlobalConsensus, + ), + Balance, +>; + +/// Means for transacting foreign assets from different global consensus. +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + ForeignAssets, + // Use this currency when it is a fungible asset matching the given location or name: + ForeignAssetsConvertedConcreteId, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont need to check teleports here. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + +/// `AssetId`/`Balance` converter for `PoolAssets`. +pub type PoolAssetsConvertedConcreteId = + assets_common::PoolAssetsConvertedConcreteId; + +/// Means for transacting asset conversion pool assets on this chain. +pub type PoolFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + PoolAssets, + // Use this currency when it is a fungible asset matching the given location or name: + PoolAssetsConvertedConcreteId, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + LocalMint>, + // The account to use for tracking teleports. + CheckingAccount, +>; + +/// Means for transacting assets on this chain. +pub type AssetTransactors = + (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); + +/// Simple `MultiLocation` matcher for Local and Foreign asset `MultiLocation`. +pub struct LocalAndForeignAssetsMultiLocationMatcher; +impl MatchesLocalAndForeignAssetsMultiLocation for LocalAndForeignAssetsMultiLocationMatcher { + fn is_local(location: &MultiLocation) -> bool { + use assets_common::fungible_conversion::MatchesMultiLocation; + TrustBackedAssetsConvertedConcreteId::contains(location) + } + fn is_foreign(location: &MultiLocation) -> bool { + use assets_common::fungible_conversion::MatchesMultiLocation; + ForeignAssetsConvertedConcreteId::contains(location) + } +} +impl Contains for LocalAndForeignAssetsMultiLocationMatcher { + fn contains(location: &MultiLocation) -> bool { + Self::is_local(location) || Self::is_foreign(location) + } +} + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, +); + +parameter_types! { + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiver: Option = Authorship::author(); +} + +match_types! { + pub type ParentOrParentsPlurality: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Plurality { .. }) } + }; + pub type ParentOrSiblings: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(_) } + }; + pub type WithParentsZeroOrOne: impl Contains = { + MultiLocation { parents: 0, .. } | + MultiLocation { parents: 1, .. } + }; +} + +/// 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(&Flavor::key())) => + return true, + _ => (), + }; + + matches!( + call, + RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_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::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::DmpQueue(..) | + 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::ToWococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) | RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) + ) + } +} + +pub type Barrier = TrailingSetTopicAsId< + DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + // Allow XCMs with some computed origins to pass through. + WithComputedOrigin< + ( + // If the message is one that immediately attempts to pay for execution, then + // allow it. + AllowTopLevelPaidExecutionFrom, + // Parent, its pluralities (i.e. governance bodies) and BridgeHub get free + // execution. + AllowExplicitUnpaidExecutionFrom<( + ParentOrParentsPlurality, + Equals, + )>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, + ), + >, +>; + +/// Multiplier used for dedicated `TakeFirstAssetTrader` with `Assets` instance. +pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier< + Runtime, + WeightToFee, + pallet_assets::BalanceToAssetBalance, + TrustBackedAssetsInstance, +>; + +/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. +pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = + AssetFeeAsExistentialDepositMultiplier< + Runtime, + WeightToFee, + pallet_assets::BalanceToAssetBalance, + ForeignAssetsInstance, + >; + +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// +/// - ROC with the parent Relay Chain and sibling system parachains; and +/// - Sibling parachains' assets from where they originate (as `ForeignCreators`). +pub type TrustedTeleporters = ( + ConcreteAssetFromSystem, + IsForeignConcreteAsset>>, +); + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Asset Hub trusts only particular configured bridge locations as reserve locations. + // Asset Hub may _act_ as a reserve location for ROC and assets created under `pallet-assets`. + // Users must use teleport where allowed (e.g. ROC with the Relay Chain). + type IsReserve = ( + bridging::to_wococo::IsTrustedBridgedReserveLocationForConcreteAsset, + bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset, + ); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = WeightInfoBounds< + crate::weights::xcm::AssetHubRococoXcmWeight, + RuntimeCall, + MaxInstructions, + >; + type Trader = ( + UsingComponents>, + // This trader allows to pay with `is_sufficient=true` "Trust Backed" assets from dedicated + // `pallet_assets` instance - `Assets`. + cumulus_primitives_utility::TakeFirstAssetTrader< + AccountId, + AssetFeeAsExistentialDepositMultiplierFeeCharger, + TrustBackedAssetsConvertedConcreteId, + Assets, + cumulus_primitives_utility::XcmFeesTo32ByteAccount< + FungiblesTransactor, + AccountId, + XcmAssetFeesReceiver, + >, + >, + // This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated + // `pallet_assets` instance - `ForeignAssets`. + cumulus_primitives_utility::TakeFirstAssetTrader< + AccountId, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, + ForeignAssetsConvertedConcreteId, + ForeignAssets, + cumulus_primitives_utility::XcmFeesTo32ByteAccount< + ForeignFungiblesTransactor, + AccountId, + XcmAssetFeesReceiver, + >, + >, + ); + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot-sdk/pull/1234) merged + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = + (bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases); + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; +} + +/// Converts a local signed origin into an XCM multilocation. +/// Forms the basis for local origins sending/executing XCMs. +pub type LocalOriginToLocation = SignedToAccountId32; + +/// For routing XCM messages which do not cross local consensus boundary. +type LocalXcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = WithUniqueTopic<( + LocalXcmRouter, + // Router which wraps and sends xcm to BridgeHub to be delivered to the Wococo + // GlobalConsensus + ToWococoXcmRouter, + // Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo + // GlobalConsensus + ToRococoXcmRouter, +)>; + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parent.into()); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // We want to disallow users sending (arbitrary) XCMs from this chain. + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // We support local origins dispatching XCM executions in principle... + type ExecuteXcmOrigin = EnsureXcmOrigin; + // ... but disallow generic XCM execution. As a result only teleports and reserve transfers are + // allowed. + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + // Allow reserve based transfer to everywhere except for bridging, here we strictly check what + // assets are allowed. + type XcmReserveTransferFilter = ( + LocationWithAssetFilters, + bridging::to_rococo::AllowedReserveTransferAssets, + bridging::to_wococo::AllowedReserveTransferAssets, + ); + + type Weigher = WeightInfoBounds< + crate::weights::xcm::AssetHubRococoXcmWeight, + RuntimeCall, + MaxInstructions, + >; + 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 = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type WeightInfo = crate::weights::pallet_xcm::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +pub type ForeignCreatorsSovereignAccountOf = ( + SiblingParachainConvertsVia, + AccountId32Aliases, + ParentIsPreset, +); + +/// Simple conversion of `u32` into an `AssetId` for use in benchmarking. +pub struct XcmBenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> MultiLocation { + MultiLocation { parents: 1, interior: X1(Parachain(id)) } + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct BenchmarkMultiLocationConverter { + _phantom: sp_std::marker::PhantomData, +} + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion::BenchmarkHelper> + for BenchmarkMultiLocationConverter +where + SelfParaId: Get, +{ + fn asset_id(asset_id: u32) -> MultiLocation { + MultiLocation { + parents: 1, + interior: X3( + Parachain(SelfParaId::get().into()), + PalletInstance(::index() as u8), + GeneralIndex(asset_id.into()), + ), + } + } + fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box { + sp_std::boxed::Box::new(Self::asset_id(asset_id)) + } +} + +/// All configuration related to bridging +pub mod bridging { + use super::*; + use assets_common::matching; + use sp_std::collections::btree_set::BTreeSet; + + // common/shared parameters for Wococo/Rococo + parameter_types! { + pub SiblingBridgeHubParaId: u32 = match Flavor::get() { + RuntimeFlavor::Rococo => bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + RuntimeFlavor::Wococo => bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID, + }; + pub SiblingBridgeHub: MultiLocation = MultiLocation::new(1, X1(Parachain(SiblingBridgeHubParaId::get()))); + /// Router expects payment with this `AssetId`. + /// (`AssetId` has to be aligned with `BridgeTable`) + pub XcmBridgeHubRouterFeeAssetId: AssetId = TokenLocation::get().into(); + /// Price per byte - can be adjusted via governance `set_storage` call. + pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + } + + pub mod to_wococo { + use super::*; + + parameter_types! { + pub SiblingBridgeHubWithBridgeHubWococoInstance: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(SiblingBridgeHubParaId::get()), + PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX) + ) + ); + + pub const WococoNetwork: NetworkId = NetworkId::Wococo; + pub AssetHubWococo: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(WococoNetwork::get()), Parachain(bp_asset_hub_wococo::ASSET_HUB_WOCOCO_PARACHAIN_ID))); + pub WocLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(WococoNetwork::get()))); + + pub WocFromAssetHubWococo: (MultiAssetFilter, MultiLocation) = ( + Wild(AllOf { fun: WildFungible, id: Concrete(WocLocation::get()) }), + AssetHubWococo::get() + ); + + /// Set up exporters configuration. + /// `Option` represents static "base fee" which is used for total delivery fee calculation. + pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + NetworkExportTableItem::new( + WococoNetwork::get(), + Some(sp_std::vec![ + AssetHubWococo::get().interior.split_global().expect("invalid configuration for AssetHubWococo").1, + ]), + SiblingBridgeHub::get(), + // base delivery fee to local `BridgeHub` + Some(( + XcmBridgeHubRouterFeeAssetId::get(), + bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(), + ).into()) + ) + ]; + + /// Allowed assets for reserve transfer to `AssetHubWococo`. + pub AllowedReserveTransferAssetsToAssetHubWococo: sp_std::vec::Vec = sp_std::vec![ + // allow send only ROC + Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }), + // and nothing else + ]; + + /// Universal aliases + pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter( + sp_std::vec![ + (SiblingBridgeHubWithBridgeHubWococoInstance::get(), GlobalConsensus(WococoNetwork::get())) + ] + ); + } + + impl Contains<(MultiLocation, Junction)> for UniversalAliases { + fn contains(alias: &(MultiLocation, Junction)) -> bool { + UniversalAliases::get().contains(alias) + } + } + + pub type NetworkExportTable = xcm_builder::NetworkExportTable; + + /// Trusted reserve locations filter for `xcm_executor::Config::IsReserve`. + /// Locations from which the runtime accepts reserved assets. + pub type IsTrustedBridgedReserveLocationForConcreteAsset = + matching::IsTrustedBridgedReserveLocationForConcreteAsset< + UniversalLocation, + ( + // allow receive WOC from AssetHubWococo + xcm_builder::Case, + // and nothing else + ), + >; + + /// Allows to reserve transfer assets to `AssetHubWococo`. + pub type AllowedReserveTransferAssets = LocationWithAssetFilters< + Equals, + AllowedReserveTransferAssetsToAssetHubWococo, + >; + + impl Contains for ToWococoXcmRouter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::ToWococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) + ) + } + } + } + + pub mod to_rococo { + use super::*; + + parameter_types! { + pub SiblingBridgeHubWithBridgeHubRococoInstance: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(SiblingBridgeHubParaId::get()), + PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX) + ) + ); + + pub const RococoNetwork: NetworkId = NetworkId::Rococo; + pub AssetHubRococo: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(RococoNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID))); + pub RocLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(RococoNetwork::get()))); + + pub RocFromAssetHubRococo: (MultiAssetFilter, MultiLocation) = ( + Wild(AllOf { fun: WildFungible, id: Concrete(RocLocation::get()) }), + AssetHubRococo::get() + ); + + /// Set up exporters configuration. + /// `Option` represents static "base fee" which is used for total delivery fee calculation. + pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + NetworkExportTableItem::new( + RococoNetwork::get(), + Some(sp_std::vec![ + AssetHubRococo::get().interior.split_global().expect("invalid configuration for AssetHubRococo").1, + ]), + SiblingBridgeHub::get(), + // base delivery fee to local `BridgeHub` + Some(( + XcmBridgeHubRouterFeeAssetId::get(), + bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs::get(), + ).into()) + ) + ]; + + /// Allowed assets for reserve transfer to `AssetHubWococo`. + pub AllowedReserveTransferAssetsToAssetHubRococo: sp_std::vec::Vec = sp_std::vec![ + // allow send only WOC + Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }), + // and nothing else + ]; + + /// Universal aliases + pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter( + sp_std::vec![ + (SiblingBridgeHubWithBridgeHubRococoInstance::get(), GlobalConsensus(RococoNetwork::get())) + ] + ); + } + + impl Contains<(MultiLocation, Junction)> for UniversalAliases { + fn contains(alias: &(MultiLocation, Junction)) -> bool { + UniversalAliases::get().contains(alias) + } + } + + pub type NetworkExportTable = xcm_builder::NetworkExportTable; + + /// Reserve locations filter for `xcm_executor::Config::IsReserve`. + /// Locations from which the runtime accepts reserved assets. + pub type IsTrustedBridgedReserveLocationForConcreteAsset = + matching::IsTrustedBridgedReserveLocationForConcreteAsset< + UniversalLocation, + ( + // allow receive ROC from AssetHubRococo + xcm_builder::Case, + // and nothing else + ), + >; + + /// Allows to reserve transfer assets to `AssetHubRococo`. + pub type AllowedReserveTransferAssets = LocationWithAssetFilters< + Equals, + AllowedReserveTransferAssetsToAssetHubRococo, + >; + + impl Contains for ToRococoXcmRouter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } + ) + ) + } + } + } + + /// Benchmarks helper for bridging configuration. + #[cfg(feature = "runtime-benchmarks")] + pub struct BridgingBenchmarksHelper; + + #[cfg(feature = "runtime-benchmarks")] + impl BridgingBenchmarksHelper { + pub fn prepare_universal_alias() -> Option<(MultiLocation, Junction)> { + let alias = + to_wococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| { + match to_wococo::SiblingBridgeHubWithBridgeHubWococoInstance::get() + .eq(&location) + { + true => Some((location, junction)), + false => None, + } + }); + assert!(alias.is_some(), "we expect here BridgeHubRococo to Polkadot mapping at least"); + Some(alias.unwrap()) + } + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..7f48d576288394f57eaaacc78b536290386e3b37 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -0,0 +1,1157 @@ +// This file is part of Cumulus. + +// 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 the Rococo Assets Hub chain. + +use asset_hub_rococo_runtime::xcm_config::{ + AssetFeeAsExistentialDepositMultiplierFeeCharger, TokenLocation, + TrustBackedAssetsPalletLocation, +}; +pub use asset_hub_rococo_runtime::{ + xcm_config::{ + self, bridging, CheckingAccount, ForeignCreatorsSovereignAccountOf, LocationToAccountId, + XcmConfig, + }, + AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, + ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, + RuntimeCall, RuntimeEvent, RuntimeFlavor, SessionKeys, System, ToRococoXcmRouterInstance, + ToWococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, +}; +use asset_test_utils::{CollatorSessionKey, CollatorSessionKeys, ExtBuilder}; +use codec::{Decode, Encode}; +use cumulus_primitives_utility::ChargeWeightInFungibles; +use frame_support::{ + assert_noop, assert_ok, + traits::{fungibles::InspectEnumerable, Contains}, + weights::{Weight, WeightToFee as WeightToFeeT}, +}; +use parachains_common::{ + rococo::fee::WeightToFee, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, +}; +use sp_runtime::traits::MaybeEquivalence; +use xcm::latest::prelude::*; +use xcm_executor::traits::{Identity, JustTry, WeightTrader}; + +const ALICE: [u8; 32] = [1u8; 32]; +const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32]; + +type AssetIdForTrustBackedAssetsConvert = + assets_common::AssetIdForTrustBackedAssetsConvert; + +type RuntimeHelper = asset_test_utils::RuntimeHelper; + +fn collator_session_key(account: [u8; 32]) -> CollatorSessionKey { + CollatorSessionKey::new( + AccountId::from(account), + AccountId::from(account), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(account)) }, + ) +} + +fn collator_session_keys() -> CollatorSessionKeys { + CollatorSessionKeys::default().add(collator_session_key(ALICE)) +} + +#[test] +fn test_asset_xcm_trader() { + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + // We need root origin to create a sufficient asset + let minimum_asset_balance = 3333333_u128; + let local_asset_id = 1; + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + local_asset_id.into(), + AccountId::from(ALICE).into(), + true, + minimum_asset_balance + )); + + // We first mint enough asset for the account to exist for assets + assert_ok!(Assets::mint( + RuntimeHelper::origin_of(AccountId::from(ALICE)), + local_asset_id.into(), + AccountId::from(ALICE).into(), + minimum_asset_balance + )); + + // get asset id as multilocation + let asset_multilocation = + AssetIdForTrustBackedAssetsConvert::convert_back(&local_asset_id).unwrap(); + + // Set Alice as block author, who will receive fees + RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); + + // We are going to buy 4e9 weight + let bought = Weight::from_parts(4_000_000_000u64, 0); + + // Lets calculate amount needed + let asset_amount_needed = + AssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( + local_asset_id, + bought, + ) + .expect("failed to compute"); + + // Lets pay with: asset_amount_needed + asset_amount_extra + let asset_amount_extra = 100_u128; + let asset: MultiAsset = + (asset_multilocation, asset_amount_needed + asset_amount_extra).into(); + + let mut trader = ::Trader::new(); + let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; + + // Lets buy_weight and make sure buy_weight does not return an error + let unused_assets = trader.buy_weight(bought, asset.into(), &ctx).expect("Expected Ok"); + // Check whether a correct amount of unused assets is returned + assert_ok!( + unused_assets.ensure_contains(&(asset_multilocation, asset_amount_extra).into()) + ); + + // Drop trader + drop(trader); + + // Make sure author(Alice) has received the amount + assert_eq!( + Assets::balance(local_asset_id, AccountId::from(ALICE)), + minimum_asset_balance + asset_amount_needed + ); + + // We also need to ensure the total supply increased + assert_eq!( + Assets::total_supply(local_asset_id), + minimum_asset_balance + asset_amount_needed + ); + }); +} + +#[test] +fn test_asset_xcm_trader_with_refund() { + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + // We need root origin to create a sufficient asset + // We set existential deposit to be identical to the one for Balances first + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + 1.into(), + AccountId::from(ALICE).into(), + true, + ExistentialDeposit::get() + )); + + // We first mint enough asset for the account to exist for assets + assert_ok!(Assets::mint( + RuntimeHelper::origin_of(AccountId::from(ALICE)), + 1.into(), + AccountId::from(ALICE).into(), + ExistentialDeposit::get() + )); + + let mut trader = ::Trader::new(); + let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; + + // Set Alice as block author, who will receive fees + RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); + + // We are going to buy 4e9 weight + let bought = Weight::from_parts(4_000_000_000u64, 0); + + let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap(); + + // lets calculate amount needed + let amount_bought = WeightToFee::weight_to_fee(&bought); + + let asset: MultiAsset = (asset_multilocation, amount_bought).into(); + + // Make sure buy_weight does not return an error + assert_ok!(trader.buy_weight(bought, asset.clone().into(), &ctx)); + + // Make sure again buy_weight does return an error + // This assert relies on the fact, that we use `TakeFirstAssetTrader` in `WeightTrader` + // tuple chain, which cannot be called twice + assert_noop!(trader.buy_weight(bought, asset.into(), &ctx), XcmError::TooExpensive); + + // We actually use half of the weight + let weight_used = bought / 2; + + // Make sure refurnd works. + let amount_refunded = WeightToFee::weight_to_fee(&(bought - weight_used)); + + assert_eq!( + trader.refund_weight(bought - weight_used, &ctx), + Some((asset_multilocation, amount_refunded).into()) + ); + + // Drop trader + drop(trader); + + // We only should have paid for half of the bought weight + let fees_paid = WeightToFee::weight_to_fee(&weight_used); + + assert_eq!( + Assets::balance(1, AccountId::from(ALICE)), + ExistentialDeposit::get() + fees_paid + ); + + // We also need to ensure the total supply increased + assert_eq!(Assets::total_supply(1), ExistentialDeposit::get() + fees_paid); + }); +} + +#[test] +fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() { + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + // We need root origin to create a sufficient asset + // We set existential deposit to be identical to the one for Balances first + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + 1.into(), + AccountId::from(ALICE).into(), + true, + ExistentialDeposit::get() + )); + + let mut trader = ::Trader::new(); + let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; + + // Set Alice as block author, who will receive fees + RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); + + // We are going to buy small amount + let bought = Weight::from_parts(500_000_000u64, 0); + + let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap(); + + let amount_bought = WeightToFee::weight_to_fee(&bought); + + assert!( + amount_bought < ExistentialDeposit::get(), + "we are testing what happens when the amount does not exceed ED" + ); + + let asset: MultiAsset = (asset_multilocation, amount_bought).into(); + + // Buy weight should return an error + assert_noop!(trader.buy_weight(bought, asset.into(), &ctx), XcmError::TooExpensive); + + // not credited since the ED is higher than this value + assert_eq!(Assets::balance(1, AccountId::from(ALICE)), 0); + + // We also need to ensure the total supply did not increase + assert_eq!(Assets::total_supply(1), 0); + }); +} + +#[test] +fn test_that_buying_ed_refund_does_not_refund() { + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + // We need root origin to create a sufficient asset + // We set existential deposit to be identical to the one for Balances first + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + 1.into(), + AccountId::from(ALICE).into(), + true, + ExistentialDeposit::get() + )); + + let mut trader = ::Trader::new(); + let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; + + // Set Alice as block author, who will receive fees + RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); + + // We are gonna buy ED + let bought = Weight::from_parts(ExistentialDeposit::get().try_into().unwrap(), 0); + + let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap(); + + let amount_bought = WeightToFee::weight_to_fee(&bought); + + assert!( + amount_bought < ExistentialDeposit::get(), + "we are testing what happens when the amount does not exceed ED" + ); + + // We know we will have to buy at least ED, so lets make sure first it will + // fail with a payment of less than ED + let asset: MultiAsset = (asset_multilocation, amount_bought).into(); + assert_noop!(trader.buy_weight(bought, asset.into(), &ctx), XcmError::TooExpensive); + + // Now lets buy ED at least + let asset: MultiAsset = (asset_multilocation, ExistentialDeposit::get()).into(); + + // Buy weight should work + assert_ok!(trader.buy_weight(bought, asset.into(), &ctx)); + + // Should return None. We have a specific check making sure we dont go below ED for + // drop payment + assert_eq!(trader.refund_weight(bought, &ctx), None); + + // Drop trader + drop(trader); + + // Make sure author(Alice) has received the amount + assert_eq!(Assets::balance(1, AccountId::from(ALICE)), ExistentialDeposit::get()); + + // We also need to ensure the total supply increased + assert_eq!(Assets::total_supply(1), ExistentialDeposit::get()); + }); +} + +#[test] +fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() { + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + // Create a non-sufficient asset with specific existential deposit + let minimum_asset_balance = 1_000_000_u128; + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + 1.into(), + AccountId::from(ALICE).into(), + false, + minimum_asset_balance + )); + + // We first mint enough asset for the account to exist for assets + assert_ok!(Assets::mint( + RuntimeHelper::origin_of(AccountId::from(ALICE)), + 1.into(), + AccountId::from(ALICE).into(), + minimum_asset_balance + )); + + let mut trader = ::Trader::new(); + let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; + + // Set Alice as block author, who will receive fees + RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); + + // We are going to buy 4e9 weight + let bought = Weight::from_parts(4_000_000_000u64, 0); + + // lets calculate amount needed + let asset_amount_needed = WeightToFee::weight_to_fee(&bought); + + let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap(); + + let asset: MultiAsset = (asset_multilocation, asset_amount_needed).into(); + + // Make sure again buy_weight does return an error + assert_noop!(trader.buy_weight(bought, asset.into(), &ctx), XcmError::TooExpensive); + + // Drop trader + drop(trader); + + // Make sure author(Alice) has NOT received the amount + assert_eq!(Assets::balance(1, AccountId::from(ALICE)), minimum_asset_balance); + + // We also need to ensure the total supply NOT increased + assert_eq!(Assets::total_supply(1), minimum_asset_balance); + }); +} + +#[test] +fn test_assets_balances_api_works() { + use assets_common::runtime_api::runtime_decl_for_fungibles_api::FungiblesApi; + + ExtBuilder::::default() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + let local_asset_id = 1; + let foreign_asset_id_multilocation = + MultiLocation { parents: 1, interior: X2(Parachain(1234), GeneralIndex(12345)) }; + + // check before + assert_eq!(Assets::balance(local_asset_id, AccountId::from(ALICE)), 0); + assert_eq!( + ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)), + 0 + ); + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 0); + assert!(Runtime::query_account_balances(AccountId::from(ALICE)) + .unwrap() + .try_as::() + .unwrap() + .is_none()); + + // Drip some balance + use frame_support::traits::fungible::Mutate; + let some_currency = ExistentialDeposit::get(); + Balances::mint_into(&AccountId::from(ALICE), some_currency).unwrap(); + + // We need root origin to create a sufficient asset + let minimum_asset_balance = 3333333_u128; + assert_ok!(Assets::force_create( + RuntimeHelper::root_origin(), + local_asset_id.into(), + AccountId::from(ALICE).into(), + true, + minimum_asset_balance + )); + + // We first mint enough asset for the account to exist for assets + assert_ok!(Assets::mint( + RuntimeHelper::origin_of(AccountId::from(ALICE)), + local_asset_id.into(), + AccountId::from(ALICE).into(), + minimum_asset_balance + )); + + // create foreign asset + let foreign_asset_minimum_asset_balance = 3333333_u128; + assert_ok!(ForeignAssets::force_create( + RuntimeHelper::root_origin(), + foreign_asset_id_multilocation, + AccountId::from(SOME_ASSET_ADMIN).into(), + false, + foreign_asset_minimum_asset_balance + )); + + // We first mint enough asset for the account to exist for assets + assert_ok!(ForeignAssets::mint( + RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)), + foreign_asset_id_multilocation, + AccountId::from(ALICE).into(), + 6 * foreign_asset_minimum_asset_balance + )); + + // check after + assert_eq!( + Assets::balance(local_asset_id, AccountId::from(ALICE)), + minimum_asset_balance + ); + assert_eq!( + ForeignAssets::balance(foreign_asset_id_multilocation, AccountId::from(ALICE)), + 6 * minimum_asset_balance + ); + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), some_currency); + + let result: MultiAssets = Runtime::query_account_balances(AccountId::from(ALICE)) + .unwrap() + .try_into() + .unwrap(); + assert_eq!(result.len(), 3); + + // check currency + assert!(result.inner().iter().any(|asset| asset.eq( + &assets_common::fungible_conversion::convert_balance::( + some_currency + ) + .unwrap() + ))); + // check trusted asset + assert!(result.inner().iter().any(|asset| asset.eq(&( + AssetIdForTrustBackedAssetsConvert::convert_back(&local_asset_id).unwrap(), + minimum_asset_balance + ) + .into()))); + // check foreign asset + assert!(result.inner().iter().any(|asset| asset.eq(&( + Identity::convert_back(&foreign_asset_id_multilocation).unwrap(), + 6 * foreign_asset_minimum_asset_balance + ) + .into()))); + }); +} + +asset_test_utils::include_teleports_for_native_asset_works!( + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + CheckingAccount, + WeightToFee, + ParachainSystem, + collator_session_keys(), + ExistentialDeposit::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + 1000 +); + +asset_test_utils::include_teleports_for_foreign_assets_works!( + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + CheckingAccount, + WeightToFee, + ParachainSystem, + ForeignCreatorsSovereignAccountOf, + ForeignAssetsInstance, + collator_session_keys(), + ExistentialDeposit::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }) +); + +asset_test_utils::include_asset_transactor_transfer_with_local_consensus_currency_works!( + Runtime, + XcmConfig, + collator_session_keys(), + ExistentialDeposit::get(), + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + assert!(ForeignAssets::asset_ids().collect::>().is_empty()); + }), + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + assert!(ForeignAssets::asset_ids().collect::>().is_empty()); + }) +); + +asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!( + asset_transactor_transfer_with_trust_backed_assets_works, + Runtime, + XcmConfig, + TrustBackedAssetsInstance, + AssetIdForTrustBackedAssets, + AssetIdForTrustBackedAssetsConvert, + collator_session_keys(), + ExistentialDeposit::get(), + 12345, + Box::new(|| { + assert!(ForeignAssets::asset_ids().collect::>().is_empty()); + }), + Box::new(|| { + assert!(ForeignAssets::asset_ids().collect::>().is_empty()); + }) +); + +asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_works!( + asset_transactor_transfer_with_foreign_assets_works, + Runtime, + XcmConfig, + ForeignAssetsInstance, + MultiLocation, + JustTry, + collator_session_keys(), + ExistentialDeposit::get(), + MultiLocation { parents: 1, interior: X2(Parachain(1313), GeneralIndex(12345)) }, + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + }), + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + }) +); + +asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works!( + Runtime, + XcmConfig, + WeightToFee, + ForeignCreatorsSovereignAccountOf, + ForeignAssetsInstance, + MultiLocation, + JustTry, + collator_session_keys(), + ExistentialDeposit::get(), + AssetDeposit::get(), + MetadataDepositBase::get(), + MetadataDepositPerByte::get(), + Box::new(|pallet_asset_call| RuntimeCall::ForeignAssets(pallet_asset_call).encode()), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::ForeignAssets(pallet_asset_event)) => Some(pallet_asset_event), + _ => None, + } + }), + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + assert!(ForeignAssets::asset_ids().collect::>().is_empty()); + }), + Box::new(|| { + assert!(Assets::asset_ids().collect::>().is_empty()); + assert_eq!(ForeignAssets::asset_ids().collect::>().len(), 1); + }) +); + +mod asset_hub_rococo_tests { + use super::*; + + fn bridging_to_asset_hub_wococo() -> asset_test_utils::test_cases_over_bridge::TestBridgingConfig + { + asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + bridged_network: bridging::to_wococo::WococoNetwork::get(), + local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), + local_bridge_hub_location: bridging::SiblingBridgeHub::get(), + bridged_target_location: bridging::to_wococo::AssetHubWococo::get(), + } + } + + #[test] + fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works() { + asset_test_utils::test_cases_over_bridge::limited_reserve_transfer_assets_for_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + bridging_to_asset_hub_wococo, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + ) + } + + #[test] + fn receive_reserve_asset_deposited_woc_from_asset_hub_wococo_works() { + const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ForeignAssetsInstance, + >( + collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), + ExistentialDeposit::get(), + AccountId::from([73; 32]), + AccountId::from(BLOCK_AUTHOR_ACCOUNT), + // receiving WOCs + (MultiLocation { parents: 2, interior: X1(GlobalConsensus(Wococo)) }, 1000000000000, 1_000_000_000), + bridging_to_asset_hub_wococo, + ( + X1(PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX)), + GlobalConsensus(Wococo), + X1(Parachain(1000)) + ) + ) + } + + #[test] + fn report_bridge_status_from_xcm_bridge_router_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + ToWococoXcmRouterInstance, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + bridging_to_asset_hub_wococo, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + || { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_rococo::Call::ToWococoXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + .into(), + } + ] + .into() + }, + || { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_rococo::Call::ToWococoXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: false, + } + ) + .encode() + .into(), + } + ] + .into() + }, + ) + } + + #[test] + fn test_report_bridge_status_call_compatibility() { + // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding + assert_eq!( + RuntimeCall::ToWococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode(), + bp_asset_hub_rococo::Call::ToWococoXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ) + } + + #[test] + fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); + } +} + +mod asset_hub_wococo_tests { + use super::*; + + fn bridging_to_asset_hub_rococo() -> asset_test_utils::test_cases_over_bridge::TestBridgingConfig + { + asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + bridged_network: bridging::to_rococo::RococoNetwork::get(), + local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), + local_bridge_hub_location: bridging::SiblingBridgeHub::get(), + bridged_target_location: bridging::to_rococo::AssetHubRococo::get(), + } + } + + pub(crate) fn set_wococo_flavor() { + let flavor_key = xcm_config::Flavor::key().to_vec(); + let flavor = RuntimeFlavor::Wococo; + + // encode `set_storage` call + let set_storage_call = RuntimeCall::System(frame_system::Call::::set_storage { + items: vec![(flavor_key, flavor.encode())], + }) + .encode(); + + // estimate - storing just 1 value + use frame_system::WeightInfo; + let require_weight_at_most = + ::SystemWeightInfo::set_storage(1); + + // execute XCM with Transact to `set_storage` as governance does + assert_ok!(RuntimeHelper::execute_as_governance(set_storage_call, require_weight_at_most) + .ensure_complete()); + + // check if stored + assert_eq!(flavor, xcm_config::Flavor::get()); + } + + fn with_wococo_flavor_bridging_to_asset_hub_rococo( + ) -> asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + set_wococo_flavor(); + bridging_to_asset_hub_rococo() + } + + #[test] + fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works() { + asset_test_utils::test_cases_over_bridge::limited_reserve_transfer_assets_for_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + with_wococo_flavor_bridging_to_asset_hub_rococo, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + ) + } + + #[test] + fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_works() { + const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32]; + asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ForeignAssetsInstance, + >( + collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)), + ExistentialDeposit::get(), + AccountId::from([73; 32]), + AccountId::from(BLOCK_AUTHOR_ACCOUNT), + // receiving ROCs + (MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }, 1000000000000, 1_000_000_000), + with_wococo_flavor_bridging_to_asset_hub_rococo, + ( + X1(PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX)), + GlobalConsensus(Rococo), + X1(Parachain(1000)) + ) + ) + } + + #[test] + fn report_bridge_status_from_xcm_bridge_router_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + ParachainSystem, + XcmpQueue, + LocationToAccountId, + ToRococoXcmRouterInstance, + >( + collator_session_keys(), + ExistentialDeposit::get(), + AccountId::from(ALICE), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event), + _ => None, + } + }), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::XcmpQueue(event)) => Some(event), + _ => None, + } + }), + with_wococo_flavor_bridging_to_asset_hub_rococo, + WeightLimit::Unlimited, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), + || { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_wococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_wococo::Call::ToRococoXcmRouter( + bp_asset_hub_wococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + .into(), + } + ] + .into() + }, + || { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_wococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_wococo::Call::ToRococoXcmRouter( + bp_asset_hub_wococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: false, + } + ) + .encode() + .into(), + } + ] + .into() + }, + ) + } + + #[test] + fn test_report_bridge_status_call_compatibility() { + // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding + assert_eq!( + RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode(), + bp_asset_hub_wococo::Call::ToRococoXcmRouter( + bp_asset_hub_wococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ) + } + + #[test] + fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_wococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); + } +} + +/// Tests expected configuration of isolated `pallet_xcm::Config::XcmReserveTransferFilter`. +#[test] +fn xcm_reserve_transfer_filter_works() { + // prepare assets + let only_native_assets = || vec![MultiAsset::from((TokenLocation::get(), 1000))]; + let only_trust_backed_assets = || { + vec![MultiAsset::from(( + AssetIdForTrustBackedAssetsConvert::convert_back(&12345).unwrap(), + 2000, + ))] + }; + let only_sibling_foreign_assets = + || vec![MultiAsset::from((MultiLocation::new(1, X1(Parachain(12345))), 3000))]; + let only_different_global_consensus_foreign_assets = || { + vec![MultiAsset::from(( + MultiLocation::new(2, X2(GlobalConsensus(Wococo), Parachain(12345))), + 4000, + ))] + }; + + // prepare destinations + let relaychain = MultiLocation::parent(); + let sibling_parachain = MultiLocation::new(1, X1(Parachain(54321))); + let different_global_consensus_parachain_other_than_asset_hub_wococo = + MultiLocation::new(2, X2(GlobalConsensus(Kusama), Parachain(12345))); + let bridged_asset_hub_wococo = bridging::to_wococo::AssetHubWococo::get(); + let bridged_asset_hub_rococo = bridging::to_rococo::AssetHubRococo::get(); + + // prepare expected test data sets: (destination, assets, expected_result) + let test_data = vec![ + (relaychain, only_native_assets(), true), + (relaychain, only_trust_backed_assets(), true), + (relaychain, only_sibling_foreign_assets(), true), + (relaychain, only_different_global_consensus_foreign_assets(), true), + (sibling_parachain, only_native_assets(), true), + (sibling_parachain, only_trust_backed_assets(), true), + (sibling_parachain, only_sibling_foreign_assets(), true), + (sibling_parachain, only_different_global_consensus_foreign_assets(), true), + ( + different_global_consensus_parachain_other_than_asset_hub_wococo, + only_native_assets(), + false, + ), + ( + different_global_consensus_parachain_other_than_asset_hub_wococo, + only_trust_backed_assets(), + false, + ), + ( + different_global_consensus_parachain_other_than_asset_hub_wococo, + only_sibling_foreign_assets(), + false, + ), + ( + different_global_consensus_parachain_other_than_asset_hub_wococo, + only_different_global_consensus_foreign_assets(), + false, + ), + ]; + + let additional_test_data_for_rococo_flavor = vec![ + (bridged_asset_hub_wococo, only_native_assets(), true), + (bridged_asset_hub_wococo, only_trust_backed_assets(), false), + (bridged_asset_hub_wococo, only_sibling_foreign_assets(), false), + (bridged_asset_hub_wococo, only_different_global_consensus_foreign_assets(), false), + ]; + let additional_test_data_for_wococo_flavor = vec![ + (bridged_asset_hub_rococo, only_native_assets(), true), + (bridged_asset_hub_rococo, only_trust_backed_assets(), false), + (bridged_asset_hub_rococo, only_sibling_foreign_assets(), false), + (bridged_asset_hub_rococo, only_different_global_consensus_foreign_assets(), false), + ]; + + // lets test filter with test data + ExtBuilder::::default() + .with_collators(collator_session_keys().collators()) + .with_session_keys(collator_session_keys().session_keys()) + .with_tracing() + .build() + .execute_with(|| { + type XcmReserveTransferFilter = + ::XcmReserveTransferFilter; + + fn do_test(data: Vec<(MultiLocation, Vec, bool)>) { + for (dest, assets, expected_result) in data { + assert_eq!( + expected_result, + XcmReserveTransferFilter::contains(&(dest, assets.clone())), + "expected_result: {} for dest: {:?} and assets: {:?}", + expected_result, + dest, + assets + ); + } + } + + // check for Rococo flavor + do_test(test_data.clone()); + do_test(additional_test_data_for_rococo_flavor); + + // check for Wococo flavor + asset_hub_wococo_tests::set_wococo_flavor(); + do_test(test_data); + do_test(additional_test_data_for_wococo_flavor); + }) +} + +#[test] +fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { + asset_test_utils::test_cases::change_storage_constant_by_governance_works::< + Runtime, + bridging::XcmBridgeHubRouterByteFee, + Balance, + >( + collator_session_keys(), + 1000, + Box::new(|call| RuntimeCall::System(call).encode()), + || { + ( + bridging::XcmBridgeHubRouterByteFee::key().to_vec(), + bridging::XcmBridgeHubRouterByteFee::get(), + ) + }, + |old_value| { + if let Some(new_value) = old_value.checked_add(1) { + new_value + } else { + old_value.checked_sub(1).unwrap() + } + }, + ) +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index f436ae9537f46b5266111f39bb039f841c3d4388..f7f6fdf68e46692182839bdd06b6ea7d7fde5b19 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -41,6 +41,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -198,6 +199,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", 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 4887fce1b0a4a5d633907cae17697b7793e781c8..943332087627c56765d1ee4199c9a9ffd7d03854 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -39,6 +39,7 @@ use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, ord_parameter_types, parameter_types, traits::{ tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, @@ -856,8 +857,46 @@ pub type Migrations = ( pallet_collator_selection::migration::v1::MigrateToV1, // unreleased migrations::NativeAssetParents0ToParents1Migration, + // unreleased + pallet_multisig::migrations::v1::MigrateToV1, + // unreleased + InitStorageVersions, ); +/// Migration to initialize storage versions for pallets added after genesis. +/// +/// Ideally this would be done automatically (see +/// ), but it probably won't be ready for some +/// time and it's beneficial to get try-runtime-cli on-runtime-upgrade checks into the CI, so we're +/// doing it manually. +pub struct InitStorageVersions; + +impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { + fn on_runtime_upgrade() -> Weight { + use frame_support::traits::{GetStorageVersion, StorageVersion}; + use sp_runtime::traits::Saturating; + + let mut writes = 0; + + if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { + PolkadotXcm::current_storage_version().put::(); + writes.saturating_inc(); + } + + if ForeignAssets::on_chain_storage_version() == StorageVersion::new(0) { + ForeignAssets::current_storage_version().put::(); + writes.saturating_inc(); + } + + if PoolAssets::on_chain_storage_version() == StorageVersion::new(0) { + PoolAssets::current_storage_version().put::(); + writes.saturating_inc(); + } + + ::DbWeight::get().reads_writes(3, writes) + } +} + /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1353,6 +1392,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs index bb850ac72c07d3ebfe576041bc56a6da5051ab9d..3e47cf077a292c21e94404a5b11ec4203ed8ee81 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -127,10 +119,7 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index d6763d2fc66f4fb68b9a0b2ed1ade7a7858d6e3d..f482064e84e9c5b918882ed47ae1afd471f3422c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-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: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=asset-hub-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 -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=asset-hub-westend-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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: 25_411_000 picoseconds. - Weight::from_parts(25_663_000, 3593) + // Minimum execution time: 25_407_000 picoseconds. + Weight::from_parts(25_949_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: 49_478_000 picoseconds. - Weight::from_parts(50_417_000, 6196) + // Minimum execution time: 51_335_000 picoseconds. + Weight::from_parts(52_090_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: `246` // Estimated: `6196` - // Minimum execution time: 72_958_000 picoseconds. - Weight::from_parts(74_503_000, 6196) + // Minimum execution time: 74_312_000 picoseconds. + Weight::from_parts(76_725_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 456_993_000 picoseconds. - Weight::from_parts(469_393_000, 3610) + // Minimum execution time: 446_848_000 picoseconds. + Weight::from_parts(466_251_000, 3610) .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_580_000 picoseconds. - Weight::from_parts(3_717_000, 0) + // Minimum execution time: 3_602_000 picoseconds. + Weight::from_parts(3_844_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_087_000 picoseconds. - Weight::from_parts(25_788_000, 3593) + // Minimum execution time: 25_480_000 picoseconds. + Weight::from_parts(26_142_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 50_824_000 picoseconds. - Weight::from_parts(52_309_000, 3610) + // Minimum execution time: 51_540_000 picoseconds. + Weight::from_parts(53_744_000, 3610) .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: `145` // Estimated: `3610` - // Minimum execution time: 31_854_000 picoseconds. - Weight::from_parts(32_553_000, 3610) + // Minimum execution time: 32_279_000 picoseconds. + Weight::from_parts(33_176_000, 3610) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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 6981c290c98ce800792292c06cfdb037888b14fb..99f8d5ae58928f6fcb04761f6edfcb1dbf1018b4 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 @@ -21,9 +21,7 @@ use super::{ use crate::ForeignAssets; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, - matching::{ - FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus, - }, + matching::{FromSiblingParachain, IsForeignConcreteAsset}, }; use frame_support::{ match_types, parameter_types, @@ -31,18 +29,22 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::AssetFeeAsExistentialDepositMultiplier}; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, +}; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FungiblesAdapter, IsConcrete, - LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, + EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -75,6 +77,9 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign chain account alias into local accounts according to a hash of their standard + // description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -222,6 +227,9 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; + pub type TreasuryPallet: impl Contains = { + MultiLocation { parents: 1, interior: X1(PalletInstance(37)) } + }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -446,11 +454,12 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, - // Parent and its pluralities (i.e. governance bodies) get free execution. - AllowExplicitUnpaidExecutionFrom, + // Parent, its pluralities (i.e. governance bodies) and treasury pallet get + // free execution. + AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, TreasuryPallet)>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), @@ -473,6 +482,15 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia TrustBackedAssetsInstance, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// +/// - WND with the parent Relay Chain and sibling system parachains; and +/// - Sibling parachains' assets from where they originate (as `ForeignCreators`). +pub type TrustedTeleporters = ( + ConcreteAssetFromSystem, + IsForeignConcreteAsset>>, +); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -483,13 +501,7 @@ impl xcm_executor::Config for XcmConfig { // Asset Hub acting _as_ a reserve location for WND and assets created under `pallet-assets`. // For WND, users must use teleport where allowed (e.g. with the Relay Chain). type IsReserve = (); - // We allow: - // - teleportation of WND - // - teleportation of sibling parachain's assets (as ForeignCreators) - type IsTeleporter = ( - NativeAsset, - IsForeignConcreteAsset>>, - ); + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 560a89b131c03520da8a574620f8641f87e66ccf..f45c3289aab49c16e2b435671d3625f78692f07d 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -21,11 +21,11 @@ pub mod local_and_foreign_assets; pub mod matching; pub mod runtime_api; -use crate::matching::{Equals, LocalMultiLocationPattern, ParentLocation, StartsWith}; -use frame_support::traits::EverythingBut; +use crate::matching::{LocalMultiLocationPattern, ParentLocation}; +use frame_support::traits::{Equals, EverythingBut}; use parachains_common::AssetIdForTrustBackedAssets; use xcm::prelude::MultiLocation; -use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId}; +use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith}; use xcm_executor::traits::{Identity, JustTry}; /// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets` @@ -96,9 +96,9 @@ pub type PoolAssetsConvertedConcreteId = #[cfg(test)] mod tests { use super::*; - use crate::matching::StartsWithExplicitGlobalConsensus; use sp_runtime::traits::MaybeEquivalence; use xcm::latest::prelude::*; + use xcm_builder::StartsWithExplicitGlobalConsensus; use xcm_executor::traits::{Error as MatchError, MatchesFungibles}; #[test] diff --git a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs index 5c66d1cabe571a5098f85fba47a81a4058cacbd6..9f429016f5302a28a61753331126a48f77ee7565 100644 --- a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs +++ b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs @@ -407,13 +407,14 @@ where #[cfg(test)] mod tests { use crate::{ - local_and_foreign_assets::MultiLocationConverter, matching::StartsWith, - AssetIdForPoolAssetsConvert, AssetIdForTrustBackedAssetsConvert, + local_and_foreign_assets::MultiLocationConverter, AssetIdForPoolAssetsConvert, + AssetIdForTrustBackedAssetsConvert, }; use frame_support::traits::EverythingBut; use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter}; use sp_runtime::traits::MaybeEquivalence; use xcm::latest::prelude::*; + use xcm_builder::StartsWith; #[test] fn test_multi_location_converter_works() { diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 08d391170014cfb0958887c09372f6e368910a56..9149728125212c9c3c980b115aa7d142905baf2a 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -14,37 +14,12 @@ // limitations under the License. use cumulus_primitives_core::ParaId; -use frame_support::{ - pallet_prelude::Get, - traits::{Contains, ContainsPair}, -}; +use frame_support::{pallet_prelude::Get, traits::ContainsPair}; use xcm::{ latest::prelude::{MultiAsset, MultiLocation}, prelude::*, }; - -pub struct StartsWith(sp_std::marker::PhantomData); -impl> Contains for StartsWith { - fn contains(t: &MultiLocation) -> bool { - t.starts_with(&Location::get()) - } -} - -pub struct Equals(sp_std::marker::PhantomData); -impl> Contains for Equals { - fn contains(t: &MultiLocation) -> bool { - t == &Location::get() - } -} - -pub struct StartsWithExplicitGlobalConsensus(sp_std::marker::PhantomData); -impl> Contains - for StartsWithExplicitGlobalConsensus -{ - fn contains(t: &MultiLocation) -> bool { - matches!(t.interior.global_consensus(), Ok(requested_network) if requested_network.eq(&Network::get())) - } -} +use xcm_builder::ensure_is_remote; frame_support::parameter_types! { pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here); @@ -82,3 +57,41 @@ impl> ContainsPair } } } + +/// Adapter verifies if it is allowed to receive `MultiAsset` from `MultiLocation`. +/// +/// Note: `MultiLocation` has to be from a different global consensus. +pub struct IsTrustedBridgedReserveLocationForConcreteAsset( + sp_std::marker::PhantomData<(UniversalLocation, Reserves)>, +); +impl< + UniversalLocation: Get, + Reserves: ContainsPair, + > ContainsPair + for IsTrustedBridgedReserveLocationForConcreteAsset +{ + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + let universal_source = UniversalLocation::get(); + log::trace!( + target: "xcm::contains", + "IsTrustedBridgedReserveLocationForConcreteAsset asset: {:?}, origin: {:?}, universal_source: {:?}", + asset, origin, universal_source + ); + + // check remote origin + let _ = match ensure_is_remote(universal_source, *origin) { + Ok(devolved) => devolved, + Err(_) => { + log::trace!( + target: "xcm::contains", + "IsTrustedBridgedReserveLocationForConcreteAsset origin: {:?} is not remote to the universal_source: {:?}", + origin, universal_source + ); + return false + }, + }; + + // check asset according to the configured reserve locations + Reserves::contains(asset, origin) + } +} diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 0a27535ed22bd447774fbf13636f1a2c09a5699c..30d3cf90b47f82af2ad59ae65e2f0cb84741b7d0 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -35,10 +35,14 @@ parachains-runtimes-test-utils = { path = "../../test-utils", default-features = # Polkadot 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} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} +# Bridges +pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } + [dev-dependencies] hex-literal = "0.4.1" @@ -61,6 +65,7 @@ std = [ "pallet-balances/std", "pallet-collator-selection/std", "pallet-session/std", + "pallet-xcm-bridge-hub-router/std", "pallet-xcm/std", "parachain-info/std", "parachains-common/std", @@ -71,6 +76,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "xcm-builder/std", "xcm-executor/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs index 7177726e07046e1d55a015016e88924db418077a..3c62faf3d5ecc6a4c5c38610c41d71232ff6bda8 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/lib.rs @@ -17,4 +17,5 @@ //! Module contains predefined test-case scenarios for `Runtime` with various assets. pub mod test_cases; +pub mod test_cases_over_bridge; pub use parachains_runtimes_test_utils::*; diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 7a8d571403c6b5c5f856dd30c08eaa092423cda5..62faa3847817e1f6634f7d692d0aed6d0682af64 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -78,6 +78,7 @@ pub fn teleports_for_native_asset_works< Into<<::RuntimeOrigin as OriginTrait>::AccountId>, <::Lookup as StaticLookup>::Source: From<::AccountId>, + ::AccountId: From, XcmConfig: xcm_executor::Config, CheckingAccount: Get>, HrmpChannelOpener: frame_support::inherent::ProvideInherent< @@ -96,7 +97,7 @@ pub fn teleports_for_native_asset_works< let included_head = RuntimeHelper::::run_to_block( 2, - AccountId::from(alice), + AccountId::from(alice).into(), ); // check Balances before assert_eq!(>::free_balance(&target_account), 0.into()); @@ -346,6 +347,7 @@ pub fn teleports_for_foreign_assets_works< Into<<::RuntimeOrigin as OriginTrait>::AccountId>, <::Lookup as StaticLookup>::Source: From<::AccountId>, + ::AccountId: From, ForeignAssetsPalletInstance: 'static, { // foreign parachain with the same consenus currency as asset @@ -391,7 +393,7 @@ pub fn teleports_for_foreign_assets_works< let included_head = RuntimeHelper::::run_to_block( 2, - AccountId::from(alice), + AccountId::from(alice).into(), ); // checks target_account before assert_eq!( @@ -1005,6 +1007,7 @@ macro_rules! include_asset_transactor_transfer_with_pallet_assets_instance_works } ); +/// Test-case makes sure that `Runtime` can create and manage `ForeignAssets` pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works< Runtime, XcmConfig, @@ -1190,7 +1193,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor .is_empty()); // check update metadata - use frame_support::traits::tokens::fungibles::roles::Inspect as InspectRoles; + use frame_support::traits::fungibles::roles::Inspect as InspectRoles; assert_eq!( >::owner( asset_id.into() diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs new file mode 100644 index 0000000000000000000000000000000000000000..a967384fb6dcaaf628349706f786203efe52883f --- /dev/null +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -0,0 +1,621 @@ +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Module contains predefined test-case scenarios for `Runtime` with various assets transferred +//! over a bridge. + +use codec::Encode; +use cumulus_primitives_core::XcmpMessageSource; +use frame_support::{ + assert_ok, + traits::{Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use parachains_common::{AccountId, Balance}; +use parachains_runtimes_test_utils::{ + mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper, + ValidatorIdOf, XcmReceivedFrom, +}; +use sp_runtime::traits::StaticLookup; +use xcm::{latest::prelude::*, VersionedMultiAssets}; +use xcm_builder::{CreateMatcher, MatchXcm}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; + +pub struct TestBridgingConfig { + pub bridged_network: NetworkId, + pub local_bridge_hub_para_id: u32, + pub local_bridge_hub_location: MultiLocation, + pub bridged_target_location: MultiLocation, +} + +/// Test-case makes sure that `Runtime` can initiate **reserve transfer assets** over bridge. +pub fn limited_reserve_transfer_assets_for_native_asset_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + HrmpChannelSource, + LocationToAccountId, +>( + collator_session_keys: CollatorSessionKeys, + existential_deposit: BalanceOf, + alice_account: AccountIdOf, + unwrap_pallet_xcm_event: Box) -> Option>>, + unwrap_xcmp_queue_event: Box< + dyn Fn(Vec) -> Option>, + >, + prepare_configuration: fn() -> TestBridgingConfig, + weight_limit: WeightLimit, + maybe_paid_export_message: Option, +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + AccountIdOf: Into<[u8; 32]>, + ValidatorIdOf: From>, + BalanceOf: From, + ::Balance: From + Into, + XcmConfig: xcm_executor::Config, + LocationToAccountId: ConvertLocation>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + ::AccountId: From, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + HrmpChannelSource: XcmpMessageSource, +{ + let runtime_para_id = 1000; + ExtBuilder::::default() + .with_collators(collator_session_keys.collators()) + .with_session_keys(collator_session_keys.session_keys()) + .with_tracing() + .with_safe_xcm_version(3) + .with_para_id(runtime_para_id.into()) + .build() + .execute_with(|| { + let mut alice = [0u8; 32]; + alice[0] = 1; + let included_head = RuntimeHelper::::run_to_block( + 2, + AccountId::from(alice).into(), + ); + + // prepare bridge config + let TestBridgingConfig { + bridged_network, + local_bridge_hub_para_id, + bridged_target_location: target_location_from_different_consensus, + .. + } = prepare_configuration(); + + let reserve_account = + LocationToAccountId::convert_location(&target_location_from_different_consensus) + .expect("Sovereign account for reserves"); + let balance_to_transfer = 1_000_000_000_000_u128; + let native_asset = MultiLocation::parent(); + + // open HRMP to bridge hub + mock_open_hrmp_channel::( + runtime_para_id.into(), + local_bridge_hub_para_id.into(), + included_head, + &alice, + ); + + // drip ED to account + let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); + let _ = >::deposit_creating( + &alice_account, + alice_account_init_balance, + ); + // SA of target location needs to have at least ED, otherwise making reserve fails + let _ = >::deposit_creating( + &reserve_account, + existential_deposit, + ); + + // we just check here, that user retains enough balance after withdrawal + // and also we check if `balance_to_transfer` is more than `existential_deposit`, + assert!( + (>::free_balance(&alice_account) - + balance_to_transfer.into()) >= + existential_deposit + ); + // SA has just ED + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + ); + + // local native asset (pallet_balances) + let asset_to_transfer = MultiAsset { + fun: Fungible(balance_to_transfer.into()), + id: Concrete(native_asset), + }; + + // destination is (some) account relative to the destination different consensus + let target_destination_account = MultiLocation { + parents: 0, + interior: X1(AccountId32 { + network: Some(bridged_network), + id: sp_runtime::AccountId32::new([3; 32]).into(), + }), + }; + + // do pallet_xcm call reserve transfer + assert_ok!(>::limited_reserve_transfer_assets( + RuntimeHelper::::origin_of(alice_account.clone()), + Box::new(target_location_from_different_consensus.into_versioned()), + Box::new(target_destination_account.into_versioned()), + Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))), + 0, + weight_limit, + )); + + // check alice account decreased by balance_to_transfer + // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot-sdk/pull/1234) merged + assert_eq!( + >::free_balance(&alice_account), + alice_account_init_balance - balance_to_transfer.into() + ); + + // check reserve account + // check reserve account increased by balance_to_transfer + assert_eq!( + >::free_balance(&reserve_account), + existential_deposit + balance_to_transfer.into() + ); + + // check events + // check pallet_xcm attempted + RuntimeHelper::::assert_pallet_xcm_event_outcome( + &unwrap_pallet_xcm_event, + |outcome| { + assert_ok!(outcome.ensure_complete()); + }, + ); + + // check that xcm was sent + let xcm_sent_message_hash = >::events() + .into_iter() + .filter_map(|e| unwrap_xcmp_queue_event(e.event.encode())) + .find_map(|e| match e { + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } => + Some(message_hash), + _ => None, + }); + + // read xcm + let xcm_sent = RuntimeHelper::::take_xcm( + local_bridge_hub_para_id.into(), + ) + .unwrap(); + + assert_eq!( + xcm_sent_message_hash, + Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256)) + ); + let mut xcm_sent: Xcm<()> = xcm_sent.try_into().expect("versioned xcm"); + + // check sent XCM ExportMessage to BridgeHub + + // 1. check paid or unpaid + if let Some(expected_fee_asset_id) = maybe_paid_export_message { + xcm_sent + .0 + .matcher() + .match_next_inst(|instr| match instr { + WithdrawAsset(_) => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("contains WithdrawAsset") + .match_next_inst(|instr| match instr { + BuyExecution { fees, .. } if fees.id.eq(&expected_fee_asset_id) => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("contains BuyExecution") + } else { + xcm_sent + .0 + .matcher() + .match_next_inst(|instr| match instr { + // first instruction could be UnpaidExecution (because we could have + // explicit unpaid execution on BridgeHub) + UnpaidExecution { weight_limit, check_origin } + if weight_limit == &Unlimited && check_origin.is_none() => + Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("contains UnpaidExecution") + } + // 2. check ExportMessage + .match_next_inst(|instr| match instr { + // next instruction is ExportMessage + ExportMessage { network, destination, xcm: inner_xcm } => { + assert_eq!(network, &bridged_network); + let (_, target_location_junctions_without_global_consensus) = + target_location_from_different_consensus + .interior + .split_global() + .expect("split works"); + assert_eq!(destination, &target_location_junctions_without_global_consensus); + assert_matches_pallet_xcm_reserve_transfer_assets_instructions(inner_xcm); + Ok(()) + }, + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("contains ExportMessage"); + }) +} + +pub fn receive_reserve_asset_deposited_from_different_consensus_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ForeignAssetsPalletInstance, +>( + collator_session_keys: CollatorSessionKeys, + existential_deposit: BalanceOf, + target_account: AccountIdOf, + block_author_account: AccountIdOf, + ( + foreign_asset_id_multilocation, + transfered_foreign_asset_id_amount, + foreign_asset_id_minimum_balance, + ): (MultiLocation, u128, u128), + prepare_configuration: fn() -> TestBridgingConfig, + (bridge_instance, universal_origin, descend_origin): (Junctions, Junction, Junctions), /* bridge adds origin manipulation on the way */ +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config + + pallet_assets::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + AccountIdOf: Into<[u8; 32]>, + ValidatorIdOf: From>, + BalanceOf: From, + XcmConfig: xcm_executor::Config, + LocationToAccountId: ConvertLocation>, + >::AssetId: + From + Into, + >::AssetIdParameter: + From + Into, + >::Balance: + From + Into + From, + ::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId> + + Into, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + ForeignAssetsPalletInstance: 'static, +{ + ExtBuilder::::default() + .with_collators(collator_session_keys.collators()) + .with_session_keys(collator_session_keys.session_keys()) + .with_tracing() + .build() + .execute_with(|| { + // Set account as block author, who will receive fees + RuntimeHelper::::run_to_block( + 2, + block_author_account.clone().into(), + ); + + // prepare bridge config + let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration(); + + // drip 'ED' user target account + let _ = >::deposit_creating( + &target_account, + existential_deposit, + ); + + // sovereign account as foreign asset owner (can be whoever for this scenario, doesnt + // matter) + let sovereign_account_as_owner_of_foreign_asset = + LocationToAccountId::convert_location(&MultiLocation::parent()).unwrap(); + + // staking pot account for collecting local native fees from `BuyExecution` + let staking_pot = >::account_id(); + let _ = >::deposit_creating( + &staking_pot, + existential_deposit, + ); + + // create foreign asset for wrapped/derivated representation + assert_ok!( + >::force_create( + RuntimeHelper::::root_origin(), + foreign_asset_id_multilocation.into(), + sovereign_account_as_owner_of_foreign_asset.clone().into(), + true, // is_sufficient=true + foreign_asset_id_minimum_balance.into() + ) + ); + + // Balances before + assert_eq!( + >::free_balance(&target_account), + existential_deposit.clone() + ); + assert_eq!( + >::free_balance(&block_author_account), + 0.into() + ); + assert_eq!( + >::free_balance(&staking_pot), + existential_deposit.clone() + ); + + // ForeignAssets balances before + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &target_account + ), + 0.into() + ); + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &block_author_account + ), + 0.into() + ); + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &staking_pot + ), + 0.into() + ); + + // Call received XCM execution + let xcm = Xcm(vec![ + DescendOrigin(bridge_instance), + UniversalOrigin(universal_origin), + DescendOrigin(descend_origin), + ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset { + id: Concrete(foreign_asset_id_multilocation), + fun: Fungible(transfered_foreign_asset_id_amount), + }])), + ClearOrigin, + BuyExecution { + fees: MultiAsset { + id: Concrete(foreign_asset_id_multilocation), + fun: Fungible(transfered_foreign_asset_id_amount), + }, + weight_limit: Unlimited, + }, + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: MultiLocation { + parents: 0, + interior: X1(AccountId32 { + network: None, + id: target_account.clone().into(), + }), + }, + }, + SetTopic([ + 220, 188, 144, 32, 213, 83, 111, 175, 44, 210, 111, 19, 90, 165, 191, 112, 140, + 247, 192, 124, 42, 17, 153, 141, 114, 34, 189, 20, 83, 69, 237, 173, + ]), + ]); + assert_matches_pallet_xcm_reserve_transfer_assets_instructions(&mut xcm.clone()); + + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + + // execute xcm as XcmpQueue would do + let outcome = XcmExecutor::::execute_xcm( + local_bridge_hub_location, + xcm, + hash, + RuntimeHelper::::xcm_max_weight( + XcmReceivedFrom::Sibling, + ), + ); + assert_eq!(outcome.ensure_complete(), Ok(())); + + // author actual balance after (received fees from Trader for ForeignAssets) + let author_received_fees = + >::balance( + foreign_asset_id_multilocation.into(), + &block_author_account, + ); + + // Balances after (untouched) + assert_eq!( + >::free_balance(&target_account), + existential_deposit.clone() + ); + assert_eq!( + >::free_balance(&block_author_account), + 0.into() + ); + assert_eq!( + >::free_balance(&staking_pot), + existential_deposit.clone() + ); + + // ForeignAssets balances after + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &target_account + ), + (transfered_foreign_asset_id_amount - author_received_fees.into()).into() + ); + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &block_author_account + ), + author_received_fees + ); + assert_eq!( + >::balance( + foreign_asset_id_multilocation.into(), + &staking_pot + ), + 0.into() + ); + }) +} + +fn assert_matches_pallet_xcm_reserve_transfer_assets_instructions( + xcm: &mut Xcm, +) { + let _ = xcm + .0 + .matcher() + .skip_inst_while(|inst| !matches!(inst, ReserveAssetDeposited(..))) + .expect("no instruction ReserveAssetDeposited?") + .match_next_inst(|instr| match instr { + ReserveAssetDeposited(..) => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction ReserveAssetDeposited") + .match_next_inst(|instr| match instr { + ClearOrigin => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction ClearOrigin") + .match_next_inst(|instr| match instr { + BuyExecution { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction BuyExecution") + .match_next_inst(|instr| match instr { + DepositAsset { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction DepositAsset"); +} + +pub fn report_bridge_status_from_xcm_bridge_router_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + HrmpChannelSource, + LocationToAccountId, + XcmBridgeHubRouterInstance, +>( + collator_session_keys: CollatorSessionKeys, + existential_deposit: BalanceOf, + alice_account: AccountIdOf, + unwrap_pallet_xcm_event: Box) -> Option>>, + unwrap_xcmp_queue_event: Box< + dyn Fn(Vec) -> Option>, + >, + prepare_configuration: fn() -> TestBridgingConfig, + weight_limit: WeightLimit, + maybe_paid_export_message: Option, + congested_message: fn() -> Xcm, + uncongested_message: fn() -> Xcm, +) where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config + + pallet_xcm_bridge_hub_router::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + AccountIdOf: Into<[u8; 32]>, + ValidatorIdOf: From>, + BalanceOf: From, + ::Balance: From + Into, + XcmConfig: xcm_executor::Config, + LocationToAccountId: ConvertLocation>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + ::AccountId: From, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + HrmpChannelSource: XcmpMessageSource, + XcmBridgeHubRouterInstance: 'static, +{ + ExtBuilder::::default() + .with_collators(collator_session_keys.collators()) + .with_session_keys(collator_session_keys.session_keys()) + .with_tracing() + .build() + .execute_with(|| { + // check transfer works + limited_reserve_transfer_assets_for_native_asset_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + HrmpChannelSource, + LocationToAccountId, + >( + collator_session_keys, + existential_deposit, + alice_account, + unwrap_pallet_xcm_event, + unwrap_xcmp_queue_event, + prepare_configuration, + weight_limit, + maybe_paid_export_message, + ); + + let report_bridge_status = |is_congested: bool| { + // prepare bridge config + let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration(); + + // Call received XCM execution + let xcm = if is_congested { congested_message() } else { uncongested_message() }; + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + + // execute xcm as XcmpQueue would do + let outcome = XcmExecutor::::execute_xcm( + local_bridge_hub_location, + xcm, + hash, + RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), + ); + assert_eq!(outcome.ensure_complete(), Ok(())); + assert_eq!(is_congested, pallet_xcm_bridge_hub_router::Pallet::::bridge().is_congested); + }; + + report_bridge_status(true); + report_bridge_status(false); + }) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/README.md b/cumulus/parachains/runtimes/bridge-hubs/README.md index 487c601ef84023310fe7e15c5642ca060c9e550b..9acdfd6d0539e025ec14149631536f111df278d5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/README.md +++ b/cumulus/parachains/runtimes/bridge-hubs/README.md @@ -1,13 +1,14 @@ - [Bridge-hub Parachains](#bridge-hub-parachains) - [Requirements for local run/testing](#requirements-for-local-runtesting) - [How to test local Rococo <-> Wococo bridge](#how-to-test-local-rococo---wococo-bridge) - - [Run chains (Rococo + BridgeHub, Wococo + BridgeHub) with - zombienet](#run-chains-rococo--bridgehub-wococo--bridgehub-with-zombienet) - - [Run relayer (BridgeHubRococo, BridgeHubWococo)](#run-relayer-bridgehubrococo-bridgehubwococo) - - [Run with script (alternative 1)](#run-with-script-alternative-1) - - [Run with binary (alternative 2)](#run-with-binary-alternative-2) - - [Send messages - transfer asset over bridge](#send-messages---transfer-asset-over-bridge) - - [How to test live BridgeHubRococo/BridgeHubWococo](#how-to-test-live-bridgehubrococobridgehubwococo) + - [Run Rococo/Wococo chains with zombienet](#run-rococowococo-chains-with-zombienet) + - [Init bridge and run relayer between BridgeHubRococo and + BridgeHubWococo](#init-bridge-and-run-relayer-between-bridgehubrococo-and-bridgehubwococo) + - [Initialize configuration for transfer asset over bridge + (ROCs/WOCs)](#initialize-configuration-for-transfer-asset-over-bridge-rocswocs) + - [Send messages - transfer asset over bridge (ROCs/WOCs)](#send-messages---transfer-asset-over-bridge-rocswocs) + - [Claim relayer's rewards on BridgeHubRococo and + BridgeHubWococo](#claim-relayers-rewards-on-bridgehubrococo-and-bridgehubwococo) - [How to test local BridgeHubKusama/BridgeHubPolkadot](#how-to-test-local-bridgehubkusamabridgehubpolkadot) # Bridge-hub Parachains @@ -42,17 +43,29 @@ Copy the apropriate binary (zombienet-linux) from the latest release to ~/local_ --- # 2. Build polkadot binary -git clone https://github.com/paritytech/polkadot.git -cd polkadot -# if you want to test Kusama/Polkadot bridge, we need "sudo pallet + fast-runtime", -# so please, find the latest polkadot's repository branch `it/release-vX.Y.Z-fast-sudo` -# e.g: -# git checkout -b it/release-v0.9.43-fast-sudo --track origin/it/release-v0.9.43-fast-sudo +# If you want to test Kusama/Polkadot bridge, we need "sudo pallet + fast-runtime", +# so we need to use sudofi in polkadot directory. +# +# Install sudofi: (skip if already installed) +# cd +# git clone https://github.com/paritytech/parachain-utils.git +# cd parachain-utils # -> this is +# cargo build --release --bin sudofi +# +# cd /polkadot +# /target/release/sudofi -cargo build --release --features fast-runtime +cd +cargo build --release --features fast-runtime --bin polkadot cp target/release/polkadot ~/local_bridge_testing/bin/polkadot +cargo build --release --features fast-runtime --bin polkadot-prepare-worker +cp target/release/polkadot-prepare-worker ~/local_bridge_testing/bin/polkadot-prepare-worker + +cargo build --release --features fast-runtime --bin polkadot-execute-worker +cp target/release/polkadot-execute-worker ~/local_bridge_testing/bin/polkadot-execute-worker + --- # 3. Build substrate-relay binary @@ -71,124 +84,48 @@ cp target/release/substrate-relay ~/local_bridge_testing/bin/substrate-relay --- # 4. Build cumulus polkadot-parachain binary -cd - -# checkout desired branch or use master: -# git checkout -b master --track origin/master +cd -cargo build --release --locked --bin polkadot-parachain +cargo build --release -p polkadot-parachain-bin cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain-asset-hub - - - -# !!! READ HERE (TODO remove once all mentioned branches bellow are merged) -# The use case "moving assets over bridge" is not merged yet and is implemented in separate branches. -# So, if you want to try it, you need to checkout different branch and continue with these instructions there. - -# For Kusama/Polkadot local bridge testing: -# -# build BridgeHubs (polkadot-parachain) from branch: -# git checkout -b bridge-hub-kusama-polkadot --track origin/bridge-hub-kusama-polkadot -# cargo build --release --locked --bin polkadot-parachain -# cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain -# -# build AssetHubs (polkadot-parachain-asset-hub) from branch: -# git checkout -b bko-transfer-asset-via-bridge-pallet-xcm --track origin/bko-transfer-asset-via-bridge-pallet-xcm -# cargo build --release --locked --bin polkadot-parachain -# cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain-asset-hub - -# For Rococo/Wococo local bridge testing: -# -# build AssetHubs (polkadot-parachain-asset-hub) from branch: -# git checkout -b bko-transfer-asset-via-bridge-pallet-xcm-ro-wo --track origin/bko-transfer-asset-via-bridge-pallet-xcm-ro-wo -# cargo build --release --locked --bin polkadot-parachain -# cp target/release/polkadot-parachain ~/local_bridge_testing/bin/polkadot-parachain-asset-hub ``` + ## How to test local Rococo <-> Wococo bridge -### Run chains (Rococo + BridgeHub + AssetHub, Wococo + BridgeHub + AssetHub) with zombienet +### Run Rococo/Wococo chains with zombienet ``` +cd + # Rococo + BridgeHubRococo + AssetHub for Rococo (mirroring Kusama) POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \ POLKADOT_PARACHAIN_BINARY_PATH=~/local_bridge_testing/bin/polkadot-parachain \ POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=~/local_bridge_testing/bin/polkadot-parachain-asset-hub \ - ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml + ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml ``` ``` +cd + # Wococo + BridgeHubWococo + AssetHub for Wococo (mirroring Polkadot) POLKADOT_BINARY_PATH=~/local_bridge_testing/bin/polkadot \ POLKADOT_PARACHAIN_BINARY_PATH=~/local_bridge_testing/bin/polkadot-parachain \ POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO=~/local_bridge_testing/bin/polkadot-parachain-asset-hub \ - ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml + ~/local_bridge_testing/bin/zombienet-linux --provider native spawn ./cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml ``` -### Run relayer (BridgeHubRococo, BridgeHubWococo) +### Init bridge and run relayer between BridgeHubRococo and BridgeHubWococo **Accounts of BridgeHub parachains:** - `Bob` is pallet owner of all bridge pallets -#### Run with script (alternative 1) -``` -cd -./scripts/bridges_rococo_wococo.sh run-relay -``` - -#### Run with binary (alternative 2) -Need to wait for parachain activation (start producing blocks), then run: - -``` -# 1. Init bridges: - -# Rococo -> Wococo -RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - ~/local_bridge_testing/bin/substrate-relay init-bridge rococo-to-bridge-hub-wococo \ - --source-host localhost \ - --source-port 9942 \ - --source-version-mode Auto \ - --target-host localhost \ - --target-port 8945 \ - --target-version-mode Auto \ - --target-signer //Bob - -# Wococo -> Rococo -RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - ~/local_bridge_testing/bin/substrate-relay init-bridge wococo-to-bridge-hub-rococo \ - --source-host localhost \ - --source-port 9945 \ - --source-version-mode Auto \ - --target-host localhost \ - --target-port 8943 \ - --target-version-mode Auto \ - --target-signer //Bob - -# 2. Relay relay-chain headers, parachain headers and messages** -RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - ~/local_bridge_testing/bin/substrate-relay relay-headers-and-messages bridge-hub-rococo-bridge-hub-wococo \ - --rococo-host localhost \ - --rococo-port 9942 \ - --rococo-version-mode Auto \ - --bridge-hub-rococo-host localhost \ - --bridge-hub-rococo-port 8943 \ - --bridge-hub-rococo-version-mode Auto \ - --bridge-hub-rococo-signer //Charlie \ - --wococo-headers-to-bridge-hub-rococo-signer //Bob \ - --wococo-parachains-to-bridge-hub-rococo-signer //Bob \ - --bridge-hub-rococo-transactions-mortality 4 \ - --wococo-host localhost \ - --wococo-port 9945 \ - --wococo-version-mode Auto \ - --bridge-hub-wococo-host localhost \ - --bridge-hub-wococo-port 8945 \ - --bridge-hub-wococo-version-mode Auto \ - --bridge-hub-wococo-signer //Charlie \ - --rococo-headers-to-bridge-hub-wococo-signer //Bob \ - --rococo-parachains-to-bridge-hub-wococo-signer //Bob \ - --bridge-hub-wococo-transactions-mortality 4 \ - --lane 00000001 +#### Run with script +``` +cd + +./cumulus/scripts/bridges_rococo_wococo.sh run-relay ``` **Check relay-chain headers relaying:** @@ -199,34 +136,66 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ **Check parachain headers relaying:** - Rococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8943#/chainstate - Pallet: - **bridgeWococoParachain** - Keys: **bestParaHeads()** + **bridgeWococoParachain** - Keys: **parasInfo(None)** - Wococo parachain: - https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A8945#/chainstate - Pallet: - **bridgeRococoParachain** - Keys: **bestParaHeads()** + **bridgeRococoParachain** - Keys: **parasInfo(None)** -### Send messages - transfer asset over bridge +### Initialize configuration for transfer asset over bridge (ROCs/WOCs) -TODO: see `# !!! READ HERE` above +This initialization does several things: +- creates `ForeignAssets` for wrappedROCs/wrappedWOCs +- drips SA for AssetHubRococo on AssetHubWococo (and vice versa) which holds reserved assets on source chains +``` +cd + +./cumulus/scripts/bridges_rococo_wococo.sh init-asset-hub-rococo-local +./cumulus/scripts/bridges_rococo_wococo.sh init-bridge-hub-rococo-local +./cumulus/scripts/bridges_rococo_wococo.sh init-asset-hub-wococo-local +./cumulus/scripts/bridges_rococo_wococo.sh init-bridge-hub-wococo-local +``` + +### Send messages - transfer asset over bridge (ROCs/WOCs) + +Do (asset) transfers: +``` +cd + +# ROCs from Rococo's Asset Hub to Wococo's. +./cumulus/scripts/bridges_rococo_wococo.sh reserve-transfer-assets-from-asset-hub-rococo-local +``` +``` +cd -## How to test live BridgeHubRococo/BridgeHubWococo -(here is still deployed older PoC from branch `origin/bko-transfer-asset-via-bridge`, which uses custom extrinsic, which -is going to be replaced by `pallet_xcm` usage) -- uses account seed on Live Rococo:Rockmine2 - ``` - cd - ./scripts/bridges_rococo_wococo.sh transfer-asset-from-asset-hub-rococo - ``` - -- open explorers: - Rockmine2 (see events `xcmpQueue.XcmpMessageSent`, `bridgeTransfer.ReserveAssetsDeposited`, - `bridgeTransfer.TransferInitiated`) - https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io#/explorer - - BridgeHubRococo (see `bridgeWococoMessages.MessageAccepted`) - https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-bridge-hub-rpc.polkadot.io#/explorer - BridgeHubWococo (see - `bridgeRococoMessages.MessagesReceived`) - https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwococo-bridge-hub-rpc.polkadot.io#/explorer - Wockmint (see - `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) - https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwococo-wockmint-rpc.polkadot.io#/explorer - BridgeHubRococo (see - `bridgeWococoMessages.MessagesDelivered`) +# WOCs from Wococo's Asset Hub to Rococo's. +./cumulus/scripts/bridges_rococo_wococo.sh reserve-transfer-assets-from-asset-hub-wococo-local +``` + +- open explorers: (see zombienets) + - AssetHubRococo (see events `xcmpQueue.XcmpMessageSent`, `polkadotXcm.Attempted`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9910#/explorer + - BridgeHubRococo (see `bridgeWococoMessages.MessageAccepted`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + - BridgeHubWococo (see `bridgeRococoMessages.MessagesReceived`, `xcmpQueue.XcmpMessageSent`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer + - AssetHubWococo (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer + - BridgeHubRocococ (see `bridgeWococoMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + +### Claim relayer's rewards on BridgeHubRococo and BridgeHubWococo + +**Accounts of BridgeHub parachains:** +- `//Charlie` is relayer account on BridgeHubRococo +- `//Charlie` is relayer account on BridgeHubWococo + +``` +cd + +# Claim rewards on BridgeHubWococo: +./cumulus/scripts/bridges_rococo_wococo.sh claim-rewards-bridge-hub-rococo-local + +# Claim rewards on BridgeHubWococo: +./cumulus/scripts/bridges_rococo_wococo.sh claim-rewards-bridge-hub-wococo-local +``` +- open explorers: (see zombienets) + - BridgeHubRococo (see 2x `bridgeRelayers.RewardPaid`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer + - BridgeHubWococo (see 2x `bridgeRelayers.RewardPaid`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer ## How to test local BridgeHubKusama/BridgeHubPolkadot diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 67c3fa37df0480793df8c7a8a0730f34a4533a71..bfb0b9e712709f01da525c9b2fcf71d33bf35d38 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -37,6 +37,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} @@ -48,7 +49,6 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} # Polkadot -kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/constants", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} @@ -93,7 +93,6 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime?/std", - "kusama-runtime-constants/std", "log/std", "pallet-aura/std", "pallet-authorship/std", @@ -118,6 +117,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs index 54b15e6b327b51eefefcb22e9987aac287401192..791751e7736851e46c26fb3056bafaed36389baf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -43,6 +43,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, weights::{ConstantMultiplier, Weight}, @@ -779,6 +780,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs index 0e740922f339de717f04f0881c165786c36ba47a..ded5dc6702e60f4ddea9583d4b66c893f6d38b04 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for BridgeHubKusamaXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -127,10 +119,7 @@ impl XcmWeightInfo for BridgeHubKusamaXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 6c8c7ab66bbdb8e149a04e56b59f9a4fe7a75722..17ee5cb6a8dca0fbebefec1c817f16a275489260 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/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 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=bridge-hub-kusama-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=bridge-hub-kusama-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/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: 24_064_000 picoseconds. - Weight::from_parts(24_751_000, 3593) + // Minimum execution time: 25_447_000 picoseconds. + Weight::from_parts(25_810_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: `153` // Estimated: `6196` - // Minimum execution time: 51_097_000 picoseconds. - Weight::from_parts(51_960_000, 6196) + // Minimum execution time: 53_908_000 picoseconds. + Weight::from_parts(54_568_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: `223` // Estimated: `6196` - // Minimum execution time: 75_319_000 picoseconds. - Weight::from_parts(77_356_000, 6196) + // Minimum execution time: 79_923_000 picoseconds. + Weight::from_parts(80_790_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 29_392_000 picoseconds. - Weight::from_parts(29_943_000, 3535) + // Minimum execution time: 31_923_000 picoseconds. + Weight::from_parts(32_499_000, 3535) .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_637_000 picoseconds. - Weight::from_parts(3_720_000, 0) + // Minimum execution time: 3_903_000 picoseconds. + Weight::from_parts(4_065_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 25_045_000 picoseconds. - Weight::from_parts(25_546_000, 3593) + // Minimum execution time: 26_987_000 picoseconds. + Weight::from_parts(27_486_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 51_450_000 picoseconds. - Weight::from_parts(52_354_000, 3593) + // Minimum execution time: 56_012_000 picoseconds. + Weight::from_parts(58_067_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: `70` // Estimated: `3535` - // Minimum execution time: 29_711_000 picoseconds. - Weight::from_parts(30_759_000, 3535) + // Minimum execution time: 32_350_000 picoseconds. + Weight::from_parts(33_403_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index 696462be9c45c31a8d4a6d9491ed1c9475fda00d..563115c8938e44acd1e2e82ace9843ca765b56ff 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -24,7 +24,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; +use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -162,7 +162,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. @@ -177,6 +177,10 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - KSM with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -186,8 +190,7 @@ impl xcm_executor::Config for XcmConfig { // BridgeHub does not recognize a reserve location for any asset. Users must teleport KSM // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of KSM. - type IsTeleporter = ConcreteNativeAssetFrom; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 77923ee74f89ed495af94ac560668186f55ee414..eb0c18f5b460b0d15cb96890e219e9fe6187d8f9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -37,6 +37,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} @@ -48,7 +49,6 @@ sp-transaction-pool = { path = "../../../../../substrate/primitives/transaction- sp-version = { path = "../../../../../substrate/primitives/version", default-features = false} # Polkadot -polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/constants", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} @@ -111,13 +111,13 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", - "polkadot-runtime-constants/std", "scale-info/std", "serde", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index dbfdc249a3cd7aad3cb5482f4f4a5e3a5493e0a0..928b9d091ec5bf85a69582794dd23e933637eccf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -43,6 +43,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything}, weights::{ConstantMultiplier, Weight}, @@ -779,6 +780,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs index 4f8c2dec7a8c890f1b4cd9ccd2cf24e92cea3817..7e9f21842725ecef79df3305b9f708d3516d8faf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/mod.rs @@ -61,16 +61,8 @@ impl XcmWeightInfo for BridgeHubPolkadotXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -127,10 +119,7 @@ impl XcmWeightInfo for BridgeHubPolkadotXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, @@ -154,10 +143,7 @@ impl XcmWeightInfo for BridgeHubPolkadotXcmWeight { _dest: &MultiLocation, _xcm: &Xcm<()>, ) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(200_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::initiate_teleport()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::initiate_teleport()) } fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight { XcmGeneric::::report_holding() diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 7c525dca051d277497e9c64395bd69d6fa5eabc2..f45f3936365281c8d592c4a79d8974fb8d468a90 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/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 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=bridge-hub-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=bridge-hub-polkadot-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/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: 23_862_000 picoseconds. - Weight::from_parts(24_603_000, 3593) + // Minimum execution time: 24_237_000 picoseconds. + Weight::from_parts(24_697_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: `153` // Estimated: `6196` - // Minimum execution time: 51_101_000 picoseconds. - Weight::from_parts(51_976_000, 6196) + // Minimum execution time: 52_269_000 picoseconds. + Weight::from_parts(53_848_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: `223` // Estimated: `6196` - // Minimum execution time: 72_983_000 picoseconds. - Weight::from_parts(74_099_000, 6196) + // Minimum execution time: 77_611_000 picoseconds. + Weight::from_parts(82_634_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 27_131_000 picoseconds. - Weight::from_parts(28_062_000, 3535) + // Minimum execution time: 29_506_000 picoseconds. + Weight::from_parts(30_269_000, 3535) .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_564_000 picoseconds. - Weight::from_parts(3_738_000, 0) + // Minimum execution time: 3_541_000 picoseconds. + Weight::from_parts(3_629_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 24_453_000 picoseconds. - Weight::from_parts(25_216_000, 3593) + // Minimum execution time: 25_651_000 picoseconds. + Weight::from_parts(26_078_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 48_913_000 picoseconds. - Weight::from_parts(50_202_000, 3593) + // Minimum execution time: 52_050_000 picoseconds. + Weight::from_parts(53_293_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: `70` // Estimated: `3535` - // Minimum execution time: 27_592_000 picoseconds. - Weight::from_parts(28_099_000, 3535) + // Minimum execution time: 30_009_000 picoseconds. + Weight::from_parts(30_540_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index 0965600c246810d7566bc9de08b60a787d175352..6e9d6d586195e7476cc6af86dd4799284d7d21d1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -24,7 +24,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; +use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -165,7 +165,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality @@ -181,6 +181,10 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - DOT with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -190,8 +194,7 @@ impl xcm_executor::Config for XcmConfig { // BridgeHub does not recognize a reserve location for any asset. Users must teleport DOT // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of DOT. - type IsTeleporter = ConcreteNativeAssetFrom; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< 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 70c62d1a34fd9fb6f375f456ad5729b52af8e19d..ab56430bc94fafd979c344271dc8809a006211c4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -37,6 +37,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} @@ -64,7 +65,7 @@ cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-fea cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false} cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } @@ -72,6 +73,8 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-common = { path = "../../../common", default-features = false } # Bridges +bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-wococo = { path = "../../../../../bridges/primitives/chain-asset-hub-wococo", default-features = false } bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } bp-bridge-hub-wococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-wococo", default-features = false } bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } @@ -97,6 +100,8 @@ sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] default = [ "std" ] std = [ + "bp-asset-hub-rococo/std", + "bp-asset-hub-wococo/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-wococo/std", "bp-header-chain/std", @@ -153,6 +158,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs index bc8f97ad97c1c15232a19b062a8f5f2bb674a809..73eb27e921630f5a6fd36607e5454800ac2cfc2f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs @@ -29,10 +29,11 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundableMessagesLane, - RefundableParachain, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, }, }; +use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; use sp_runtime::RuntimeDebug; use xcm::{ @@ -51,12 +52,38 @@ parameter_types! { pub BridgeHubRococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(ParachainInfo::parachain_id().into())); pub WococoGlobalConsensusNetwork: NetworkId = NetworkId::Wococo; pub ActiveOutboundLanesToBridgeHubWococo: &'static [bp_messages::LaneId] = &[DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO]; - pub PriorityBoostPerMessage: u64 = 921_900_294; + // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value + pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; + + pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); pub FromAssetHubRococoToAssetHubWococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen(X1(Parachain(1000))).into(), + ParentThen(X1(Parachain(AssetHubRococoParaId::get().into()))).into(), DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, ); + + pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + + pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); +} + +fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_rococo::Call::ToWococoXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested, + } + ) + .encode() + .into(), + } + ] } /// Proof of messages, coming from Wococo. @@ -73,7 +100,7 @@ pub type OnBridgeHubRococoBlobDispatcher = BridgeBlobDispatcher< BridgeWococoMessagesPalletInstance, >; -/// Export XCM messages to be relayed to the otherside +/// Export XCM messages to be relayed to the other side pub type ToBridgeHubWococoHaulBlobExporter = HaulBlobExporter< XcmBlobHaulerAdapter, WococoGlobalConsensusNetwork, @@ -86,11 +113,14 @@ impl XcmBlobHauler for ToBridgeHubWococoXcmBlobHauler { type SenderAndLane = FromAssetHubRococoToAssetHubWococoRoute; type ToSourceChainSender = crate::XcmRouter; - type CongestedMessage = (); - type UncongestedMessage = (); + type CongestedMessage = CongestedMessage; + type UncongestedMessage = UncongestedMessage; } pub const DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO: LaneId = LaneId([0, 0, 0, 1]); +/// On messages delivered callback. +pub type OnMessagesDelivered = XcmBlobHaulerAdapter; + /// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWococo pub struct WithBridgeHubWococoMessageBridge; impl MessageBridge for WithBridgeHubWococoMessageBridge { @@ -136,13 +166,15 @@ impl ThisChainWithMessages for BridgeHubRococo { } /// Signed extension that refunds relayers that are delivering messages from the Wococo parachain. -pub type BridgeRefundBridgeHubWococoMessages = RefundBridgedParachainMessages< - Runtime, - RefundableParachain, - RefundableMessagesLane, - ActualFeeRefund, - PriorityBoostPerMessage, - StrBridgeRefundBridgeHubWococoMessages, +pub type BridgeRefundBridgeHubWococoMessages = RefundSignedExtensionAdapter< + RefundBridgedParachainMessages< + Runtime, + RefundableParachain, + RefundableMessagesLane, + ActualFeeRefund, + PriorityBoostPerMessage, + StrBridgeRefundBridgeHubWococoMessages, + >, >; bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubWococoMessages); @@ -162,6 +194,18 @@ mod tests { AssertCompleteBridgeConstants, }, }; + use parachains_common::{rococo, Balance}; + + /// Every additional message in the message delivery transaction boosts its priority. + /// So the priority of transaction with `N+1` messages is larger than priority of + /// transaction with `N` messages by the `PriorityBoostPerMessage`. + /// + /// Economically, it is an equivalent of adding tip to the transaction with `N` messages. + /// The `FEE_BOOST_PER_MESSAGE` constant is the value of this tip. + /// + /// We want this tip to be large enough (delivery transactions with more messages = less + /// operational costs and a faster bridge), so this value should be significant. + const FEE_BOOST_PER_MESSAGE: Balance = 2 * rococo::currency::UNITS; #[test] fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() { @@ -213,5 +257,16 @@ mod tests { bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME, }, }); + + bridge_runtime_common::priority_calculator::ensure_priority_boost_is_sane::< + Runtime, + WithBridgeHubWococoMessagesInstance, + PriorityBoostPerMessage, + >(FEE_BOOST_PER_MESSAGE); + + assert_eq!( + BridgeWococoMessagesPalletInstance::get(), + X1(PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_WOCOCO_MESSAGES_PALLET_INDEX)) + ); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs index 5178b75c30390a21e8319b0d80ed58b000430311..fcd9a6229ff2c76db5edcfc7cfeeb5cbb6434280 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs @@ -29,10 +29,11 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{SenderAndLane, XcmBlobHauler, XcmBlobHaulerAdapter}, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundableMessagesLane, - RefundableParachain, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, RefundableParachain, }, }; +use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; use sp_runtime::RuntimeDebug; use xcm::{ @@ -51,18 +52,44 @@ parameter_types! { pub BridgeRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO]; - pub PriorityBoostPerMessage: u64 = 921_900_294; + // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value + pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; + + pub AssetHubWococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_wococo::ASSET_HUB_WOCOCO_PARACHAIN_ID.into(); pub FromAssetHubWococoToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen(X1(Parachain(1000))).into(), + ParentThen(X1(Parachain(AssetHubWococoParaId::get().into()))).into(), DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, ); + + pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + + pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); +} + +fn build_congestion_message(is_congested: bool) -> sp_std::vec::Vec> { + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_asset_hub_wococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: bp_asset_hub_wococo::Call::ToRococoXcmRouter( + bp_asset_hub_wococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested, + } + ) + .encode() + .into(), + } + ] } /// Proof of messages, coming from Rococo. pub type FromRococoBridgeHubMessagesProof = FromBridgedChainMessagesProof; -/// Messages delivery proof for Rococo Bridge Hub -> Wococo Bridge Hub messages. +/// Messages delivery proof for RococoBridge Hub -> Wococo BridgeHub messages. pub type ToRococoBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof; @@ -73,7 +100,7 @@ pub type OnBridgeHubWococoBlobDispatcher = BridgeBlobDispatcher< BridgeRococoMessagesPalletInstance, >; -/// Export XCM messages to be relayed to the otherside +/// Export XCM messages to be relayed to the other side pub type ToBridgeHubRococoHaulBlobExporter = HaulBlobExporter< XcmBlobHaulerAdapter, RococoGlobalConsensusNetwork, @@ -86,11 +113,14 @@ impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { type SenderAndLane = FromAssetHubWococoToAssetHubRococoRoute; type ToSourceChainSender = crate::XcmRouter; - type CongestedMessage = (); - type UncongestedMessage = (); + type CongestedMessage = CongestedMessage; + type UncongestedMessage = UncongestedMessage; } pub const DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 1]); +/// On messages delivered callback. +pub type OnMessagesDelivered = XcmBlobHaulerAdapter; + /// Messaging Bridge configuration for BridgeHubWococo -> BridgeHubRococo pub struct WithBridgeHubRococoMessageBridge; impl MessageBridge for WithBridgeHubRococoMessageBridge { @@ -136,13 +166,15 @@ impl ThisChainWithMessages for BridgeHubWococo { } /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type BridgeRefundBridgeHubRococoMessages = RefundBridgedParachainMessages< - Runtime, - RefundableParachain, - RefundableMessagesLane, - ActualFeeRefund, - PriorityBoostPerMessage, - StrBridgeRefundBridgeHubRococoMessages, +pub type BridgeRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< + RefundBridgedParachainMessages< + Runtime, + RefundableParachain, + RefundableMessagesLane, + ActualFeeRefund, + PriorityBoostPerMessage, + StrBridgeRefundBridgeHubRococoMessages, + >, >; bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubRococoMessages); @@ -162,6 +194,18 @@ mod tests { AssertCompleteBridgeConstants, }, }; + use parachains_common::{wococo, Balance}; + + /// Every additional message in the message delivery transaction boosts its priority. + /// So the priority of transaction with `N+1` messages is larger than priority of + /// transaction with `N` messages by the `PriorityBoostPerMessage`. + /// + /// Economically, it is an equivalent of adding tip to the transaction with `N` messages. + /// The `FEE_BOOST_PER_MESSAGE` constant is the value of this tip. + /// + /// We want this tip to be large enough (delivery transactions with more messages = less + /// operational costs and a faster bridge), so this value should be significant. + const FEE_BOOST_PER_MESSAGE: Balance = 2 * wococo::currency::UNITS; #[test] fn ensure_bridge_hub_wococo_message_lane_weights_are_correct() { @@ -213,5 +257,16 @@ mod tests { bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME, }, }); + + bridge_runtime_common::priority_calculator::ensure_priority_boost_is_sane::< + Runtime, + WithBridgeHubRococoMessagesInstance, + PriorityBoostPerMessage, + >(FEE_BOOST_PER_MESSAGE); + + assert_eq!( + BridgeRococoMessagesPalletInstance::get(), + X1(PalletInstance(bp_bridge_hub_wococo::WITH_BRIDGE_ROCOCO_MESSAGES_PALLET_INDEX)) + ); } } 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 dbdc2133ec8881deca3600ef29fc551e83f0a45b..3a8507ccf93e1005ffb4fd569ded0b3e57ddd2d3 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 @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +//! # Bridge Hub Rococo Runtime +//! +//! This runtime is also used for Bridge Hub Wococo. But we dont want to create another exact copy +//! of Bridge Hub Rococo, so we injected some tweaks backed by `RuntimeFlavor` and `pub storage +//! Flavor: RuntimeFlavor`. (For example this is needed for successful asset transfer between Asset +//! Hub Rococo and Asset Hub Wococo, where we need to have correct `xcm_config::UniversalLocation` +//! with correct `GlobalConsensus`. + #![cfg_attr(not(feature = "std"), no_std)] // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] @@ -27,6 +35,7 @@ pub mod bridge_hub_wococo_config; mod weights; pub mod xcm_config; +use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -45,6 +54,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, Everything}, weights::{ConstantMultiplier, Weight}, @@ -91,6 +101,15 @@ use parachains_common::{ }; use xcm_executor::XcmExecutor; +/// Enum for handling differences in the runtime configuration for BridgeHubRococo vs +/// BridgeHubWococo. +#[derive(Default, Eq, PartialEq, Debug, Clone, Copy, Decode, Encode)] +pub enum RuntimeFlavor { + #[default] + Rococo, + Wococo, +} + /// The address format for describing accounts. pub type Address = MultiAddress; @@ -122,7 +141,40 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -pub type Migrations = (pallet_collator_selection::migration::v1::MigrateToV1,); +pub type Migrations = ( + pallet_collator_selection::migration::v1::MigrateToV1, + pallet_multisig::migrations::v1::MigrateToV1, + InitStorageVersions, +); + +/// Migration to initialize storage versions for pallets added after genesis. +/// +/// Ideally this would be done automatically (see +/// ), but it probably won't be ready for some +/// time and it's beneficial to get try-runtime-cli on-runtime-upgrade checks into the CI, so we're +/// doing it manually. +pub struct InitStorageVersions; + +impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions { + fn on_runtime_upgrade() -> Weight { + use frame_support::traits::{GetStorageVersion, StorageVersion}; + use sp_runtime::traits::Saturating; + + let mut writes = 0; + + if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) { + PolkadotXcm::current_storage_version().put::(); + writes.saturating_inc(); + } + + if Balances::on_chain_storage_version() == StorageVersion::new(0) { + Balances::current_storage_version().put::(); + writes.saturating_inc(); + } + + ::DbWeight::get().reads_writes(2, writes) + } +} /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -439,7 +491,7 @@ parameter_types! { pub const RelayerStakeReserveId: [u8; 8] = *b"brdgrlrs"; } -/// Add parachain bridge pallet to track Wococo bridge hub parachain +/// Add parachain bridge pallet to track Wococo BridgeHub parachain pub type BridgeParachainWococoInstance = pallet_bridge_parachains::Instance1; impl pallet_bridge_parachains::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -452,7 +504,7 @@ impl pallet_bridge_parachains::Config for Runtime type MaxParaHeadDataSize = MaxWococoParaHeadDataSize; } -/// Add parachain bridge pallet to track Rococo bridge hub parachain +/// Add parachain bridge pallet to track Rococo BridgeHub parachain pub type BridgeParachainRococoInstance = pallet_bridge_parachains::Instance2; impl pallet_bridge_parachains::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -494,9 +546,15 @@ impl pallet_bridge_messages::Config for Run >; type SourceHeaderChain = SourceHeaderChainAdapter; - type MessageDispatch = - XcmBlobMessageDispatch; - type OnMessagesDelivered = (); + type MessageDispatch = XcmBlobMessageDispatch< + OnBridgeHubRococoBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + bridge_hub_rococo_config::AssetHubRococoParaId, + Runtime, + >, + >; + type OnMessagesDelivered = bridge_hub_rococo_config::OnMessagesDelivered; } /// Add XCM messages support for BridgeHubWococo to support Wococo->Rococo XCM messages @@ -528,9 +586,15 @@ impl pallet_bridge_messages::Config for Run >; type SourceHeaderChain = SourceHeaderChainAdapter; - type MessageDispatch = - XcmBlobMessageDispatch; - type OnMessagesDelivered = (); + type MessageDispatch = XcmBlobMessageDispatch< + OnBridgeHubWococoBlobDispatcher, + Self::WeightInfo, + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + bridge_hub_wococo_config::AssetHubWococoParaId, + Runtime, + >, + >; + type OnMessagesDelivered = bridge_hub_wococo_config::OnMessagesDelivered; } /// Allows collect and claim rewards for relayers @@ -583,16 +647,16 @@ construct_runtime!( Utility: pallet_utility::{Pallet, Call, Event} = 40, Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, - // Rococo and Wococo Bridge Hubs are sharing the runtime, so this runtime has two sets of + // Rococo and Wococo BridgeHubs are sharing the runtime, so this runtime has two sets of // bridge pallets. Both are deployed at both runtimes, but only one set is actually used // at particular runtime. - // With-Wococo bridge modules that are active (used) at Rococo Bridge Hub runtime. + // With-Wococo bridge modules that are active (used) at Rococo BridgeHub runtime. BridgeWococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 41, BridgeWococoParachain: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 42, BridgeWococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 46, - // With-Rococo bridge modules that are active (used) at Wococo Bridge Hub runtime. + // With-Rococo bridge modules that are active (used) at Wococo BridgeHub runtime. BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 43, BridgeRococoParachain: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 44, BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 45, @@ -948,19 +1012,19 @@ impl_runtime_apis! { impl cumulus_pallet_session_benchmarking::Config for Runtime {} use xcm::latest::prelude::*; - use xcm_config::RelayLocation; + use xcm_config::TokenLocation; impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; fn valid_destination() -> Result { - Ok(RelayLocation::get()) + Ok(TokenLocation::get()) } fn worst_case_holding(_depositable_count: u32) -> MultiAssets { // just concrete assets according to relay chain. let assets: Vec = vec![ MultiAsset { - id: Concrete(RelayLocation::get()), + id: Concrete(TokenLocation::get()), fun: Fungible(1_000_000 * UNITS), } ]; @@ -970,8 +1034,8 @@ impl_runtime_apis! { parameter_types! { pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - RelayLocation::get(), - MultiAsset { fun: Fungible(UNITS), id: Concrete(RelayLocation::get()) }, + TokenLocation::get(), + MultiAsset { fun: Fungible(UNITS), id: Concrete(TokenLocation::get()) }, )); pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None; pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; @@ -986,7 +1050,7 @@ impl_runtime_apis! { fn get_multi_asset() -> MultiAsset { MultiAsset { - id: Concrete(RelayLocation::get()), + id: Concrete(TokenLocation::get()), fun: Fungible(UNITS), } } @@ -1008,16 +1072,16 @@ impl_runtime_apis! { } fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((RelayLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + Ok((TokenLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) } fn subscribe_origin() -> Result { - Ok(RelayLocation::get()) + Ok(TokenLocation::get()) } fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = RelayLocation::get(); - let assets: MultiAssets = (Concrete(RelayLocation::get()), 1_000 * UNITS).into(); + let origin = TokenLocation::get(); + let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); let ticket = MultiLocation { parents: 0, interior: Here }; Ok((origin, ticket, assets)) } @@ -1028,7 +1092,7 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - Ok((RelayLocation::get(), NetworkId::Wococo, X1(Parachain(100)))) + Ok((TokenLocation::get(), NetworkId::Wococo, X1(Parachain(100)))) } fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { @@ -1233,6 +1297,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs index 40a2036fb49a9b3ec7c121c5c1dd2a8451118497..78a0eed91740d645e0c292d86ae1f5909fa395c9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs @@ -62,16 +62,8 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { fn withdraw_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::withdraw_asset()) } - // Currently there is no trusted reserve (`IsReserve = ()`), - // but we need this hack for `pallet_xcm::reserve_transfer_assets` - // (TODO) fix https://github.com/paritytech/polkadot/pull/7424 - // (TODO) fix https://github.com/paritytech/polkadot/pull/7546 - fn reserve_asset_deposited(_assets: &MultiAssets) -> Weight { - // TODO: if we change `IsReserve = ...` then use this line... - // TODO: or if remote weight estimation is fixed, then remove - // TODO: hardcoded - fix https://github.com/paritytech/cumulus/issues/1974 - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - hardcoded_weight.min(XcmFungibleWeight::::reserve_asset_deposited()) + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmFungibleWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { assets.weigh_multi_assets(XcmFungibleWeight::::receive_teleported_asset()) @@ -128,10 +120,7 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { } fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - // Hardcoded till the XCM pallet is fixed - let hardcoded_weight = Weight::from_parts(1_000_000_000_u64, 0); - let weight = assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()); - hardcoded_weight.min(weight) + assets.weigh_multi_assets(XcmFungibleWeight::::deposit_asset()) } fn deposit_reserve_asset( assets: &MultiAssetFilter, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 8f9fbc912454b5c89759fad5faf440c3275cbcf1..cd1a673cb53979843ecf191e636865b54b035a3d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-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: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --template=./templates/xcm-bench-template.hbs -// --chain=bridge-hub-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 -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_benchmarks::fungible +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-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: 24_521_000 picoseconds. - Weight::from_parts(25_005_000, 3593) + // Minimum execution time: 23_601_000 picoseconds. + Weight::from_parts(24_226_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: `153` // Estimated: `6196` - // Minimum execution time: 52_274_000 picoseconds. - Weight::from_parts(53_374_000, 6196) + // Minimum execution time: 51_043_000 picoseconds. + Weight::from_parts(52_326_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: `260` // Estimated: `6196` - // Minimum execution time: 77_625_000 picoseconds. - Weight::from_parts(78_530_000, 6196) + // Minimum execution time: 75_639_000 picoseconds. + Weight::from_parts(76_736_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 500_000_000_000 picoseconds. - Weight::from_parts(500_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3572` - // Minimum execution time: 32_804_000 picoseconds. - Weight::from_parts(33_462_000, 3572) + // Minimum execution time: 31_190_000 picoseconds. + Weight::from_parts(32_150_000, 3572) .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_921_000 picoseconds. - Weight::from_parts(4_050_000, 0) + // Minimum execution time: 3_603_000 picoseconds. + Weight::from_parts(3_721_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 25_436_000 picoseconds. - Weight::from_parts(25_789_000, 3593) + // Minimum execution time: 24_265_000 picoseconds. + Weight::from_parts(25_004_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `3624` - // Minimum execution time: 53_846_000 picoseconds. - Weight::from_parts(54_684_000, 3624) + // Minimum execution time: 51_882_000 picoseconds. + Weight::from_parts(53_228_000, 3624) .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: `107` // Estimated: `3572` - // Minimum execution time: 33_052_000 picoseconds. - Weight::from_parts(33_897_000, 3572) + // Minimum execution time: 32_195_000 picoseconds. + Weight::from_parts(33_206_000, 3572) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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 e3d8645d49e7e6e6b0d6a7dd82a244c5cca90ee1..b35011b095f5263ddcad366b66b7f53c55f7b924 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 @@ -17,8 +17,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, ParachainInfo, ParachainSystem, - PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - WeightToFee, XcmpQueue, + PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, + RuntimeOrigin, WeightToFee, XcmpQueue, }; use crate::{ bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, @@ -30,18 +30,17 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; +use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::Get; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, - CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, + ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{ traits::{ExportXcm, WithOriginFilter}, @@ -49,7 +48,8 @@ use xcm_executor::{ }; parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub storage Flavor: RuntimeFlavor = RuntimeFlavor::default(); + pub const TokenLocation: MultiLocation = MultiLocation::parent(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); @@ -57,6 +57,7 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } +/// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. pub struct RelayNetwork; impl Get> for RelayNetwork { fn get() -> Option { @@ -65,10 +66,9 @@ impl Get> for RelayNetwork { } impl Get for RelayNetwork { fn get() -> NetworkId { - match u32::from(ParachainInfo::parachain_id()) { - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID => NetworkId::Rococo, - bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID => NetworkId::Wococo, - para_id => unreachable!("Not supported for para_id: {}", para_id), + match Flavor::get() { + RuntimeFlavor::Rococo => NetworkId::Rococo, + RuntimeFlavor::Wococo => NetworkId::Wococo, } } } @@ -90,7 +90,7 @@ pub type CurrencyTransactor = CurrencyAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -154,9 +154,10 @@ impl Contains for SafeCallFilter { // Allow to change dedicated storage items (called by governance-like) match call { RuntimeCall::System(frame_system::Call::set_storage { items }) - if items.iter().any(|(k, _)| { + if items.iter().all(|(k, _)| { k.eq(&DeliveryRewardInBalance::key()) | - k.eq(&RequiredStakeForStakeAndSlash::key()) + k.eq(&RequiredStakeForStakeAndSlash::key()) | + k.eq(&Flavor::key()) }) => return true, _ => (), @@ -206,7 +207,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. @@ -217,13 +218,14 @@ pub type Barrier = TrailingSetTopicAsId< UniversalLocation, ConstU32<8>, >, - // TODO:check-parameter - (https://github.com/paritytech/parity-bridges-common/issues/2084) - // remove this and extend `AllowExplicitUnpaidExecutionFrom` with "or SystemParachains" once merged https://github.com/paritytech/polkadot/pull/7005 - AllowUnpaidExecutionFrom, ), >, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - NativeToken with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -233,8 +235,7 @@ impl xcm_executor::Config for XcmConfig { // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native // token where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of NativeToken of relay chain. - type IsTeleporter = ConcreteNativeAssetFrom; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< @@ -243,7 +244,7 @@ impl xcm_executor::Config for XcmConfig { MaxInstructions, >; type Trader = - UsingComponents>; + UsingComponents>; type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetLocker = (); 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 e5fe67f2a8e5b29a46adcf2a133ce9e956df9d5b..dcde07dc287223d1551e4eb68f67726f6ebaf677 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 @@ -19,7 +19,7 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_hub_rococo_config, bridge_hub_wococo_config, - xcm_config::{RelayNetwork, XcmConfig}, + xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, DeliveryRewardInBalance, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, @@ -35,7 +35,7 @@ use sp_runtime::{ }; use xcm::latest::prelude::*; -// Para id of sibling chain (Rockmine/Wockmint) used in tests. +// Para id of sibling chain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = 1000; parameter_types! { @@ -55,7 +55,7 @@ fn construct_extrinsic( frame_system::CheckNonce::::from(0), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - BridgeRejectObsoleteHeadersAndMessages {}, + BridgeRejectObsoleteHeadersAndMessages::default(), ( bridge_hub_wococo_config::BridgeRefundBridgeHubRococoMessages::default(), bridge_hub_rococo_config::BridgeRefundBridgeHubWococoMessages::default(), @@ -191,7 +191,11 @@ mod bridge_hub_rococo_tests { } }), || ExportMessage { network: Wococo, destination: X1(Parachain(1234)), xcm: Xcm(vec![]) }, - bridge_hub_rococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO + bridge_hub_rococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + Some((TokenLocation::get(), ExistentialDeposit::get()).into()), + // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` + Some((TokenLocation::get(), bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get()).into()), + || (), ) } @@ -222,6 +226,7 @@ mod bridge_hub_rococo_tests { } }), bridge_hub_rococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + || (), ) } @@ -243,6 +248,7 @@ mod bridge_hub_rococo_tests { SIBLING_PARACHAIN_ID, Rococo, DEFAULT_XCM_LANE_TO_BRIDGE_HUB_WOCOCO, + || (), ) } @@ -268,6 +274,25 @@ mod bridge_hub_rococo_tests { ExistentialDeposit::get(), executive_init_block, construct_and_apply_extrinsic, + || (), + ); + } + + #[test] + pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_weight_for_paid_export_message_with_reserve_transfer::< + Runtime, + XcmConfig, + WeightToFee, + >(); + + // check if estimated value is sane + let max_expected = bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs` value", + estimated, + max_expected ); } } @@ -275,12 +300,38 @@ mod bridge_hub_rococo_tests { mod bridge_hub_wococo_tests { use super::*; use bridge_hub_rococo_runtime::{ - BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, + xcm_config, AllPalletsWithoutSystem, BridgeGrandpaRococoInstance, + BridgeParachainRococoInstance, RuntimeFlavor, WithBridgeHubRococoMessagesInstance, }; use bridge_hub_wococo_config::{ WithBridgeHubRococoMessageBridge, DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, }; + use frame_support::assert_ok; + + type RuntimeHelper = bridge_hub_test_utils::RuntimeHelper; + + pub(crate) fn set_wococo_flavor() { + let flavor_key = xcm_config::Flavor::key().to_vec(); + let flavor = RuntimeFlavor::Wococo; + + // encode `set_storage` call + let set_storage_call = RuntimeCall::System(frame_system::Call::::set_storage { + items: vec![(flavor_key, flavor.encode())], + }) + .encode(); + + // estimate - storing just 1 value + use frame_system::WeightInfo; + let require_weight_at_most = + ::SystemWeightInfo::set_storage(1); + + // execute XCM with Transact to `set_storage` as governance does + assert_ok!(RuntimeHelper::execute_as_governance(set_storage_call, require_weight_at_most) + .ensure_complete()); + + // check if stored + assert_eq!(flavor, xcm_config::Flavor::get()); + } bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( Runtime, @@ -370,7 +421,11 @@ mod bridge_hub_wococo_tests { } }), || ExportMessage { network: Rococo, destination: X1(Parachain(4321)), xcm: Xcm(vec![]) }, - bridge_hub_wococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO + bridge_hub_wococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + Some((TokenLocation::get(), ExistentialDeposit::get()).into()), + // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` + Some((TokenLocation::get(), bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs::get()).into()), + set_wococo_flavor, ) } @@ -401,6 +456,7 @@ mod bridge_hub_wococo_tests { } }), bridge_hub_wococo_config::DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + set_wococo_flavor, ) } @@ -422,6 +478,7 @@ mod bridge_hub_wococo_tests { SIBLING_PARACHAIN_ID, Wococo, DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO, + set_wococo_flavor, ) } @@ -447,6 +504,25 @@ mod bridge_hub_wococo_tests { ExistentialDeposit::get(), executive_init_block, construct_and_apply_extrinsic, + set_wococo_flavor, + ); + } + + #[test] + pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { + let estimated = bridge_hub_test_utils::test_cases::can_calculate_weight_for_paid_export_message_with_reserve_transfer::< + Runtime, + XcmConfig, + WeightToFee, + >(); + + // check if estimated value is sane + let max_expected = bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs::get(); + assert!( + estimated <= max_expected, + "calculated: {:?}, max_expected: {:?}, please adjust `bp_asset_hub_wococo::BridgeHubWococoBaseFeeInWocs` value", + estimated, + max_expected ); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index d56c32d8afabb3c40eb861f028c5f954889cf60d..2ad79bb24886f26760a3b107b979506877b0225a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -8,7 +8,6 @@ description = "Utils for BridgeHub testing" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.20", default-features = false } -assert_matches = "1.4.0" # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -19,6 +18,7 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features sp-io = { path = "../../../../../substrate/primitives/io", default-features = false} sp-keyring = { path = "../../../../../substrate/primitives/keyring" } sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} +sp-tracing = { path = "../../../../../substrate/primitives/tracing" } pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false} pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false} pallet-session = { path = "../../../../../substrate/frame/session", default-features = false} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs index aa7fa16a9791c626eaa4473f6de5914e6f5867ca..d4e5aac34369732e15aa48e9a7b7f0d994e739f4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs @@ -16,7 +16,6 @@ //! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities. -use assert_matches::assert_matches; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch, SourceHeaderChain}, LaneId, MessageKey, OutboundLaneData, Weight, @@ -47,10 +46,16 @@ use parachains_runtimes_test_utils::{ }; use sp_core::H256; use sp_keyring::AccountKeyring::*; -use sp_runtime::{traits::Header as HeaderT, AccountId32}; +use sp_runtime::{ + traits::{Header as HeaderT, Zero}, + AccountId32, +}; use xcm::latest::prelude::*; use xcm_builder::DispatchBlobError; -use xcm_executor::XcmExecutor; +use xcm_executor::{ + traits::{TransactAsset, WeightBounds}, + XcmExecutor, +}; // Re-export test_case from assets pub use asset_test_utils::include_teleports_for_native_asset_works; @@ -137,6 +142,9 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< >, export_message_instruction: fn() -> Instruction, expected_lane_id: LaneId, + existential_deposit: Option, + maybe_paid_export_message: Option, + prepare_configuration: impl Fn(), ) where Runtime: frame_system::Config + pallet_balances::Config @@ -161,6 +169,8 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< .with_tracing() .build() .execute_with(|| { + prepare_configuration(); + // check queue before assert_eq!( pallet_bridge_messages::OutboundLanes::::try_get( @@ -170,10 +180,35 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< ); // prepare `ExportMessage` - let xcm = Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - export_message_instruction(), - ]); + let xcm = if let Some(fee) = maybe_paid_export_message { + // deposit ED to origin (if needed) + if let Some(ed) = existential_deposit { + XcmConfig::AssetTransactor::deposit_asset( + &ed, + &sibling_parachain_location, + &XcmContext::with_message_id([0; 32]), + ) + .expect("deposited ed"); + } + // deposit fee to origin + XcmConfig::AssetTransactor::deposit_asset( + &fee, + &sibling_parachain_location, + &XcmContext::with_message_id([0; 32]), + ) + .expect("deposited fee"); + + Xcm(vec![ + WithdrawAsset(MultiAssets::from(vec![fee.clone()])), + BuyExecution { fees: fee, weight_limit: Unlimited }, + export_message_instruction(), + ]) + } else { + Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + export_message_instruction(), + ]) + }; // execute XCM let hash = xcm.using_encoded(sp_io::hashing::blake2_256); @@ -231,6 +266,7 @@ pub fn message_dispatch_routing_works< dyn Fn(Vec) -> Option>, >, expected_lane_id: LaneId, + prepare_configuration: impl Fn(), ) where Runtime: frame_system::Config + pallet_balances::Config @@ -249,6 +285,7 @@ pub fn message_dispatch_routing_works< XcmConfig: xcm_executor::Config, MessagesPalletInstance: 'static, ValidatorIdOf: From>, + ::AccountId: From, HrmpChannelOpener: frame_support::inherent::ProvideInherent< Call = cumulus_pallet_parachain_system::Call, >, @@ -267,12 +304,14 @@ pub fn message_dispatch_routing_works< .with_tracing() .build() .execute_with(|| { + prepare_configuration(); + let mut alice = [0u8; 32]; alice[0] = 1; let included_head = RuntimeHelper::::run_to_block( 2, - AccountId::from(alice), + AccountId::from(alice).into(), ); // 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP) let bridging_message = @@ -343,6 +382,7 @@ pub fn relayed_incoming_message_works>::BridgedChain as bp_runtime::Chain>::Hash>, ::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, AccountIdOf: From, >::InboundRelayer: From, { assert_ne!(runtime_para_id, sibling_parachain_id); - assert_ne!(runtime_para_id, bridged_para_id); ExtBuilder::::default() .with_collators(collator_session_key.collators()) @@ -388,12 +428,14 @@ pub fn relayed_incoming_message_works::run_to_block( 2, - AccountId::from(alice), + AccountId::from(alice).into(), ); mock_open_hrmp_channel::( runtime_para_id.into(), @@ -528,15 +570,24 @@ pub fn relayed_incoming_message_works>::take_xcm( sibling_parachain_id.into(), ) .unwrap(); - let mut dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); - // We use `WithUniqueTopic`, so expect a trailing `SetTopic`. - assert_matches!(dispatched.0.pop(), Some(SetTopic(..))); - assert_eq!(dispatched, expected_dispatch); + // verify contains original message + let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); + let mut dispatched_clone = dispatched.clone(); + for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() { + assert_eq!(expected_instr, &dispatched.0[idx]); + assert_eq!(expected_instr, &dispatched_clone.0.remove(0)); + } + match dispatched_clone.0.len() { + 0 => (), + 1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))), + count => assert!(false, "Unexpected messages count: {:?}", count), + } }) } @@ -557,6 +608,7 @@ pub fn complex_relay_extrinsic_works ) -> sp_runtime::DispatchOutcome, + prepare_configuration: impl Fn(), ) where Runtime: frame_system::Config + pallet_balances::Config @@ -591,6 +643,7 @@ pub fn complex_relay_extrinsic_works::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId>, AccountIdOf: From, + ::AccountId: From, >::InboundRelayer: From, ::RuntimeCall: From> @@ -598,7 +651,6 @@ pub fn complex_relay_extrinsic_works> { assert_ne!(runtime_para_id, sibling_parachain_id); - assert_ne!(runtime_para_id, bridged_para_id); // Relayer account at local/this BH. let relayer_at_target = Bob; @@ -617,12 +669,14 @@ pub fn complex_relay_extrinsic_works::run_to_block( 2, - AccountId::from(alice), + AccountId::from(alice).into(), ); let zero: BlockNumberFor = 0u32.into(); let genesis_hash = frame_system::Pallet::::block_hash(zero); @@ -678,7 +732,7 @@ pub fn complex_relay_extrinsic_works, MB, ()>( lane_id, - xcm.into(), + xcm.clone().into(), message_nonce, message_destination, para_header_number, @@ -769,18 +823,133 @@ pub fn complex_relay_extrinsic_works>::take_xcm( sibling_parachain_id.into(), ) .unwrap(); - let mut dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); - // We use `WithUniqueTopic`, so expect a trailing `SetTopic`. - assert_matches!(dispatched.0.pop(), Some(SetTopic(..))); - assert_eq!(dispatched, expected_dispatch); + // verify contains original message + let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); + let mut dispatched_clone = dispatched.clone(); + for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() { + assert_eq!(expected_instr, &dispatched.0[idx]); + assert_eq!(expected_instr, &dispatched_clone.0.remove(0)); + } + match dispatched_clone.0.len() { + 0 => (), + 1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))), + count => assert!(false, "Unexpected messages count: {:?}", count), + } }) } +/// Estimates fee for paid `ExportMessage` processing. +pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer< + Runtime, + XcmConfig, + WeightToFee, +>() -> u128 +where + Runtime: frame_system::Config + pallet_balances::Config, + XcmConfig: xcm_executor::Config, + WeightToFee: frame_support::weights::WeightToFee>, + ::Balance: From + Into, +{ + // data here are not relevant for weighing + let mut xcm = Xcm(vec![ + WithdrawAsset(MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(34333299), + }])), + BuyExecution { + fees: MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(34333299), + }, + weight_limit: Unlimited, + }, + ExportMessage { + network: Polkadot, + destination: X1(Parachain(1000)), + xcm: Xcm(vec![ + ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(Kusama)), + }), + fun: Fungible(1000000000000), + }])), + ClearOrigin, + BuyExecution { + fees: MultiAsset { + id: Concrete(MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(Kusama)), + }), + fun: Fungible(1000000000000), + }, + weight_limit: Unlimited, + }, + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: MultiLocation { + parents: 0, + interior: X1(xcm::latest::prelude::AccountId32 { + network: None, + id: [ + 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, + 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, + 109, 162, 125, + ], + }), + }, + }, + SetTopic([ + 116, 82, 194, 132, 171, 114, 217, 165, 23, 37, 161, 177, 165, 179, 247, 114, + 137, 101, 147, 70, 28, 157, 168, 32, 154, 63, 74, 228, 152, 180, 5, 63, + ]), + ]), + }, + RefundSurplus, + DepositAsset { + assets: Wild(All), + beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(1000)) }, + }, + SetTopic([ + 36, 224, 250, 165, 82, 195, 67, 110, 160, 170, 140, 87, 217, 62, 201, 164, 42, 98, 219, + 157, 124, 105, 248, 25, 131, 218, 199, 36, 109, 173, 100, 122, + ]), + ]); + + // get weight + let weight = XcmConfig::Weigher::weight(&mut xcm); + assert_ok!(weight); + let weight = weight.unwrap(); + // check if sane + let max_expected = Runtime::BlockWeights::get().max_block / 10; + assert!( + weight.all_lte(max_expected), + "calculated weight: {:?}, max_expected: {:?}", + weight, + max_expected + ); + + // check fee, should not be 0 + let estimated_fee = WeightToFee::weight_to_fee(&weight); + assert!(estimated_fee > BalanceOf::::zero()); + + sp_tracing::try_init_simple(); + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for `ExportMessage` for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee.into() +} + pub mod test_data { use super::*; use bp_header_chain::justification::GrandpaJustification; @@ -928,7 +1097,7 @@ pub mod test_data { ); /// Simulates `HaulBlobExporter` and all its wrapping and captures generated plain bytes, - /// which are transfered over bridge. + /// which are transferred over bridge. pub(crate) fn simulate_message_exporter_on_bridged_chain< SourceNetwork: Get, DestinationNetwork: Get, diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 167f460610d6f15a6064783a1b7b458b2faedf94..e66cef31e56f4817fa31def359d5c7e132ea9c49 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -43,6 +43,7 @@ sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", defau sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -57,7 +58,6 @@ pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} -polkadot-runtime-constants = { path = "../../../../../polkadot/runtime/polkadot/constants", default-features = false} 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} @@ -72,6 +72,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } +pallet-collective-content = { path = "../../../pallets/collective-content", default-features = false } parachain-info = { path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -95,6 +96,7 @@ runtime-benchmarks = [ "pallet-alliance/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-collective-content/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-core-fellowship/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", @@ -129,6 +131,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-collective-content/try-runtime", "pallet-collective/try-runtime", "pallet-core-fellowship/try-runtime", "pallet-multisig/try-runtime", @@ -170,6 +173,7 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-collator-selection/std", + "pallet-collective-content/std", "pallet-collective/std", "pallet-core-fellowship/std", "pallet-multisig/std", @@ -190,13 +194,13 @@ std = [ "polkadot-core-primitives/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", - "polkadot-runtime-constants/std", "scale-info/std", "sp-api/std", "sp-arithmetic/std", "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", "sp-offchain/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b055ffc8abf1337e1260156cd149fe21b0573ba0 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/mod.rs @@ -0,0 +1,255 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The Ambassador Program. +//! +//! The module defines the following on-chain functionality of the Ambassador Program: +//! +//! - Managed set of program members, where every member has a [rank](ranks) +//! (via [AmbassadorCollective](pallet_ranked_collective)). +//! - Referendum functionality for the program members to propose, vote on, and execute +//! proposals on behalf of the members of a certain [rank](Origin) +//! (via [AmbassadorReferenda](pallet_referenda)). +//! - Managed content (charter, announcements) (via [pallet_collective_content]). +//! - Promotion and demotion periods, register of members' activity, and rank based salaries +//! (via [AmbassadorCore](pallet_core_fellowship)). +//! - Members' salaries (via [AmbassadorSalary](pallet_salary), requiring a member to be +//! imported or inducted into [AmbassadorCore](pallet_core_fellowship)). + +pub mod origins; +mod tracks; + +use super::*; +use crate::xcm_config::{DotAssetHub, FellowshipAdminBodyId}; +use frame_support::traits::{EitherOf, MapSuccess, TryMapSuccess}; +pub use origins::pallet_origins as pallet_ambassador_origins; +use origins::pallet_origins::{ + EnsureAmbassadorsVoice, EnsureAmbassadorsVoiceFrom, EnsureHeadAmbassadorsVoice, Origin, +}; +use parachains_common::polkadot::account; +use sp_core::ConstU128; +use sp_runtime::traits::{CheckedReduceBy, ConstU16, ConvertToValue, Replace}; +use xcm::prelude::*; +use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; + +/// The Ambassador Program's member ranks. +pub mod ranks { + use pallet_ranked_collective::Rank; + + #[allow(dead_code)] + pub const CANDIDATE: Rank = 0; + pub const AMBASSADOR_TIER_1: Rank = 1; + pub const AMBASSADOR_TIER_2: Rank = 2; + pub const SENIOR_AMBASSADOR_TIER_3: Rank = 3; + pub const SENIOR_AMBASSADOR_TIER_4: Rank = 4; + pub const HEAD_AMBASSADOR_TIER_5: Rank = 5; + pub const HEAD_AMBASSADOR_TIER_6: Rank = 6; + pub const HEAD_AMBASSADOR_TIER_7: Rank = 7; + pub const MASTER_AMBASSADOR_TIER_8: Rank = 8; + pub const MASTER_AMBASSADOR_TIER_9: Rank = 9; +} + +impl pallet_ambassador_origins::Config for Runtime {} + +pub type AmbassadorCollectiveInstance = pallet_ranked_collective::Instance2; + +/// Demotion is by any of: +/// - Root can promote arbitrarily. +/// - the FellowshipAdmin origin (i.e. token holder referendum); +/// - a senior members vote by the rank two above the current rank. +pub type DemoteOrigin = EitherOf< + frame_system::EnsureRootWithSuccess>, + EitherOf< + MapSuccess< + EnsureXcm>, + Replace>, + >, + TryMapSuccess< + EnsureAmbassadorsVoiceFrom>, + CheckedReduceBy>, + >, + >, +>; + +/// Promotion and approval (rank-retention) is by any of: +/// - Root can promote arbitrarily. +/// - the FellowshipAdmin origin (i.e. token holder referendum); +/// - a senior members vote by the rank two above the new/current rank. +/// - a member of rank `5` or above can add a candidate (rank `0`). +pub type PromoteOrigin = EitherOf< + DemoteOrigin, + TryMapSuccess< + pallet_ranked_collective::EnsureMember< + Runtime, + AmbassadorCollectiveInstance, + { ranks::HEAD_AMBASSADOR_TIER_5 }, + >, + Replace>, + >, +>; + +impl pallet_ranked_collective::Config for Runtime { + type WeightInfo = weights::pallet_ranked_collective_ambassador_collective::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type PromoteOrigin = PromoteOrigin; + type DemoteOrigin = DemoteOrigin; + type Polls = AmbassadorReferenda; + type MinRankOfClass = sp_runtime::traits::Identity; + type VoteWeight = pallet_ranked_collective::Linear; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 0; + pub const UndecidingTimeout: BlockNumber = 7 * DAYS; + // The Ambassador Referenda pallet account, used as a temporarily place to deposit a slashed imbalance before teleport to the treasury. + pub AmbassadorPalletAccount: AccountId = account::AMBASSADOR_REFERENDA_PALLET_ID.into_account_truncating(); +} + +pub type AmbassadorReferendaInstance = pallet_referenda::Instance2; + +impl pallet_referenda::Config for Runtime { + type WeightInfo = weights::pallet_referenda_ambassador_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + // A proposal can be submitted by a member of the Ambassador Program of + // [ranks::SENIOR_AMBASSADOR_TIER_3] rank or higher. + type SubmitOrigin = pallet_ranked_collective::EnsureMember< + Runtime, + AmbassadorCollectiveInstance, + { ranks::SENIOR_AMBASSADOR_TIER_3 }, + >; + type CancelOrigin = EitherOf, EnsureHeadAmbassadorsVoice>; + type KillOrigin = EitherOf, EnsureHeadAmbassadorsVoice>; + type Slash = ToParentTreasury; + type Votes = pallet_ranked_collective::Votes; + type Tally = pallet_ranked_collective::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<20>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = tracks::TracksInfo; + type Preimages = Preimage; +} + +parameter_types! { + pub const AnnouncementLifetime: BlockNumber = 180 * DAYS; + pub const MaxAnnouncements: u32 = 50; +} + +pub type AmbassadorContentInstance = pallet_collective_content::Instance1; + +impl pallet_collective_content::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CharterOrigin = EitherOf, EnsureHeadAmbassadorsVoice>; + type AnnouncementLifetime = AnnouncementLifetime; + // An announcement can be submitted by a Senior Ambassador member or an ambassador plurality + // voice taken via referendum. + type AnnouncementOrigin = EitherOfDiverse< + pallet_ranked_collective::EnsureMember< + Runtime, + AmbassadorCollectiveInstance, + { ranks::SENIOR_AMBASSADOR_TIER_3 }, + >, + EnsureAmbassadorsVoice, + >; + type MaxAnnouncements = MaxAnnouncements; + type WeightInfo = weights::pallet_collective_content::WeightInfo; +} + +pub type AmbassadorCoreInstance = pallet_core_fellowship::Instance2; + +impl pallet_core_fellowship::Config for Runtime { + type WeightInfo = weights::pallet_core_fellowship_ambassador_core::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Members = pallet_ranked_collective::Pallet; + type Balance = Balance; + // Parameters are set by any of: + // - Root; + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a vote among all Head Ambassadors. + type ParamsOrigin = EitherOfDiverse< + EnsureXcm>, + EnsureHeadAmbassadorsVoice, + >; + // Induction (creating a candidate) is by any of: + // - Root; + // - the FellowshipAdmin origin (i.e. token holder referendum); + // - a single Head Ambassador; + // - a vote among all senior members. + type InductOrigin = EitherOfDiverse< + EnsureXcm>, + EitherOfDiverse< + pallet_ranked_collective::EnsureMember< + Runtime, + AmbassadorCollectiveInstance, + { ranks::HEAD_AMBASSADOR_TIER_5 }, + >, + EnsureAmbassadorsVoiceFrom>, + >, + >; + type ApproveOrigin = PromoteOrigin; + type PromoteOrigin = PromoteOrigin; + type EvidenceSize = ConstU32<65536>; +} + +pub type AmbassadorSalaryInstance = pallet_salary::Instance2; + +parameter_types! { + // The interior location on AssetHub for the paying account. This is the Ambassador Salary + // pallet instance (which sits at index 74). This sovereign account will need funding. + pub AmbassadorSalaryLocation: InteriorMultiLocation = PalletInstance(74).into(); +} + +/// [`PayOverXcm`] setup to pay the Ambassador salary on the AssetHub in DOT. +pub type AmbassadorSalaryPaymaster = PayOverXcm< + AmbassadorSalaryLocation, + crate::xcm_config::XcmRouter, + crate::PolkadotXcm, + ConstU32<{ 6 * HOURS }>, + AccountId, + (), + ConvertToValue, + AliasesIntoAccountId32<(), AccountId>, +>; + +impl pallet_salary::Config for Runtime { + type WeightInfo = weights::pallet_salary_ambassador_salary::WeightInfo; + type RuntimeEvent = RuntimeEvent; + + #[cfg(not(feature = "runtime-benchmarks"))] + type Paymaster = AmbassadorSalaryPaymaster; + #[cfg(feature = "runtime-benchmarks")] + type Paymaster = crate::impls::benchmarks::PayWithEnsure< + AmbassadorSalaryPaymaster, + crate::impls::benchmarks::OpenHrmpChannel>, + >; + type Members = pallet_ranked_collective::Pallet; + + #[cfg(not(feature = "runtime-benchmarks"))] + type Salary = pallet_core_fellowship::Pallet; + #[cfg(feature = "runtime-benchmarks")] + type Salary = frame_support::traits::tokens::ConvertRank< + crate::impls::benchmarks::RankToSalary, + >; + // 15 days to register for a salary payment. + type RegistrationPeriod = ConstU32<{ 15 * DAYS }>; + // 15 days to claim the salary payment. + type PayoutPeriod = ConstU32<{ 15 * DAYS }>; + // Total monthly salary budget. + type Budget = ConstU128<{ 10_000 * DOLLARS }>; +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs new file mode 100644 index 0000000000000000000000000000000000000000..3ce8a6b9e5d1bf7f70dda395f1998fd66d20cbeb --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/origins.rs @@ -0,0 +1,135 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The Ambassador Program's origins. + +#[frame_support::pallet] +pub mod pallet_origins { + use crate::ambassador::ranks; + use frame_support::pallet_prelude::*; + use pallet_ranked_collective::Rank; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + /// The pallet configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Plurality voice of the [ranks::AMBASSADOR_TIER_1] members or above given via + /// referendum. + Ambassadors, + /// Plurality voice of the [ranks::AMBASSADOR_TIER_2] members or above given via + /// referendum. + AmbassadorsTier2, + /// Plurality voice of the [ranks::SENIOR_AMBASSADOR_TIER_3] members or above given via + /// referendum. + SeniorAmbassadors, + /// Plurality voice of the [ranks::SENIOR_AMBASSADOR_TIER_4] members or above given via + /// referendum. + SeniorAmbassadorsTier4, + /// Plurality voice of the [ranks::HEAD_AMBASSADOR_TIER_5] members or above given via + /// referendum. + HeadAmbassadors, + /// Plurality voice of the [ranks::HEAD_AMBASSADOR_TIER_6] members or above given via + /// referendum. + HeadAmbassadorsTier6, + /// Plurality voice of the [ranks::HEAD_AMBASSADOR_TIER_7] members or above given via + /// referendum. + HeadAmbassadorsTier7, + /// Plurality voice of the [ranks::MASTER_AMBASSADOR_TIER_8] members or above given via + /// referendum. + MasterAmbassadors, + /// Plurality voice of the [ranks::MASTER_AMBASSADOR_TIER_9] members or above given via + /// referendum. + MasterAmbassadorsTier9, + } + + impl Origin { + /// Returns the rank that the origin `self` speaks for, or `None` if it doesn't speak for + /// any. + pub fn as_voice(&self) -> Option { + Some(match &self { + Origin::Ambassadors => ranks::AMBASSADOR_TIER_1, + Origin::AmbassadorsTier2 => ranks::AMBASSADOR_TIER_2, + Origin::SeniorAmbassadors => ranks::SENIOR_AMBASSADOR_TIER_3, + Origin::SeniorAmbassadorsTier4 => ranks::SENIOR_AMBASSADOR_TIER_4, + Origin::HeadAmbassadors => ranks::HEAD_AMBASSADOR_TIER_5, + Origin::HeadAmbassadorsTier6 => ranks::HEAD_AMBASSADOR_TIER_6, + Origin::HeadAmbassadorsTier7 => ranks::HEAD_AMBASSADOR_TIER_7, + Origin::MasterAmbassadors => ranks::MASTER_AMBASSADOR_TIER_8, + Origin::MasterAmbassadorsTier9 => ranks::MASTER_AMBASSADOR_TIER_9, + }) + } + } + + /// Implementation of the [EnsureOrigin] trait for the [Origin::HeadAmbassadors] origin. + pub struct EnsureHeadAmbassadorsVoice; + impl> + From> EnsureOrigin for EnsureHeadAmbassadorsVoice { + type Success = (); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::HeadAmbassadors => Ok(()), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::HeadAmbassadors)) + } + } + + /// Implementation of the [EnsureOrigin] trait for the plurality voice [Origin]s + /// from a given rank `R` with the success result of the corresponding [Rank]. + pub struct EnsureAmbassadorsVoiceFrom(PhantomData); + impl, O: Into> + From> EnsureOrigin + for EnsureAmbassadorsVoiceFrom + { + type Success = Rank; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match Origin::as_voice(&o) { + Some(r) if r >= R::get() => Ok(r), + _ => Err(O::from(o)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + ranks::MASTER_AMBASSADOR_TIER_9 + .ge(&R::get()) + .then(|| O::from(Origin::MasterAmbassadorsTier9)) + .ok_or(()) + } + } + + /// Implementation of the [EnsureOrigin] trait for the plurality voice [Origin]s with the + /// success result of the corresponding [Rank]. + pub struct EnsureAmbassadorsVoice; + impl> + From> EnsureOrigin for EnsureAmbassadorsVoice { + type Success = Rank; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| Origin::as_voice(&o).ok_or(O::from(o))) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::MasterAmbassadorsTier9)) + } + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs new file mode 100644 index 0000000000000000000000000000000000000000..073d8e6ee362ad97f9fa66c612fca5e1a8123ab2 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/ambassador/tracks.rs @@ -0,0 +1,282 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The Ambassador Program's referenda voting tracks. + +use super::Origin; +use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS}; +use sp_runtime::Perbill; + +/// Referendum `TrackId` type. +pub type TrackId = u16; + +/// Referendum track IDs. +pub mod constants { + use super::TrackId; + + pub const AMBASSADOR_TIER_1: TrackId = 1; + pub const AMBASSADOR_TIER_2: TrackId = 2; + pub const SENIOR_AMBASSADOR_TIER_3: TrackId = 3; + pub const SENIOR_AMBASSADOR_TIER_4: TrackId = 4; + pub const HEAD_AMBASSADOR_TIER_5: TrackId = 5; + pub const HEAD_AMBASSADOR_TIER_6: TrackId = 6; + pub const HEAD_AMBASSADOR_TIER_7: TrackId = 7; + pub const MASTER_AMBASSADOR_TIER_8: TrackId = 8; + pub const MASTER_AMBASSADOR_TIER_9: TrackId = 9; +} + +/// The type implementing the [`pallet_referenda::TracksInfo`] trait for referenda pallet. +pub struct TracksInfo; + +/// Information on the voting tracks. +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = TrackId; + + type RuntimeOrigin = ::PalletsOrigin; + + /// Return the array of available tracks and their information. + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + static DATA: [(TrackId, pallet_referenda::TrackInfo); 9] = [ + ( + constants::AMBASSADOR_TIER_1, + pallet_referenda::TrackInfo { + name: "ambassador tier 1", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::AMBASSADOR_TIER_2, + pallet_referenda::TrackInfo { + name: "ambassador tier 2", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::SENIOR_AMBASSADOR_TIER_3, + pallet_referenda::TrackInfo { + name: "senior ambassador tier 3", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::SENIOR_AMBASSADOR_TIER_4, + pallet_referenda::TrackInfo { + name: "senior ambassador tier 4", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::HEAD_AMBASSADOR_TIER_5, + pallet_referenda::TrackInfo { + name: "head ambassador tier 5", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::HEAD_AMBASSADOR_TIER_6, + pallet_referenda::TrackInfo { + name: "head ambassador tier 6", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::HEAD_AMBASSADOR_TIER_7, + pallet_referenda::TrackInfo { + name: "head ambassador tier 7", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::MASTER_AMBASSADOR_TIER_8, + pallet_referenda::TrackInfo { + name: "master ambassador tier 8", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ( + constants::MASTER_AMBASSADOR_TIER_9, + pallet_referenda::TrackInfo { + name: "master ambassador tier 9", + max_deciding: 10, + decision_deposit: 5 * DOLLARS, + prepare_period: 24 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 1 * HOURS, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(10), + ceil: Perbill::from_percent(50), + }, + }, + ), + ]; + &DATA[..] + } + + /// Determine the voting track for the given `origin`. + fn track_for(id: &Self::RuntimeOrigin) -> Result { + #[cfg(feature = "runtime-benchmarks")] + { + // For benchmarks, we enable a root origin. + // It is important that this is not available in production! + let root: Self::RuntimeOrigin = frame_system::RawOrigin::Root.into(); + if &root == id { + return Ok(constants::MASTER_AMBASSADOR_TIER_9) + } + } + + match Origin::try_from(id.clone()) { + Ok(Origin::Ambassadors) => Ok(constants::AMBASSADOR_TIER_1), + Ok(Origin::AmbassadorsTier2) => Ok(constants::AMBASSADOR_TIER_2), + Ok(Origin::SeniorAmbassadors) => Ok(constants::SENIOR_AMBASSADOR_TIER_3), + Ok(Origin::SeniorAmbassadorsTier4) => Ok(constants::SENIOR_AMBASSADOR_TIER_4), + Ok(Origin::HeadAmbassadors) => Ok(constants::HEAD_AMBASSADOR_TIER_5), + Ok(Origin::HeadAmbassadorsTier6) => Ok(constants::HEAD_AMBASSADOR_TIER_6), + Ok(Origin::HeadAmbassadorsTier7) => Ok(constants::HEAD_AMBASSADOR_TIER_7), + Ok(Origin::MasterAmbassadors) => Ok(constants::MASTER_AMBASSADOR_TIER_8), + Ok(Origin::MasterAmbassadorsTier9) => Ok(constants::MASTER_AMBASSADOR_TIER_9), + _ => Err(()), + } + } +} + +// implements [`frame_support::traits::Get`] for [`TracksInfo`] +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs index b97e44dda1be6d263e9c3d19249e159153a508a3..2a2757ea5cebc28a1f85bbc28d50e0c523b54d90 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -20,11 +20,12 @@ pub(crate) mod migration; mod origins; mod tracks; use crate::{ - impls::ToParentTreasury, weights, AccountId, Balance, Balances, FellowshipReferenda, - GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, Scheduler, DAYS, + impls::ToParentTreasury, + weights, + xcm_config::{FellowshipAdminBodyId, UsdtAssetHub}, + AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, PolkadotTreasuryAccount, + Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, DAYS, }; -use cumulus_primitives_core::Junction::GeneralIndex; use frame_support::{ parameter_types, traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg}, @@ -36,12 +37,10 @@ pub use origins::{ }; use pallet_ranked_collective::EnsureOfRank; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::polkadot::account; -use polkadot_runtime_constants::{time::HOURS, xcm::body::FELLOWSHIP_ADMIN_INDEX}; +use parachains_common::{polkadot::account, HOURS}; use sp_core::{ConstU128, ConstU32}; use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; -use xcm::latest::BodyId; -use xcm_builder::{AliasesIntoAccountId32, LocatableAssetId, PayOverXcm}; +use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; #[cfg(feature = "runtime-benchmarks")] use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure}; @@ -64,7 +63,6 @@ pub mod ranks { parameter_types! { // Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting. pub ReferendaPalletAccount: AccountId = account::REFERENDA_PALLET_ID.into_account_truncating(); - pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); } impl pallet_fellowship_origins::Config for Runtime {} @@ -72,7 +70,7 @@ impl pallet_fellowship_origins::Config for Runtime {} pub type FellowshipReferendaInstance = pallet_referenda::Instance1; impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda::WeightInfo; + type WeightInfo = weights::pallet_referenda_fellowship_referenda::WeightInfo; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; @@ -107,7 +105,7 @@ impl pallet_referenda::Config for Runtime { pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; impl pallet_ranked_collective::Config for Runtime { - type WeightInfo = weights::pallet_ranked_collective::WeightInfo; + type WeightInfo = weights::pallet_ranked_collective_fellowship_collective::WeightInfo; type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] @@ -139,7 +137,7 @@ impl pallet_ranked_collective::Config for Runtime pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1; impl pallet_core_fellowship::Config for Runtime { - type WeightInfo = weights::pallet_core_fellowship::WeightInfo; + type WeightInfo = weights::pallet_core_fellowship_fellowship_core::WeightInfo; type RuntimeEvent = RuntimeEvent; type Members = pallet_ranked_collective::Pallet; type Balance = Balance; @@ -197,12 +195,6 @@ pub type FellowshipSalaryInstance = pallet_salary::Instance1; use xcm::prelude::*; parameter_types! { - pub AssetHub: MultiLocation = (Parent, Parachain(1000)).into(); - pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); - pub UsdtAsset: LocatableAssetId = LocatableAssetId { - location: AssetHub::get(), - asset_id: AssetHubUsdtId::get(), - }; // The interior location on AssetHub for the paying account. This is the Fellowship Salary // pallet instance (which sits at index 64). This sovereign account will need funding. pub Interior: InteriorMultiLocation = PalletInstance(64).into(); @@ -218,12 +210,12 @@ pub type FellowshipSalaryPaymaster = PayOverXcm< ConstU32<{ 6 * HOURS }>, AccountId, (), - ConvertToValue, + ConvertToValue, AliasesIntoAccountId32<(), AccountId>, >; impl pallet_salary::Config for Runtime { - type WeightInfo = weights::pallet_salary::WeightInfo; + type WeightInfo = weights::pallet_salary_fellowship_salary::WeightInfo; type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 70e62a4dcdf96cb990b191bce3577f08b4e94e22..ff16f93d8f54b39be8a553883949165acf653521 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -36,11 +36,13 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +pub mod ambassador; pub mod impls; mod weights; pub mod xcm_config; // Fellowship configurations. pub mod fellowship; +pub use ambassador::pallet_ambassador_origins; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use fellowship::{ @@ -66,6 +68,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ fungible::HoldConsideration, ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, @@ -292,6 +295,8 @@ pub enum ProxyType { Alliance, /// Fellowship proxy. Allows calls related to the Fellowship. Fellowship, + /// Ambassador proxy. Allows calls related to the Ambassador Program. + Ambassador, } impl Default for ProxyType { fn default() -> Self { @@ -326,6 +331,18 @@ impl InstanceFilter for ProxyType { c, RuntimeCall::FellowshipCollective { .. } | RuntimeCall::FellowshipReferenda { .. } | + RuntimeCall::FellowshipCore { .. } | + RuntimeCall::FellowshipSalary { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Ambassador => matches!( + c, + RuntimeCall::AmbassadorCollective { .. } | + RuntimeCall::AmbassadorReferenda { .. } | + RuntimeCall::AmbassadorContent { .. } | + RuntimeCall::AmbassadorCore { .. } | + RuntimeCall::AmbassadorSalary { .. } | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -616,6 +633,14 @@ construct_runtime!( FellowshipCore: pallet_core_fellowship::::{Pallet, Call, Storage, Event} = 63, // pub type FellowshipSalaryInstance = pallet_salary::Instance1; FellowshipSalary: pallet_salary::::{Pallet, Call, Storage, Event} = 64, + + // Ambassador Program. + AmbassadorCollective: pallet_ranked_collective::::{Pallet, Call, Storage, Event} = 70, + AmbassadorReferenda: pallet_referenda::::{Pallet, Call, Storage, Event} = 71, + AmbassadorOrigins: pallet_ambassador_origins::{Origin} = 72, + AmbassadorCore: pallet_core_fellowship::::{Pallet, Call, Storage, Event} = 73, + AmbassadorSalary: pallet_salary::::{Pallet, Call, Storage, Event} = 74, + AmbassadorContent: pallet_collective_content::::{Pallet, Call, Storage, Event} = 75, } ); @@ -684,6 +709,11 @@ mod benches { [pallet_ranked_collective, FellowshipCollective] [pallet_core_fellowship, FellowshipCore] [pallet_salary, FellowshipSalary] + [pallet_referenda, AmbassadorReferenda] + [pallet_ranked_collective, AmbassadorCollective] + [pallet_collective_content, AmbassadorContent] + [pallet_core_fellowship, AmbassadorCore] + [pallet_salary, AmbassadorSalary] ); } @@ -910,6 +940,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs index 9ddf53792ea4f56fd7460f697d8ec4835dfdaa06..b5a3a892f79a56f034b60cbb3c4e142a5ff6ef16 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/mod.rs @@ -22,13 +22,18 @@ pub mod pallet_alliance; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_collective; -pub mod pallet_core_fellowship; +pub mod pallet_collective_content; +pub mod pallet_core_fellowship_ambassador_core; +pub mod pallet_core_fellowship_fellowship_core; pub mod pallet_multisig; pub mod pallet_preimage; pub mod pallet_proxy; -pub mod pallet_ranked_collective; -pub mod pallet_referenda; -pub mod pallet_salary; +pub mod pallet_ranked_collective_ambassador_collective; +pub mod pallet_ranked_collective_fellowship_collective; +pub mod pallet_referenda_ambassador_referenda; +pub mod pallet_referenda_fellowship_referenda; +pub mod pallet_salary_ambassador_salary; +pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs new file mode 100644 index 0000000000000000000000000000000000000000..e66907b9453060a29b5e6635fa03a31e0dc782ad --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective_content.rs @@ -0,0 +1,94 @@ +// 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_collective_content` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-18, STEPS: `10`, REPEAT: `3`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --steps=10 +// --repeat=3 +// --pallet=pallet_collective_content +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./parachains/runtimes/collectives/collectives-polkadot/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_collective_content`. +pub struct WeightInfo(PhantomData); +impl pallet_collective_content::WeightInfo for WeightInfo { + /// Storage: `AmbassadorContent::Charter` (r:0 w:1) + /// Proof: `AmbassadorContent::Charter` (`max_values`: Some(1), `max_size`: Some(70), added: 565, mode: `MaxEncodedLen`) + fn set_charter() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 99_000_000 picoseconds. + Weight::from_parts(99_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorContent::AnnouncementsCount` (r:1 w:1) + /// Proof: `AmbassadorContent::AnnouncementsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorContent::NextAnnouncementExpireAt` (r:1 w:1) + /// Proof: `AmbassadorContent::NextAnnouncementExpireAt` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorContent::Announcements` (r:0 w:1) + /// Proof: `AmbassadorContent::Announcements` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + fn announce() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `3507` + // Minimum execution time: 273_000_000 picoseconds. + Weight::from_parts(278_000_000, 0) + .saturating_add(Weight::from_parts(0, 3507)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorContent::Announcements` (r:1 w:1) + /// Proof: `AmbassadorContent::Announcements` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorContent::AnnouncementsCount` (r:1 w:1) + /// Proof: `AmbassadorContent::AnnouncementsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn remove_announcement() -> Weight { + // Proof Size summary in bytes: + // Measured: `450` + // Estimated: `3555` + // Minimum execution time: 326_000_000 picoseconds. + Weight::from_parts(338_000_000, 0) + .saturating_add(Weight::from_parts(0, 3555)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs new file mode 100644 index 0000000000000000000000000000000000000000..f40940a8b25faa7c441b1ac9b237cb34e671cf17 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_ambassador_core.rs @@ -0,0 +1,223 @@ +// Copyright 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_core_fellowship` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_core_fellowship +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/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_core_fellowship`. +pub struct WeightInfo(PhantomData); +impl pallet_core_fellowship::WeightInfo for WeightInfo { + /// Storage: `AmbassadorCore::Params` (r:0 w:1) + /// Proof: `AmbassadorCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + fn set_params() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Params` (r:1 w:0) + /// Proof: `AmbassadorCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:1 w:0) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:1 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn bump_offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `66011` + // Estimated: `69046` + // Minimum execution time: 96_000_000 picoseconds. + Weight::from_parts(111_000_000, 0) + .saturating_add(Weight::from_parts(0, 69046)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Params` (r:1 w:0) + /// Proof: `AmbassadorCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:1 w:0) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:1 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn bump_demote() -> Weight { + // Proof Size summary in bytes: + // Measured: `66121` + // Estimated: `69046` + // Minimum execution time: 99_000_000 picoseconds. + Weight::from_parts(116_000_000, 0) + .saturating_add(Weight::from_parts(0, 69046)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + fn set_active() -> Weight { + // Proof Size summary in bytes: + // Measured: `360` + // Estimated: `3514` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:0 w:1) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:0 w:1) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `3514` + // Minimum execution time: 36_000_000 picoseconds. + Weight::from_parts(36_000_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Params` (r:1 w:0) + /// Proof: `AmbassadorCore::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:1 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:0 w:1) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:0 w:1) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + fn promote() -> Weight { + // Proof Size summary in bytes: + // Measured: `65989` + // Estimated: `69046` + // Minimum execution time: 95_000_000 picoseconds. + Weight::from_parts(110_000_000, 0) + .saturating_add(Weight::from_parts(0, 69046)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:0 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `331` + // Estimated: `3514` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + fn import() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `3514` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::Member` (r:1 w:1) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:1 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn approve() -> Weight { + // Proof Size summary in bytes: + // Measured: `65967` + // Estimated: `69046` + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(104_000_000, 0) + .saturating_add(Weight::from_parts(0, 69046)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorCore::Member` (r:1 w:0) + /// Proof: `AmbassadorCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCore::MemberEvidence` (r:1 w:1) + /// Proof: `AmbassadorCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) + fn submit_evidence() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `69046` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 0) + .saturating_add(Weight::from_parts(0, 69046)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs similarity index 87% rename from cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship.rs rename to cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs index d053513b53accc68cc3332ee1e123b6c3a08bd83..434986b03bba84c8ef43250c2192a946de09b286 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_core_fellowship_fellowship_core.rs @@ -17,24 +17,21 @@ //! Autogenerated weights for `pallet_core_fellowship` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/release/polkadot-parachain // benchmark // pallet // --chain=collectives-polkadot-dev // --wasm-execution=compiled // --pallet=pallet_core_fellowship -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --steps=50 -// --repeat=20 +// --steps=2 +// --repeat=2 // --json // --header=./file_header.txt // --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ @@ -56,8 +53,8 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_077_000 picoseconds. - Weight::from_parts(9_356_000, 0) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,10 +72,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `66111` + // Measured: `66144` // Estimated: `69046` - // Minimum execution time: 128_419_000 picoseconds. - Weight::from_parts(149_318_000, 0) + // Minimum execution time: 109_000_000 picoseconds. + Weight::from_parts(125_000_000, 0) .saturating_add(Weight::from_parts(0, 69046)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -97,10 +94,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `66221` + // Measured: `66254` // Estimated: `69046` - // Minimum execution time: 127_629_000 picoseconds. - Weight::from_parts(130_928_000, 0) + // Minimum execution time: 112_000_000 picoseconds. + Weight::from_parts(114_000_000, 0) .saturating_add(Weight::from_parts(0, 69046)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -111,10 +108,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) fn set_active() -> Weight { // Proof Size summary in bytes: - // Measured: `460` + // Measured: `493` // Estimated: `3514` - // Minimum execution time: 18_655_000 picoseconds. - Weight::from_parts(19_331_000, 0) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(27_000_000, 0) .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -131,10 +128,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn induct() -> Weight { // Proof Size summary in bytes: - // Measured: `218` + // Measured: `251` // Estimated: `3514` - // Minimum execution time: 28_764_000 picoseconds. - Weight::from_parts(29_385_000, 0) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 0) .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(5)) @@ -155,10 +152,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn promote() -> Weight { // Proof Size summary in bytes: - // Measured: `66089` + // Measured: `66122` // Estimated: `69046` - // Minimum execution time: 123_179_000 picoseconds. - Weight::from_parts(125_302_000, 0) + // Minimum execution time: 97_000_000 picoseconds. + Weight::from_parts(129_000_000, 0) .saturating_add(Weight::from_parts(0, 69046)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(6)) @@ -171,10 +168,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `431` + // Measured: `464` // Estimated: `3514` - // Minimum execution time: 19_700_000 picoseconds. - Weight::from_parts(20_319_000, 0) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(22_000_000, 0) .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -185,10 +182,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) fn import() -> Weight { // Proof Size summary in bytes: - // Measured: `385` + // Measured: `418` // Estimated: `3514` - // Minimum execution time: 18_048_000 picoseconds. - Weight::from_parts(18_345_000, 0) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(24_000_000, 0) .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -201,10 +198,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) fn approve() -> Weight { // Proof Size summary in bytes: - // Measured: `66067` + // Measured: `66100` // Estimated: `69046` - // Minimum execution time: 108_578_000 picoseconds. - Weight::from_parts(111_311_000, 0) + // Minimum execution time: 89_000_000 picoseconds. + Weight::from_parts(119_000_000, 0) .saturating_add(Weight::from_parts(0, 69046)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -215,10 +212,10 @@ impl pallet_core_fellowship::WeightInfo for WeightInfo< /// Proof: `FellowshipCore::MemberEvidence` (`max_values`: None, `max_size`: Some(65581), added: 68056, mode: `MaxEncodedLen`) fn submit_evidence() -> Weight { // Proof Size summary in bytes: - // Measured: `151` + // Measured: `184` // Estimated: `69046` - // Minimum execution time: 94_484_000 picoseconds. - Weight::from_parts(97_930_000, 0) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(52_000_000, 0) .saturating_add(Weight::from_parts(0, 69046)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs new file mode 100644 index 0000000000000000000000000000000000000000..a6372c4b89dc222ca6a5a6acd36306d79ea3ffb2 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_ambassador_collective.rs @@ -0,0 +1,177 @@ +// Copyright 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_ranked_collective` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_ranked_collective +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/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_ranked_collective`. +pub struct WeightInfo(PhantomData); +impl pallet_ranked_collective::WeightInfo for WeightInfo { + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:0 w:1) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:0 w:1) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + fn add_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3507` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(23_000_000, 0) + .saturating_add(Weight::from_parts(0, 3507)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:11 w:11) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:11 w:11) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:11 w:11) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. + fn remove_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `508 + r * (281 ±0)` + // Estimated: `3519 + r * (2529 ±0)` + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_500_000, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // Standard Error: 158_113 + .saturating_add(Weight::from_parts(16_000_000, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:0 w:1) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:0 w:1) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. + fn promote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `210 + r * (17 ±0)` + // Estimated: `3507` + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(26_000_000, 0) + .saturating_add(Weight::from_parts(0, 3507)) + // Standard Error: 180_277 + .saturating_add(Weight::from_parts(650_000, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:1) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:1) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IdToIndex` (r:1 w:1) + /// Proof: `AmbassadorCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::IndexToId` (r:1 w:1) + /// Proof: `AmbassadorCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. + fn demote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `508 + r * (71 ±0)` + // Estimated: `3519` + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_500_000, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // Standard Error: 335_410 + .saturating_add(Weight::from_parts(550_000, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Voting` (r:1 w:1) + /// Proof: `AmbassadorCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `566` + // Estimated: `317568` + // Minimum execution time: 57_000_000 picoseconds. + Weight::from_parts(60_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::VotingCleanup` (r:1 w:0) + /// Proof: `AmbassadorCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Voting` (r:100 w:100) + /// Proof: `AmbassadorCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + fn cleanup_poll(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `209 + n * (52 ±0)` + // Estimated: `4365 + n * (2550 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(18_500_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + // Standard Error: 11_180 + .saturating_add(Weight::from_parts(1_335_000, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2550).saturating_mul(n.into())) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs similarity index 82% rename from cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective.rs rename to cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs index 561edda953b9a75df47a3388245eede3ec78ba51..7515aecbb525a4b4de59bd05e8329166a5515ff1 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_ranked_collective_fellowship_collective.rs @@ -17,24 +17,21 @@ //! Autogenerated weights for `pallet_ranked_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/release/polkadot-parachain // benchmark // pallet // --chain=collectives-polkadot-dev // --wasm-execution=compiled // --pallet=pallet_ranked_collective -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --steps=50 -// --repeat=20 +// --steps=2 +// --repeat=2 // --json // --header=./file_header.txt // --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ @@ -62,8 +59,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 16_027_000 picoseconds. - Weight::from_parts(16_501_000, 0) + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 0) .saturating_add(Weight::from_parts(0, 3507)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) @@ -77,15 +74,16 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Storage: `FellowshipCollective::IndexToId` (r:11 w:11) /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617 + r * (281 ±0)` + // Measured: `608 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 27_829_000 picoseconds. - Weight::from_parts(30_053_705, 0) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_500_000, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 26_813 - .saturating_add(Weight::from_parts(13_088_861, 0).saturating_mul(r.into())) + // Standard Error: 254_950 + .saturating_add(Weight::from_parts(15_900_000, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -101,15 +99,16 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Storage: `FellowshipCollective::IdToIndex` (r:0 w:1) /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `314 + r * (17 ±0)` + // Measured: `310 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 19_762_000 picoseconds. - Weight::from_parts(20_493_905, 0) + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(25_500_000, 0) .saturating_add(Weight::from_parts(0, 3507)) - // Standard Error: 5_519 - .saturating_add(Weight::from_parts(349_033, 0).saturating_mul(r.into())) + // Standard Error: 70_710 + .saturating_add(Weight::from_parts(400_000, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -122,15 +121,16 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Storage: `FellowshipCollective::IndexToId` (r:1 w:1) /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `632 + r * (72 ±0)` + // Measured: `608 + r * (71 ±0)` // Estimated: `3519` - // Minimum execution time: 28_092_000 picoseconds. - Weight::from_parts(30_800_398, 0) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(37_500_000, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 17_223 - .saturating_add(Weight::from_parts(615_330, 0).saturating_mul(r.into())) + // Standard Error: 150_000 + .saturating_add(Weight::from_parts(350_000, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -144,10 +144,10 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn vote() -> Weight { // Proof Size summary in bytes: - // Measured: `666` + // Measured: `700` // Estimated: `317568` - // Minimum execution time: 46_255_000 picoseconds. - Weight::from_parts(47_590_000, 0) + // Minimum execution time: 57_000_000 picoseconds. + Weight::from_parts(57_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -159,18 +159,19 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Storage: `FellowshipCollective::Voting` (r:100 w:100) /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `500 + n * (50 ±0)` - // Estimated: `4365 + n * (2540 ±0)` - // Minimum execution time: 14_975_000 picoseconds. - Weight::from_parts(17_408_362, 0) + // Measured: `343 + n * (52 ±0)` + // Estimated: `4365 + n * (2550 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) - // Standard Error: 3_134 - .saturating_add(Weight::from_parts(1_222_024, 0).saturating_mul(n.into())) + // Standard Error: 25_000 + .saturating_add(Weight::from_parts(1_395_000, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2550).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs new file mode 100644 index 0000000000000000000000000000000000000000..fdc451c5d31ccae8a1195482ef32e99163c22442 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_ambassador_referenda.rs @@ -0,0 +1,536 @@ +// Copyright 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_referenda` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_referenda +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_referenda`. +pub struct WeightInfo(PhantomData); +impl pallet_referenda::WeightInfo for WeightInfo { + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::ReferendumCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `255` + // Estimated: `159279` + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(34_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `317568` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(68_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:0) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `1165` + // Estimated: `159279` + // Minimum execution time: 97_000_000 picoseconds. + Weight::from_parts(123_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:0) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `1173` + // Estimated: `159279` + // Minimum execution time: 104_000_000 picoseconds. + Weight::from_parts(111_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `702` + // Estimated: `317568` + // Minimum execution time: 140_000_000 picoseconds. + Weight::from_parts(150_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `601` + // Estimated: `317568` + // Minimum execution time: 81_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn refund_decision_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `317` + // Estimated: `4365` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn refund_submission_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `167` + // Estimated: `4365` + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `311` + // Estimated: `317568` + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(45_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AmbassadorReferenda::MetadataOf` (r:1 w:0) + /// Proof: `AmbassadorReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `626` + // Estimated: `317568` + // Minimum execution time: 183_000_000 picoseconds. + Weight::from_parts(187_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:0) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + fn one_fewer_deciding_queue_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3636` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_000_000, 0) + .saturating_add(Weight::from_parts(0, 3636)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `1412` + // Estimated: `159279` + // Minimum execution time: 88_000_000 picoseconds. + Weight::from_parts(97_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `1412` + // Estimated: `159279` + // Minimum execution time: 87_000_000 picoseconds. + Weight::from_parts(92_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_insertion() -> Weight { + // Proof Size summary in bytes: + // Measured: `935` + // Estimated: `4365` + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(46_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_slide() -> Weight { + // Proof Size summary in bytes: + // Measured: `935` + // Estimated: `4365` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(43_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:0) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + fn nudge_referendum_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `951` + // Estimated: `4365` + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(50_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:0) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::TrackQueue` (r:1 w:1) + /// Proof: `AmbassadorReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(171), added: 2646, mode: `MaxEncodedLen`) + fn nudge_referendum_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `959` + // Estimated: `4365` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(48_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `263` + // Estimated: `159279` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `311` + // Estimated: `159279` + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(28_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn nudge_referendum_timed_out() -> Weight { + // Proof Size summary in bytes: + // Measured: `208` + // Estimated: `4365` + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(20_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `546` + // Estimated: `159279` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(46_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::DecidingCount` (r:1 w:1) + /// Proof: `AmbassadorReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `647` + // Estimated: `159279` + // Minimum execution time: 87_000_000 picoseconds. + Weight::from_parts(93_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `159279` + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(120_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `683` + // Estimated: `159279` + // Minimum execution time: 90_000_000 picoseconds. + Weight::from_parts(100_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `159279` + // Minimum execution time: 77_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `704` + // Estimated: `159279` + // Minimum execution time: 68_000_000 picoseconds. + Weight::from_parts(77_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn nudge_referendum_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `704` + // Estimated: `317568` + // Minimum execution time: 99_000_000 picoseconds. + Weight::from_parts(104_000_000, 0) + .saturating_add(Weight::from_parts(0, 317568)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::MemberCount` (r:1 w:0) + /// Proof: `AmbassadorCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `159279` + // Minimum execution time: 87_000_000 picoseconds. + Weight::from_parts(100_000_000, 0) + .saturating_add(Weight::from_parts(0, 159279)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::MetadataOf` (r:0 w:1) + /// Proof: `AmbassadorReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `419` + // Estimated: `4365` + // Minimum execution time: 23_000_000 picoseconds. + Weight::from_parts(25_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `AmbassadorReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorReferenda::MetadataOf` (r:1 w:1) + /// Proof: `AmbassadorReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `4365` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs similarity index 87% rename from cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda.rs rename to cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs index 12d92a803cad9be870465264539c438b9a7487e7..5b4aed06899fcca022895488477ffb058ae76399 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_referenda_fellowship_referenda.rs @@ -17,24 +17,21 @@ //! Autogenerated weights for `pallet_referenda` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/release/polkadot-parachain // benchmark // pallet // --chain=collectives-polkadot-dev // --wasm-execution=compiled // --pallet=pallet_referenda -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --steps=50 -// --repeat=20 +// --steps=2 +// --repeat=2 // --json // --header=./file_header.txt // --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ @@ -60,10 +57,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `355` + // Measured: `389` // Estimated: `159279` - // Minimum execution time: 29_271_000 picoseconds. - Weight::from_parts(30_285_000, 0) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -74,10 +71,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `366` + // Measured: `400` // Estimated: `317568` - // Minimum execution time: 52_128_000 picoseconds. - Weight::from_parts(53_504_000, 0) + // Minimum execution time: 64_000_000 picoseconds. + Weight::from_parts(67_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -92,10 +89,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2004` + // Measured: `2038` // Estimated: `159279` - // Minimum execution time: 110_018_000 picoseconds. - Weight::from_parts(114_369_000, 0) + // Minimum execution time: 99_000_000 picoseconds. + Weight::from_parts(109_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -110,10 +107,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2045` + // Measured: `2079` // Estimated: `159279` - // Minimum execution time: 110_231_000 picoseconds. - Weight::from_parts(114_517_000, 0) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(111_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -128,10 +125,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `802` + // Measured: `836` // Estimated: `317568` - // Minimum execution time: 195_619_000 picoseconds. - Weight::from_parts(207_157_000, 0) + // Minimum execution time: 135_000_000 picoseconds. + Weight::from_parts(153_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -146,10 +143,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `701` + // Measured: `735` // Estimated: `317568` - // Minimum execution time: 64_020_000 picoseconds. - Weight::from_parts(65_463_000, 0) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -158,10 +155,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `351` // Estimated: `4365` - // Minimum execution time: 30_701_000 picoseconds. - Weight::from_parts(31_528_000, 0) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -170,10 +167,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `167` + // Measured: `201` // Estimated: `4365` - // Minimum execution time: 15_173_000 picoseconds. - Weight::from_parts(15_787_000, 0) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -184,10 +181,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `345` // Estimated: `317568` - // Minimum execution time: 37_886_000 picoseconds. - Weight::from_parts(38_679_000, 0) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -214,10 +211,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `517` + // Measured: `587` // Estimated: `317568` - // Minimum execution time: 152_111_000 picoseconds. - Weight::from_parts(155_738_000, 0) + // Minimum execution time: 185_000_000 picoseconds. + Weight::from_parts(196_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) @@ -228,10 +225,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `174` // Estimated: `4277` - // Minimum execution time: 10_712_000 picoseconds. - Weight::from_parts(10_976_000, 0) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) .saturating_add(Weight::from_parts(0, 4277)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -246,10 +243,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `2418` + // Measured: `2452` // Estimated: `159279` - // Minimum execution time: 97_671_000 picoseconds. - Weight::from_parts(104_911_000, 0) + // Minimum execution time: 82_000_000 picoseconds. + Weight::from_parts(90_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -264,10 +261,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `2418` + // Measured: `2452` // Estimated: `159279` - // Minimum execution time: 104_019_000 picoseconds. - Weight::from_parts(108_208_000, 0) + // Minimum execution time: 91_000_000 picoseconds. + Weight::from_parts(99_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -278,10 +275,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `1807` + // Measured: `1841` // Estimated: `4365` - // Minimum execution time: 50_199_000 picoseconds. - Weight::from_parts(54_350_000, 0) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(44_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -292,10 +289,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `1774` + // Measured: `1808` // Estimated: `4365` - // Minimum execution time: 52_459_000 picoseconds. - Weight::from_parts(54_382_000, 0) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(55_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -308,10 +305,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1790` + // Measured: `1824` // Estimated: `4365` - // Minimum execution time: 57_810_000 picoseconds. - Weight::from_parts(63_690_000, 0) + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(53_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -324,10 +321,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1831` + // Measured: `1865` // Estimated: `4365` - // Minimum execution time: 56_778_000 picoseconds. - Weight::from_parts(59_556_000, 0) + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(54_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -338,10 +335,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `263` + // Measured: `297` // Estimated: `159279` - // Minimum execution time: 24_377_000 picoseconds. - Weight::from_parts(27_031_000, 0) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -352,10 +349,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `345` // Estimated: `159279` - // Minimum execution time: 24_717_000 picoseconds. - Weight::from_parts(25_578_000, 0) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -364,10 +361,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `208` + // Measured: `242` // Estimated: `4365` - // Minimum execution time: 17_280_000 picoseconds. - Weight::from_parts(17_845_000, 0) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -382,10 +379,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `646` + // Measured: `680` // Estimated: `159279` - // Minimum execution time: 36_996_000 picoseconds. - Weight::from_parts(37_970_000, 0) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(47_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -400,10 +397,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `747` + // Measured: `781` // Estimated: `159279` - // Minimum execution time: 91_681_000 picoseconds. - Weight::from_parts(98_640_000, 0) + // Minimum execution time: 90_000_000 picoseconds. + Weight::from_parts(95_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -416,10 +413,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `800` + // Measured: `834` // Estimated: `159279` - // Minimum execution time: 149_940_000 picoseconds. - Weight::from_parts(167_561_000, 0) + // Minimum execution time: 84_000_000 picoseconds. + Weight::from_parts(93_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -432,10 +429,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `783` + // Measured: `817` // Estimated: `159279` - // Minimum execution time: 157_443_000 picoseconds. - Weight::from_parts(168_023_000, 0) + // Minimum execution time: 88_000_000 picoseconds. + Weight::from_parts(98_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -448,10 +445,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `800` + // Measured: `834` // Estimated: `159279` - // Minimum execution time: 155_539_000 picoseconds. - Weight::from_parts(161_877_000, 0) + // Minimum execution time: 81_000_000 picoseconds. + Weight::from_parts(93_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -464,10 +461,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `804` + // Measured: `838` // Estimated: `159279` - // Minimum execution time: 82_000_000 picoseconds. - Weight::from_parts(87_101_000, 0) + // Minimum execution time: 74_000_000 picoseconds. + Weight::from_parts(77_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -482,10 +479,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `804` + // Measured: `838` // Estimated: `317568` - // Minimum execution time: 154_590_000 picoseconds. - Weight::from_parts(186_418_000, 0) + // Minimum execution time: 105_000_000 picoseconds. + Weight::from_parts(123_000_000, 0) .saturating_add(Weight::from_parts(0, 317568)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -498,10 +495,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(155814), added: 158289, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `800` + // Measured: `834` // Estimated: `159279` - // Minimum execution time: 149_822_000 picoseconds. - Weight::from_parts(164_866_000, 0) + // Minimum execution time: 90_000_000 picoseconds. + Weight::from_parts(100_000_000, 0) .saturating_add(Weight::from_parts(0, 159279)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -514,10 +511,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `386` + // Measured: `453` // Estimated: `4365` - // Minimum execution time: 21_413_000 picoseconds. - Weight::from_parts(21_938_000, 0) + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(24_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -528,10 +525,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `285` + // Measured: `319` // Estimated: `4365` - // Minimum execution time: 18_927_000 picoseconds. - Weight::from_parts(19_423_000, 0) + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(23_000_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs new file mode 100644 index 0000000000000000000000000000000000000000..0522420f2f5172ecc2840b70ecb9c74796bbddc3 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_ambassador_salary.rs @@ -0,0 +1,190 @@ +// Copyright 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_salary` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-polkadot-dev +// --wasm-execution=compiled +// --pallet=pallet_salary +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/collectives/collectives-polkadot/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_salary`. +pub struct WeightInfo(PhantomData); +impl pallet_salary::WeightInfo for WeightInfo { + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + fn init() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `1541` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(14_000_000, 0) + .saturating_add(Weight::from_parts(0, 1541)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + fn bump() -> Weight { + // Proof Size summary in bytes: + // Measured: `191` + // Estimated: `1541` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 0) + .saturating_add(Weight::from_parts(0, 1541)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorSalary::Status` (r:1 w:0) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Claimant` (r:1 w:1) + /// Proof: `AmbassadorSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `3551` + // Minimum execution time: 23_000_000 picoseconds. + Weight::from_parts(23_000_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Claimant` (r:1 w:1) + /// Proof: `AmbassadorSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `467` + // Estimated: `3551` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(28_000_000, 0) + .saturating_add(Weight::from_parts(0, 3551)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Claimant` (r:1 w:1) + /// Proof: `AmbassadorSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, 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::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `879` + // Estimated: `4344` + // Minimum execution time: 68_000_000 picoseconds. + Weight::from_parts(72_000_000, 0) + .saturating_add(Weight::from_parts(0, 4344)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Claimant` (r:1 w:1) + /// Proof: `AmbassadorSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorCollective::Members` (r:1 w:0) + /// Proof: `AmbassadorCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, 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::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::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`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn payout_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `879` + // Estimated: `4344` + // Minimum execution time: 69_000_000 picoseconds. + Weight::from_parts(70_000_000, 0) + .saturating_add(Weight::from_parts(0, 4344)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `AmbassadorSalary::Status` (r:1 w:1) + /// Proof: `AmbassadorSalary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: `AmbassadorSalary::Claimant` (r:1 w:1) + /// Proof: `AmbassadorSalary::Claimant` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn check_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `3944` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(28_000_000, 0) + .saturating_add(Weight::from_parts(0, 3944)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs similarity index 86% rename from cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary.rs rename to cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs index 3a6825cf6415887dc284555aaad14d52628de58c..9bb7e68d3145c339505f9c6a729eca1217c02537 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_salary_fellowship_salary.rs @@ -17,24 +17,21 @@ //! Autogenerated weights for `pallet_salary` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/release/polkadot-parachain // benchmark // pallet // --chain=collectives-polkadot-dev // --wasm-execution=compiled // --pallet=pallet_salary -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --steps=50 -// --repeat=20 +// --steps=2 +// --repeat=2 // --json // --header=./file_header.txt // --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ @@ -56,8 +53,8 @@ impl pallet_salary::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1541` - // Minimum execution time: 10_579_000 picoseconds. - Weight::from_parts(10_898_000, 0) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(17_000_000, 0) .saturating_add(Weight::from_parts(0, 1541)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -68,8 +65,8 @@ impl pallet_salary::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `224` // Estimated: `1541` - // Minimum execution time: 12_723_000 picoseconds. - Weight::from_parts(13_221_000, 0) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(18_000_000, 0) .saturating_add(Weight::from_parts(0, 1541)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -84,8 +81,8 @@ impl pallet_salary::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3551` - // Minimum execution time: 18_522_000 picoseconds. - Weight::from_parts(19_120_000, 0) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(25_000_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -100,8 +97,8 @@ impl pallet_salary::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3551` - // Minimum execution time: 22_270_000 picoseconds. - Weight::from_parts(23_325_000, 0) + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(29_000_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -132,11 +129,11 @@ impl pallet_salary::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `703` - // Estimated: `4168` - // Minimum execution time: 54_436_000 picoseconds. - Weight::from_parts(56_347_000, 0) - .saturating_add(Weight::from_parts(0, 4168)) + // Measured: `774` + // Estimated: `4239` + // Minimum execution time: 67_000_000 picoseconds. + Weight::from_parts(74_000_000, 0) + .saturating_add(Weight::from_parts(0, 4239)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -166,11 +163,11 @@ impl pallet_salary::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `703` - // Estimated: `4168` - // Minimum execution time: 54_140_000 picoseconds. - Weight::from_parts(56_312_000, 0) - .saturating_add(Weight::from_parts(0, 4168)) + // Measured: `774` + // Estimated: `4239` + // Minimum execution time: 66_000_000 picoseconds. + Weight::from_parts(71_000_000, 0) + .saturating_add(Weight::from_parts(0, 4239)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -182,11 +179,11 @@ impl pallet_salary::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn check_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `478` - // Estimated: `3943` - // Minimum execution time: 24_650_000 picoseconds. - Weight::from_parts(25_242_000, 0) - .saturating_add(Weight::from_parts(0, 3943)) + // Measured: `512` + // Estimated: `3977` + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(27_000_000, 0) + .saturating_add(Weight::from_parts(0, 3977)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index b4db73e3ab4401da08b38ec36632cc07edce25a0..79d4c53c2ee2c5475fe58dae270062dbd2d25035 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -24,20 +24,22 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; +use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, - OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + parameter_types! { pub const DotLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Polkadot); @@ -46,6 +48,17 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); + pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); + pub AssetHub: MultiLocation = (Parent, Parachain(1000)).into(); + pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); + pub UsdtAssetHub: LocatableAssetId = LocatableAssetId { + location: AssetHub::get(), + asset_id: AssetHubUsdtId::get(), + }; + pub DotAssetHub: LocatableAssetId = LocatableAssetId { + location: AssetHub::get(), + asset_id: DotLocation::get().into(), + }; } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -212,7 +225,7 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. @@ -227,6 +240,10 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - DOT with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -236,8 +253,7 @@ impl xcm_executor::Config for XcmConfig { // Collectives does not recognize a reserve location for any asset. Users must teleport DOT // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of DOT. - type IsTeleporter = ConcreteNativeAssetFrom; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index f6fccc0435425adbcd8d9a067dc4de7db7760a81..414c7ad9d9423ec880cabe582eb25ec35bd92f10 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -22,6 +22,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -52,7 +53,6 @@ pallet-contracts = { path = "../../../../../substrate/frame/contracts", default- pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts/primitives", default-features = false} # Polkadot -kusama-runtime-constants = { path = "../../../../../polkadot/runtime/kusama/constants", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} @@ -93,7 +93,6 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime/std", - "kusama-runtime-constants/std", "log/std", "pallet-aura/std", "pallet-authorship/std", @@ -120,6 +119,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md b/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md index 387bb24bb0e07ef982b89634ae98d7a663c47ef7..10df15ba72779f5ef70690da74e72648583b571d 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/README.md @@ -1,7 +1,7 @@ # Contracts 📝 This is a parachain node for smart contracts; it contains a default configuration of -Substrate's module for smart contracts ‒ the [`pallet-contracts`](https://github.com/paritytech/substrate/tree/master/frame/contracts). +Substrate's module for smart contracts ‒ the [`pallet-contracts`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/contracts). The node is only available on Rococo, a testnet for Polkadot and Kusama parachains. It has been configured as a common good parachain, as such it uses the Rococo relay @@ -16,7 +16,7 @@ If you have any questions, it's best to ask in the ![Contracts Overview](./contracts-overview.svg) This node contains Substrate's smart contracts module ‒ the -[`pallet-contracts`](https://github.com/paritytech/substrate/tree/master/frame/contracts). +[`pallet-contracts`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/contracts). This pallet takes smart contracts as WebAssembly blobs and defines an API for everything a smart contract needs (storage access, …). As long as a programming language compiles to WebAssembly and there exists an implementation @@ -54,7 +54,8 @@ Once the executable is built, launch the parachain node via: ./target/release/polkadot-parachain --chain contracts-rococo ``` -Refer to the [setup instructions](https://github.com/paritytech/cumulus#manual-setup) to run a local network for development. +Refer to the [setup instructions](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus#manual-setup) to run a +local network for development. ### Rococo Deployment diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 399ada1be2c739c6ea4931fa99c6a38f3c039dd9..70392c5ecbcc2baf012fb9925ff405a7636fa1db 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -47,6 +47,7 @@ use sp_version::RuntimeVersion; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Everything}, weights::{ConstantMultiplier, Weight}, @@ -694,6 +695,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 7433b8e94d6c1e9e343c7b90f0412826d667cc6d..ff8f46b9d117c25c4a09364220dcb13658a96127 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -24,6 +24,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; +use parachains_common::xcm_config::ConcreteAssetFromSystem; use polkadot_parachain_primitives::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -129,7 +130,7 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. @@ -144,6 +145,8 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +pub type TrustedTeleporter = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -151,7 +154,7 @@ impl xcm_executor::Config for XcmConfig { type AssetTransactor = CurrencyTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; - type IsTeleporter = NativeAsset; + type IsTeleporter = TrustedTeleporter; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml index 0ffe59b927f9d2435276472e5b5c5e6434b4ca77..ad13bf05a3eccb750b922d0b20398e09cba7efbb 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/Cargo.toml @@ -24,6 +24,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -42,6 +43,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } +cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false } parachain-info = { path = "../../../pallets/parachain-info", default-features = false } @@ -71,6 +73,7 @@ std = [ "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcm/std", + "cumulus-primitives-aura/std", "cumulus-primitives-core/std", "cumulus-primitives-timestamp/std", "frame-benchmarking?/std", @@ -91,6 +94,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs index 41cb0fceebb59c42a17b1b528830f3aa58950693..f5d52239e54374a0274289a896a5c3c472c4e615 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-kusama/src/lib.rs @@ -64,6 +64,7 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, IsInVec, Randomness, @@ -80,12 +81,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use parachains_common::{ - kusama::consensus::{ - BLOCK_PROCESSING_VELOCITY, RELAY_CHAIN_SLOT_DURATION_MILLIS, UNINCLUDED_SEGMENT_CAPACITY, - }, - AccountId, Signature, SLOT_DURATION, -}; +use parachains_common::{AccountId, Signature}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; @@ -122,10 +118,28 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for .5 seconds of compute with a 12 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 = 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 = 2; +/// Relay chain slot duration, in milliseconds. +const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 6000; +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + parameter_types! { pub const BlockHashCount: BlockNumber = 4096; pub const Version: RuntimeVersion = VERSION; @@ -183,6 +197,13 @@ parameter_types! { pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(2); } +type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + impl cumulus_pallet_parachain_system::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnSystemEvent = (); @@ -193,12 +214,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type XcmpMessageHandler = (); type ReservedXcmpWeight = (); type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; + type ConsensusHook = ConsensusHook; } impl parachain_info::Config for Runtime {} @@ -208,7 +224,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type MinimumPeriod = ConstU64<0>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -216,9 +232,9 @@ impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; + type AllowMultipleBlocksPerSlot = ConstBool; #[cfg(feature = "experimental")] - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; + type SlotDuration = ConstU64; } impl pallet_glutton::Config for Runtime { @@ -339,7 +355,7 @@ 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 { @@ -347,6 +363,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_block_builder::BlockBuilder for Runtime { fn apply_extrinsic( extrinsic: ::Extrinsic, @@ -452,6 +477,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 1b68b720d977dd6e01902c358dee9e45ceee3571..d9711b57b3770355474b43245366cf6adb8c6e98 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -20,6 +20,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -63,6 +64,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 34e82737f82bb38409327b9b4cc96166e0ffcda0..c2bcaf8a1266702a0d5c8d6fbbd6463a5d46dc34 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -46,6 +46,7 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, weights::{ @@ -366,6 +367,16 @@ impl_runtime_apis! { ParachainSystem::collect_collation_info(header) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 46cef8d4ae083062b0c8521642ede074feb70035..675abc07b77359a65f78b21a90ced4978eafede5 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -19,6 +19,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -64,6 +65,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 477933b5c8d25b04205331ae0dfe17c42e7b555d..4aad553e6a3baf78667cad1271965d223ca3ea2d 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -53,6 +53,7 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, weights::{ @@ -398,6 +399,16 @@ impl_runtime_apis! { ParachainSystem::collect_collation_info(header) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 378d9ea4c42ce27d0541b2c5ef567801d2e32bd3..1ecbb212a0e6bdd5a99a31000ff5a09c0dc9e0fd 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -27,11 +27,11 @@ cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue", default-feat cumulus-pallet-dmp-queue = { path = "../../../pallets/dmp-queue", default-features = false } pallet-collator-selection = { path = "../../../pallets/collator-selection", default-features = false } parachains-common = { path = "../../common", default-features = false } +parachain-info = { path = "../../pallets/parachain-info", default-features = false } assets-common = { path = "../assets/common", default-features = false } cumulus-primitives-core = { path = "../../../primitives/core", default-features = false } cumulus-primitives-parachain-inherent = { path = "../../../primitives/parachain-inherent", default-features = false } cumulus-test-relay-sproof-builder = { path = "../../../test/relay-sproof-builder", default-features = false } -parachain-info = { path = "../../pallets/parachain-info", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false} diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 8289a80baa11a8542210b7b691765bed05a9a0ae..3215242464aac5177c9931f9974095cdbcee1bd1 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -24,11 +24,12 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use frame_support::{ dispatch::{DispatchResult, RawOrigin}, inherent::{InherentData, ProvideInherent}, + pallet_prelude::Get, traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable}, weights::Weight, }; use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor}; -use parachains_common::{AccountId, SLOT_DURATION}; +use parachains_common::SLOT_DURATION; use polkadot_parachain_primitives::primitives::{ HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat, }; @@ -49,7 +50,7 @@ pub type AccountIdOf = ::AccountId; pub type ValidatorIdOf = ::ValidatorId; pub type SessionKeysOf = ::Keys; -pub struct CollatorSessionKeys< +pub struct CollatorSessionKey< Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config, > { collator: AccountIdOf, @@ -57,8 +58,14 @@ pub struct CollatorSessionKeys< key: SessionKeysOf, } +pub struct CollatorSessionKeys< + Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config, +> { + items: Vec>, +} + impl - CollatorSessionKeys + CollatorSessionKey { pub fn new( collator: AccountIdOf, @@ -67,14 +74,43 @@ impl Self { Self { collator, validator, key } } +} + +impl Default + for CollatorSessionKeys +{ + fn default() -> Self { + Self { items: vec![] } + } +} + +impl + CollatorSessionKeys +{ + pub fn new( + collator: AccountIdOf, + validator: ValidatorIdOf, + key: SessionKeysOf, + ) -> Self { + Self { items: vec![CollatorSessionKey::new(collator, validator, key)] } + } + + pub fn add(mut self, item: CollatorSessionKey) -> Self { + self.items.push(item); + self + } + pub fn collators(&self) -> Vec> { - vec![self.collator.clone()] + self.items.iter().map(|item| item.collator.clone()).collect::>() } pub fn session_keys( &self, ) -> Vec<(AccountIdOf, ValidatorIdOf, SessionKeysOf)> { - vec![(self.collator.clone(), self.validator.clone(), self.key.clone())] + self.items + .iter() + .map(|item| (item.collator.clone(), item.validator.clone(), item.key.clone())) + .collect::>() } } @@ -225,7 +261,7 @@ where AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, { - pub fn run_to_block(n: u32, author: AccountId) -> HeaderFor { + pub fn run_to_block(n: u32, author: AccountIdOf) -> HeaderFor { let mut last_header = None; loop { let block_number = frame_system::Pallet::::block_number(); @@ -360,7 +396,6 @@ impl { pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight { - use frame_support::traits::Get; match from { XcmReceivedFrom::Parent => ParachainSystem::ReservedDmpWeight::get(), XcmReceivedFrom::Sibling => ParachainSystem::ReservedXcmpWeight::get(), @@ -375,16 +410,20 @@ impl) -> Option>>, assert_outcome: fn(Outcome), ) { - let outcome = >::events() + assert_outcome(Self::get_pallet_xcm_event_outcome(unwrap_pallet_xcm_event)); + } + + pub fn get_pallet_xcm_event_outcome( + unwrap_pallet_xcm_event: &Box) -> Option>>, + ) -> Outcome { + >::events() .into_iter() .filter_map(|e| unwrap_pallet_xcm_event(e.event.encode())) .find_map(|e| match e { pallet_xcm::Event::Attempted { outcome } => Some(outcome), _ => None, }) - .expect("No `pallet_xcm::Event::Attempted(outcome)` event found!"); - - assert_outcome(outcome); + .expect("No `pallet_xcm::Event::Attempted(outcome)` event found!") } } @@ -415,8 +454,8 @@ pub fn assert_metadata( expected_symbol: &str, expected_decimals: u8, ) where - Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect - + frame_support::traits::tokens::fungibles::Inspect, + Fungibles: frame_support::traits::fungibles::metadata::Inspect + + frame_support::traits::fungibles::Inspect, { assert_eq!(Fungibles::name(asset_id.into()), Vec::from(expected_name),); assert_eq!(Fungibles::symbol(asset_id.into()), Vec::from(expected_symbol),); @@ -428,8 +467,8 @@ pub fn assert_total( expected_total_issuance: impl Into, expected_active_issuance: impl Into, ) where - Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect - + frame_support::traits::tokens::fungibles::Inspect, + Fungibles: frame_support::traits::fungibles::metadata::Inspect + + frame_support::traits::fungibles::Inspect, { assert_eq!(Fungibles::total_issuance(asset_id.into()), expected_total_issuance.into()); assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into()); diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 547695e7621079d8bc7ca33b9fed0c2a41ac15db..a7fd4b30b75f942d1b7e179aa580fd4cfd2b44b8 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -7,7 +7,6 @@ license = "Unlicense" homepage = "https://substrate.io" repository.workspace = true edition.workspace = true -publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -44,6 +43,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -117,6 +117,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 9a758cdd97827359ac546c204f66787c36c208b2..fe0f19c306321e8c8f22d1225611ac6281f44340 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -36,6 +36,7 @@ use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, pallet_prelude::Weight, parameter_types, traits::{AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, Everything}, @@ -832,6 +833,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index f2ffc451b10ef2f2b0f37983bb3fc633a020193f..710dfd79877cb1e26e50a228584791d3caa21165 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -160,7 +160,7 @@ pub type Barrier = TrailingSetTopicAsId< // Allow XCMs with some computed origins to pass through. WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // System Assets parachain, parent and its exec plurality get free diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 54055ca732ba994aefd2a646daaf92cc3d21364e..029d5d10f98684d20f8917af3d90a4df29f3410e 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -27,6 +27,7 @@ sp-api = { path = "../../../../../substrate/primitives/api", default-features = sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false} sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false} sp-core = { path = "../../../../../substrate/primitives/core", default-features = false} +sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false } sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false} sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false} sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false} @@ -90,6 +91,7 @@ std = [ "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 362ad0383a2319d4ccbd26b826912d5974691dab..50c5a445c25fe0c2c0e09b4979539e9a5f0146c0 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -40,6 +40,7 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, match_types, parameter_types, traits::{ AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, @@ -796,6 +797,16 @@ impl_runtime_apis! { ParachainSystem::collect_collation_info(header) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 5591e80317ca819e1fb0039aaae63f0d33be93c3..3c2069c81ef4f58e8bd4747fbec917f17bd34a56 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" @@ -27,6 +27,7 @@ glutton-runtime = { path = "../parachains/runtimes/glutton/glutton-kusama" } seedling-runtime = { path = "../parachains/runtimes/starters/seedling" } asset-hub-polkadot-runtime = { path = "../parachains/runtimes/assets/asset-hub-polkadot" } asset-hub-kusama-runtime = { path = "../parachains/runtimes/assets/asset-hub-kusama" } +asset-hub-rococo-runtime = { path = "../parachains/runtimes/assets/asset-hub-rococo" } asset-hub-westend-runtime = { path = "../parachains/runtimes/assets/asset-hub-westend" } collectives-polkadot-runtime = { path = "../parachains/runtimes/collectives/collectives-polkadot" } contracts-rococo-runtime = { path = "../parachains/runtimes/contracts/contracts-rococo" } @@ -87,6 +88,7 @@ cumulus-client-consensus-relay-chain = { path = "../client/consensus/relay-chain cumulus-client-consensus-common = { path = "../client/consensus/common" } cumulus-client-consensus-proposer = { path = "../client/consensus/proposer" } cumulus-client-service = { path = "../client/service" } +cumulus-primitives-aura = { path = "../primitives/aura" } cumulus-primitives-core = { path = "../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../primitives/parachain-inherent" } cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" } @@ -107,6 +109,7 @@ default = [] runtime-benchmarks = [ "asset-hub-kusama-runtime/runtime-benchmarks", "asset-hub-polkadot-runtime/runtime-benchmarks", + "asset-hub-rococo-runtime/runtime-benchmarks", "asset-hub-westend-runtime/runtime-benchmarks", "bridge-hub-kusama-runtime/runtime-benchmarks", "bridge-hub-polkadot-runtime/runtime-benchmarks", @@ -128,6 +131,7 @@ runtime-benchmarks = [ try-runtime = [ "asset-hub-kusama-runtime/try-runtime", "asset-hub-polkadot-runtime/try-runtime", + "asset-hub-rococo-runtime/try-runtime", "asset-hub-westend-runtime/try-runtime", "bridge-hub-kusama-runtime/try-runtime", "bridge-hub-polkadot-runtime/try-runtime", diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json new file mode 100644 index 0000000000000000000000000000000000000000..064a2dfc0db8446340d05722b4df93cb44a18e7e --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-rococo.json @@ -0,0 +1,80 @@ +{ + "name": "Rococo Asset Hub", + "id": "asset-hub-rococo", + "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-2.polkadot.io/tcp/30333/p2p/12D3KooWA3cVSDJFrN5HEYbt11cK2W7zJbiPHxR2joJXcgqzVt8K", + "/dns/rococo-asset-hub-bootnode-3.polkadot.io/tcp/30333/p2p/12D3KooWPf3MtBZKJ3G6wYyvCTxFCi9vgzxDdHbjJJRCrFu3FgJb" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "ROC" + }, + "relay_chain": "rococo", + "para_id": 1000, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xe8030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x50cd2d03000000000000000000000000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x267ada16405529c2f7ef2727d71edbde4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da90395122802460ba3fef86b6eef716f2358c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da936311af37f3d62b64610d04a45b423a8acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9a79b78a206a5c0e4c36a85f8342b9ea5fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9dcdb4d826419bfb6cb11a9e4558a0deee803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x110e2473746174656d696e65", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd00589c9d04bec6c5c9114f1068ca261d6898ea2b6f604b838543946d20353b4808a1172684cc7f2c32f33a1e6d3deda1da9643964377abf0d25fd0ab56e867512ce027e7200a8d6ec55d3b5793e2e8ddc8de726f29a59432a51480120611ac111ec0dae74809f3f79485ccdfe48839820b0d6400034e6fc09ab3efee0d37fb302380396c2ed7584d726ec34397aa8bf9ba6bbc73e7d0f943e715fbb93560cfebb2f1f0c6a74b5526e952c57ee812741dbad41e3a06de78e81ce81ef7d3968d15f3d0e6eb0d3ebd85cb43cfe9523f8410bad5251d9805ad99be42bdb9c971ddc33fcdb12eed983aca7cb57924b3f9a4a151f2bcb5e82dba74d81a8cad357a855f4a7fbc1d3dee3f2ab320e894b71da053eed3d2a3432abd39146a9794920a61790f4b515191103f7d2f20d7acbda484d07d5a5f403246086343d3777bd81696f7de7befbd4885e2993367eef8e8b32de93eeda850fb98557e9909cdac36cb1bad43fd23af7cee05645dc15e8a2b12e2ab74a178871067fe8a7ce98e064d77de68bdbcf2e72dab58ad553a21a9650821beca15f8d1afc4b762fa98b5ead1dabcf2960df58f3221bee3e74587faa75b54a8fdcc7094f0e99dbb0bc879455b953eddd12bfdce67f7573e798b449fbed7111ab32a84e59d57eed38dd6e71cb36afac87b01452c0fbd51495b7ff32684e55fa3ecb27db5627af626d4fe49a1f6cefb52e2de65416f89fbe77d297959107bcb84b07c6dcf8e7d5374d2389ce6eccd9be2346f8f3e9bf4c957129fdf2d52a3b34b1a675b7c1d698f2e697b53d21ea33729a5efa5048877e200d3b76cb7883cf25c3a841ed43cfa94b48ad09a292afaa11e2fc4675e7a15a1057c5b23cdab0c596ba4f9107ca1057caf91e60d887e272feb034c2fb3dd22adaf23cf5b26dda7cd6635dab32d49d9639b7c21e123fc2ec32ca601e38822333c30818011648cf0d2fb80250ec0a8d97e43e37cbaf6c9d7720dc6947f29302b9f34d3d75752d2799ea2e88d5c5f1cf897fa1ae1f9f5a7e479e5b3a26d55f4f95e482a7f3e5dd17da6225f47240dffdc0b68b9066b12e5d2a3f3055465d5f495fb349f8ef486ba26ad53743e7a85bff215b62a4af9a3fb6eb6e6d64642ed718eb4972e335f23ebfc8f52595074e915dd779790fce77bed105d6634bb3556cdf975e7cd6f9ab4ce5712e8eb956cd2428a037dc51415bd007e465aa34b9fa6a7bca295bf7249ab034c65fc6e91caa5fbb48ab24bba3fd9da8bca84dab7cb7621f7cfab739809f1bfcc14d99d99354c5107122f80038d379af0b3d6dc9ebb5d06bb69123bd624f6f8fc3d5875b69e9d6f7876761dbaf49eddbbb46366d0e5d975ba877ff8ab0dcfebecabc3adbd51245850731abe3efbdcc5a1f2fc333d25d5bff99cd79655a26f5ea91d160affb22fce9f2f75fea8056a408219677ed61bad58be55e8524c517cf44af4cf7773d8ada1ee890826fc107fcca6ec1b2fd4ce9c79987dc1b24e64d2c2cc8fcb8a2a967f596d5ea96ff7698dd2f0932d47d7f7d2c006a1cb4fa3347c236253b72602a94b5ae0e8b996a90db9e6d680b557f9ad796bde9ab796e58a6fadb52665320063df3ec0face2c5cdebbd4deeea64bed3a5d72dfa721cc7cbbd53dedc77d2df29df3ebcc4365b233eda15b77b7e6f25b86b3a4f9f3d62dabfcedbe7db237f6dad89b2f7b505ba6cecc5fe941d37ffa2bf09acddac581bd56fee6ebb3511db0e6eb7b2169999ccd62dafeba022d37fe8a355a1caa70d10b2de0d9dbfb62e28a8a9e9d2f2558d1b35b5ddaefa2a5abd33d85b9bf5daaedebae9dbdae6f93b649ce0f80b533690fda96f9b4a93902736bc09cd79b7fced3a52a6fe852c5485daa3cfffcb90d5d6aff4e4468f9e739ddd33f3afcfb5ae49f635d6a7f6ed3a5e6cf9f5b5d627fbe3a2f0bda13d15c5f9dcaf3cde752fec917906b12fb3689b33ad4de355f409c2971be747fcebd90c0acfa43977d2dd7b8266575a87de5375d9ade3ca74b71468aca2ae59553d1c27e1deb52f4e6365da2bcf98c947f52749bb44db29c2f24fcae4956562daf3cd27d8b0eb5a77c722fb7d146ba3fe97e45ddfcba6c3d46f8cff6ceae919af39b55e8cf9bcfb6eb68e5175ac0baa443efd7faf639dbda0b664c9756f9ebed5aaed9264d77edd6584dd26952f3e8dea4d8207559e587be14a3dba4f697c9263576d3a5fde68eee7b97d69bcbd6e38a9a9316875675be39cfaf0ca68a9f0be62200dbd31045bfa7223a0cf07b12828bf76fdfeb06ec54e4c657f7ed3e2dd9a5dcd6b3bd53b167afd857f9edae4bebeddb25e8ebae4bd17f7d46ba0f29ff5c1eac597c01c18cb1e87b25d9e8932f25d06356a1439f7d29c11efa5eae49cef7027aeed3d0f76a732f9955d34b8fb44a1869751f7d2f20e933d2da808f3ef7a2b21ac4531e69ddd34787b4c2243c60c0c90f40d4203efa3629ba4f83749fa242edcc9933743cf448ab0eef7cb215a97326f1a3a442f16156f96326c467ce9c39f3d5f4cf275b90eeef35d4fe65dba4ea9e1ddd26b137ba4daa36cfbe3a2db9696156f9ebb3293f5366abe9beebd2f3f5c96c3df6d9d662ed43ac2e60cddb9fb70be8658cb1cf663dcadf17fb5ecd7d7a2fa0769f9e6c31dd6fcabf1704f6d97ddaa74dccccc4dc01609366752af6cdb74becedce99ba26359fcb837195df7c2fa06d52739f2e61fcec38ecfbdba4f5ce7096c86f97df19ce92f6e7ed2f1be2e76c9be4b2ea7ebdf95e4ad83babedec3ebd3a2d0bc27e653035e624e66e0c9816e7e5442689d7b2668a8a8a8a7ec0ec9830c4fcfeeacc0d80010a40006cdfdc0660557ebbecd28ea9a3ccb75b5dda93162ddf8e7569bddda64beced378b037ffbea7416e4bf3298981530b7066c4f424cf155febaecd29ec494f975ab7bf867fda64b3ba68e32bfbe5ddaaf39bfbe3a9b05f9af0c26e6054cf6ed525de76c9bb4be6e62fe31f754e4e537ceb501db375700d8beb9d8fa42cb08bca5882b2a6b0a9614ac255841b0946025c162c35ac322825504eb07d6180b0d8b079618eb0bcb0b0b0c2b07161756171613ac32d616d6159611da0e1a196d0c98051807c4026402ba002e31b330e398589857985598549870585f2c2a1e0da21462149c175785ab819381a5868b8193c2d9c045e168d0bef40ede10bc8583819b62aa317f307d307b30d39863261a53cc3c63869966ccd32c63ee607231b7985acc19cc2c261613ccb4625631bf4c2a660de61493065306d3cb9462c260be6042319f984ecc263a09ad84364223a189d045e8367a08cd461fa1d7e8310d8426d33e68335a4c07a1cfe834ba072d84fe8155036b8ab98539c794a3c9b062604961c1c08ac27a810585f544d7a051d164d08afa4c77a1b9d072f4145a0a3d47d7d155682a341c7dea321a4c4fd14f34146e0b6381afc056603738094d0cce81b4825bc02ce0151829c2810d9c00082a534420e549098e98200139e00064b96121c1ea8115c632c33a4d226616be01db80abe02f4c05d780a7601af00c5806ec8563c052300c380a7e0143c14fb013dc0433c12ee0259a4b45a6fa41d583cea3faa2f2a2eaa2e2a2ca41b545a5459545854585830a4c754565457583ca065515d5978a8aaa06d514d518ac846a0624a85e50415135d15fa0b84079c14a83ca02a505ea0a541c1416a839ac332839a82d5056a0aa404d819202f504ca0c4505aa0b54142c329610ac362c1f5847a08e4019812a0245048a0ce504ab09d4102821506c5048a09240b5d1633017bd855202e506d5048a09d412a832141c1414283aa837a82f5041a080c066a83a283b283ca83b2835da0eea071d054a0ccfc159a04e4d0c4506250615060506f505d505c50595036a0b4a0bca07540fa834a831141a140f281b50545035e036282f1c86824163c14ca0bca0cea0c250665065503ba0c6a0744065416141e18002435dc1633018dd0565057503aa0aea0b350545036a06940ca818505274172a0aea051414d413941354131413940ba825a816502ba0ba502aa052402941254121411d41194171a18aa088a0b6505a980b54166a084a08aa489e9179483ce41dd20e5987fc82a4437a81b720bb20b920e79072c82d482d4833320b320e8905790569055905490509879c8294828c827c4342413e413a41ba219b2099209720cb4825c824c836241b1209f208d208720d590449042ec2d243c82148325208320812085c865443fe40fa40f640a6d15bc831128d1646f2408a9167c830d20c7962391a07ac05b90349861c438a21c36021740ad80a0946c3829bc04ee028f014180ed985e4a2b520b7682ea416cd825e42d42282894d4423e0175a08f9256611958048b4114f0b2fcbcb82fbf2d278631c156e066d8dcea285d172d0b6685ab42c1a0efa8bd64187d14fe82d38e926b4180d467bd15af40c7a05d41a4d4467691a341e4d477ba1ef602f7017b80a4c0586024b81dfe02770195e0223a1b53010580d0e02ff807dc06934303c86d1601eb0183e8377c064f017ac031683c3602f5a05ac0567c158740b18070c86af60214c210081059a090ba80005de1561f22f535da86e50ac3cf94013209e40f9a14993c9cd8729509a34a996a148f9c093a12923004193a11ea05489e2c394284d9a08a9b030aaaed043132a2098a2448a142a0c18ea018a142954182080ca0a6b454a942743507c6802050a0868a8a8b0544030254a931254813202a1265180f8a12950445082273c7805c742e9610a95294d9e348902c443e9610a15080c4d1901951e7a7818aa29f840a507283e10a9a4b0564a0025a889152b2580b2640a952856ac409900ada2b0248802c45781125485ca0598d0ea8d8532f4c48728529e5c69026504504610010af800250421784201015450582b413d40f9a10737d6cad0142855a0fc30258a574d9812050438d512b6872856a644a9321404942625900204104f9a5481e283942823f809ea818a949f9caacc8aa0c993a1273e3c1982b2434da504134491f224ca509429517e546c6c500f54a47ca00994a111f4002508283d2a246c152a0cb0aa23ac15285186a254a1f2c3d0089ef8a88cb053a844197a5265043e3419a222c54a932840fc932a23f81f405e12914c1a4e88f935cd3d15153d9b9a10e8d6706b30101c1d0318b00c58c00296015bb9c7cd5c75d5cddccd32bc57c950ad5b57b9dde7e2baaa7231be0729e82aebb957b58bf155eec15745e7d8519583cef5c2f75cdce7aaaa7a303a18ab7695ec57b9aa6a55bb76b1b57e0d5d4357b976f1390aeac4172be8e4bae7de8b313ae762007e02e064a8a273ef558fbbb95f77573939392e2727a7aa72727272ba48d5b1aaaa2a56b1bfaa7a880f2f4001b2ba9a8170bf4ac87575732740871c70a8aaaaeab6aa21dd5d75d5558500aeaac7950c55cbc0c37c43d5d3aa8a5fc5d5907efd7698b9c2b8723b1577f30cef55fdb85455cc554df55ebbaa7a5d5591abaede7b55abfa55556b55ab5a6b55f55e1fc0bdaa498f00cf86aa717cef55d5ab5cf5aa0254068855acaa573d9e57bdf70a400012e5ba7a03a8dceb8ab9ea19aaaa6a9eae5eab5c55bdc7afaabae2ae6aa866a8aaeab9f6d195ab5ef5ba7a5575d355e59eebea55ef41e71c15ab1823350023ce45f7aa2233b4f79c7b0210800b400002f0deabaa9ddee97e6d4855f5ab48edbdf7ba55ef7155bd57b9c734341a666eaeba5fc55c55ae7a55d58fbbe2565515572ecaf8a2e357b9e798b9bb7aef55ccbc15775575f59839ba2a42a713a3a49ce52a6b06f81e5b33bc58cdf0f801a0c1d71673f77b55535555bdf7baabea75c5cddc91691e57afbb9bb92b171d25a3833ad1b2acf76255f173705dc32a565106e7aae79a9febee2a36333b7e9bd15de66526e2fc989d6bb75cbdc75c5555c5ccf06d2589cc6e9cc78f2bae78e356f15996655995d59a65b565040b092d8625c0d0932a50a64009010008e003141960d80220800007384001aac890b3058062c50a942a4088804a0f4daa40b942a50728559a3cb1e2430f509a1020a874800200d103941e1c1fa05481e243152a50a254190a00941f726a40303482264353a2540102069a1fac4499120504240b0451aa40b9d2e4871e869e7c80ca101025a8d2030d3e44106568ca08aa34e9c14a14110c590284808a142198d70401c58729519a4c89f2e4871e4000022a9901a44409e21142c30d2908a947911e340009c00f1ecc0729517ee8a1c99094113c0101141f76aa3c19b242036645c8dc0250a1526548500f4f3e20450a952a01b07902a5ca901240096a321404942931f81882120221232b4356a2040125c75a024ca11265a8872756a63ca932d464288a08444085d4630b1044141040a902445653e50914293de0603e4c810204104f9a4009c1932a5486ace4d0488172058a9426413c1141084240450a111b4a30044185044331dc5000028c4a072840930240097a22e5034d423025ca0f569efce04d04315c9902a5f512a0c9142a51ac548172a50914285540d0a40a95a1273d509122e54993a120a0e45c9902a5f9d82e41152a2280220278650a9416802b4c2f111111918988d7c99a1e9189c8244dce5411352293c9999c245aa2e728274b6432992a9373b244444b44444444c444a6289d9898a8393199d8c444a6e68488c8d49c6c13392726222632111135274444ed6489d8c91211b51313af131313b113222632b5935d2744a6364527265ed373b226e864d76432999c13139bd8c99ab89d98d8643235270d6874f0eeb208ac3cd9557ebd79d75abaa849ae08ec6575dd782e7a27dd20f276c8ccb918f3d8d0de16932e875e46df87fe6896e8584c3fd12753e9916e8940169d69db6187b4a2a0e8a1b78b89738e11d89fe73eddfcd12da69fa58ed6ce1a67ce44fc7a0713a77dbf3aad3c78f4c95657599050f3dacff76916e7584c3fce1f358173a1e6556655be6cca39e7b22dd0a9f6e83e4d561e3eeafc3ae422e4c77953a12f2e33c2f996f79cf3b7bbc3bec5ad3fdfc2eed85f86b59df52dbb3b2ebb693bebfe5be4779fa899fa392f7375aa07451f7975cffcdb7ab068d93ccefc549e658be9874bfca9b26d3b9453535ab24b41cee78d03a1958707e2373e777178374f884fb6863835841a420da1865043bc929eba39f3427c5a59756fb57feda97eaaffb5c73933ca97caaae5a35d232fab9603719f66511e7e442bcf9149e34270665784fc74cb9bee1ab1b2fa9cc6294ae37c29912f04dd4a90e5371e64f9a38134d029a7a1a8e596d3b84f53d4ca84268ef7c0b92ef7e1108756ecaf1bdf0fe243e88dd3f85e48b8e8778d08c9ea4df69c0608a5f120b4f2f034d1875866b0e8345ee5d3f8648bc66b741a57129df2a724fe732651889fa2e8fe83d7f3a6958f502e2586dddcf8535e9df454fbc82bc98ae542d36b10ff7c17072abb22e481787d6ef97cd6cb84a657aa726b3ae5963f4aeb73ca7ddaaba84c0848f6c5881ffea3fa51d9f4f0e15bb6779e63bee565edfb34eec3a75b3b729fb6a1b2edb4fba0376da7bd07dd52d38e6558db69a7a195871ff98cd676c9f279c58b06399fcfa7452d2f60d3f9cc57ca2de70bc8ca18b32c6f599d19957da9bc5d95cf477194b87f2edffd181d88f92abf8d11c38d6fadd1ca7f2504d5f453e20fb57f6e7a217e2fc35942f9732a7b3b5ce197198e12f9d0a5c4bfd23e66d0f9cbac26312482f1f52062ae4eedd316ccb95b1c96ab582f8f416f2fd0ab68d06b67d16083f1cebb4872e92eedc4bb24fc5ab0ca5ed84bb77be9f67af341bcdd1b6c125e40d05bb3a1fd732fca25a5a28c93ad01601750e5998cd3239dde28f429ac49f7a90ba8b9941425259509c547f96c926aee7b51b37974d85c3e8f147d9fe6d3728ddee636b2f1cae7646bb11be70be88be50dc3c1f1b73d97d778bd7a30af3f4ad16b0e8eeb3ce983a4938a14699273c717e5a2b6e33cd25d52748c6edb1942c4dde2900383b7acf2f0550acff7e8e142cf6b104232a13df35f687c362a44480cfe326f92f31e990e67c19c03f1bd4842fcd2a76c59dbe9e13d322126a8f11e3c6442cfa5f790cd85c8cf7677aa10efe13ecd453f7e3891acca1f3e24abd86e69975483fc0f8f590df2958bfac2f176015138de865efa7689f21ac45b9810df0b4848b64dea0b02fc114b05e26556a3f770be807a587660fe356652783e48e8796d7ea5fd17ccf7a557f692a5c6b1987e6a1ca326a8117a5e8778737701f14004ff5c7ef95e12d89f9a1a9ac554f493050bd199329a90052fd881c7999f1adf62faa9c9b68cfcca76776af31e4232a118b22f983f1f42f761a05f6a3c877ee1e23f352e69e5e17bf8881271d1c94b172e5a8610e227cb9ef9a1c9b808f9c1322330bf30cc2fd976dc162cc352c540065d3ce182327ee0e5672fdf82398d6f196558db715ee35b68b29bb6e37ce4eca5f5d4644eda8ef3d110aff2cab6ed0871f68265f5e62b7bb970701cd6dc49f321599542b28a7d5d375acb1ad302e6c6b30061b9cceacdd775435220cb0e8c729e26b99821a1fc8626b9fd46ad2e6094df00b58c31cadd3581fdb1a8ec0b17ffb1b276935529568c71d24af4715613e424becabde21a696c9982ad7629e123b806e994c388e134e7249ec7789f9e14652e5c03f4b8dba4d956a4cde7115c03f4d920749f163d892633a1f836947fb60df4489b4b0a7dce6849ead3e0a524fef44c524ea249d2295a4d4fbd4c287e739f96cd278d968c92b78d6caafd204068f577fe8356795fd9cb3bb7a143fc40d0ab7fbeadc7881adf82d560966c3d468c7ccb35ba2eaf3182c6b78c684623af71e737adc7081fbe85c6478dd3605e931971f3b305cb8c903f5b88968d2af0d8b2c61b46c803cccf163094d738e6354ee32e7ad579e73de88ed1011bbfad677f2ae99daf103fd58677be98741da44b31d84bafabc6bbdda9372fb3c6b46067d011a6866edb918e51d976a4d3dcf0d2473c2ffda2db762ae9a55bd4db8e748a6eabc19a349d7249b7d5584d9a99742a9b8b513e17ab9a346bb64933734da2bccab64914e57b49f7e9244e8cd1251ce994ef69064b385f4054c698fcedd29ef802921963eef792591227c668d2be4f47c6f87d1ad2d7a75f194c1634c947448c2a622aa09e80060daa882edf7bef25e1df8bb249ec1009f4e83ecd316324888a1087194428f306128e50f140081718cff960f2700ed69627b51ef7b3be3af4e32e98fcc874bf10f1fc8061ff02bdd1a1f6405fb8f80fcc88787ec0bc0c6789fbe6ceb9c6679cc1c5ef29cc125f80df53182a9ec9f01a7331e97b010d3520e83edd5efead3b5f773dc048ce51e96da83de5d239e554a9bd6532c31c85d48609ec514ea34b2e7b589ea2b2da1c5e48606683b51e3eb59de7aff2a962fff8d4a4e7ed02cc79e5d33f314d7aee5c5226e3d39cf54ce69ff3a94bd09fb398eec18a8a8ab4fc3c775d720e7dd7dfa71db59a84b51ef7f35a269bf4dca797c0aafcb764befa3faf6be69f3b793e74c9f9f31f3807fee741607b0a33c53b6f5efddb8b736372b57ada6b91dfaac3ef8af95d27d9d03df2671dd2b91dc0768c13d8f89adf316e98f9bdba34fa6a732a2a2a22e2a7e6f4ec4fd579e8db7a7eca48d186171880b9c20b7ea8872719dce0e1182d54f130ab5278fe653223c2f6d9b7f5c81f666f4d5defb0a300bbf93dc980055ffd9e64c0e589d8c4ad6710c57abf63b4408328d8a4915eb1df6af3ebf5e6d72baf3a95546df8dd759e1bbad4dcf4904aafa8e923b5d25e3a0dd532f70298f3e8faa34f67d1502d344e042f019af38fa3a1448079ce3ff3597b452bd27d1aba3f7b45f7e92a086789e5d32d9fdeef685b236b8935b2a253d0712edfafdc519c2b3b4279e555f665beff42428d6f56d074cba7b326854e5d5ef95e4aae6cd748bdbc799509f119be98f45f59509dee9c7faf25fc5556fb839c5b313dbc96f05b59e53e8d29cb0e4c7a8dde96f43bff2a331ce7d09dc70cc7398ecb963c87999297ed1a69ee325e238d884db3610ce612607d27124b345e9dec9f6f37adbcaf0798ca684db99a5e394bca832c9fd3fbba2ef7e9b6da55ab2a13a2a9a9f1ae46d528be6dfc9c15bdf2e713a33818e615e6238a83ad1d3fa2fdedab5135a2c1e347ed694634eed365686823a9c95c939a53d9a4e6230a3da8f2e9d5a79bbe1712f639a7fbf47457129fea555555f9e4afd61a692e79b9d98dbafd80b92221fef2e693a2d53de5eda2f1d69ef28bc64723ca87e08f7cb245d1da4ff945ab8c7c083e8defb5a409cde8a214ddeb0194536a5dd2ca31c39a94fdcb6e9ad4eed3341cb760a2a9cdd9b74bce1d84c2bb4c52cea96c8accaa7429262dcc3ccc249677ce2ebd51170415bcccbe4ce895e82ba4724a02b49c1e7a75590de2db940d4297875e4df04e6653f60d1eaad8410d4808e3b888f99cdf13172a7eb60569143ff14b1110266891850a45cef94b110c4ad460092f5500e0058b348a8680d837fe4b510d4808537425015a4e4198e0a17f1962dff88959d1bef1b3199675a22952c8a00d21ee282afa79599196a2226f5905e29bf5e8baa3cdfbdacb02354e6002157964397366af2436dfdad4446c622236f58365cceef2cd9b22c182a0d3f015669c4493f62727016571a8c2f35fd64d2b0567dfcd5ca68508233fceb9f8f849a24b36df7c88e505ac4a794ea249cd79a2c083163784554ee29bd78dc237c7b28eb51dd3cf72218a2f62f045166e1415fd38e71fa645ce8a14d060881990f1a38508233fec5c7cfc6821a27f9e7351c00fbba35c14f083050c05d8b1f0d0769a33996fee1c0b180a3c7719169fb6d3fc6558c050c0396758bced347719cfb69d2abfeee9c45e97cc76a1881e7cc142126ee00422587860fb6372811a64482185196c6c21c7cffeac571e0a7851d10f7b125da281bb10b5899b93a239479f3b8ef23d6f2e9fc7f7a0a30cd45d34e979bb9ef3ef890833fea6496f368b9dc3c7efba9fd0dc75695d2e0eaf7193de286fd01bf4e6147409a137bf69ad357fd0675b4d86739f6e87ced0711c8e2b03fa8bd0b5991eea984fb0beb8acf14e263f59bff8adc581bdddead2b21c7bfae76e717813521b9af488c8c1f334e9f95eadca27d25b4fe5cf49ad67faf39c2eb926497f7ec3e2e06b44faf349b1de915e51d93bd265ebb9e91de9cf6fba44f90bf2cf7789af36fcf320507acb82cfb8f4e6bf66e461e6739a24a5e3446fdf8ff3d1f744c417bf2722baf89b26498794a96c9b24237d6b648dacfb34a4fc446d7addb89842fc9d0232482c7fded40a7f7b5f49f6a92ce8d1daff9c69155e23cf87e40bed999fded711cbab6a6623b8f9a19be7ac5f537e8bee80cdbd006639e573be4939d3cacf4ed1a6d5f4cdb452dedcf2bd94506eb94f23893e9de9748a5adeae25d2a573b66b84dda72d5a3ba37cd2dacfeed3aa75ea8a7ca19647d1af475a87d804b9dde0a26f2efaf5d93dfb958bbeb6dfd3a90a262cc46f56b9e872bef48afb754797d0ece2509dcb84687eeb9ef9dadc5aea42d8b78c8bc098db3dd279a3fc5afe9df1108a25de3ffadc1f6c4f4fccf1fecee79bee524281297ef015491e4330f83a54140237be0e752912fa3af40432f1eb08563006086eb871a43223c50bed9933792cb9214b169e7d3e8b2fa08a3516bfa71590f9f6f27b5241164ffa3da5c08d6f3edb8257c59a17bf27265af07cfa3d2d51840fc0efa90567be395f4c645111b41c6d2fa996256325fe95fe105461246ec9f3ceeae90553bcf3f6771d7190e22c39e39d3f1af4bc5a31bdcbaefc80f351a13d73e60c13ffe831ab267ae547154788bc739f6eface784887fa9df3b584c8bb25cedb210d72de3ee191e7d1f752f23c6643f3b749754f504cf143fd30abceaff0c346fd21f57743134888ff0212eab61acd9e2f20215754f4ed716ce1e7b31add397e3e0b5e47b6ccb3cf7d1042e81ac2c6104ad288bdbf519e2762d36b0806a3e1ddcf5985e785b85b5ceee62274cbceb9d1fa9c6d3d8f1427fa3e8e92ea5b2644f35786fa91f03c0f294e74fe7e86d47dfb46970bd3598dae1d0f69ffa49ad73d0a8ed6178f67da1e0af199873ee3368e6eb4eed3fc8d6e995fcaeed336734d621ae91af9016b217e9bb45cf332ac4934bccb6e9ac491db14669b8d46c1d8abfb7d59d2f8ee6e7fee8a82b1efbb95b91f6009607b52e28a17c0cfbd00f6bc259146121e30904416adb546ea12ce53220a6961c0491277b81fe75a0a9c701d0c74a9929c74a9623f38779bc63b77fe802eb977ced3a53d2961e69ddbd03defc74917d378e3dd5ee1dde379e745ba549bb73b1c25aec87dc3fa99b3e7adca90f5cf776915f621f84df975ba24c467de625a657d08fe73be9634f9f64785887067bb45f83ac2de7c3e68f175849b375a9b439f90d613fc732c2840015124eaac9abebdadcc6a7b50cc6af3f5fa7c7ddda7dba5a4356f5945c1cb2a7f37bbcfa68d9bf712f6b6841dbaf31c481fddc76c4e4914f18fbec76cbaf4dcf97c94f1c8238fdfebcc16597f94cffc5e455b64dda71fed22219e1f535acc8582351f304b3a21737bc09c73e75c3677be3a6e00edeb349d05d1b6ce3e9dc5d7916bc97ab3ef0730e8fbedec93af23b47d42baff98406f8f34087afb7c96bb1eb0147abb76581cf82f25701d66952bf7e959d15a396baf3a9d270deaebc82ac1a2effa9c7bed40f9667c0905a16508218abe4ae5564c5f552e544960071e67deca92a96289237eba15d3cf6c9b5465759750d985a47a08e17bcf39d75aebee771de18fdede5cabaf2355b6feae23d5ef1aa9fb4b7196445f5f8f3588cd82a42b915fa1733ba45b63fd9e88b8e2dd1a79545213c5ef093fe6d680b1d79b9c2eb56fdf76d73abd4db0f66a6100981b734e97969c4e425772addb99339d430755e197ef8ad379b49a445155ca0def9ca2e488afb6da74d5a3b64bd5f973189b7400cc831e0f015beff648a5fceae83a1847358877ceeb7ecbf867bd86a96cc188d31529b0c214c61633c8a20d3ae490e38a196aa85b220c127444a1c7efc90675b49e1c8c400713c26cd1861800b0c0b40216e8b8230c2858e0051d47e68580d6a150938a8777de2867f5d16a02daecb94f63762ba62f43c9906a8ac13b874d7897ed1ad9acb6ac018ebb47d5f43e4d60ed754f41607b12a3e5d9d7fbed1671ded61badcf57096c526dbe4c5e56b1e03477dfdca7dd2e69b3a055e29e7dc9b41c48d85420830d3efacd151f2194523a94504624624c426267fcbc41e38b981bb4a0cd5184151a4481066108a1032c8a64a0c20ae42f1a4fe0c14e2af2eba429308082175660a30ba72464ee073ed79a6367bc29065f10620a2cb294a1441a3ff49b93c47c3b638e2775a9928a74a93d9ff1c6b3db744feb3cfb0ed6de57e30b887b80c9df7e1d481e6e65cc6d3d4be238820865ae10842694e017a85620002deef0a28c2394380d81c817bc9cbe7002f27bfac20dbeb0c48bf2864da3e47adccf5a5b84cc29ccf810a28262050ffd06ca17a3b34b965c62f46d3d45b8e8e2022d3c11c70ea6f0135d7629868f8e6de1e313787c84cf39c7ccbc739b1be7dea5ea9d93b4c013069ee1c3062724ac2046117ac083a229c060c61a2f3852668920a4a00d25c080053956b8808a1a17541e90a1851a617041420f706e90052b8a689ab05205357070ea220658dc60c80ddc40e3893000f83ddd4007ffe3770c1737683a363333475fac31336795f2e8448ad8a0838e7baad4bc521e7d5294f2a6bc51ac65edbcde540c52599599cc0e80f9ef37ccaa7c59c5bee5fc8ddb1df6ed52f7b89ff675efd3987b622ed6526258d65875fe32e71c66aebd3a5f47a57bd73ec8b96b52abced7fd6ea94af7b5a4c90360fcfbcdb7f5f0cfe65085dfd17ebe96ec8c96a3fcbb380cf5f792057c4be7b89531c40641f8510512d87b5fecf867852f4ba8f9a206cdefe90b1944c82d3abc1c2a3133cb0f30e0a2280a4f58a3e80d21360823cc1598b8b43c41451d79308185327640c68d0dae30c306752801450c1153a49186154728234817141a5fcad880090ccae12c85227edeeb7fd15d86458ebe8cb59e7d6f0c21fc6be2e73d28a133bff7c6f8e29f133fef6199633635bfa731a8f88ab90a4c5e4c81074098c269093ed001902e4898628822e400074518228c1f988b7b03223bac80c20c164f588111365594a9e20acf0c22b0208a234811071a2cf0510512aaf062f3104208c374a18587eb7efc9eaa0883b91f5c5d4458c51546fc4408cd88438d2184fca25105186ffd9eaaf0f215f3e6848e8e57f1b173604ad83b9736cfab6c1fe9c5ccd934895d12e19c738ea1114611ef62760333eca6edb0b357b7deddbc3b7da9e25d515151d1961fe7365995a2f3ceb1267117d83efb6698cd905f33b420c4c3df9318707cc55c7a994d7c81c1dfd03c1a346f6bd24699dc0ecaca1a613d6c2ca648f685f80c0d33c796bf69d2ee3237d9680dccb81a408199bb01e9e29c7b300815d28a3146490121635a555555d3aa8a30b2aeebba4634f0f744c5126a2c0cc3b09a1e3d7e4f2715d8583e7cf8f061f3830a2804b18000010224c88d1a510cb18408112264084ecdef890a2dc060e55c407bfa9b266dce25e43ee70212e2334fad91f69c0b0985e19a3158dce41a691f2284ed898aa2af96e5a8c561e5e240fd9ebe0cf1374d2262b1f57bfa82c4dfcc8a92113ed79ad71aed1a59ffc14415c3ef690c2edfbf6664e10899c46e018a1618010b5cdcb8238e1e769c4e592a2d5070606646efbdf74e6524e15f966a8c1345545023c82f1a4fb4f13e7e4f658c914500c5f1a50b2735bc7cc1849a0e7cc1c416c06002971560016b3ddb8614ec90c20b332df8c2135863606e97d88b8a8a86f8711263bfe952f5bc17ab800b840be012c71086a0820eb470c10f1c3db4821c34bfa71317ef7ecd88230a17d0ac81cd00a7484c1b271d68710116ae1acc600b21ef8867a24205605e40471c7810918535c5991a3861ad200354c0838e3a8ec882125a30a790630c0bc81ce0f734c50e1ec8ef698a2a5e133a49f74d93dc8d6b6657e3439330c8dced9c73103ee79c7bef393a628c51c6183dfa5235146812f662e49632c618294ac618a3f4d9ddb223149c73cbee9c7b8faeacf1695273e6e5f77699d939e79c73bbecd8c2981fbb329a796284fc0086903946d8fde01cce39e71c747f8739e7e07bef3de79c7b0fc2e79c73ef3dc765ee00305f870e77d7d570a049d2a14787fc24c65a6b913ee677bcbedfcbcd0cb1b60379799979a5dcb8cbcd6dd9490a39b2c378924e51b2190671e50c47496cca9fe7344932659612724b29655551524a495194cc82785ac72ad4e079499850438d7508630da9f9e6bbb92164ee6eff77d3761e764512ceb5bb0b88bb9b6384ccaebdeb48b7ec12b743c8ddceb0095338f101b8c250992ff27ba24116ffae6eadb51a20ba7999b98edde5aeae9bb9460a3373736bddecb5bf9d39dbdde5e666a6d9b6d6cdcbccfb84f77a16c275350d70ee3dd79c730d1e816198a458b76ed9beafe6872651dedcf7796bad51925a4dea76d72ddb39ee4c3ad75a6bedda75b773ed5cb7d8dd4e8528c46fc5f410baf4086b7880eebc41081d4a192384efbd07238c10528aa2282a46d8ae23f07d61ee7677cf7abb806493641226d8b99386ceb596020cc39c73d0db9f6f3be71d2f200799b12717c39c6bdd5aeb31babb39e7fdded6e8d024ac49cd6a526baebde75c6bae35d7dddd5c73ed3d08db73ae756bad5f151c4d1226d450e3b918656c527b1e1dfa94cfe3832f93ce3977ee3908df73ee39f75a6bcd3df79ca3d5613166dbe07bae39e7da13a0bbea2094cff7d560a062eba4d505d86ebac40e1deb12bc8060bc92ec634d7a1ea9d5a4f7dcbdd7e28b11c2faf361ef1e7cf03d5add3f08b36d11c2f71c36a18e24f60b77dc8c7105cdea446abaa4fc43ac2e60384b9c4b9799f32a331c25cfa33f8f33a3bc9d68e0e5757e4f33b8e3e353591226d490d54929a3afabc9691256c57d956ffae8f0924d8a6e22edbf6b873ad44f51499858a34bcf179378e64c1226d6e897cefe499828d36b748f6c3bd0f7933041268adfd30cb460bf63a4b8e2c3d891c4ef4906737cbd79e837bf63a418e3a3f705d41750f42e5379e555765559357d1cea979e840937224dc2041b4ddaef0b280913649ab49f840935ba64fa7dbe9230a146d72461228d26ed57f99f840932179318b3244ca8d1a47d588489647fbd6d2b0263df1c2617c15bb0f58ddf7e45f6e643ac2e608df23b20f6be9ab3c376e6299c0ead03e7d042dc704380baf3eb95fe2e55cde66e5a0fa9ed3c97d02bf6442a917f4e6a3d3cb49de75242d237e97b3e6b390747316a51d924e715a5e875a4ffc7ee387f36103172030018deb9b322e5e7a1f500d1769e4b49860ce507827d39ab3fbeddccfbd7a0973edf728f38b35923d892da1bb596d43ea95c527b45ddee111bcc3a228fb877991096972eb33bfe791c02a249cfcd7017a884c6cd3d7cce0df550ff1176216676bc83c754f6445e1cfa975df6c5f209e13abc8036838b83252de74b3a5b40d45e55564d5ff1ab54d2550263e75d52031aeace1c13f73dfdb984ecef4ab2cfd950ff74bfd7cc709654ceced995fef6caab267a766ecd61797677ed5045b61aa0bb4b49fbf62bfdd2eb7be84deb099e1d5e3bb42ae32541879712f7edf05ad25efae46edc4695b72a136a2f2b352b4bd2a5ae779cef0533470411b7832f9847a25b36c09e3b4712f47c88df79cc82da87f8f94dcda5b93a57b01d6385997fee7fd3cdcedb598bb1bb0ba8f97bef416bb1e7f002626fed39c8dc68733595a79da76d939ccbdcbb90f83fe91cd30ba8edb527c78508a157716ee535d8288351419557de3ee1b584ffcd08fd29a91c5610ba75a4ffd1fe8eaf4b8dc5701aacc6efba2969d073e990d617953cd72e252fbe18331ce947fa5fcae8d261352b6b4e5ab1cb1a5d47f8f431abd647276556db291a44732d99987529812e7dafad5c7a76a47f9b34fb7d5ac5d6bad1e1d12109059c480982b570178e82ab602e68fa0705a48a10b3b64b41d09f5555e95da107b996348f71de44792991ecf2b94b099cad1d6f7b23a6f83a626e97bea0e55ba89db9e3d9fb52d2454ed22badc4451f925f65087bf6dd1a38abcea11252758ec53d252878d712f7adb9e9db85c4f4ce65979af3b54347aba5d52e25ae35b791f4bd8eb49799c36cbbe4983c6f3bbccc55fe964953e4a6a3bdca1d00d62ce66fd72debc63f9fb55d72ce1710678cb5bb2bc97e73dff09db116ace9c03d84b93b60cd9f4b37def9ee2f067d2ef67cf205041dbe26356ecd8d768dc02ae4e15b7e0e1ff2f5acb53ec7f78b0c3e047a8e4f7701e5f43581fd91c1275b39947faf1cbaef2e1c9f3e3d7128ffa48bc390f6d05d192ddffc01f1bd806edca26d494284c4dd11b2350871222fc4a9202fc425cd0bf1e8d3e974e9397452978238f4225d0ae2fe51ab0bcfe7ab82b8bc92ec07f1bd808204b974dc07ad33b80fff41eb0f27e213ce68411aa76892f37204561f99a2978447e6adf1d8d011e241bcca6f770c696632af4ecb3b6f2edc5f3a06dd44aba091e823de3d21908867de0432df1cc7e76888c70be879bc8074e0c548603ebc797b0c4ec461f0494383cb0b68069717100d3eab19301a66a061a706dbe921390d3300a0c74e8feed1463bec83f2e17b1df1e17304039118ba2ce144145e2666e1d07d8a9a16911968e5cf7c2e56c4f7021280ef0554c4e7f2721bd110846e938450d7c39281d65c8fcc5be388e8c54c8482735040578bc3be731c1adc799ca24b333800bcca225ee31502f08a05c06be4e29d373ada1c553c4f13980ade5557c4bbdace942cafcd8e77beb5d5f1cea70f0be769709f9eeda37db4110d8ed317927e1d1c217ee857dcbff7bcbdcaaef0c3acfaf0ccf93a92f98eef85241b3204074221412014820361902119ce92cc777c276b5c7469c79d37305a0fc969bc8bbaa4e3ce5b4b73e924bad45dba34c49df712456873a349ce0540db1b4d721e00dae06892f339ad9a0bc90cfe9c089dc171e8fe7c948697d1e07c21c111e2dff12b2e73181c47887f885f71382e44f33838de0e2f26443ccbaef0ef64f5790cfe2e26cd71b22bfc43b2fadc87fbb4474386b36406c7719c2cc8874f9f210b8ac187f889b84f3fba3db8b7f57823e8d077684ba349ce49b4a9d13bce69a06d8d26399f8136369ae41c00b4956952148f7946bb8a21b4a7a0ed250a21b475682f41bb0bed2460a0cd85b61623b0202ec46b33f3ce6bdc69e91e2d60e073e7cd8c2bea52e6ae87b7391a1ded8e2eb93b9fce1a6211a1beae051d19dd2742f95f5ca23a18afbda83b8fd6904b495b44a87b48bfc8e04f86d3d747e61df630ab5cad7f3ea3135d22e20e893f0c1e8357f744fc22925518322b86eb92ee8a10cd43c7a9d1cbbbe8e50a30c4902903479ca3280927a6c8628c34e41a5dea773e65a05ac03c27c27fc0408f4e509f94c5d70e411c66357bead9982db87cb3b06b495ca249ce61566d9ae4fc65d1892639cfe83e76614d72ce5cb01abb1071770141cf683f0eddada15217e27d31217aead18997d57eead8b52488d3ac5ee1cf99f26282bd0b71be9804f11c9f4ef91f6d67ce7c0eed213ec721adf21cfaa4b1883491181cd22a3038f409831371488408112230401fd07a741f3618204e1022b495c01959d6e599102be9af28781c9f4330eb512704067b212142c43de71ca1f99709d1fcf31868fb9b0b09f6426ce688bf10bbb13100a12c48376788b3629839fb0c03e517625930cc68c540f961a0fc39941f1ea9441c1209f1d067eddaf278e85df96370774ee45a12c473b2fac37a48bae81f123ef344b25d233164f5390c9e93c5703109e295ff3519ff2abf107f179205fccb8416f0cf73283fce3e6e37b2d20f24c4a3135de277de2ea0203e84f2c72e5d12e2cee3125d0ae2cea3133e4d0805e23734086d2e4d726e432bbf8dcfca62430899775e6b1e56eaa1efe28064dfc6a1f3f6f834c9f37b01e98b49f3e7d6b5e4b2f8daa1fdf8e10cd892e5ce7d38871bb806e7ce7f16071cd68873e7f506dbb6137db7e7729ff663df07ddef41ab4ba28ac368ed2bde390dad373fa2b5a778e717ad129d5b749754170acf3ee9107ff38a0ac5e63753c0c1f90d9cc3720dcf9defe270e6d9a9acde78e1d9e5cd6f169e3d66015574c9f2f649593de810c7a810ff41f9292a029d0f1ae2d0a7256fe4e4f90173492aaf2bab3cf0fcf4b9d8c8f702da0b683457470acf5f59a3ac4b043a7f6541d3737c424af9a439396ed3a51aefe110ba2f0e411cca1ee7ef87c38cc9b49df6d95ebe6b6aa40c42bf70f12a1fce6bbae5d3a2589320f48bfea035d4a649d07bd01b9ad33b13cbb6493a0f336ac8109f7488ef35736895a2332beb07b3d1a4768cf21a4d6aef41990c0c2a93f9f6bea24b550acf4f1fe2658a2e0919e2ed9d45979692538e7e64d81a69afa1364d6a1742bf38b7e845abcdbb6cdb4edffc80a9f1bd806a1cf32bab377fd18a8dbcba39a74bda2fc06a7b692fadc7797b57d125e8ed17ccaed1e57c0159cf27b5c168957233a90bc826636c4ef73ce49e5d686da8fb2a53e3db6bd2b8997ed12a7fd2ea6f01f18bee8fa810968fd524d480d01b68d5a14636c96a924d478135afd6b7e6738df7df317770793cc43ccfef183c9678eb47d798335e9ef43b260f3ae65b3e7d58cda1cfcaa22ca7b06d3d34cef25a52fd152f243d3cfabefdd7a54bcfa7cf0b68ceec07b5e69555f797573ea2157b78391cc1cbe1c87dda68a8ab8bd6f623df4b497b1b77d3abd1121f04da643695cf20e83540fcf2bd98d86440b2da3f8364b5aabc5e5eafea1a8dacbd90b4af331bf9452bf6262c4441fc6555145ceed32e5a398aa01a27fa496bfbcbaf4b49334d5addcbcba7f4a1fe2b136a5ff9a14f5f1793da5fe3974bf75af99c59e52e2f9d1a6533ab5436d40fb3a1fe4bfa805ee3d3abf4ca5d6c5a8f8f25d06b247f8d0fbf6a668653b9e5f2f2995525974f2697e523672e9cc3f451368178e52e6f790f5af97bf8bc908c7c6641d36bbc1a59f2029249eb92523a7521b92c97d76549ecf41356104208ab1a994d672e3f68e53d30f741697acc0c03b3c6f26a4dab66e496f4e9735a7c04e700b7cc1c6299c1a6d799d52df3d087da8fb2a0cb299fd6e5b0f5b81d46d36566d13ad4fef299e148af1ccea17ecbeb96f92ab3ba800db5b7bc0eb51f392cf375a86986dabb90581e34ca2a771713eb2d2bab564c3fbdcaf808ca471710753df892ee5fb496e02f3fc15f7efde55e2a994fb9b52e7d3a07bad47c4ee7233807fee9d6053433c6b84b97cbe528c3b180731a9780739a6cdbcec84d3f6995d5bde517adfc978f689d7e21995e5dd4f4165d367ed2fd2ae323b88698bd46c4a68a884d1d972cd1dc3b982722c4d0c1df34a9df1a691784edc90c2d1f7f4f629af8268688931829b691b0f17951e9395d92365d8acd7196486f4ee3ad563e7cd7480f97b407f541abf49ae6557a6ceee3593993b2e405045d52cb6dba147d18a99249731f595f4c9ecf9165f33c4aef41790f8a03fdf27dcc7d9ac66b688dde8e519c25cf69fc394d86031d67c9e5945f4e3935f211bda845832695c9afcf6366135b5bc2dc0f60cedb1d4d4e977096489f2e7d3a732fcd884bddbe39e7cdb1109f990fbae9d055115ac0377c58054ee7f0b9222fabedef01fe7cd2584d9b3faaa4bd65ed0bad499df385a4dd496fcee75e4aa45f3e6da8a49537dd7fe39de32cc92a7420ee807e78b7d34c26ce6b7b182defbc993107d00f9714f3a6359ed325cc39ba4f6f195f4c283975bab43e9dd3a5cad99f8ffc519c1f6ee32edda781b8a4384b2807e29403c9707e64474cefc37196d8f8c86d7ce423df8b872cfcc36597003da0db501f3de8b69d1a1ad49c728c56e82da3a14123eca2d127bda149dc59a532e81e29cf75c465f03ad2eebcaf253c3658e16fd9ae91f6ceaab56ba48e9edde488d88435c9466bdc1e0d6a25e73c41cea12b591cf83ae21c1ae106f834695aadc7a6777a3a6e27b03d62fa1b6cd0a1cac6dd46cd67cbb056b246d89bbb0a73fba67d60428a8408ccb09b1c7fe3db75dab1c6e1db2dbee18a1ce6e9a2a984d70837c110c2930c1e429d2edc0ae6c41c8c7b83054e194bfccbb610758210e48b1f3300529d76904445461d300b84d5890c2c08f93d91b1c60c3357a7ae1bdf8a342909cc75b8a124e69b3fa04bed0636beb563a03d4c0b18ce484dca282555d2b317e1e912bf8c272335a9911a8fdc1ed3184648810b2344a1088a2afc34c7b667efd0620c22145991023260fc34bfd99e057c31033258d4a185195efc34f7ed4940911c45b8020c146020e1a7b91b6bcccada18638c31c618a5fb748c9b05456f47a2c7f7de7befbdf79efbb4a0e7ce8ae99fcf4a4a29a594524a29a595054987d0ad985e42aa72cba7555d973319ed5252f9d59792ebbaae8b56ced0ba68d0c82f9f23fafca2cee525bdaf7801451fd1e8176dd3b22cbe9854ce5550e5ecb3a2cf993a26557497557eee9c9dafe74c8364f57c2f6931adbc5dcf2b1a24fb7a337a45a373b68ede5c3c6930b74b55b2d7e6ae35efd6dc65dd5aaf2bb9c6adbd323766666f6627ba478b7422fc476660da69507bf3219617b0f655d2de9ad748b7735f3bb42a90b706d7be5de987192fc9bd7727709712186326d45ce688d804bb6921461c5d6aeb00ccc5b7462c14847047163188d8d2460d10d00417d0186286315ce8720522e4182e64f1d7ef983884780d0c1eea391eb38522b9d239e7e0182d8c6931464a9a8ae470811c65ac78c30a63fcc41b3e8e894308f89ce7c900ca20038f186540d1bc49241d7f1d17c30a9bd84b7a7650e7a9c01d60092bc49c80a0e50c377e5ccf3b27461bef5e146389f79c7361e0f1ae891fe7dc73aed3e3d78c2d4908038eafce039bd8ede961c28e72913fce21a54017fd385f5a897e7194b09787af659508fb7115c24c88a69abe2d1771d13bba6da7ed742b420a8ad24843093313c0d60c24bc7c95d585c1c6b7b724d376b7756badb5d69edbd75a6bad35af1b71934209374845cc38628caf374770419a34d3716b1ec2aedb7539bc6e1dbf11e4d7ae7595d06bf36daf39b7d7563669336e9277ddaeeb75e85e670dbba85d383c44df9f55a685881b7ea273913fd3dbb1d643c599551e29455120be65cd0df0ef5ab253f8967dc1798e654f3f25885e02ca5dc9b5760bfcc4cec155e1f7e78ed3321e287f9904f687cab6edc8b6b3eed3cf596b649d8d8d8f76c367b07af38d8413df9ed33dfc5349df4528d0453f94cf46d71f55d27cb3ca1f332ef287f276b80c597ea1b278d37682f8e620843268a8bf6557da3bf7f1f15a42c3bbec4b09a2bb926bddce9cd975bb6ecf9cf989bb6ed77d89be970516f0135d73aebd6809b9a9f9a57e7b7877d63973e7cc7960eccf35e71aeb7c73cef130119b9e1bb2860a649939f7dacc91706b9b918090f05f40bb48f8a183b0354348f112e6835152724f74701670b417365a17e9714f74701670b41736fac108e9e02ce0682ffde0db131d9c051cfddc890ecea2db9ee8e8ba27c68365954c8d5c6bdad25823eb26c9d41673756a73e37bb7bb4a777c4716d4d80e3becb0c30e3becb0036b1ea51c3977d6b3a0152d2f707416749c980bd781359f4bc99173d9769abf806d75fbd32e5b0fff7463e3bbb9a104d2e7908ae8403d57c9207c6c1f239549e7dcf2e98a47c2bea132795324c618230f892464a60e28a058a24b185e28f1fce09b17813ce001e4017c38064f15214b33675cff9caa320cd21b1b1b4849c8020344810b4f98420842182105073899d1e29f5b2ccc51c9c5a48b2a18c3c51472e0600a58e0e1031bcc6c97076395f188282b78638e2958d1022e4430401c5280557481318b038c17fd06f33356e09ca4f3b035fefdf386f9d3691223f11e035a50441a36c841145438c2cf2bc03f2c0ce19fcb4863cc3c6144e6efc591847fef3d1821b4f12190d9e2f0b9eb54bfa72cdce0afafce23695ec0634159615fb4c0fae8d2a67d946e492933796a3bfbcf27adfc2aaa93820e281103218081630b551c410039c20823471992227d4184128ddd6036376178c15a8fdf784147493a7b9398e43a19894cdbd997d2bd8003db5825185cc0e8a2c4b2c1042fb42c21451c6a74c183853261bca001c975aabfeb90745e16323e92dc49d88debb0a009ce535171c9e86105254609267efc8a49628e31742c3184174d30e2e4050fbc9a3a3cfb74d1822abacf257a679ff2ed1e1f2fa2e89d7decaf242a2fa6f878f2428b8ff0b9eef922b8d176f69d3363056bfcfb35830866a80647174a10d1451144c8df9317648cc1821b59bac8a2a58ba22c3c38e28c8fbf3c408209180770861053982fcb7bef95f907239459ce1822050fcf282ae247bf6748a10820ccd56987d336cd3dd19b17b9a101bdb35e73b0de59af3c3d94571dfe66d3f8ee9d76abd3889ac9351be1d7b90ac6473d41e5748715753cb1852accd4f0852b8ce19e7bcf6a81498a1544b1042f4d14618528065047145cd8808b16b42fa81723175b3ec6181d45c598832f7c8c3152ce27456f9a44c518d70a1f471f3dc6ac4ac9d865968f113eeb370c12a77fbf6192a0e22be6110923468c90400c257891042ba0a1c517466094010f177408a10d23ecf0224711337c40bd970330fe5539c08114ee26a7080d57941c8ea2729c73ce6ffc260b5a6e6eb8b51bf80be128c12578700414a81a5c2970c0181ba881c6174708030a02c8c1113968024638dae28e2db0f01e13a82d4c08f3b0e36194110a11e60c11639c100763bf61f250e371692ea094a0469722ca78c1105f028046992b6cc186cdef690b313f7fc3c4e00534bf691c5184b9cde209efbdf8a2cb82095908e1352fa4169d209cd1061264aca08c1a3b598c89e22901811808c1841258d0c08a364863ae10832cbc4008d338c2cc43eb374c1751c862074664910324e07b2f0b30ffde7bf065e16508436051842c61f228f3eef7944514481688b348028d2226701c8da6877799b010dfb2ca45d7121a7aa5ed36ae617d361b400c0fb81082cb290b22b4c8f07bc2020a581c016b8ea5744e390c75d45405dbd3154e745b1c1cab2089bf21633633bfef5dd5d8340907fa9eb878e39be3c0ec483f74fe2dd2a50d83011fbaa79d360c1e74f06c1a5a5c511e5dbe2e192d56983beef8ba657e9338014693f61f4dc244a3499810d324d7e9120dbf499c38ed92d8a649fb6a9230314793f67d7cc57ec1a0f1eb56977cfcfaea6c16b4668ae6ea14016bbe985bcc39d69acb1aa6050c03317700cc5d701ccb6797cf19ce12f6e7ec2f1baa2e0b0fc81023a68cf4389d73ce39e79c5be79c50fc9705b9dadc8ae988f33625ad324608df73aeb5eecdaa49287e9505412b26e84cab74ca274597d7c0aa4a56d2831c10c5f202a21ccf762991ce590d0a72dea4f3e55cd220e88f2f27adb885aa7c573667d2bcb9926b6de13a2f7cadedb656356f2dcb6952f376ff865943c098d6f5e8d26b8ceb713d2866dba4d70e69e5babe1ea3a375e8fd7a269bb472cbf4dabefeda5de6d8955cdbcea17bbbb3d6edb84d31b95b03b220d0d005e432c96fc5fc80e1b74538f0cf1d8458d6e548d169459ad48874f801e3b0e85c111e770e4ad1e19d6bd993ef7d21bae1070cb3d5da0ddfdc50bb8cbf10e9fc8079debd6fa34e944d8a991c7aff9cfc73b7aede0cbd7f6dba768ef78d768d38ac3df75a66610ca70dcf3e7908d063853042d8dee473f75e9107fdadf7f01a1a7dd6488d3f5a57ccd7e870c328ab3a3ff28a9a5e9d4bcc6553dd347eb9a3d22f9c25f29dcb7719ce92cb9d5fd2e5a5c4f995d5e72ec8b974524ae99c93ef4deab9f79c94cf49f99e93f2bdd168341a8da265494b4a4b4a4b8e7c34b261448b34a9c6493ad362abc6275bd65a394daa7124948f7c52ca929685599665c927e57b4fbef7a47cef4929331b9a349da255879fd67bef3d5293e68befbd77d3a46959cf7aef3debbdf766ce4ff85cfbf92cd73fa1f52c781d71bb469e4f6739e72ce7629396e4d92ce72ce7648c319b5693a65b96f5735a1892fd1bd688b3a26561d67bd67bef49afef59ef49e7de935edfb3de93cebd27bdbe67bd279d9b71d678936a7cbb64f176c95aab06b3a29591b01a6fafe941ab9415f3ce6b726a2a1a1b8a3489721a5a6f78ca67b373eeb5b52ceb3dcb7aefbd6745daae8ddcf52c386325294a567142eb5d6ed4681ae31a6b7459342318d608e5efab73cec167559da79c871091603e7247b1eb9aeebdf75e5f40d650b7656d979e37cbeb7bef59ceede95d96d32487d1aaf36e9b4493f91a71ce44c0f6bdf7de9cefcdf95e8d31c6f99e1bd12a45075e40cf494da2bc49143311b0f5e79c9bdbcd3d1879e528678d508eedb68d313a17bd3ae75c8c317a8c31db97ec9cf318638c31c618638c31c618638c31c618638c31c618637ccfbdf377f368a39ba8c449d9a83341cc39c8109a119a49129000231640303018108b45c38124499a0f14801191a45250204b635112c4280a8320831022c410000c00c0185343449c00ed78fb9a2d8854db1a7d5ab0ab6ef43ef2e84186ec2066fea225ef0081ba52419caa8dd7b794c588fd0ed01338d80c7d8073c8c5b138b6b9521f56cbebb8da8ecb1108e45e91094bd5aaa470500c6d8881010d430e08aa5a78db39a7cee30682885f4d3600af31018f51cd2b5d814687beb70b9ebb5b2c289cb2fbb92e285b4ccab90ea15c5d48104518c094b2c20f19ce1dd0204e9ec193c95a6c40d1bad760f4dd8ed8d3f2dc812ce48f9ef5416662528b6deaac79c6fabdabbbaead5c5d3280604443e9e7c66d18c3cf3639c43a7f29fc8225a76fba766de87eca674222b8f1851e9d88622da398db5e176636e6c6b75655ee3e68e6859359f80e4c51a793ecfce02b85e71ea19217a53abc4c1e93ca8d9f47b43c2d69aa83c7ab409705dc26277528d1e1978819bf9ef612f5bd92637660640aeee08caa88b67595026cc076b86e8d9f71ddeb442b79d426880da338ef3f7a89199b997566f6c9f733e3508222ef6c00fcab618a66ada23d33a744105766deeb8ab0e92eda9491d70d50cf535b7c58ee5650d78db923653381e72d8ab5f1042e7c181b1f65e07e1c44e0d9d5536a0e4739d57ce7eb53a08042f89441571d3b6afb66b189668989a9a53b8ba7952e968728b483dc4289f5c4eefef541c06e7a36327af1729ec9b7a0db95bfe78c44978527b0d387b24a7344cc8f608fd45a26e06b923281a4bf5365758822594b0d14ebbc8a339a12523238ab2351fafac63894bcd9d192c0f3252787b8e6259c8dbe3dd4b8bc1c22f567676ea7dfd733767372d648110875abff3ab6a9362c66389f403559f48cfd9277f61a4890a1daf3c55447da4f8b64d58decea4fb95906e271ffc2a1b42d22beb1ba7879c9a6b6ef2671ec08964a432afc53c1e6fa60f3f5345b49c427ae4f1426029ecb8e82ddba569f17911249eda77988c74e86a28b4dc612151cd583e0dada18aa9d692a2b2f08137aaf23170b4971cf92ce5fb6f3956812efb1882095b5749566d3f1ff953bebd1a446a5b4b1718fe8cdca332396787a384a33f1f62fc59a226d79fe3ca9196d6d0883681aa458b4720e2598b5336726f190c71cd225aa9554c6f28ae8d4082c38ac0552631f4b246e626c740da0a5bb43b31b6734913cf869eccc6ac68664658cb06d5676460284a69c40ca7bf977be3442c3cb514e8b0d883d56b15272e1cc75616793ef8edd69efdc036d4b4b00e30d6b2dc38d242df6ca0e36244955c8dbdbfb26cb0bf25c9f5f220987da291b7a119916b08dddd881d2c1a07ee4db7be3fb4e8ce8607f3fb369e8ed5eb53401c862a090cc5415436586f03d2f3c9394119bce10098f2029f9d4dbaffcb30ba2679cc7d298f9eacf491f80334efede9dcb59aede02ae94ea4464df2421abae4676f502c3725a968f20cb22e1e995df9b5623665e3c814750146126a0f3e6077a0393e187b9a9681dd0333094de60bea8f8e1e042c0181bb34c0c8c5247bee81d50d39152e66258e680ecf56c4d70a7c8d8c8de35cd2ac8a5a4e1546470ec34cb377e49e5b111dbe5f580af8456c92761b2d617e32e61b13596b3c8e46494143461f434cc934bf7507daf9e0af10d3a11c04656cec005bdce7490fea96e125932b5bbc86bfa27264408d7c9a04ec7b91a4c12bac2a7582469e5c61b4b9256c6e363151c8a30c78a3855a1b9754e38de2227cbeb70827d975377b8ae24a824376cd77575cbd4133cacc7cccd7557c1dc0e1f4c805b7714ad9b6de45071f149751475a56f7a86c463736eb62500b6997ac6e8660cc48fd0f3f42a63348d2284676ac17e8e576b3eabc78c1c45361f765eef20c207618230390c39d9dbfa049a3db600873132d552f0fa8834e5f5b1b507afdc891d2d542de4b8981114ab98b08d36d40835565d13c534829a5df8436ab759cf5e717353d51242588e4a55ae6e29e2e2420054b26eb947241e9889f8a8fa1140e84d0688264fb855043fda23adb44fa1d1938dfadc11acdc40018b46c9b5d3727738bd215c1dd8476ee632381d508229771b38875a8dc462b080df022e37bd2f7fb3906e898c166dbd59831f63af791daa02f233bc2d4f4e88e338d099c92becb35ed06630b3e2592e31596fdc1bdeabc436578b850dc9b7e8cb3a2e454e1306d9f2796cc0455799c7d63b121d20fca53d47acae01406da962e6ee12c4c2b0b72450a1b859047835aec6a6f03352505fe79e658d3f938b2e359ffb4d9b35adca8194c6a20e2c34fb7b21db7f91c0c95582cc38228d96c2e45fbeffd4847e52a3f3d321823c4e6345b8aac2c1a6115cc04cab06ebeeca657b162a56f7283e9353af3cc218147d79d8e81751a4bd2a4da2c630f6043b5974a8ca1deeca9430a3c45cf5671d3773f370d80ea99a131c34b01d801a2e4075e850679e1e64565e63a72462e7f4a43c3295bae83dc821eab34c5ceab88d7cc93c268942af3238eff8fce51ff492314fa5835e5dc183de8c35d11f7797e8d4cdef36e47daa69aa3c52a1d5267caf92cddfb7ab59c72295637199f82e607f59fb479cd4160295de168bcbe0f53515314b4f88afcee21c2eaa837f6a7c919bc8e680498361588fa55a017cfa007d02178d853e107a1483a83b176f4310aad34132037619cfe82a932b059149d33999cd2b0338b22f208d99181bc12ae0a903f976b654abcad12e1e4132725da706f9c78e9cc621eefe5f7db155032c6a47f752cd6ad117b3cde346d02e9a102faa6d60915f5f10197026bb27b7f7631d4618f6c05237a3887a30eaad93e9c910301b137aea901a61d5d598a8a64cfc2aa65142ded0f3c27f416b88e3d17841a8002e9bc32af1eca8d48f007fa68bdd441e717179760eacc4ee3a4be3e55728e201b0cb2dbe9538ab0c4b9145303c2bcae7f238d645585cadc3a28d948ed0588d176f347c9d0587bdc5779f741677b027f8f1fb6d64b0a8ad80cbe6b04e343b3a6df10e901e682cae30885233d672fe7c599b08bbf3117784d13f5d2d907e95c039530706a07a0870eccf89a5d28dca951ee4b7c22fdbf4b9db9c736f6c6d2875d022039f473c565ea4c4a54dd5061c87f4b4ab41d3dbcca145c4493d6c6990feb3e092ed7d4703990f84e2654ca95a1a7126ddbf3b6e36b3f7275d359c96b6ef0edadbb220698ae6a872c863811ee2ee040068035ede1b10a340986ac24b27c452b22a25bf4914d6e6f3401357b9f14b79f004900d4c5b146666d5841cb08572f069a2f0a961c7b1067c93d69cd9c98de089063c7d4fadfb261af0d8da6d0e313b210c00a2895ecc94c1e2389d709f8d724ad254355d26e07151d8d1297c6dee0465d2f4b4ce76b48a9c9f481e646ecbbb3f11b78e054123578fdbdb381068ba76c94047c102692b96718217f4872f83d1fbf02044134de7cd9b2a7afa13ace594eecb104f7ce68f91d2da3e6d2b3b7ffffc0fce65d0eef361f6baab90efd7c3a8f5de642e91944a508cba6e681f34a2c984c60b95b4b48a51ca4ced2e91b10300071c79f6635bb2729f983c15af0041ec4d7dca12f2ac37b4be1b9d031ea749bf03b4585c13195daf45e52b5e9b5d7cb476406fe5c7a78271f0b3269ea0fb2bf4603bf6c1f58a3c764b233249fb60a47b3b766a7b8ada6d2aa959a45d9646ad039c235af75fe0e7c0b943e603765b051315af82ca7cb150c6ffc0a70081d217df41f83fd1f215eacd339bc76ca67fc9123b63a0d52fb21308423b25bc799987869fe33d74cf2e11987a345cbffd2d0602bded069741eeb99a88492353c81a9e96d8494653d312cd85f6e8de33ef07104bd4eacac31cdd4b74da3e609dc6f6c351898599c51034e32cedb15660d17027d3b8a28acb53aa968625905ce3b037fe6a43df78291740cf7b7cec106faac57ded46b0d988c6a95bb71397a6219a7a1ce246f650c3096227901b372600fed9c7b9eb2eb120a404c1f2961ebd5baf4f8f3f945c0a51b39d3a6aed8538e0a216b8207e323ad3caacc10344f45082de7e2d73bdf9dd3f513c717e13172d2db49275e2141c3d0859124f39cf255501f6d816f18e05e74f577218b41ad5195af3592e1ddd8779ce5c6fc540532eb8d73c1c6a5459b5c90a4f357b0391443aae221ab70fb0bfd5b330a1e4da18fd8968717d18c0d0dcaf2812a698695c21b250a446ad4619eabb952549baf25006e106434ed0e92bdf9f6f19b8fe7e3cbd8cd8084f6ffd7caa8e783c304b2eb6f70acc562d4c1dec630144fe5a55ebc47c5d1db7635e82a28d9fa45c0a4fe00ece474418861b4ae0df3d345629cf5499ffd28d21be386ae8d94642ac1c6b0d2fc32a840b22d93d53b223d45cf1212e51940b10424ba273b600f2d3bb89a69444af661839f1b385296105b750fc8da288f140f428931b6bd9c24102f5e25c553a728032a9c8416c808ec81e7d89b8bc2febd0bfd65b3c4b4bc6f32d059fa59b611fb3f3f12740a2b614e4fe9bd8f4dde7c12ceb0b90fd9da7965bc0ba701f5c818031e42ad3bd58e1755399293117fa5cccd5f8f2f28c8ea9e09069638f7929837aedc0684c3ea5cc3da48f49563924e501f90471dae30d7c67bb7853c9328d9d578ddf9955ebb9abf1a980c1fb045447b30a63a06fa2affcf1ceea6a7c682f7ad1af03fc8128047485a03ab151fdd1a7086e8b8e0e382934fb6a1e015a57e4f9a2b32033c97eb432574946ce9d3d942052edb73e61aa421969c02e75db2fce1c7ed34ff291aa0144bb79053a9376f98c2a7c269cc0e91cf0995b5f0b87b3270742775596989ba2b6f2ba4910ac66e3a7461bb2607bc402103c6abb0df2d82fe4d8cfe15a8bdd1c71adfd81a4844a80339e66dc217a3cc51b1cb0986984fa20db73afd21b224cf175582e553c694576188fb06eea6f809545a070276f2257f87d697bca6e67b3ec9e1cc294afd10cd9ad65df256282ff12876502bb3f542a896d5b074a9d09e57bdb429b981d7e78e7470c84d056cd2650bb095a431eccd1a9fafdb7696eb6dfe61165841829df2619222332761896de15177a563a70f05a95b6765c72764f647945b022c4ff7d079f326219a29995044950fc87fe9f6c7f94b47da32e247d13b572b2a99578e8b9667520086e0b173467cabc40c41e4fe30553d2bc6b8a4850000f48c23b18109ed0baa6106bd0248bc4cd2e322a6180bfd827a2e667a0e66b0e38a11dc092061646ab75d17fef61108370b05fa376c1923cffc0f60811eb440d256c42e8b6843710c54c1489c6f6ac97b731e795a72857863b0e027ec641512b527c114b1691844953461860326c9c9e28dea8f46b9f363def0a6b6cf0522eec9f27da8416e72d39a71c65d89124eed88caa4a46ca58f9aba05a20c4e2a61db22f469f1731f0537ca3d0c8a157a4904ce466d0185388bbfc43d2dc3cf340a808698f19fbc455c5de54d3c4399e121f0434401cb910e2e2e61baa0681611e81f8c68fc7aceea75976fba87d4a5e29fba4c19ec8d61efed593272cb3907993e920b21b32a305188d4021c7579acf562604428bc6894cb27cffaa3f4ca1325ca24b46bc9a4c74161433445f57816eb6c0b940aa683ddc1eaad4b8382b3cb965f34cf7f3848af8a659cc527e127a0682430711241492a54231d951692a791e8c2731f55f915e612a740424fa6344c802b15cfec869a78a11c4408b94fbf4d06f0caf6154847bdd6194051a26171d5b2076af1301390ca1eac24ebc8ff7543f57d9f1448a20616611f8a9c80515c701fee46c9d8500f54ad67737cfa6cbb09e433338d7a2e3b45e411ab44ba4e2c23aaff3b55d14b8f177be92ba408f9cbf6da68ce2daa6ae36539091159b230b54fe82483e96cb6bb3a757e7d082be05d8d10142cda16c5e61650ca107051e740f1ef407dc25d8d35748ae3deb47b48300d833620ea50faad7890c2004db741677c7ec282cd6be350b4c20e368d0f0b5200cef967927ba9a569ad8d4d53520789cfe45b8340a365c1d0fac705e238d0a3ef41774b1f1c98af5b1bf1ffd9d1f9412f602ee20f04f267c07a60caedc64e0b8af8f4f7f4713df04e377c73076e31d6fc717f9dba593a9056c871150661055a8e26766327fa6d94506c09ee6dfda1b93cac8f6006f9d18a2b925049d7950189a2ec1ee90cd4175e31ed963797a5b55201f0ec49792c2f9e58e36a6d0dcfd1cd7166f0f76fffc5d4551cdb71b2cd7d2c9eb83ab900eb49eb4de34e68c58edebd962753ee653cebedbccb555086c8716580728fb4d5876215de2cd40bbce651e3648e5df5d1ccea8ad868ecb4cbb96fff70e2b0facb7c2fe0d5734ac7cffb3d517d120c9b347877afb5510e7b4bb9ca480feb5481d7895f1354e3d893dd8821d32c87247e4ed06228e2b21d267b7175edb5587b47cc6702f500fc8e81b6f3b1a234f4621ae189007f2fb62871bc22b1f9e4d1ba26e49a1e6c4053d0093cca8ee6a32f8a8b950b2b18044497293ae8a5d1788a90630089f03feeb507782cbb60dfe487092099b611d7d568f40c3b6f49239b90f891a1df5630aac738e34297f32f7e308e84e8601405dc4f6db2d985c74ac62fb68fb76df4f64a05202c3b86ae8422a46b710d23e56be02ad3cdcff6942cbb7c46781141fcc57d404d0b471838bf3e26e0f34fd8294feecf3c12b1c5c68bfa7ddef5ab86a62570b682adde59ca6aaff5537f4b9cfdf6b51d66d7b4d1810e69679d9c9b631be5c34647582e85e0a629202c9fe717966b191a44f6838ee900e4b5708fb1f4e013e9affcbbca193948a7a42d9bafe878d1cc58894db610ec031b2259f31c34caf52f3653c7fd7f11ebd509feb5ef4a9f167346c0009224a9ca496c7cc0d4fbb0e12c59ea5be1984ee5887a08098e4640e81b98d5b9dce3e2d34c9ee77aefb2327d1aaf2a6226d45844f9dc657d168840c022e982bb4264428f7120e3e28130ce793293599450449b8b47b9d2f018b88f611cf09ebf92caeda4147c1c9133ac4fe412a9884621d92990d6db0b5060529fd06d9ff25b0311fae40c96884b07fdece5aa8e9b20a0531b058efafc2407cfd2e838a8a438686b350d2be9f6001667831b013451e5bc11659ba32f8c9be4a61605dada060d7cc8bbf60a27a6561d288813201ee69ed4f70dc5c3cfabca47769bd0423fef3a45c2101a9c072074dde35ac396002d168fe9f0c5c2bb5c238e74f70b07a714956eae2ea413a9c107b265a3aa9d953f024dc83690481dc981ec5707d39d0d81ea38cf8a43485a742acbd59b3bc9e9a41aa100112222dc588cdc197cd11fe487c5b5a441690c63de24827ad04b19862b904ca6c048ebfe97dca61b3719d1852188172d00cd80323656dbc116e75e1dd10bb071de6bfc47db7ac4bc16bfc7e92875402b85a7c7cbe5eb01f9898cb10abee7aa85e10f99d19e1c370418cd6ea034fb5d0863b71286b112b3b4cb319dcc827a4dc70bc0b317a35e46270d7c3291b42101824e164bc498c303605c3045265d0b3f2a5bd5c6d7028fe658cbe323f75bb250f61311534d870bae01174be74924fc17242ef56a4aa98e5acf75fdf2373e38c4a237266b2cf3d93962d44ba81dbb8d218781a8aaaf9cb6c054936375ef175dc9aaafcd6d8099392657ba2374caa41830b7eb344b2e68505c3e6097f0942ad859426e32168a36c0628239fc86c249d89b7e8d561b74f46b8e5d043eaa5ce855c5a45ddc845d062eaf5c065c539358b5ce1b83307e9abc148ab1d34fc0ed09bf4193de1b04492a94abda6f3bd1a29dde59996a0d2333d7aa6aa461def846a4abf37543a11de5b961fbb233f4fbfb213dd4e3efe7879f1c6fcb2aa112f5735dd991e9c0cf117792115efee60cacd91d906e8d9a5ce90d2e5e3a5f22a58a50157e8ff7841de6b511c86f112446ce824dd45a7d05b0086d2515d1f6fe89bd1b6e14b5aef82e58554a47ab148a3319739fb297c123c9760bf615fabdf4ad3cab578c63424f7eb37ac4015e10e735ff69eb4a4007873fb60916f0d17610dfeda7f0698c3fb3282780e3b5da758b453556e256466f9a2609dfef4f8038fbc1b27a24f0dc06fdc2920ac2f68c22a754d8faa789202128444fc5c96489420d4ee37f0899fba18ca53a9b505d3c125152f3c96e4a35c31bc8ffce6d80ff5d8e503b336a4e0f75139e1704f193331e4a03417197af249dbe89ec9b4215f058c77eb18a601d810c5b291ff0bd2e7ea63e7f4ee936887a071297f390d9584fd47b5c2826ad32991ea299067ebc7b2f2e3385b45f82854cea91c3b838068310b41a4bacf88db7abd8cbf95e272b3a9689e2b3e712992ad44d9c055da3aac2be62d7193b2452a5ddc857f7125db888f949ebe5f1d9e7046b9af129589f25bc0f5b336319022c5b50a295e3bcf898ab46dc8218f4d8ffbbc9f58d5e4d0b127b57d365dc7b5aa421d36efb48d713e162c4af93937e1dbb0bd21ea74645fcb3607a7a1de0e100f0ab4dcf621312f277b94a74085d00722d439b7278c94cc27b0c4249f635f05edc7310667385478134b56014e0a2c53d4c1f4e594453595432a4c3359a0f62033f80bde0bee87d49a560cf99c0591953d52ad863d6dbb9b712c15d749890dd009eabeaf005a64e1743f18d576d85661ed6e61275e8e1403b485536fc93db0f4dc137fd16a8a9b797a012f1e5156d5a49cba62ddbfe35b24fd13872b507fded773eeee8342073294ead62893b581efa80186e431683c2c0ae8cd0311360181a7fd31188804b894363a7cad97e8cf07d2d199a9978c2a5446b9a26dfea9df356029a749f69abc0eaf6e299d1bb9bdc6c548e87dbd58a101da4c7708019f51ae8078fc8c22bf541484eb247a69eaa97e11369f888b24a6376939381b94a5f2195520f76243ca1618f53d5c67f6610ea4c331ce77e62d5a7d60cb11977fb6f9b9a2e450f5cee9292da93df008305061051a4897271610f2478f8993586e50a1d22076b6c690ff52b13a1228cbe2712fed34684f25374f46a86d711ccb98cb002ae31946deaf055ab8f28a051e4753deefd70d359b4b1c15867f4508130e3bc4b02129c8ca972f5e3e928672fca6268f1f941aeff29a6a614b15e7cb48b74a1c91178134cac7376819a42c348812d1b02a7d7afaa55df196a700d64dfd69899a2f5eebffe2c7bbb85803088bd31d6a7e204798450b8387b90d20ad3f336793ca4512871453e32f8962a27c7815048bc915c6a33b59a1f2d2ec94289bd14e45362ee9fa7050cc57bcf044eb5f5b1170d12fddcea486849e25a69e675cce489478d8951b567ff80a89207c3a84a010a93027c686b0002ed5e8650179e009b95d737feb5b452e99f0a17a13920ab431864e50feefa07280d015c1ac68a48fc490a4bdedd78aa54d4680c8c9eaf6499684d0497108a8bfc97cf503cc7b08d08fa1022a00b4bad24ff7aa6f90c9d0428b30b30f335f9282cae7a0a018828de1be1ff5a77990fa9d76fdfafa6c27cbc27ca048c36690f62719e50154a2c741366fbebdbd7cf2d2365f9ef273d295c21b58a8cf2592eeea5a046c090300970384c0f770b17fe11ad50f1f64313f4ac05ff1b1a011e4a18134ff11320b3942d63597794474358060b88b0501882806c5628ba6a9ccdf02535f5b364f5a39372d48cc56fb8e593330cc38c42e31c5201f7b98bca68772b76c72f5ac20870f7db7769b0666526885e46f67e4f1a9339b11e37c7964e634f0c92663401acc9da2c8285e0da8dd4464a9d98857bfdd118574eca4caf79df1537415d42ccc8428835e3c42b3797b27fb1bb729a5ed2fc3e5d95d89481ad6a8fc753a27e7c7338663c31133dcd8577157eef48040aa6dbd91cdae1d98c37ff018714e598dd936f8dcf43acf9a59114cb44981f461c4b688047a19e810de0d3d55ff2409640e231530f2c2c069aaa626d8b286d8fd4e75ad270a13b80f074d6c3f0e57b3654377789a7de600058e42681f79983e72cd3af4924242a4d63448fb51eeec962375e4d79eb4f443929415c68542ebbe7e13d466bf856b4c442fa8161fa118d7f1d98019f7a994693e58c54f85d21aa3ad11d9e05b9e6b0615a3e9d294901119d45bdda114f615baa7a7f1552e32003a5730e7831ad5dfaa665d2bf25a942214801afb91f7397f5503e80e65871abac011dc3aad7caa545ca9ff7b657663ddc912fda419d62f0dc220a5057ce4b4f354d5310baaa74f69bd4d6ce8c39e5945ca261bcfb6063303f41a8b9e90949b6b32d07cff7e2648270821e343e4e929d5487687f5a1428b801e45a6ba665a396bc1a4ccb1eba0f142f866f1aa4fed86da9a669332c7e2e4aa4b2760a5e9e25439026eb07fe7e03431ac0ae7d93324d0d7589723833c6fb01c9d618bd0fb349110ca130a08c16c313c526904ac974011360e804e42c7a87a9a08b47601ca22d085aac8dec1196cc84e495462a7fed167e11c1bd0614f97c169c0ca4d44efa7b56a534d5fe4fc9164b227c36a2cd022169989a2b7679c0d642da71cf989ba75b5de869e82f0d6031babd0181bb21e0883a17f96b3d02c5f55d9f34b960cf6d74dae27630fc82280e8b06247cfce19ef7b0c00a9e5a0a663a097cb31e257cce4c0bc3bed66538f8db19a92aa80e03099bc97cfa9cc99cddd7b5dfaa329a5ded2d7a2920a5c162c8c69c8f5fba93c4b04766ef610e336685778462252670bf48f00fa9288101911001ebee252abac0d4bb937755a4701c01959b2d066513e1c630873eb1d883c875c0b74ce99bad8d39cc18da1b3dc8109240fc2df9aff45b3bf6ddefbe67b69f637cd7eb759afcdeeadd92f34ff65f3bd97e699e32db8c2a91ad6d9194410e88b72ad9a112394e3d1b41dfbd55ed1ceb153da524a9509efd2049ef7e871ad22d9d87c77c960837357812fed71e78c31dc4870353fb2b6372b7ea21658269c4d9c47c7741c1983835bc43c2e2cd9b319824b29ee621e3df66259a05354185e27fb13eb56302ccf56b495a8f971af143b8102d3984c18486308e308b6bce251d2b1cf9c036da630fe1cf887638cb871cdb2dddb8ad0ab0566cbee6dfa5193af1bfa10285d34d2d71b43eb10bf802d1b433e4b4425877f0ba11a06074d4c827f3f1d7cba510a818a697013793ec8760e54dd4ce9aa38a53da57cd18ec81ba93ff389d57af0f11d1f1b717d0ff04fb444c955cf525b6809a276402c7db15ea402e8f0585bfa0d1cb44884f7479afd0566db02b4a5c0ed315f72aacc1fa0f972c555d093cde94f08261bf6bd5acd7ceb7cb40d610c55fb813ad309f90b48730c511134b1f16ec15e0145357649cea4e1559d4f35abc3c1dfb0f45f72291488aba4d25342bf5dd842a85e6d4f05d6d20b22c3596bc87ddd95b69d85a43c00dbda903a296497f9be6a8df78ddda52db43ca74211024757d9d22099f2cceb3de52cdb1a04b9b12ab71c669963e335e6b024680082c321e81820870f4c395e687da03ca4a4efce30236656379d7fe3f81e356c8014cff439bb8bc76f8f5e57ee6274a5178d7ddc9bf0e9de409fce4d7d70ddc4a72b37fc8830fa914990818b7139bf2ccc2e94263f1d827d7a81562600e70a6c53a00b431b27c3148e5059055d74719f43bc85f08d35e2194782c9337de564d631d567ac93ebc6cd2aa8c770a00aedcf41fa1137020dab0a9bb2abe86457d900da58d621a33a05037f963868ddd6f422fa0ee879ff12e2c684f9137c15cc5f8d0dba05fcf45cdd030843182372904ce8f121d0af22ef626e4b6acb60faf02ed40ebddb9c72e7f3bd7531735b85a1824dc5e0b82a7bd8df47030b2b5950ec512d18b60ed017f20daccc4349101f2058859e94b227a9416f9c8aabfd10c6fbb2acafceb5ef13085c2e1f8a860d144a00f97e37038e456503a0b5457d4001ace46184db7cc778c8932c2c54268c029ede2d148d6ce5ad68d3de3829538a5b01dd0c0d25233bd8ec27dfec8f18bb3b5637b4e3e6e97b8f81fc971ed8e4b0c416c865bfb3b2c755283185531f836b59aa0e06d61d75e1a4c9428aa0494b6eddfc409c63e2501448759297f345cf5052b62773a738c73b82de0fe8454ec484191de30f358d7a21d0ef3cd62de0a83429f078b19f8af3809be5a9ccd5c3d65c1d597f47a6b5588f4aaa5fd42d98c695f840e81176205e31abe10e5b34e2c3278d6d6c9849a1f17d9cef1c145b08da667f19cbd1e9e65ec358b2efaeff92aa0dd833db884b2f98d1e1d9c5cfb63dc3487023aeff8e9e020c1cc6fdf846c9eda4ffb7114d08ae2b1ec800eb3a8d9def449b454334cc703dfae9abed506b5c1c18f7b81fe3ed501655f2e8456c97c4385aa997397ba04a917f820c843fbebc04f7f576b391052e83052fe630050715f63fc67afb856eec659da4b0efeb155a7f362cdfe47f7aa0aab5fa60093acd369532506c63eef9f39aa83fded5a291f8d27dd84a051d39dc54e8d7509a7e1f586e8a38f75a86a927319647bd6a94f5abad95740c6c9d1ee58c44da86c726b76941607ff150a3aae904dae0d66f35c175026660f7683f7758776609d5e02f6e88e33ee636333ae12d28050f48a931678c9ed72fa36981d8bb2d02519e8480f17dd68f0ab01801ef88ad96c8c55651bfc9c4fecc4eba16261d115b1769f0055c87b7e91ed2b57dd16fa6e2167d92ef643e3e17f6b681d68b2bf0e80dd8e449c5e50696bc6d0601466bc9de2f9285e35edcf58d77a061a3661d6ddeb3f8f058b609fd1b3547f42b6c91fc777b4afcaee7f598b49fa6e5ab759d307d98cfdab6559998f7826d5a213b5b1038f15bd68bad5d95db4b5261b1c8ed137d64ee22442ea065bad02335d045239c3dd1487e0c9385272885fb7adfd0b21f68877171cc5aa459d16adf6db2f4a648235b192fe5d544da852293e93a138109a917df9ad2e52e7771ab436b6c59f29448541c530be8e2c2077becdd632267e8923de3815627fd71f757dd0356fdbf0a82c8a49eceaf88ebf5db00ee524cbd0ef95eb869dcd1a86c96428663d75ccd8974d95271ef104277592632a628f383917ca4c0b1c1868e7f70a35acb518a31a251b1e21c5fc654233d197e55338665ad1c679be1a6c2b991b6f15cbd546d6788b90b0c795852ba92d8e0525d15fcb10391d896e71aade21c195cfc4b4bbb2514ac323efe07b922c87b279da3484c8dba4eb4e2dd7709c73294bf78807a75afe6201cd742d2d985523af063f855e7276d92a2655155041567b2e8cbdca38cd6edda6ac87346135b7b34f3544475e7cea7babe18c3c9d9942aa0ce8605efa9891b73e3a9e22e817851479f3fc6a0d3d52d52a70f0e86e96ec7eeef64cda33c14a11792927011e8ba143fb1d6b665ea08beb65aeb7e328e65d66b3c8e6bcf16f59fc959de882f486ef105fd377a5aa4caab059a52c31f6e4b59f40c962f120046978cf3b7e26e078a2cbf20d340154e4d63a3c44bc96ebc2c9417c61c3449d691910a984003cf8890af02403935f0915264b2fb3350b3c43c61f741b8094b0b23f21c7dc65c531d434d9b79e43509fb56fa73d5c2321783a0e0233eeca33ef3799ff3998f4b1fa50b0383c1fb9caffd62aee2efb1eece7cfd2154e2b675f6adbaf6be4917c85620177679c246bcba34da0e4d59437d0496089d9c3f16b6114c6e54d884ea3a20647e711052e38226d4d7812354397352d6f41b98bfc7dca84003d5f5c10e55ce949c35bd6f0ccae68e089c50f9f1f32dbc4932735a263a3b89fc99247f44a0898aadc9309421088c71327b1a1f8dd9a334f4052ce85d6a69c3139f352ebf78e259337563aae49553fddd04180c75aa7ff3565b5a19d90752c2818fb6916bb501b506d87a0a26b75ddfe16c51d2e69055277cd9f885bff1d4aa5bc7b7d50d39df949986a7f74fb19159ee69aa40b1242e8aa174c38a5c68ec5c2b33964b3d57ba646ae2835342fd523d12817a18e0356a46572fa3710276dd30e4d8dd8b216bfb3ae407cd40a78f5e5c9edbe35f0875eb3c9239e72a09fcf5489247f2e2e841508ff50058146c6ed564904b533ad13e5f34458d35c409d03df19b622de105875be042c4c2625dc8c7e7c10482de352e3aed1c4dc9fc08225d7193f707da2019e8b8c13cd23119bb46afbfc8897fee750bfc961fe8c69ff171af14eee424e7abc58baeddb577c3a952c07a09273719e637094b4b1cf92f7914a240b11a1406dd424436a576112bbfdbc280f7e527c5afa72827b110694d477d501816f86d3340e5d247d08708c527d205e937aea18656d8831ff7eb5654b9ed91836c5b7ace11d4d3f9ac560c7ba68a12a1239b718dde00d5cad4df16aa5439f370b49529510f0de300377a12b052e909fde74fa0aed1ab257415743bb644316c5cd052c26cc2068318beb9066d427cd90e88326e2555092d5e928496b9a21e316350de8444be697f0e099de2a0e339988e92499b0ad303f750e892066d0974441e125cd8a464d09dd16dd5e675c637f30809343471aaec73cac11a17089080e814dcad1b33c2b26a4a580031b8b6fd7595730a3b0831f12073db85cd63d6bce791eecc37580215399c650d5194686666aa1b8433f3c618fcc76460db015813ed7a9739ae961fd6e6c41f7ab8818a42b3db14766b4c01353e65e3d8b4d41cf321da2c8384a154635ee8f369525435c1d1694cacaf5be909bdf985c80f2807f5e289d24089c67bfadd82c3f4ff33d9b12c1671f6ce59e3f49b2fde9bdd42dfa41b237308571fcd747961127d275441f4125e0a9653ba0eb919533ccd59cb6826625af9383866e87b8a0b68637399b47658e5eff18d0b4932fe6a3701e9646198674a550410020127739fc8782e8d0c3151871cde988c0a54d3be75db3cb11651c0e6a205bea52a97c433c16d0e8079977c79daca6257e3928600541af72c0e17e881860f6d5d79e9a172a61d1781d15f6c3c38d5d1a747d0e1edf33280692b99a3e555ac0245b6c4fffc61edaef938291f7c7eea3e3c174aee894e137c19f0a5d310a1f438bb26f13cc3cba20486116b1dc927cb7686270b09aba877166d80f7806aa547900c941256d901d35ddb4d8ae2d01a138c4f9a0095490ff43fdcd09bde6a164c6517d2205d99b72e39b77b9ccef94c2cc1dff98a5ae22af304bdff7cb1eac70bd2dca1ea751b34fa90c6383d99993155384e59f63e9f1e5399be9d0af24196702212f552987c72173fa04dcb27c82912879a265b6c8ae37adb274564c23ab1cc4ded9af082157f503ae3529934f2af7b95f7dfb071576fd07ea84925bcc740e06548bc71d6a3cb8c5a95a9b41cca9d8873d119814c73e7d20c8e12da654375d275645dbd80f08f33ebff4f49fe2eebb1ae98c3ba576b12c121d6950864db467ee968940d40dac19168957662609241c65f478ef9b98cf11619f791a474edd3c6f6b116df0def512164324da12fa3a9c1caaff2f40c54d10a94796054a7c2bceaa3c47b302c9a0b1ea9e69fc9e837024408050609f51985fd3952594cf65ca4c28295c0830c28242ee555140800757581b0ea5626d6311db66ecc1de1ad7f2abc6861c10f20ff12c345238e5dbe56d22198792f9cfb36a1b5a8baa66a60d414f680dd04215f065a2958d4d8bd475f6e70cd9060b38968a46899e5b086121e9c2a7da5f51b04a0a24687f9e0ee8dacd9d399eb2f051267f924adeea8100d3dc820ad055b194854c2ac986a69b3c8e62af4ed1b21378f6c6a1100e3f417d5aa987fdb3900cb4310ef7a085014d4522749b12c6b800190f56e4c31132fce475463dc39c47955d496b95eb43d549315a3258952d243b9d13cbb7082e5faaba57af4e4d9fafdfc745639f4246853fd39281a3b069ae6983c39a31e2d330d75b3ff6ae067c55077b16e2500c081abb01bffddb4c8370dc00b22d9b84915221e40d7849fa70c947a8dac446a09c9a4a03bb0a09bc89397d6e03bd9b35634ed090edfb36b30de5f0481d6048d1ef6abb4c26d4e10bc3d9f3e7492a893b11d49cb9031d04a87e296919264c3f8ec6bbecd4efad8d338bf318b4bca321f754a11e387183955f722e93fe8392d436af9a015e5e6e44676a6c8071fcbf9dc3368271538e684fbd18a5b528759405dad4b300eb4685ecc1d9eeaa2d1630e95e3ef53fe374e1326fe294a1c9ee75813772314793c6319ffa7c43020804e6996e03d5136adfc764bf882494310c48cadd757ad412d1ab64d54445ff98d021a73a5bfea4efc26de09664765ec394a2a97bb94b47376da50527a270a62cf307b1e62083b645a6dd55f829c1463400896fba64cadfadf4bb7c172a9c752d62476962b7b762d2765c740111997263c5a40f3acc08d613c9a0de01cb54cf51593b6cec22cc3b788d39f27c96ec974647cc8b559ed09aae59702c6c83203914e47fed70860d3002ec7e03680080aee2e1457f759fb2311d5ae96a66501efd8211fe199277e415e04b70bab1927d31631259d9ade75c48f0c4203e60efedf8135d958baa87df46da77e6532cda8b3bcd3c9b5ca102228775d14a0fdc88231a877fd5cf0689b7091089db80e10ed138b52758bf8d416d0d9f1748f7d1fb59592e193a8289ed5c2800003bc22ae3cea6a39425c6d7da03f468734ae6d14aa7480204d01de93837c99053901e3c9456683da3657b29a442bbe56ce4b91d58af6d1192aca4a67900b610ecf2e51839e409baaa80a4db40c48d22dcf5864bec2e8700b0b12669b93bfd69d01d6b3d41f58f0beb6bbd4158ab50d7497c70cb1d767745dca3a0437acf93ca5a9739a618addc4f51d73ce13b1de3a74aad5b0d0ba0d0c80cdcd6db48ef30205665cd1ef1d125f285261a8ed7c2749e4dcd00499d0313ee447f360c02d87ac538ef122ebeebd6e6b3360ecac37881dfe0bb9427d2b1cdfdefade4708a803489a37ea93fb670ae18ea1a44a5032718f1fd7afa737cc581ff57adfeefe568247c1832f8d826013506c865718f4af7c41dcd523da6e3c79d5fc3ff5c7d76241389a0649bf1655eed6a0b523425fb82da8e68592e42988b8fbb5ffa203ff5848f6deea367fd8cf8a23e7d262d43de6a2b25f645731d7d8b1b2851700b53853ce88b6fac2bbab9de6ac4b09478a84dd113aaf7d0862bed21f338cb9f076740fd0af9b40e14d96b583e3a2d3ae044280416f8fbb1759eafa39290acc6360d8d60eca3c0ca92bc858aa8f7adae866ce6ff063aec5fbe702dbedca1c1ff276d6943f502d5213610a727cdad5780983b5f05df515a521e9686bf6752027d67d76bdf1c4f7c3e2a0406d710c91c360310137b925176caa8e4e00fae985141693b0c6ac2fa44368701cdda6f0b636bf7035f06c0d8cb9072f3b8744ebb5c3d171920e57343b12df218b26921afadc685ac0c93a70af9af3fd88aae3b1cece07e874ebb2621b47ef96945f255b8e8f6093c4b16187c1e743eb8e32eb8577570cf6cc2e8757c38e7b4f22d8f3ca75500b03c11fa1ff56726d05b32dac32f49ad4c2745c2ffa0897659432a68d4ecf86dfdb3f0305c06c50bb4352330e88aed241587e786b940effa8c114af047aed0f634c47e153163184991657cd6a6c3a80204cff2397c16055a29ec1e6320ac8fe7f01ccb244aae5d8a5cff28d309ffdabc115ea16093fee341befae1d3a64b08b966f5699d03fe5fe37cd0e293112b5fc9cde97b3a30735f49519fb395244d347ed818da27f9243d2abe9474805a7484003c0b9d70d4312665a0a816812f1b6a0c4c4e3928127637f0d3db61bc53071cc8848653fcbc53fa150f943790ea244ac4267fc163a7f6ee778ebb0d8a80dbe86f6486a75b239177216efcd5e1220ced4205918c5b9c924a73645b2828c50c03be0defb616d60587560dbba962fcb05610bcae06b64da5541c888411cce84ade98b687729b9c8690d341a14949640bff9cf367e0b600350fa3a06aa9357862be1fbbaf7fb304c7116d58b9e1fefb9214f63e7736b276fcbab6631f0045fc6d0fb6060a4e82ac5e549fbc2b31a0cde5d40344f52a2ea472be40563aabf2296ddb384411354ba92433aaa704e1c0c041204010c522e095199400b0b2d7f9292b50ceb6eb277d6e701a645848306f7819c1f10c17e581dda6e85f461c9ef9f5792cc011cfc1528172dc0626280086aa798c0bbd9a35b07141155f0b98f424d7e1e0a95d8a355e3cae95e56575f93f28e691d2269b20fe09c7baee3ee7c8a7bec372861846e1d98c6b174299a02178a4578823a0cee91e123bb8ba4fe9b5bd1564224d79f54781e0b8d4f3f2ee396a1d3088882dba29ee299e1d21c40203bec3e6c5801e3bd47b3c6a7264bc025bac52c71e214aab9ae73e843d6ab6304d6a44825e2ca311baac6a2ea354aed28565a63cd2a4b6fe59e07122bab21ce653e16c4b27846332b6f775ac2fc424d77b58d9fd4a6446383dc71d8e09d9ba56667c1e4f9532ea240908e1ccd94f40d7a51fceb2d18fe8461988da30696568d21328eed225e3a49c153563e3c8d9437aac8182ecaed138507ade4c6cf7790997ec4691f095504f95294145960096ac30d379686bb4f25e38ae120abf4ca2a7e4acab2eb1374c4d66baf747d52726a18ef1d99d5d20940f459ac328ab2c0c533700af7005b8817d97109e2b944839f4a810cf06c0fa30f94d7b3927eeff42c347b73335b5a19ee4ece453131c1a36532dabe941140375829e3d1c59df2e034e37b84cb683d6889ad724250388af2ab76c384bba480b409b17d68095c4b2d934d4a2a091b8864ce890a797778bde0f7adb34c2ba957b2ba21b42e7dcebe62b2ccbb837dd262b5942aa43806b524ee342c50a5334e5d329bab8120b8be23259a42ecc5bba5556bfa9293ff7f3e90b4a63d297b970eaf55747e84883d01731a5981d5d7e5d55644ec11b3d2151a37c7f24c8e57f9aa308c1e608628e837e13bbef3f4b7978e945b40f69594765a7537e69f63c09d4b854c6291a6c505b01093fb7136695e97585cbb3576771b2b84395346a6ac2ea117b5f0404e5bd0cc8ee7e479d2b1887dec18e1837e29953a118759c460566526b7ef88a1499e5a541792724ebf863574c2bd8c66ce6a526b8f03dd803a6d268cba2cc9c0765f60551518a35b60780c0265a1395aa6af41d37e7addfc4d03894682ab08e1de4c5d1ce3d02f02cf21a08790e001000c1aecda604059346e4214283fc54958bf822464e2db208459c974f53c102a36a0d5d6c18e345e0dd201491e944419350327a11f1d852758ab16c4672191a9df9c65992e2868497c077af24ce411026f4dba1efa92d8dbb36155074f272b314e905616026ff83f4265daf57174b93974fb327b03e65c79ae4ec12df546360bec01c1a255819d5b88bdab48ca067e4a812ac9c4a21f00eb23fdb5d4d1d3c239ea6fcaac8416eea78dd5ce5ab22df4da91ceab0d075982c29339ed1cfef4cacf6cc95d832bef565c6e41ba82c944e11f12ef402526a5976ce83302770131c55cb0156fcb97647d30252ad0dd8a9537669145a03a1eedfda17dd5876142ff7b2854d405feeb7f172f83ded09edb8d4e0720a0ee47229f70f9f923e4c85610d26686c73adb9f509361a67d616fd9dd103e7ca7e200ce4e103cad51372150a73335b7623448f33a6981f858eb000d386836917a356b5a2613a30745070e318c808580149194ec37eebc6ebea2fd492071a3b8a2236ff604351f750e0d64d75a50bf2c05738c1fcad2fb8720b29e138aa38047dc0f0133e7c795be76697825bc0ed33a3bb28b1e87f7c85918423e182b63e4a8312af160b559cadd76631fd08587429ddae5dacd5995ccfcfefdb3fb3e7d8782f793a21e37319c10930b8fb4d951215c33b5abcbfdd94b55524b7cb1483266f47a4adeb274adf13415791db282512429a60245c2fdf27c40a0c28f2df911b54f917b6a8d473b9bcfaee978cecfd9c6fbc09b8aa517d525ab1d9f6a35b9bf946fe909db051dbaa6029f8178e052bee3e699a570a248282e650f3a4531623bb71cc036e94e0056fcf96c34b0d7715b2466b43434c274a03d2b97107123e8fdb38835572c4cd390f26072fb6984be8f7ff8368d98c81e4052deb6d07a3fa14a3835589b7495184e4e6adf10a43c8d9f964cfbf967f71e1986548cc85ea1a9f300c87077ae7cea4929df51c9db187b6e8ca7f14a999a6c8004773fadc4b0c0e0e6705888ed0cccd8b977404e61977d060aeb8ce8014e810b9aacd234a36b10febf195308dc0bd2285bf2a4370a373d0b6d65864c4946d1e0c15022fdf7572a5429b840f2fe0a9f60e63acbee6a83707ec50857e182d0e77835729efc42b1aeeae8b4b7c48cce2d4fdec1a210f817b42e7d2063f6077a5f82a01e908cd70129c7deaebacff261da55ce1be2c475830ff1cb5ed68301ff4e80e4066621c3fd406f83fa43d4353a044a727ea7c90d7bc00b05d626fcb912a49f3150822b1958916a2a157bedf3c4a8c59160c48bbdb1db1acfd784732e901cd72e07e4b3eaa287f73a05be3bf359e8a2cd3db803a0ca297b337e42ae900c80080785e6045a689bd0ef38f9ba7cfc1e10eb54f966dad615efb7394b98e1061a26b6320185e030a4f373848c51ccfd359285eac2e12f9ae08549e0bee8c9075b939a5ebf0d70d59d27a049329c4172847789b6f7b6c625ca00161a32b6a178cc0e914a1c4d8c22df384e9d157c563734e6470b879e1aef75194e115d841bed04359826d977daf70db14cec4c7a45ca9da57349b3a1764d1c29630b231777f3c7c7ff147725be365ac6c0fc1792c298c09020c59086e748eeb6430e35025b193c2193fabf16f7d3cbae3fbf62040c0957d134dbe6607ae1d43d0653283ac8516285ec6d8612cd217a28b48d27bee104c1c5262c163a6f2d34410a9fa6c25a1c2c28571e5132b455b5088f322541583ead35503dd26242fff300fb0bb844438d5da8d0056e4601aa13e8f3f205270f5b80c20a76678ba12ba39d8995f8f833852441cdf5efee7ae485498513c61629e9b38381143812963843242e98f242c1da484d0c6cc655dd450f53d77223e67fa46d2802eb075e2bacf16893cdd993fed5972cf2c4d4ebfb04b7091b0f716fadb5e434894f3984efe4002aa6d38ca1e5f3302bd398c649a9ee1deeaa43261524fe9084a1385d6ad1fb901116572aae144ce83ebfdbfe18f36845f48d58743711c503bd1be33e67822338324f8b5ed4bdb0a5ee225724fa8bc748d8428efdfade6d6a8475fb46e06df5b931a42b05f8f30424dc03b62cfdebf3ab3074891a0e4506b9a40066fa681f03745c07b170bb07fc835e90bdc144f0f6f4281d48cd1e59cfb62ea7ee6835868c34b2afb4992cc41ca86100f1050971269483152c5e486984c7f9e7833b7f95a2e3ece3aa5fe5ca284a5270075f2cc0c55bf86c034b42dc011c725682710b74734736188b0084a731ee7cf3dece0d819710dac09cf3dac2f808a19b147cad2d2498ccd068124a9cd2ef58ac23759c68736256bcfe6190afc978f508a7c0a691c4e9a944b576ad5f0400720508f497538c5bb945467a882b0e3199fc311a7420a409554951b9805e7d63826a6f899ad8797b1d46ae59df10dda61a7c08e067ffc7b1c00db7f44a5cae356789e997dd77dc99eee48df2f7714691508b4281957a436989420b731ad609c8a9fb21bfc600dc311a618bde38c96c3f6c80d279a2bc83222ba66626c978517f42dd580a31fa19748a63135596a01ab5fd63a956929a43c4db182e266cec412168858bdb0b4f0470119773c357c16b003a04b9918240f00c13dfc5640066920c3740dc7e8ffe0980ea4661ca80abe10171be02d9b4d74aba785d4bbdb9355f18c8477084be84440390fb5cb8d3d1cbef3154c1a394f49731bf3b3a69334628703e0cf3b5d36f773f15d84abdefeb67f3be12c713489eee3d94f3007d5ba7e55913d96f767d0cfa56748e9b75c987a593bc6b39e611c79cb6fc958568aa2d01908f236eb0043db1fb663ce5484af119fd596ada0bad69a68f65b72a5c21190b288db9b684abf1cfc13ecda5c08174474fbe4be1db86eeaefe3422767cf470c39d6d0a75074f51da20c45ae08257b9c5dab08e08177604c21e37465a54fe37dbf7108b5ddd6a83b02fddbcda1955b04b6ccfb230b4c1cb1a462091b3ce483d6a260d5615405e887866a846824e7e00357c4161738546390051475f710941543b033c03516bbf70252de2d99947f3132ff59804a8dc00d4785028f1987e40f6b60492f089b503016778eade38a1880aa3a55bcb54273e0e242fb83c52b7cc9d888ffdf180b525db01bbc8b01f382c5ccc9e6c3e465014b08f69b112b8d32fea6f89c5395ccdf51228d78911323b2f2010500be199dea51bb882c8a139d941875453f6095799f9e9a34e98d10f54eda7daa90b46b835eddfc0d0eac4088bc75cd3f2a6cead1551fc5198873ccc8d8e170d4b1f592f175f0f6f95e5c0dcf827f0d478bf2deeb8da1e31b39229cbdbfc113402e83346394c6483ecfcd0b7b968665d691efcbffa6d5c678a40c5c0e8576dd71613282c6e74284c2785b16ddb76323913b663ec2e9e78979b6dad38006e2bf8f2c693fa159a10251213d8b4409da36fe7b6693f9c6bef0179f4271ec1e65edf630e0b8661d6a51592750625e5858842cf263ca4c0db5e5e9e6707bd715e6074c3965cb317b56357e4c3a0656575c888eb78b95c244d09102d56482e922f21c50d57f456b6479624314fb464fa272da9a5f6a42edc4ff601ee2540e1b4fe07595dd1eb064150a799c2148341f0c52c60a4362e135e08b1f1e809561cec75a18e8dc57b43e80df959da7eaef062f05f2590da821787eb96c6bb041290c3297b07dacf4452ef38b798d3eef1c026d2513c1c574f5944730f4a4f980c22f50e8f9beadd277ca3d811246d14c3183621e9b6c98382725c80cc7f63f4439b5c7ddddcc641749f6713afcdc25892fe1c5daeac0a29b688ce7b8b50a818097c16caf357acd4575ef159cf0a25f28cc99acbe7b278870a35ab61dea9b2d5b88af622153c9f85d737f1d7cde8b5c9b62347ad8b75f379a1fefc4df5f8d6d4fc9dc4fd2074b9b12c4d626542abdf39aa100cf3c45379fc5edba4a763bfe6bf9615ddabb5d10216edf383b4a6426e769fe87364e3c26e9c19148e1ac6468b02a8963ed384623dd653abcdb2e683f9c95951d36f3608fcdf9d32cb7c84b74959380b6f56b647439de5034e64417763c2cbcc07dafe42675996db217585a835ac3f0b0b4a9014b7e0af2efd223063c1bd144e0362ebe976c94a35ed575664d2399ba2122c33f0f062962e2f4f2a47197ea3d9dead4568496970b2207b0e7da3921fded8af3e27270f85511e1eac864f9e7265a38532e893ef470dc4aa82854cbd75b8550b0f8764cc097d7415fb8ff885c494594c913eea9bac5e2d0dbbf2f90f4a6331ec0ddac9809a63f9d529f37d7f64b16ac5fa9f1ab0110b7fd7d8fcb8f6e63d5f63adb7db5d3acb7488a58e964fd032fb7884d53584fa34aadf19651ee47b1190886bbd8cb06c33584adfac195ae0073419cdbb6efb14d90fb0c180af715ebca8ddd5cd7ee885ebbd4efaf9eb5d5711e7d021ea7833c185191b7edf99cd7ee190645cbbfa191d0da565d73c1ca6a0c55f0387c263536822c665f4a3457ce2b078a8aed02324746ecaa177202641c07bd9bbf2380f1419423c58790a75c4e26fc3f658bd3f1cd247a42e2e8b04e2e0fa3420bb656f8450f90c0842154ab4c0bddf7a9229c82bc015191719701ecab3c8227c4c78039c411d6e32ff3bcca6413c0d5600f2e02cb05c842ed9adee6d4c463defdc5f43505cbe4b1b32c2c6a37915eefe9d606046f4a0c0a8919d8fc2bb8c44c21949691bf4e39907ea44c64368d8a66cf38e8ba520ca05db74779dabb2b487c1d1c95f7ff81e4bf971ddf36eb2624b6bb3a45e5c6c6b88012eb3527a6cf7046554a3fe441506af34663a71ce294d53a554c1b9fb7b38d93837b572e24cf967ec71ba4adc512b0c8546f587b162c6fe40c62baa62d0eb17d8d3e141f4131849b14cb2dc842142677a353085d9996d88f5dd969bb40a370d76985ca4bea251a27600b57c74b6fa1f99614d2aa068dfe97fdd2edf6d4f098acd503ba8d255c29f608f6956cb33b6ed9d784a06200c5d0c04876c80fff3e606f0336252e4713b9656db83591ab21cd304744f4340d0bc582c2cc0e7e36dfabcb0d8c30e1b270262c18558292367d1d7631f80b86e8b681c59fee8401b62e8ffa32470b048b3bd9146834582a2187316010005621ced7cf15a0c2d949a47dd4648cf45532528f3057a41e8abf58acd5973d1c82bc181e38ccee64271a4b3ce6e841faa12c1e501555bb0bb67e40699c6b2b4b0f7f919921197c97487c6fa2788d36140dbe060ef125a5cd08336046aefed450f4add073b9c0c8a7c3711b5ac0b8aae1cb7cc4c3a58039af30a8e02617ee18217d659d6eb7fcd61c1cd899e660fe98d942cf002ac777078620911c2206f1a88dba9f9da87e37e9f87338d009872c0a9923ebf21ae580845c4a755a7a1a7e6ec8b8de114c08a78c9de8d33c912150ec6b837e5ec1645f516ec47ed2fa4465226907858c45d74a27cb3710a498dda5b04fde806e61bdf95d97a22aaea98532b32ed3e608d3ca0f87dba246e3a7a020343dcbcb9e78036e1c6072a8eb3e4ea67738b6f0e8b4a2001154091b0cb8a300330067775fdb24eb69c2a5f562463e646d76ecf2b4b744c74ee8fa700aca0efb9e0336d86f8f1c7e0534a089f0cd16d30c83bd965c6eaaf9f756bcc14369e477c6d0495d3fb22b8d9c750dfb11f4182db83f128f9ca5169393ce1d0394d2f0ddbfb4db806f0a3ce56828198925b7a300b858e96ab9310e14d41eed64a7f14b4a533f24394913cb068136f2daf1dddd33227d334003990cdfd40d95d1817f24f3535f6e1bbe4dcbf2a64a923cd6b13c2123901cc2da652c46c77807dd745e7cb9ac223df408f18b33915d0e01a91a0c56f8b46f460cb8cbe19a514fac1fe05f1cdfb9d6ab1062f3122b992188f9a53f56c56445b2ffb6c5e9c976633d20146e73c70d4b1aae093744f91ea3febf1749cae053f723c24606d4a1dab1cb8b5cc13d1e89fa59756f9032c6961f6cb5d2298ab7e20c36710fd40038b5dbcce9b6ef049ec2c8651c0f07a9ef9c4470c81bee036d413e18e3aa8b3dbdb07c1287c6f9b369ec090e0a2e7b2cc2397184ebe0e92f15084298fc993d0f12b0bf302cd72da3350e9d8526303ec97f74939cc9cf70de607e0bc44d863cc36af6baa5f3a849eea92078bbccce2b0dd73bda5bf2e6a0f23892444ec7f2e8996dc8cc0003332b3827771ae4026181a9f3df3b3666068e9160d6a2192036c0b9666199c79b0860f744d23ae9ab433602e0b926e01dd3415abb92471222a85bd8d47b55e4d5d2b0d65aabf2453d902312720d22e88c07abdc186d832df3a3ddc3b23e512507b9e19f6c9fff3685b6cf8fd94ee7cc13bacaa9ec8dfffc6290678ce0066588e763b4a1c354eb97a18daf247b2a34bd0dd9f598380b9d04ce7cbad5c116bc7bde4ea1a0e3446519c034483e79ec19a1ea5c88d6fe4f201781a3a00c460419bc6c7df876f1dadaa4db78b3cd581baf051a2f2378f9acdd6041311632680da2b5ebf07577b4859b83c3ffbc3c738349a8ad70260a4176e1f2bd706d2b50b7b7dac4412ae870217605410528b1e6e84be64f9942840dd46c3899a7ce38ff78c477cec0da437505aba9edd96560b62c4d64e6f8554935cb232b024170b97e24d40e567f5ea6011a72bad5d867055733347c3027abcd908fadd86bd49037fab7afd2b639b4088ace7c8190fa29ec04c57f162ddefce70d61a50e7f646f80cd8383571b72a54801fe73cca31e020008049b059ca9e9fd3ed09bed6bded75da9edee8210e33e07a0fb41d37d743950ffed01b0f9c4968788f1751f9cf1e808c608045f1989a8ab897320e538434bddff56494421d1ded22398bed8f194e6d8f0920fb41ba0c78304138e9e685e2632b5f962b185b3168a491b85f79ef117475896f911b74451b4817a2b80032776d38e78d70e0170601c4a88d0237eef5457c346ee3f9a3eda639af4051022d17a7a26c8f63cb87ff98b82727fcc406c5890bd3fbc2e11efcdc66671962bd2a5a85bbd1e552903a497fe62c07d7e97f9576a4e656462465ea2638c9b5c82394632477aa4f0c3be2770e14e151df678a7b209e4ea45e231392a8d2c58fb43f99d868521f590575a6fe8b9606abfcb0b44a72381553430d2d2cc3268d33ad1eeec75f3357ae8b71c850bd8ffc12ee428cd2227962e7d0283e7ae70ee7f3ccbee3f44f686975267c075566c7e18980f2b0864dde2004501e14b53eacbc4e356cb685443f73f9f0e2f05d6ef1fa945135c9267b4e60d16bf2d13a5e9aedf98ad4b32cc25c883525af21cd97527d91c1049058891ec92048c2e47799f5e30b911da9f4317790b10ec266b56e26c3392ad866c9cd863bdcfece70ead10e5a365c8b8c4c66faf23d8268e7860be01065d34abdd6590b131cb374c1b5e3d9a6b06d5aa62f32c726d9939213db5f27ff73a9eed07745c63302500ff9816ed5e7d7cba1c90c003f4bfc46f8b5d5f76f2311cd3be5842290e0397e81dfd0262c5114f2ff06ff44007c506d72ffc265d0e5b092f0050c642a98197db44f3add294f56cf6c2216d208d9ce8dce016f9d08d7c8e3687c5e46e150e6ae00bc19ff127212e63ba15a63dd036b0061b64640622ae12cb274b1d57a29041607317b6972625cda94ffa9b364ec5de8e54c821a58c29d511c9a424311149c6f833a35a52b88690118782c55327f63147413fe967890fb5a5a0e508ea882d49ce1861f49976140df8192da3ea3000bf79a953fccc4d89128a4909ef4d8198cd80561909845e0380ab1a40cf877727fb9a96474632ef2c8cbe368e5ad9d59db0269a6e44910525b0001b27724513acca42dcfaf6b2a2f440b0814bda0423389e8ffd605d5cbb813eb3356452d6fce83326413d0ae22f398ba66852730ec7023fe65334831b8001297ce1141fa90f02d0f8dd0b775bbac77e248e14478db7b446ae32618cdb714e6814ed9585db0a96fd5d33f0cfdf704e1223ccff8b47304622b246a25f06508bd000b9487ad44177b59cfcdf912e26bdc19159f730cebdb048746269ce1088792b0519c5f657e34cf177a13363c31f824bad6665df627586da470956c9a8b332e6ee3c0b8da159e0f92f18a88d5f5d8563cc33f2cd49a5012afe7b55c67b3f8df61f5d65846f97255af753014ff1fc6d07a108dff1ca6703df834b6cf80b652f1354845782c1b5d61dcc11f61609b1e4f4bec1d7b1e7083ae87d6465d70f6de501cdf9b998bd09f632f7f9388efb1a1f5a39912b689498419621eb0a6ad23b1ad33da7d00d0f39094d6592654a61979d046f42dab6f429edc757e1513f969fb83745884a769ba4af9804f5edc0be06972a37829cd285e73df8b50880e1e1d6a5896a64f29210fcb9695356fb49f8abf305de96fd1a256719be12c2276813e94786da4112128ab01d83345641e46978fb142fcbc5602ac2f9bf6737b631e4691d118380afc73cfc2043701fcf302bac962895830542a4a7305a8ab8f996ce5d48f24022cda533240713e8c753741a6c2f28f867c53f35e61a067ac016874f0c3338702c8fdc1c11c082656e115b0e7e7ddf934393fb9608e85b06d0ceb81beb5dd88f592dd8db46e42427624082b09dc08381846dff0cbcb7595be50eae2e2d272875b6e7698e5e660b7de49f40ca60376f3e88d25a22a88ded483e80d48075a13f4e1339b616b1b8cf4e13dd27a86eb41dc063e3ba44032bd75abc2263039387cdde1eb99cd39a12a3d13b2d263f40c3d95bde1d029bd095d57b34b3743597623c5a1d4bac316767ba74754f3f4883ac8f6113d6a253cd46a1c54c7468fa8d3eb7ec6e8d16844a5d123ea6d04536f237da4aae2cc7597c49f9f34ba21ec2535bb2a98baabd233d6a93b2b4dd37ca8b779ebb06d98b71edb869ddbc85b9f6d83bc75496f2c7ae30305dcdf2542c4197931d43de02e0f763b2f86ba0f1368363fbc18ea3d4ca0d9f427d06ce6e5b3e3916f36fdec8c600abed9cce7f683a94b695dcf8ba13e6d8fa4ee9cbc18ead13a9bca369b764f30f5b90527b5b2775402cdc6f9bc18ead2fb3b1c71535e0c756861acb630d63ca34e1786bed94c972e0cbd303b4c9f40b399ce83b391ee6ca4cf0b63bd0f2f8c04faf03cb853af6cb389d6d9f4dd1f8e222dcd608523fa53942349acb7347ca058c1cda70849e01cb18b8f86883cbcb4ad67c8b4d120fde9e6b41b1f0d111d1bf996e87bbb3ef070a4f50c79488f5e0c7c91d633c8f3009237be182bde9a935b8f4477b86990e939f1ce1b1d74563f2ba8b74c04c3a905a1dea6c93d4ac2496f7644b075d9da86ba04a6dacd1fa0a74016b39908c63ed9ac4304b76a776e53dfda867a8910a92fd204f4d6336041a8eacd5a8756beda6673513c298a9aa669a228ea5d7210091428f0d4eec6b7dbb3924be8a9ddb90d9d3613c1f3ad6da0974893eb449ac8d3cfc30b043ae8e6f40502c9ebf292d4369bb60d4ff7a46abea21a94dae2d88906a1ac792a87eaf3e6f42b6949b3834c6fd2299b894c37eb58360778e9359d63ae51a9372a52d41dd20f260787a7bb67bd0804900a7ad23bc4efe5bc03e92b39d705d97ae0a0c4a767dc1bce2209dc7cb27003cb809b0f165bc08d0299b0bbb5a665fb48c10de3d0022b7aa6f95871822f1c943ce9191877254f7ab418482ba4b0a207b1499502777ad0c00ee6d4e673840d9c27ee9e32708f1825b0c970c220d77bef411ada0e691afa10f77defb92adedfbcae392f1fbd9910529cebbae8b4104bdb7a54d94859e9dd4303de883dd33ad3b5183d75b41a226e8702cef676faf62aea19d0416fd7d16a886fdfd16a08bdb51e7854001919a61a15bed7aa60889db52ea58c969a7025e190c5d16290557a55551662eb593715c4d29b82a36d5cc938a5adb9c77bad8696e7e357b187fedaa3c16e65b9ad4771aa51592e2f2f7a2341a0d75a0c2cb67baac8b61e490b71c83eab8f12c499a5148786a5bb043ba54b766e83dd223d6c9ad4aade9a8e55d42f3d750bfc4e4d526b31e0349ce7cdefd5e3cd4f021d3eebf0810e290e08f4466f4056606baa51250c7128a5015b1063c966196c411863f567631178c9c14fef5d713edea7c33741a18114076ffe4107fef4480743a8037bf4da757b577bcf38d0a345906f5400e76ebfdbbd7e53bb9eae7bcd93facee9e8517bbe00eec307dfcb1009778f9716433b6cf73639284536996a553be0e92ebae7262b44064f1d90799794cdc7148e671d9812bde5d467cfbc3c3be5ee54f3a6ec4d6628653870bca6a71e1e5e82bda65fec8bd5d1a37e8b6d18d4fe3c8bad56d4a3ecf5fdd1a3c1de13cdec18770a7aeb99eba1ccbe47aec61ec9607721c85eb361d7f05da462bc43243cbd8706bcf1c61b78a2a40ec860e9e6dc2ee2409214457cef2d63355b06b5a23744dc5a0c570b96a7cf2f584a1dafd65b8c7533112cdf2a667963c152ba19c678f36c378bf2cb75b38ecf9b4738577a7301b0bc597e6a79e535fd9255ea175a60da8c50438ee71685be651a309574bad95934070b4ff98ae2b09cfea56774e086a3611c6ff00afce9191c3792da971eb5a8c43db1fe1c6b2b79346e8a7bf268dccf8e5b37bbe0ec944c4ec9bc3a4e9fb45c3eb1a6699a1a364d969506ce3c3eb19b33fd350dafb81fa2cf4a62b3b51c63655554895c44527429a508dd68810d92d112e43a7d4b6edcf283a30064720c96381a4d7d01d99e17d397b7654e2ef3e64c6f892edd325f1fcd059c1157b1acba54f3f44a9b795cd18511fd7a743f8fa677787cc7cd2e54bda4e3feec78cbfdc13d0fc9703fe4e7bd743cc31f7c9d85e594e2c8cf9b33dff2292f3785c7cd2ed8b3fb7a73dc21bda2d5338875dc1c25c5a1cfa9ea2d3ac56197ba53b29bef9448e76ba4e8cd755d957ab09ca4098b26c4a2960baf4032606c8ebfd8eb2ef685b3d8869dcd2e2ced028fc6197934bdf3627a26bbe0dcaa54b7e83492e36ecaa3e99ede7934177037bbd4eae61aaf75e7dda157de1ddca73b24bae3e6cc1d973de115f7233b9ce3d39bfb519d8f7ece81e575bcc7a800320dc65945add500f38c03cbbfb41a583e85c880af672132c89b339fe392deecdcf439e96beb10e98e0bb3e3d7a77a8147e394b8b8744fad5570532132e0f82c44062c9dc7b30cbef2f51cf6a5c5109f23e5f844834c1c5f1f0d8ee694c8f7b300622c96cf55de2c44064ccfe366193c3925b8ff02bce27e44faebba446f2e39a569ce39e777e4784dbbf98327e93acefb757530b519ca80e5e7a4d3e688104fab83a51019708e0baf381fd3715cb22f3a7a46bae8b8fc057a06bb3cbcd2647aa6e5f232f4cccbe569e819eaf210703f2ee7a32f1f819ec92ebf43cfd4cb53a067aacb2fa0674433eef20fc0a1d5c0727920ad0698cb3bf8831bc57175b8b86018865171b13bf4a8b760b114ae15d3e79602f71b8b9d7066592cc4b2d51c9fee013c2b9b1dbde41dbdb96e8e539b4d6d08c4b23abdc9aeabf43d337a7a294ead6f7a435f2d0820a67708c4f29985584e93c53e5c33db4e7ad4f3fd6e8266118b6d9c054e1022892ec0200b2f20c3055250c20424b46841141610e1081faca0890a9648010c78546004182828020c2344ac91e4ca10534002060a96b0730421a608e2c9099c38720320626082235c099a308433d20413bca1852efc70410c379ed006175b90a2852ad800c21a4fa8c1240b4aa4d1022c308108349870e48c367ed030a30a57aa94e1051949b8c2155690a20a3c188309316640052553f8c288caca174248e18d28ac010533aa881146184ff0c209598001a509446042145f38416589174a74810417548cd8828a104b7843096b6861c61431b20823095e60918514284820c211a230821351964051a208485ce1851156782144156f50b1c6145d98119b8f180d08c3062f1890c502a0fc20420d5128c0091a96d0283183c40c5d182143174224e00d04ac71003364c4f0118601bc88218b02402100110610458c13a325025022004800800b237a7021040c6fdc35ac19178347182f78b1230b1d50608890230a1c4ebc2c7151a20509962d8c106d2144e88d6c0dcc8c2a06288ccb0b9ac584228910ad27d5139109aa065312120b6011af0ad1f52f55f469094670e37e14bdd5e0e0edeedb262b83d41d00dcdd4dc3bb323474b78f12d8c0dd175d197799d86f8d2dc8e81af628b6f4607e77d0750f214dad5dc3d7574772d3146de561d8333d1bba336424484d93165ce0699a26898214a4aa29529ba6295252a0549de8a58a0ac269fa019e0ea7699a8abcc728050cd0e20a9e24f81e30b8f96821036ce1e6a3c511385f86a24f44221ecec1bfe8e0001064e07e019ae6d97415bdf4ccacb3a79880ce132f8c7882060bc4b032844d93f786869a47a7e1c812b8bbdd3d720486aff93c23a4046ae306050a6bc8177a706fe066e50e1d3039ea9126f0ca2510477dce2652a76c4ba92f957a8fc8834b53515bea0e7983c32c301445519488baa24e97de7a50486428ab0d4aac1e69d2ef2f4b5cdf5addbb0609aa0d4ae8da48baa34020ce3a229053ec514ba957951e01da54d4199237382c3169d5065b0e0fc34bef2e716f246e4a38ba36d312bc30ee0e4b3806b2f578b34752ed91d42c2c42ad6a7b3130ee8ada7a48ce888cf50203379f2cc8c006c0cd278b267095204d75c43d88dbb8db64ba9b1ea7699aa6037924c0ef3db58b364b23d0e1f930351fd21f05f2307c081a479b2711e07789ead06d245da240622e724337d7d712f7dca97e4c48aa1e69d282b84deb198e3469ee4d01f2bdd6a84982af1d164a1c86c2c439d70f8b28ed62010408a1346141058b31f00bdc818ceded4566f85cc734092a859b0f164560881b94222001bb773b24bae013041144048188293888628c06a851a93045067674909ca1868f124e3cb104226c78c235a50a367e00854001105048610c145ce1063860001a6f545348d90196b841b9c2105e5ebadf468c1831d2639361630088aa8dac07c3242a6e3e52bac00223d2a8c2942b4fb8c153059e05f848214200b8f920810a528ed0020b071698c28d8a26661c0992460fb428c1158ad002153fc8d84182125ce1e683042b40505d7dddefbd8643f0c19491233da2da250e0ca7e047d3cf11bea66b0559871b8cb48718ba2c82330bdada97481fdec3fa7c689b4d5b59a8dac764870d84b6d10a72b86b4d3f9aae625d23f8e0e673851bd8076e3e4648017e4c7aa6f918a10ad806782a7bd31b7a93ddc7a4092ab6b798c224f7144cdd7a346263bd815c5c4eb9bc511809c0bbe378381244036caaef389b7878230a859ae8112543430fad0a1e22e12ccb60aa0527bbb99bcf0f35449a50a00f2f11f8be3bbc18ea44da87e3cbfad442bd6e0f36ad67c8105bf7a21ace3fe0da056cbdc5f6e0b075453b6cda361bd9d0369b8c3e74472d9175d8b211591732828748d8ba4b6a134e24c8bedcb259aba04b375dacc3d43a8cbd1c5b6f56bdeee88da337aed5fa76351406a857d6c119b6c43433ec9675b8f54c08609ee38e06c16edd1cebd85b8e757a41a73613f12104a10f11fdba9006c17e617f3a98e6b8ed8107ce8179c321db030f0c7390a52ec79bdee07866bb07b3305447b3d16e54d11bbdb1af69eb3483e17acd7edde596cb2dfa4cce5625bde171496f76dcf794f4887af7647aebba7533bd1fd0c1a1d74b2bf4da72fa0983a441aed7faeb35afdad02ffb5aec539205c91eb2425633a9f9ed60eaf929a12d9719bd69b9aeb7d3333c4efd25e9991da7fe78b25f198f5b56e411a2373caeab9407bde88e5f1467c78e533b1ae6d16221b69ecb258561c9fbcb9b0671b975b3cba5e8d9cdd9ddcdd773763fa083779c1ef48b1e260787a93b4c5d989fc75b6abd97cd42173dfba34140bf6eb60e7ad320f4a19bade72bb39948ce7550901dbfea77dc7cd5bae3ed85466f5e784d4b1876e8c340c1504314ca1118076e3e5754d9e231a1fe9a681a6743fd3dc94f8a2a04030ca1eb030fee7d1ee09dbb247087270111779bf478e8301cd40300bf07c001d0c3362c433d423d1eea118281a237f7525a3cc037a9a1507de8b5eed8f1da72185eaf4aadd96876b30e9e40b36922386749bfe1ebf59252ce467140373b0c7af6b64dae87deda0698ebfac0037cbf2f09faf09200bed9908008bc4daef79b4de8180d72c1f0fb466fee2f1e87e1573d0c370774d9806cc3219b89e06c2fba65b30ea65487965f37ebe096d7f4b5cd86cd81c7ebcd3a98c72b7a93d9372cba15d9696776617e73e0f196f3b8cf48e3ecb9d940729b77fa4a6f6866a71a15a337a2466fb26796d54ebaee784b8bcd0e87b29b7570f6da7aa67b3ed120d6af9b413b6ed90fe8e0ec8dea509f3da3373baeabd60e8b5a2f9c529c175eb8a340427fe1668743976ebe601bde1124f4ece67a5b8a1e510f759417435d64216e71b4a9bc18ea353da547548e66a2e6ae82a977151f2b53c6704246123f3d69f44c6e293075ea3d85caa3a1de511e4d10a7de3ece9ac1ba2c36eb601d7db3b793ece664b76e3fe91175fdba59c7b3db49349396a267745c9653af79ddf3681e9317439dbaaedb4b3c273d93ebafe7ecd2b2cf498fa867f63169a2d25bcf8f09a6baa747d4ab7d4ea434a57b4c72e81b96d76c54ae730bb5e2793114f5217d530fe90de82f33c75ca3369cfd35f198f44c966559665937d6cda1b74e511de86d263777123da2def2562deb583bb12c6aa71a92e2c041df38a80ef4fadc3d98a29ff4865e166299d9c642e8afcb4643cf6c081cce4ead107afa90cde109b9b23b4c1dce2ccca9ebbe60ae065a8f32eb308e379c23c77515470e1c386ea401d3cd1bc0d9ba90173c39cbc6183fcd7961701a9e17863e67fe7dde77fabe0e9eac65f3106c3d46d774b065854c5c499f6c1661a9c61d421cc8265327097409c2de7a48cc3a5c310cc3ac8330ac56090349c76ed5d83c57bb7a73ae57568caf2ed96cebcd1063f5586e1e1c2096f2946ebdd2ad28cebc6c1d0f79e88dc3e145697733946cae5887481109f47607e54e02d75f36a77a11ec6c7e58a2a09b7530c85dd2af3e02e70acab9582ebda65f9d63a9aee6c15574738cd3751774bdbaa4aa5ebaea8501e1f068644487d2ddcd40a4bb4b77f59dc4fd70af1773d8a7b528ce54bd9a301691e8194acfa9373b4aaaf5f056d1a5ae34511f2c2f10c8367c5dd7755df7cbaa79d3a2f48d06b95e3fad677f7934a12bf368b2fb2e8cb336cd7357e6d45ff5eed7ed229c0fd0ab5bd3a00b531dbb75994783c38be95399e96e819e85bc501407f49ceb4ed071788ed7a5517083eebc18f68bde60b24a13ae6cc3b5d65a71753937db1d834bde316ab23e6dd6b999187667b3c3f512b3380d636f8a43551dbbcd6118766140cfc12e1d845d3a865dc2dca96aaf7a41bf405d84f361ddd9fc822d795f3dca831b8db348eb5c459c8e935a9ef862098ce106e58b1560284ea4c0cd078d3408801b949e34308cd2334b26138e7c61055fe1c614dcdcc0ed8a2d2c81a1b4c106a52ec907bfcb366f9ef6b252b2d7f529a56cc97cf6d0a74ff466122d990f3da3d305f175476f8abcd834a1def406ead304a2398424096330401a530f81067470c31805e2a687f07477678fae4f4fa669a26ea8537a23fdba3948d729fb82a8190ec159ba9089a7c3283d23a567b2bfc3295bf44cf597211508067ebfaa9a8659484a93084b78ba33649fbcf7362d2b852e85a63e0253d47df262de33f4c1d913d11c2c8a231f7a6b986a783ae509d11beac21eb5278fc61979e294344facdd3c8fe6f54c3cf85d4a2bcbb2ec56abb2ccb28ec0399455f5d46b9a16e17e640f895eafe8e60e655928cb2ea53443a76cae588748114a3a4d325dba98a249846c4e7c113cd9fc30951d628c7ae8b61e611fd29892b2d029e9589eae83f5989bf2606c9aa61b250bcbb11e1d9683f588859e9117f33e854e5d88431726bb74ecf5b0bc1e7a7bf003427dfa143a4de27e4c0f5da961cf94e7a238f4d3a5546a262fe69de52e375797b760d45fa8b74c8a433d2774b3935428147ac1de4c42a1bbdc66126ab92cb7995014a37cb0b432cbb2ac2c62773a4de27cd0d73c9105bd5af8ca4a97924227d49b1ee81d3a7995824e26e804bf67d89561372794b122dc8fec30765d37f4e97908d57e6e4ee8d827e966e72810ec353b8cb3364775b0b25f53e8d8cd106717c6ba749adf13fc1edf6b8dd3e9100a5fcf43289cbd7aee24587ac1d7b390978c733d27bbd8291a64e28b0d0ca3e0971d64618fb29b8750787a757327c134fbcb5e76b39077dd8c5de9469221dbf0348542a187a62a293729e5c1f4209b7530e84d6f40529a8c4816a7e16049d7fa740983d3b07461b2e748a79eddd946d5c1218bbd519cd0cd8e358c595a84f3415f279b5f5c124c2f9b3b099e3a49d3349be98da23e499af9e9b408f7c3e1e94d7970a3f4c2698fcc07719b799b5897d62beb4d71986a54eaf0d365531c1c8652f50450032965bb7731c61829f762aca22ce405578ff4267e9aa6a97970fcd4144817e15cf3e0f6e924ce8773af6c17e17cb84f3f38275987a727d92c44273a490bef359d1bea3ad8d9e9ef392ae74857c8c4efaf0cd92612e703d35c821a52118786e3711a8e17a67a4ebcf4eace362a0c9078294ed7c1cfe63904bb53b68a3647ca421d6c854c0cef44e27cb83f4bb9c7856c734eda703f4b9a539ad4e1214ce26ea63b0a44ba5b76dab61088ea0e2d6be308bef1334195ee7a7a6c9461650a2320999246196054fdf923031b3ca0e1149bfb994271f3f9a9c239d7ef4a19694008a5e98a922b3c57e674f6ca138a55615996943f55ae6c019ace42f97181b35798502788de8040a05ab59862594ca0a61f1908414dd38f0d3084104ab08a7e9e8094d4ed4d3530a30d49080d32518616128c54486dddfa22aa2258458967024b90ac000565d860084b14e10a981ab518040a52550f265970620d2bd0606206577c3149664041a9c0005aa82184295819e30c2bd85056f89801e5c2cdc78c242825a658092336339060899bcf9537ceb841110de50c154081822b3f3f3f434c5500518320a49f36a0244915b6335690a4a93076ce50429226a9569185733db5c6cf4f1540d4e0a70d21e60aaa304118672881a720cfb8019433547006142f518b2358c02f50a060060d647b34ed093000420655b842250757d8e45805ceb52dd02036c2016db8a0093692f840081ed84c5494318432a898709be2a78d1a5841096e3e558802f6816770d581cb10b07caebd77bd708165cfb783df7b0826b8070a7f0062f9c828034f32dec0d91018a6df7cca88014c5f11a6e6b396152958c6d9b66ad64571dbe653c61358a75dff604e494d9b260d4301e9f4f4128197ae6303c303fdd57ae497f651c56978d46218b5185c9cef2175cc1ef33a1d3ab09b5ea2f5ea71662113576f33aaf52aa7bab5425ba922ade3e0f34246404e97da34fdb519f74c1d4a97d474f8a09b7a4e3a4c364acdd570e9530e0d88506772b0097933dba8efb04738c3341c2100e183f0d1be403e70ee857a24f60cb567e8b78ec94143cda3295270ee81fbc5e5781d40900e37286355591964ac0c811f6e54206982b30ca6262b26a8a47e8fef3d6a7a4f928216ba50473f5c10c38d27b4c1c516a468a10a3680b0c6136a30c9821269b4000b5220020d291c39a38d1f34cca8c2952a6578414612ae708515a4a8020fc660428c195041c914a2608495280421052e44210d285ca14a14c2f8e209539c00058c2134a1074c68e28b1a507981175048411750d8e1e28d2dd45842194ab0a24513a628210b2324c1078b28a4e8000936384212465841942a48a054294111d8b8c20c2ba8508513a8d8620a24f85041841f0cc189109648218320b000086124f94118403cd9421467f8608c1e840145173cc06207563c1104273b7002073ae8698244134f2822074f3801136ee0000b4cacb0040a37a062832c9628420d844003286690831e1a28e1021938812706012d6f3d032fcbbb25f48be5e6ec97f4169b43bfde10f57d09e8135ec8c42d7794e5fa70037fd372095bec4b8f5aa8ccf2eb6990811d17b8f960e188abd64bccb6b4b4b45c1897e7b4fcdda5e5ef2db7e5eff33a58b2d9650f852e129d85e52d36c35f77f406e9188b8d5864270ed98a332bc2d042ac816eeb98ab45372facd2a33e182f0535474845be2878e20ca938c14dbdf7eef786e145f85de9dd494df474d8e112055a0c73fa89459c0e852c2d907d97e319517353c1ee4da5c1e899eaee5da567acc8bb37193d73ddbd7fa048c30d9c053770f341c30a4c036e3e59b0023f24aac3d92d51abcfd782fa767ae4289d2e9b756ee2df3b8852d00df092976c863de66425bb1fec787ae4de11d58db012b7f3687e6881049f11092681a5e711764ab054c1bff9c30e96ee1c0f96ee33e2de6ef4c89d05d53991fbd4e0cc8d0423bde177079d53d2a3062fddec92e8c1ed1d511dcecde755598215b2854c2cfd398a8290a22005a7d75517d04a45a5470ddb565424f81eb4817453ecbf17abea55f054c34b6f0bffecd44fea4f1036b4dd97fe5ada426adbfddab586fd20ecee43d8d26b5a42787ba0a4ee7e77a77ddfa369064dbd3fbba384ef2ea11e257a03a725d4a57bf4bdc989ba45a64d13e9d21d8412861488bbe49c831488bb64e125fc5e950c8e8167c00dca1b4eb0f4d6234327b82fdd27e892c0d12991373f29b80fe58df092e2547710c286e12b2ace5af4e6dd971eb518ebcb4bf567e91b1b2e4a84efa5b171737d4e3ae78674bb9c93d23dbe9b3b3a179d7cef1ebef7e0045f59b139d48be067f3c3d09dc2c7473fa4317441e26117f214fc7ba33ac853cfe68a0aa6342dcf11637f6fb1edc5f8dc697aefd21c79ea8fca539f9ecf9c3eaf022fa6ff28789f75eed3e943a2ece61720f0efefc5575bb81feff14e8f0a7daea8e0a9529cecef82b2e939e23ae5c574882574511cf89c78b35318e37b4a8cef2cf4afe7a10bdfb36a074b296167db84a594d251f4356dab2d9c8f57d53c6c7a9cd5e6096f4f813ceda552c1a0d7741ff23c9a087962853cb89de5a8bb28a57573e0e9a525dd2ca459c9f1be16237d518789ca78ea4a78ebc2509ffec3cb0bce31bf234df37a7e78342e4ac7dbd8887fcd0a96a7bf268a4ec1d98d81fb205b7b9a15b713e5dd1905b7b42a3b29ca360c2184909a6ed585f3f12eaaba703f1c7e56b0bbf41a6c4d054327a2e6b1866c3d76a040ab417ab30253a0c5e0feec0e3d72cdfd30240535b7283fb85ff370a840cf34ee6f000a99f2f15487fb411bad474b5d9270a341266c553811ead8f4146fa54f36de3c714b97f0e3a9f2dd09bf705530fc4352a94bcf6ee73b505ef619517fe819f7e60686900aceee155173f3c10dc2394518de490fb41ebd993e756ee825c862d874ec4ecf6e5d07579b5d6e5632cce678436d1834ef7ed9dc03cf37e76c774a2a7ae3a6a98af1456aa2e00461efb418da5d156bf259814fec9925d5a54fc911511b4ebb01be35d134b16b97dad4e45ba3ac685d5ede25d523bd99ac25d5e327da626b56758bbcdcd09f9ae6d0546c12a62810ea4d755314c8f4beed949d1e5b6c537753ef1c5b6aaa08a0099a87d33a4cdf7bf47a8f3aa5f35def149d77484f13a5976eba43fa4eb34b22f362e09b5a929ea13793cc835236d0a5bcae794da704bf5b36c7cd37795d9fd3b2fe2e7973ac3becf3fa93d3cd0cbb19e85ed6ddb39039dd792f9947f36acef9e9ddedb81fd3dfa5997a5b8be280dc2b10c5a653198b0f746aa264a814d775b97ba75bd6ed381fd4a5a5af794dc9f93cf1bc59c89c7a3aacf72fc68a57e64cb79e85387a9917034f5d38d773aa0bfa24531d56f312c93ce852fa8bde50cbb2ac693a24d37dda86a54b424defbd5f7717b5e6ad296f86489c0f2a5ec925c18d4af385986091520f96fe92f4108fd3387e8ab6df10957afd04ba90092328de09994831d68322e592c49e17233d438c3d2635c6367790cc243d43bdf63cc9b2d51d4ff7cea3793c2c8f14c330ecb465184669c5421389fb81bdc690455fd315c32a86c55b41f1a0b9130f9a4a70aeaacdb15e04470c048a36435c51af150866a057f1395ab9b1950457315e10e87908156f05ba39f4a04b57e5406f1d14ab14a5c77aea460a7af5781e0d74e1c1528c8fb17eeeb81ff1f5825ef3aae79904837e5d2c8f3727de620175cb5de2ab17ea2ea07a592ea95aeb4bf55652af4b8b12ea66962a4a81a584312c62ccaa6e7c4def381fd67cc84ecf2ce8d7152d494994a674a8e429c1d2b14b62b5d6ab3e5f48a89497ba3f37279e1ef49b9db3402020f4f1d861ad7754078a5d0a9938fec22e0c3de8567e3d58e27931d2a57a4b3e879edd0e06c9672133430c7aa438f23958263364322dec11561fbad9ed60eb8e07bb84dd2c64e2faeb929c4840a04ff40624a38469b513a6b6e118638498d22a36bd999711546b3d4ec3f5c260cfa9a75e2f75ecd57530c84af968f3c4f158b539e288033abd6e861389f311b1357770743b31568f317e22713f6612584d14455d27899c8e349cf41cbf8724d7dc7cda4847f6edd1a33f216ac58d8a2439c06da7f63b3c0db8c9b41733c2ef513b94692a92244539bb416f13d4a0be30b8674f6b5a6d49495114451d5287a72efcf5771ddc76deb24ea939c9b7b55984658fe45451a92a4ae9711aa617e67a0e3d754afdb2b959c9935a7ac3bc7ccdabba703ee0084f4e49a37a724948d30a787cd830829b0f1a56708e3e5838026a3d1a91ebedc5bc60577be49c4d7c31ae69bbec345d98860399faa8440bd8c93335ec98a219910000004315002030140c8885c3c1702045613f14800d95ae50643e13469218053110c3300883300003020000000000036044003eaad01da8dbfb18800c46d3e03ecee1fecb271c7330d90780f7e199e6863dbe3e86d2a9c5f2dc501160f14d2b224f282644d4fc403d7087b59d36e5d20f5dc89a848367ed9d6bab737d0f7e952a763dfdd4e31809ee345a4a03b267bd3e7074ddd5b2679714da955de4d6117e1c4acd3be43caf6a45eadbde87ac828841994e204c80749957d5be72b0307b91e90e27cc1d849bb548465301ce2a17f8a1b48f0afbeb612ddb50166513a3d4f7ac6cb9f4164955a17fb20db7d32c8e995241c4f4181c032fd8f5468e7511b4ea1958c059a7444ca364f7c9e26287dce5ad4c5178c7a2eb4b1cab0f73535cddb0b6a75b71f15a0611c1437d4401a2f4aba163d50de8072571f2e34de52189ea83c20814413bae83c4dc090e7a315824620413a5ec09c97f338b59a72f0c940ad7c52de26d9e009aef67424b7c1e45438024f12f40f069d76881b90302f9ed84b320e095b1a8ac14c3e7ac571bf650d9fe2e17c7b3570156add5b3bd32b196e8b1d9196a7c297733a8d91f2902ac5573f650ebdd82b526553c1cae4893b2b7eeb298c2e3ecc0697e16c2cb02af482a0c34d54dc8cdfa97911328f8f19b4f79c6fef3c0028b218d1257bb8d3417e4536ad98c14b41768e5419499c1bdc945f09e5353f7157c08ba61baaf2e4fbc507b8d51982a0058a9ecc358c123828561ed0d84a467edcee1ad7ced3e68aa253897f85b663ae863657c0a3086f3166af20fc4e6de9eef13e5f2d4210f3324448fd549c3d337696dc4630fb6ac07c4aad67d5dddd9121b8024b0cdc29843728ef176a2aed0c167206f858b38a92916496520181cd311791e1e4640b9a04d3d7601bc2407eb8fab9d4907d39d3e6421b8a9c000cd165dccc7131c90d2c26f70823b8d8178284fcd3dc0aa70a401abc58d81692f2cc2bde632d9458724ede2c3f46ab690d474d7ebc829dac7f5ccbac2e7496321bb1f969e77e68121429e682c4145e5f5dc15ed1119c77b805406f1aee009769de4c98cd0d4cb739d922a263f9433914270c91a5dc5dd590dd92cec10ad19bc468b1da37b40019ae09fe4d5238b83cbff75ea56bc37edd0d9e375ccb9efee149b625032235542508734901d5b886d54bf16dafef173491ed3ec4ffb37f5eb303769040422736725e0a70bb507a38905a7102c6e7a78f83f22b6433c6d48432572ad76eca7c40da1722b9dba16a80e0f3b982a90884c1137354fc020b8314abdad577af3ec7b074a1eea8cd743c9c414e8b7ce33f722e9aa33325567c8110f0ba178347a36042c24708c53cfeb0175a684688b867b84869bc773ea4cf4de80eb081e70327f1eccd4e16f3723e42ee2d39453caa5e07467ce0fea244aedb4958b09618b0c48b92c92bc92df52bcde8a5ad407b9cfbed9170b075bcacac0218d4fe02463ff79475ee8ef08ba223e940cb40ed2e7f48f426f0f65e8175b0d2fbdaf1c7afaaf151725f36c3e2b71ae8e056c8c3d0485427b1a46f7ebf646b6daafbfb322c21e906bde61f694fc7ccfc19f676b7d48573b77010573348259bf83f5a50c306455e6862f6ede120931755e3a644434f191d94c26054b01fb4dc8161a9620cd04eed651fa1d8b35062ae91131f3cc300862733f5e5f173bd24a45ebe421489e7fa391262154a8c11fa19b7fc26d9ac1217f0060e0d4708ba406af2c6be2aa83882e110c77b83f6af47b36ae6b02a37347550dd4d7ba3c2f845a394e161a8ff949e7bd447d082d62fc90147e733c6963321d585257929b5305a08002e4839000c4150f5f93390e0cc38b4714cb9a21a02b9e4e303e1c664e5831518b66ba84a349b08bf4be3e197776f3cc034a37329d71cb2ce30df123fdaba34999d626b40d500e5c90da954be0f1b5d630e1642e8f76c04bbb79896f298489e35ad3528bc3db35bc86d04edf582e559bb10f556913a856600241a39df3f5c658e3bdbb35b22e8b9b63edf47223214570fe949b68dcaaa7ddc23195786d9b8df186b64b9b449635b7e7e7114a7d04075b3b659e48f9ba65443f9219e2d5980bf3caa504377ea43d239b1646cda01855aa4458536c613ef0aac84253e8d891b65633b828d7964fa67b42cd88bf0c1c4a9884c0d2b806b853e7bbfdff3fff67c78f4624cc8e85268b8ba266bce992100e3b2f6623073834a7f4fc066dc407b60151161728a99df2bcf015fa2e70a9fafb45ef18c89680e6aa89458a697a4ce23c6f99778fdac2c700e17aa4e0dd75a1bb478dc72c05b3f6e7d423e9a25a2e2dfe8d939ff0a9dc13c637c630cc2bf3e4e01b1563da986232afe52eb5a4806fcac0caf98d60042b9c9bc8a8ca20d31975e06f4f1be2ced24720b53eac467137773288f2a404cceb675256ba1bf3218fcb3d031edee2599529ac55407148058541f2b996e3c9ad81497908f1dae31c68b7cd9c2de783240ce5c04ad4023a44117281bf817de70db0ca17981bae0ff079837d58b5a850ecdf8a19bb7895bce4c6bcda0e292193ef9a5400ac139ccfa629de1827521257d0e029c2f14f5c592e482b2efe28bb418315ba90c4ded229470db4c36f456161bddba0a155eceb38a10c42d1f589adf3b9673a2c21672bad2a3917d6b8a1a9484896a271d586ca13515178b8c1d0a36af96055dbc91785689f7a9acbbe6a71b8ccb92be500237b63ac5c06efdccc709276e186e9380dd4b6c56df605e1361a88deae649480976ebec0c52cceb5f803a37a24cf6cf487fe6b4ae999b5da1a4e151723e5d215950550d0745554a7ef697b074c02d4071ef9a827a99e754a015c389b69a6a5a307ff79d60859cecd9fb67a435c14d97553109778d07b6dd2de1f1855586ccffe41f3f5800fa362949840cee542771a1acad986fc92aa7006f0036fd1d3da3bad8d2aaf05c88efa54a2aeba73d75dba9595d4ad41dff762c5923daee02dcc43f795375ce5d44c11006279b1e94cd9c3c5a44f91c6c37253dd6431c44ff89715dc76971bd945460b9edaf4673921a11e1b62702f886320fed40d52f4e9f302ca494ddcf238480e7a302d97bc20695a4641fedd6bb672d08c4e4bac23884f891dfd85ac1b95a23d81e07c332a6bb32172e0d30fb551bb8301e2884520d908d3df00a94f3cba4546473985dce71bf9f914453fee285d4e06e9c861f4c9b5f74d2b7d61d3793ad9c257356350f6057c47c519250ddb0ab930f2f754f7f5a2bbc6fb2dc86f972648b70befa660be30c336b8db4ebb6dc744a093a42d67c635f07928d0ba0ca142cb1f05698c69e0c19ec6caef68eaec01e1b85c88db05d18e5529b9ada5474d089dbc97ccb34c58389250d1f06656f36fc1f8e04fe16fa6513f14052d84fc2018169042ae6dbe10ec8e7d82c72e289fb20f19433c01f753d1154fb86b565bd16bdfcbc6fe8ee6b43dae33f6c585f30b68794d58c667ef80014b3bc05db5fb2f8f896e0b61229a03042893bfe458dad48e91ed68da7045326a7bb80c809ee709a989656beac98d7d4379861bc4fa9212488e92c89ea66b9f848653d877d65930a99ac105fd69c97cbc5ba128bfd54b3d2c66447bddfa2ccb02d3b3ca236a4bf4c4d9421827a33a93b6fa0896ed09d6e6062520022bf6c0b26b2d1d481fece631ccc344f09b91b43942704df8081b5cdc3f70e4f0829e4c32988470c53a2974f447bf9fc571d2e05a0897bdb64a3a18aa2f68bfd9f08d267c0276af87dae528075b25c4a3d60e6a94cd662d506bd6fa9067cd37bd3b25780c34d6c99e4359d4f4a3cc45d358d4b4b6b0b4732ca24df98d04b22c2736825f041199b59565adb929b57bd0b17b40ef78633ae1405fbf1e7e9ea6d3b4a5e0ed9ee27d7f7d7cc1d6d3e8da115975ee6e99190599149b1a52856ad292a404764defea1cb200eea7e1f0abedd70d1e1e428d665aa7b8b46f94018e33aa3842372961b11c1b89b3dc45a74c4c541cdc5065243ae7a077727e9f848905e6844bfc40ab7924c3d9dcba191e61f8b30a259c9c3da0913e3d1949d9dc06cf10fba293a50435069bae8b6397d701cfbda4251161f36d4c89c645e258e56da7fa5403988cba54a7692ae30d7ce1ddb76c31e0ad3b8b8417710310be44f4a6ffa7bc5b219e3112be7abbe7a7bc1b24caad1849aefc7014cd21af064879041589156903614d138790783edb6ed821de26121e180cd79a56080dd0494d731ee00a7414745133ca31b8421ae5e8736960ed2e4ac2509e2ffaaec1d89b8a16baaec343152508ef594b52125f92e48147071b845282d3ba55cd230983307f4fc51e7d04ccdd71e525f841b81178826ac374c0005c9b4eb44246063a1c8095086a7f5319a8ff7e7f2415fefd56e7529ca8b776563e840682d8944a3cd2ff53d4f236219eb8ea196906cbac7a137b1d424378940cd54185694d8ffd92ea227ac0d846a70eb99d99cf5753f8581d91edeaf18a6f82a75d6c19153a0b03bc3cbe94426e6f243defcdfcc9a7d42a5306a46e268d517e9b991f3e995aaa0014dfa662cd8b062f7f5e016ee5d6fe5daa50ba967dba03705bd2276f60796509196365209a769a36251760aa6df393958a3afc710a796d5ccf726bbc0f7dcadf1612d045261c42548de78756a4fc511b5ac391c15df73c372b432ea1be9e7dce2df7b08f5d664114896652a82b080cadeddbdedfc807aae693f062c03677a0101180127000ab68bd2edf9ab289b4209d0c05360a40dd771a8c08231018b6cfcf860059b5bd1ae838038274ea0fd9898bf9ed33101b82e87b6cdcef350416a206e0125a98fc133e21f2c695b4dbc1538cb451b89fddfc92634aea47b13e88827526e76c745ae910d455a1f5236d1cb9e5f430ba3e4ac163022cbfde98d645ef5cbbc7cbd442a6331723a137747d48d4c372b57a598d0f1ebfdcd31b9009653a5a08c473c839e902ebe4638d180327cc709be49465b8e3f341de98bac01b1da59b2ca929c16172966b34abcf47e3b011133836041d7973487a21e5911f650636ba9ca2cfc238d6303602ab6ac13b964e95e91bf6e0d996c3dddc75cd63da8eff53c84cf4cd767bc381a3f22834e6e3948725160869d822bb401f2c6f292e3ef8213c62b50bb77b85a73cc29765ec2e52d809f393502a8fc0acf1566aeee36a1d0c95b5d1d423380e3338c747defe09bb64d17eb174de7cf551d5132092ba31a8b459a63c88ce139ad020f61f76d89d63aa2f8e0d1a36ae1a32a9ecf362f3615425cd8d60023c9294a68444ae81203c26ebbfbc83611b3ed1a654843054e58001a323917e430f3fa806465f566e05ea38bf522bb20199ba9e6590e78fa7a92d2b211889a5861abcb89aee2dec9dc0c9b33288ccd459deb6cc5f6f31c420e2f11515daa88170bfaf13cc8a85904b2f48141eb9c1e545be0b70f9e289757fb20d93e40fd6a10ff2d9c9c4dffbc5b483b44fe58b46a65189a5334b23f6e0ce369ea202e0d529c1a9bba826a0e9df832f4436f91c3f3445c08e25defa12cc550ae4c2e36392be4faa341b516da8320034be53abff58308f1378c03034fd9c7d553d62cdc2e911701da88c75a8022c18d0bed30b64823c197f5f1424c7a938962037ba71395625e24f2d78d7c8c99152b29e6c6fe21624496b3f7ed02c046604969392aa84dd5c49dd250f6384aebfa022be4533716bceaf06dfdc4b2ced124a110a2ab3e9e4facca1a765ad4626a42f0673ef1d15336757ff3b26bfc5181e21d89e117edd432e464b255c8bc5589875d72df767f2f95d95584e5f872dd0a159f181608a906a4000ee9d2f9014c645478db0cff18040014d2fa96c30eaecc31c52f7007564e643711133e52ca7f2fe92029e29798bc0f4cf28a90fc9a269f69357f66dd4482b5e77391d0867b9656b1beb03d64a59c904cf52138fceda9b86456c10ef4c330440ba47452e1ff104e03eaa0be6fcfe3c21655e17a9d1447ed3384b84239c6584794abfa7ce271b75f44f1ec20f9df202a0927f0e983c94a47e4ba923588241652f0aeda9642e588648f1debe8b833a012887a16649a18ff28f5b6799b102500b31d6e0606a1146dda597b6435111a89bead3521d3a608cb9b8c241c406978583b17241870457620cb373dac65b0216884d0a0a9915a3801ce5c339bcddf7f9752653c42373954c078b21691b8de52c1cb96f0b8b31d21db29754f3cf5d6bdfdbb2c24ecb606a607c6f5b55bd61a25f12173334edb151256b4006764d9ede1ca1ae24c94953d99c5b556471f1ffe1890b3d3d77b406c8f46da0cece2d20d8826765424c546dc80b72b67984db7cec54bce35d64474505540b2f87031c55a1e2c26078774874e2acd6a3b3e5f5159332244909ef3b8f3a0e9537228a378ff8577e8824708c6adeda16648210fdc1b3d472f9db8ebcb529ae98308cc77552c909d85c1b16df1f50b27e97178bf04c8aed4667ee63f89846f6fea1b8781c4797ee9d0c5adb6049720cc5445513179643d067d483c5d7f8955a1d2f9c567b1d478c52dc52cad798b42f2e224ef00e230daf204c8ed5cea785907d64637892128c01054343b77183ef8035ff72d7e94478d1c735bfcf09a7ee9f2287cbb530dd5844aec262cba36b73a169a14f6313e9da7e56d2eb24d231745691cc16d86494aefb2bc15016c126dbbae528edc051274e091930c6b4438673972ab82b70df1a181855ce20a691168033e9627745b49685d73c701e4a5b31e61d848cb8d159de8160fc36b172d2f58f5e78013c9f284e238c6737d16054984160a04ac9825f740e553a921accc52fb766333f456bfa201747efbae18326b4aff93f8a8b764aa83430f6c7d129be840cd19a2026b16b4586dd4459788134cc07c17de3f74952404757b097d7b0cc4e79e910500862e11ad3883777c3a6248d03b051669992c6212ee946a1384bcf97ae0498ea02938742e617dd51333b7403269bd9a8eaf97bf40d72fc4cc83d62190d40285e2c5d4c7ce3ea96b72cd7fdea1a5a15ea2db59ad6a8c2ffcc4b2d48b11f0a6eadad3033ff8481a1f7b2f0bfa3158e9ce61e8e08ad508b9776d4d70a073c80540f2a53fe49b77e36a8679c08f2d99c1594387b9805501387a66fe9cc1223fdbcb90bc4f51fe48c337dea83f286c57b7973aa58b5f91c08c3292cd0a58735bed86267326344d07641c0163660359e944bc8be53b1502b6610d773ed9d2f4d988e89617812eface416e7e8ca0580037bdf290ef0d998ea5626f6330b798e475fd7a6d626d331ddd3b495678815b1dd07308a3f22055d0579cb567dd633fee68bbb39d76c6f9c8ba5d414c4c36c678d7e9f6b8f9c88876a52862cee565156396a4fe60756647393b96c13f839587a06723451326d3a222096083441b561f7db2d65946f753bf3322ee7776d077ac9d1d8a158d43c1a87f1c0ee517d825af464abdd1b9377a51e5ba985a6b72b889f486ba422e1e76fcfe91f1ef547aa0d4c8b1448e808b563e9c98b314e23bb7863cc5b4033d3425e9c41528cadbf72309960135cd8f83088c3ca9fee8527389c0670a8be84d16e1692656b096c6fdce2d8a227ac6059b01190c7a6e4d206f7bc181e41af46ed497644c36039e9f38f6e0914c2abceac004c49cd89efc01f79a04d61139b1d7bb32e87f938f5406b96b75aab5861956641b23b99964ba393260b94c694c601b922698c45e2065980994043502c28d827a4458d485ddc9f5edb5fd90dc696e3e3db18956b75648351aac8b58517ce21c71a98166e4706d4abb34d5c161251488e1ee2f742df8cee45d5ed9eaa413c8fe8a9aeb88402375bcd5ed9ff024849d66d392775035f0d2cdad157a62d34dd1a47ab49bcc16f2b22783b650329968f82d3721bf4608698eb61ea487c929c29e3e4217a96c1034575fb6839fece52113ffea924fa501324f1a8e4f8753b64cc1fadb2ee432428a75b79add51d28874f649f889fa6946bb8ce4dd6130e165666c03ecaa59f7daac789b62b99cfcfcc32143a379df41908b66a58b424104be34d9682f39d5408cc4e3f8f2136588b1aca5767688e8919c692a00d6ce27f3be76a608ea264d733ec98995507b945e547952b00b70b9fc96c4715bd9609be99d78f7ea0e4e74435b35fb8c40b7552afa44ea83ab224c97cec494d26c1ac2bba7d7e2e1ea60faac7e0f3de1c5547c75d0acce891e77d6ffea89c176070a624468d7e8e572d36485ba911cb4889475805d3dbfe0fe81b330e0499f20e6ed6c0e184ea41e90750ce45810a33f4e43d9d11c368a9e4595b8740ff7c1367f8f488a276ded3f337b665a934ed2f85e9967d8e7bbca7b7ced491cb884db90d0acb47eee819b0bb14435455e0bd96c4cb15becfad89dbf6db2d816fae270adb2f5d6ca222bf1e04fd4e1f9e4fab4eb9bdab20a0eb8ba4ac8bbdcd68e3eedf8a0a365ce31ad914a1783bfde3ea4421f61ca212fae856f8f6085f3da619d6043b984103c504302a640ffddd7812f35eee8a658b6d232f40fe3845562caba0fa665d3d72e5dd3996d7a2ae249fb02bab38055c16110a2dae8ea5f48644930cca2aaac0ab16c0adcc84394554436e4546fc18f27e30b546a0bbb68ec51e1ef40ccd361cf7fc8d628fe0183d0e061201833eb9da7c6f07544ef7b22088add3d2caf29689e64036b82fec115faeb633f6856cf86d1a4122b4d6a253682589db01eb3f748916c0c6291f3be317fc0d0e483b2726fd565dc95c40ec4c5f412f0c4900f95f1a0edfd617bf8cccdfafd88686f2c60964e3fd4f45a814fdff7b4b1ed07f919e3a24a21343da0fcddaff5e2699b37f03e75ee41c5460aa01631224cb5216d2521852fb0f89e13269b8f543bb1cfd47ba9ebe6da53704055a5e0e1be72a3bc663afbf4c89aedb1afa0fc15d71323939cf7b02c745bf4ac60080221f8874e35bfdc8756ae4839a10a28184b14e86d224bb15f93af040cc8eb1627a569fe62a7ffd692bcafede399440e54e14f87ee6c02721788769a40a35ce9e4db570556cc6655f69ad07bdcb1564ef403f3fa501de73697a44d1de3589e00faa9ac5855c7ad4770b9c55f4c088ce95c5e15b6b2ea145f1dba2325f2c4678f6382901b8fc4287ebb67d42e9b43db7c6e4bd9e046fc9c43b273602e67b53784c32c75bb346ca534d27b683aab40ecd2d14a4876abf6948e63523174c98555c0f75778c5cc277d27bd3e961653fbcfbc8d02f2d5b5b10b5b8221aa04e2d36b1b962d56e0dd7993e1c621bba5ff77e3121f576a90457f66b8df6c005caf886dd75b2d32b66981090d7c6784cb1c160700adfbbbb20009e91658473d5b45d3525283a28f1260b3934bf8caee32c0ce35aee4c160269dfe7feb53de86fe731971ed5db083057ae9a0d63db225492c110be6b5342088c30022b8ee1595865d8406f716ace64442d0a4578f1c220536fa3bb43f64c82cb376b0e2e303b4bc79e3c74d4f5213b1e3020d76033cbe97196cd996d1c32231e9b66b2169493e59c6dc99a31681e5cacc9406f49d0f358f37a1ead97d63c00b79da72f53954f5a587acc9cc19ae506dedf44a111fc7a8c795271561f623842511174fc411d674d7b61cc95d3e32d635b2e21b1210929b9a13c563bb4c2e2fbaf2f46b3a6987c602770cc32fcaedc80443ab96f9bad9a650e040a2ea514763f9e7d046cc7ebb896c20fe0e1ebdd60cf348bca0329ce4dc800632a0e3187c07d148b2b98c0d8bef9063cd1dfe6d8432422987e9e10767b018356ee8d3864b82d680da4bd3dc06e3b994e6edf720bbd97ebd32cab060194a7bda25d898bec6f3dfddcb34568960ab4c069c05e8b1fb7bc66f148803226659e464d87c3d015f0a2d819bff471b143455907f36d957406103d880f310e35b98a8e35c92f79d4dd814c8472ce4992c68d2ad9cdb5f047596e35ce7c1ec90a45906c04af42adb4095225a615d712154b6b4168d2fde43d7822e540fe00c7c61de6ca15d6aaa9a0e437d45619a0cbc360eb15fbbe7f3481b9c5524fb85337af9b96adb136a57695782f07da2e26f1919642b7a7cb44830619a5aa083f48e9e0ec1475d4af017cda58927f5afe7670e348faac906ce22912191650ea2a7292eaf4f40e7ec6242a3bdd43387b05d3a172239c01f77541af12a7baf073e7fd1a0c3d631fad1f2d6dea439d48fb58d230108b94315662524544ef86711b62bf9ac834cbf4935b0d75e62800062251f587bcb3d5c262d5d4358ae932e6507f2b9b9725500004d2433446b2ceebac4eabb36197a41ce499695294e4e12acbd667af16ba17fce60ce88cd6eb69a74af18f9779079b3960e33aae8342ac8249da93f4ec92d9f7453138f6a710677b60897d938227db8c2041c71f9bae3e30339cf42e7b501a7a70e17b87fe4fcc036c633f0b98f648f8a7a28a30ae17c1a2a58f70c5a4c08cb41401a372446ae25e4bd8dbcf0f8548774bf49b47e0d67a464c55efabd12405d0d7dc88039b17dcdccce6dd508b53cd170c8c92e0d42536e9ab3e253a5f71568601f6fba81a7ed1ec290275c9a1f73f7025bba780ff51aa605e30ee94b0084597da5a2be89b0a13ea1a2482041628ba6c7adb542c4fbcd96428508ec5bab1e37400fcb62bb049e09e01a8962234d79f562ad1157a3674e4f8d62c023d2517650f39ad859744461789ae7e9fe6fdbee924a475a4a46ec4f84a36fe97d3576f889617cc716f83c623905346ff2be78733c608c0f9315a97ac653337f087c732a8e42264f898c4280005c9403b4496ba616a929058973c7311b0a811ee30962a31360e91b22cc7bb6b80780ad747d45727336430ffdba503e875a5f84a1dd838701cc84e266bef1372b8f439d642120cf679002edf8bce548726b20614cd47d2f51b99e66d8dfe5b0a81cbed408ec8049bce8dd48cb874e72dfb645243f0854a0b9498c0d4403441b239c63ba076bce780c6617adfbb708b786f33b1dac715f944ffdfe1acca5073ce2aa0abff3fa2dbb4123377fa053d1982a9fee6326e4016bf7bbffddef411bb7f93912036109cfc6e46d5281db71b321388f9402e2ec626ad36ed75ec31d2547baf6913280a1a2ac2645a7cc088d20f51c484465e6046e94384028f2dfe671cd0e7c965ea7a3ace3a8b9109e9063eb1c4e94eced4d9ba20fdc1820c019de8ea9b27721f42fbbf03e1e08d213b2c7375aee144a3f64ab370fe73712264a96cedcc3f750755f327a7426183503ed3e434dd06cc6631f910a0b9d18ade42f3300176bceec92937cae1ce0051c199d3c920be270038d187af0aa1bfdf7f29423de2d3ceeff71102a9080e8ae9e28122474bf95ed8a832f3b0dd026906b352f134b076d2cfb4023621aa7e95ddc7a75552157eb934ae183a53415f2a040bec6dcfca885e998303460455fa229112d3993ba9f9316bb1059cd4f5426afd6349e979c159002c40a31223c4dccb8722920d86f1cf9027700675be6f08e992246c31e735891cae0a805300dad6570e4ee0a06b010eec5cbedcd4e2e858d64036294873a0ebc112b0842fa5ea457ec533f4183a0f4ace1a2326a965f5349c606d495a4ccbdcbb49f83f4141fac1101d2b2f0f89d0f5d474f7428a304c4f6027dc4a2753ae2da9d6f5881688c91cc0c54165f8d7697fc6e93f7db9527769547a930f54da3d2794de163017740e2c6d23bdaca026b8c0ca18fe487541dc32d01b0bd0604ad81cc82d705c5b00b3d464f3dd163e0118fabe976dee1486c32a831f8775aad935617143b039e22b20ebd690b18a6b91e7452279648490cb5aaf7c892bbd8e0fc5d808bc630ba5e80010a756202d02c32d3c014b3f43b6d68a8f1885424e59553a3c928a0b0a4d074f088d76de0c4592aaf010cb5225c1f24cc7bbd9de951a8966496ad290f1a83361992bc3a71753b64518c30c6d5caf44099ccab57e858f27150dc4459aa7f91cd6f477c42bfcbff5b52aa27c24eb019c0a99a6dba50998f85662f2de69c780956f5626804c355ebbb22f494ee8b15105af06c19da806a093df56fc1356f7455061691dd831df5cdc12ee6a51783d9ccff3f8c874d8413b0088a79f3179a4c534446efd44e40cfbac269af1b87cf3865b6d7d7b94677b66bc5578dd72adb6e6aedb69f46db7d4d669b3450c502bcf80760b7d3beabb351fdd525c6dbd15db73ae6d9afa96737acbd9de2a006de718b72df6adc86f5ae663682dacdbafd4ed8cd7166d7d8b93b6f5646e1701b7f90e5bb6db96f863eb2cb2bd64b17d59ad957d410b5dbfd545d97e60b745025bdc872dd66e6be4bd7d22de2eba6edd2f5bf2efad14cd7607caf6a1999638482ddcf1564bb33de2d99e1b6d955eb6dcabad99cb760acdb62bb575d86e1105b7f286db6d1ab4631f6bcd8eb614575b6fc5f68cdb36adb6e59ade726cb78ac0db3946db967d2bf2bb6532de5ab0a4fd46493be3b54559dfe2486d3d59db0580db9cc396edb625fed93a8b6e2f596f5fd65bf9d7164a2d5a5d14b59f98db82c016ff718b6ddb1a796f9f886d17ae5bb7cb96cc6b2b85bedd81b27d6a6d89835bb8c76ab574688f796c4fc65bc5d72df7656bdebd9d42b3ed48d93a365bc481ad3cc3769b6e3bf2b135e173b57c3d9fd61673fb87d9160b6ef11eb658fbad91d7f68978bbe4b275b96cc9bcb75234db5d68dba7165ae200b570c75b2dddf688777b62bc5578dd7259b6e66edb29b4db8ed4d669b3451cd8ca1bc6b69a6241376aed7ed9a97d6ab6c4035bb887ad767d7bc4637b32b255bc6cb92f5b73aeed34ba6d47cad6b1b1450c6ce518b7dbe869477caf351f6d295fb6ded5ed19f76d4add9633bde5d46c1500b67318b72d9badf8d79679bcb568dd7ea16ce7bcd1a2ada5c551546cbf039fea6ff4d83de5605ffb231d73e61d186d4f4cee625ba567dbd111b6b87db672cf6ca123d872f96fe7866d414bd8eafab7c505bf85a658ed6e1fb570e1b7a22dda72f16f71916f4743dce2e2dbca3db7858670cbe5b79d1bb6053d61abfbef1637fc169ae2ed6edfb57061d08abe78cbcd678b4bbe1d1d618bab6f2bd7dc161ae22d97ff76aef816f484adeeff5b5c305b680ab6bb7c5bb863d28ab6082d379f2d2ef976b4c42deebeaddce75b6808b65c7eb6736163a04b3afa654b0157b155f969eb8b7caba17c3b3af11697df56aef9161a24c2f277a3fa0f7113d233871164ae1c993ffd9a0dd08e04205c29098234a0a30805bc85603546102a39f96ae256b3065dcb4a8877b47c6539da37478c17131b97bbf654e58641176dbb1b9cf5cd04b85544deb2f494abc64dd70df80d66b6ac9e4661882959df2730794c59c6c31c08bbfd84b02fa7e3d681dcc20b86aeefa7c94b1466fc6f6a4e4ab5d4b016b16781b9362c037535649b1bd073ffb94a18dce41bd9a842d71b0ad03e321f719e34b2d220438d2a32b374254ca46771c2e9a8a3424d69be665b72f843aca302a4d6fb7861dc82beb4a978e220e2373ae3798c5965e7e2680c22e5c28c67d509e49686213eb62d88c6e315d0687c699900ce748c55ff7a233de0ae388bb5254089e9e8a1d4e64d48ff4621386cb960d02c31a49f2fb58b68f41d2efdf0aa6c713aa12e8fa114164046c5f1a6a06807e5558a60b82c8ea091094b066848a605b6f0e081e478e3114ed5a6cf68170a9547ebc6cc37682510832260a10400c35e37014b62615cffa2f836101621aea605c3182cea2fd4a769ec43cd8187b92dca4d5d2a018f8e959be1feeb0f278f3d087d2ebe580106b91fb25c95e0381db515368de63d02bb456dcca0490d5ddc31109f4afb84b11756f50b97ee6c25ed44f3276f3cf92a6cbf428fcce5767173816f0f0ce9f3cf7964c163178cbb67a678c3a920adae25efdceb5e281a3a53227827d70a2ea9bb7738db90871a32c3c65bba22ce0ff86fb5c29af4569de59fd845ecbc81599c6a752bf7548cd102afda5c68333fdc277c660512963945d23f6ca447a03499f24b275bd228999ee48c0f60d5e4c63d07857cf32fd9772124f9c30d13f54baf0a110d0aac6a07719cd5989f48466c689370fa59ac00635014872ef948ed2b7908cfcf433c21a0e670d884ae0c1b11e0bc2154dadb094b826a23602cafc5e780685dced46780da4c717858298e8445ca7c3b7c5f3b12bda48b7fc13d56d069ddf2593898beee1e4ea82a5882951e98d5339804b873a9f53cfdade042393fbf4885afcf194e950620529d67e1a8407c19c5f74cc36054e5f21c9f7cd02087870a14b104032698721864a03f376c777f75344a1aab3a59e039e194a15b7edaf3584c6473e9425772d3750a06d5a58829189cb837c2a250353e72bdbda67e95553f9b5321f2c612d84c814a3339ebffd8f76ea0f05cc0a68ac2bbc1075f9ac64ede96ce55c532b2577abe3f6307c55143babe18fdda46ee4061321e291560c0b97848634cf4f15162eb77c740f7db32e5fd813d4ff22f204f21acc1ea08f71c0c1429e6713af196cbebb325f123db8cf5579a42ad149a70c2c73411b9a7aab3fc71e7e6a3c0a4c984176e6b827a7fea034448982db802cc380485ed3785be362d8ac88749f088adf4d9b7d76bde335d03f5048c426ce9f621512666d528592677d52cab5cec6441e5897aa6e2929cb446003ba69f0e53c876854b970808c3590d75d52296f1a9a53d21dcffe29138d62cfe71746bae1dea02ef0f72d8d51f87c13ae3b89c8c005694030e02d8422f4b1b4a3f0edc1356845835c0cd88a032d58a57e2e17fe567d3b2de25807f39e02b1a74c27268cc9669c89db6dd0a8003de8b86c0744fd1f57f139f86dd98297ba72b91b18963eda6f65da7acff39a8bb6c974dea0cee5eb23693f0db0f0b9c5ac3e19c2b9648d3e296b4bc05b0d5089d149a46b67f83ce0d3658b30670a8997d430feca3558098917f00bf2bf97b1cc3aea86af2360798b835b7a2b7eb2b1273fb7dc1cce44826bc0c98dab7c90b2aeaf5755b8db1cc9f0aacd75b8463d5094166d2324cfa617427e9ee0120c952a6eced3f2d21ed28b113b2a67dd77503b436a60044ebffd334de0fd6295a0489ef189c41ffb42bbd781b28c149ac9f8e408fc609101fbfc37191aef37e37d9fab1ff5b3ef061944725ea477955a6a15c0dbcb03dcc36c1ae6b3607d0ce7833742c580b62469fb9cada612241ff8d8e4dcd4f5932212551c5e8c394d265b6c91d0c0d6f7229641e68dfdbf8e41b085189b0085c2a43143c88a205853958e524338755b97c5d760caaedc516d9246be027a44fa334f35a80ededc11d135bb62804e9022f274f34c6ca89ba4c1a2911f705b76258b94d8918067cea47230639fb077cab2ed0841d36478c3df90cc59ec76e725b5bbd9ae4ffe2e8e9a90848e42f7ab3db7abf2e9950e56249b8dba49eca220c1156e8163ec86cdc235e5581c5b2dd00d0bf5de2cee651b0b46f749e4a1fbdc7bf470e2e1e57ecef3bb2bc5ee345ad0301d67d1178d6501cd897db7b1a0f9681f1bdefeb17e91dd1a78f0b63f85c0ceb855b5550be24b2c4cae84adddde25023e7e5cbfa2bdae242f2d17a6fccbad758308a703c5815a01a3d314747876dfb045ac289ed727ba57efb53e9b9450b9f6a6d1aa286c8d4b80b0bb24647e227a3073cb075763e1e70a16fcf38ad07360ae907109ce6c058960e2754308bb6f16c6dceaaadbf322de1f9cc057d6290a4c0b25d3c3ebbd065746720954b95e9d956864499e17edc0a4266f1932220e8da81a4241b0de0e9f215d21b26713608e67006b471c349c636adcec7a123c461d8e0597fad72f0092588df8a1ddb4f17835206007a5f8aaad27152f57fbb40775e81f0ddaf67ac4aa136b1ea5b8523ecef7125365646a4ba7e82a736d5cc0a629142f98d8ac07c8a1355220815b4475845742258f1347699c04169a1ab245e082e1e985460823419dba67f33d9c5c294de2e354cc8160d469cdfdc9775d852168915056e10a139d77a8cd036fd21569e4f90cf9fc41544e84abbd98cc25753d5c3ef0b3cab0e4c22b35aec23b8c5b7ed7c0cb3661b65c61b159f619ed9d58b85b57a1a40ba87145ce58f8c28705371a9a4022e0614276b26d4fbac3a0e22a03b274a34352c13fcfbc3264f248348a7f120fa2394c42d0ce3b623ab87bf57408afad827accf00897b5ca92ba2491ea6bf808499eb420d1a8b955a7e8b09d8e9283afb344613547d73cc0c9650ddd7cd8cbaf14b64b90f40f1dadd704406fbf92a286e223738ebba4231635706b46b5a945d0e8f5c4990a0974770832adfe6639ccfb44dbe6b2b4c8ce8496836a1c0afaea297524989b783ee5f9afde3127248c55ab71197b736047411a1aaacb7de96c2321e67b4f9596d9878fbb47e96f20178de97c1b78ad067cc7a48dccae7ae48e0e8d92c865289a05d9df89d8e7f5b7a5cdadfe342e1e7ce66af705f320ba58ecc0689aa485353a0f841bb40ebe3b526d99e0f2c766da0978e1043b6d1dd6b527efb9ba3a3ae0a6a2cce962074a2dd18e5c019b2c57730974a09f1ed3c9ee080c9a36e3dff44934bf7a7339a07dc1071fc70b58ad2c7ae263089e849b57cebc57918532042c564030e9de7318c4e775c3edd7bd9bfc4a5fbff98db27367a454eef0caeaa89d7e185027888cf363391612697836657b760014ad01f76cd95ff470da757ce4bb64c89ffb14bba35d106de20bdc7755bb0a1e545263e77c4c95232a67fd6a104a602e5a7e2a339ec4d200cb7cab0adfc9f6958386d487ed0a0f0f3df6b38d76af0c3ed7fab5b5e741cadad2547ed1cabb0c72f0b225f1349b1956b8d013ed3557c5c2320e042bf2cee35decd09a2389ea563d3182d078e61d07e7fb234cad17282941fdcd5262d58b70146bd29d4f09736436ca887d376c4e89965367a9868f264a5844422c286e23d7fe2a53adbddd1cc0eb2af3784d0f5cefc7d737374aa9344f0ee173c3234bed4318833a8bc254a228e261f8350ca0bb2bc1837ed34d1a340301a34b660015cdd45ceb927557eee63af6ff411df604b64aa32cb55d8223f4ec8f43a5578497bbffe7a51eea493baf0af5513f0d88ec67c8b1c296550db0c7a9a5224e4c69a8028cbaa8061bfc510ecb1947df4a39cf75e5ad0f43e5381a580466291c5062755356e021eaf120d80303208b7e752d7e4989e53ee6be69cb1546f18be6549f25df89714ecf0edda799f2b1e6cc271da82960c66b5dec298b4575703e48ee5fa48aec9bb889e88d27dea5b800268007275e71a964000d9e8a635eee5da12704599faf1341c412ed98769aac162e3cdfc40d7f304fb3d36993cfd000821159e1d3a37c9dcb8cc28390224927f44a67cfa4a3ced99cdfe723fd899bf294e9689bae986de04bfaf92125cfca36e395411525aafa3b7aaea9ebd7e8349ebbe01b692960f8f9d4bcc4b58a3ee6eb5d2f4e3e7862576e95a1ef9bcee10993af14df309c78b1ae36f1f4664f810e875c6a9f530978385b9185849d13cc2109b746e49082b8c4b8284b8e45a4bfaecc3c131267d62e1fbda7f12918a4b24466a3db856d215eb9f6c7e1e62a4bae1b2c5af4ee900a8c7297f9aebf2a57f057eb7bc2f01bc573dc3c8e170e60ddb6bd546faf13a6e8e1ba864d6e897aa5e42246530f990193130fbe38defaafb28cf79dd1cc2618bf2863faad02268c483424915d45aee2059480cc7b780d801fe851b000437fd79ce66d221408b48a22136042fa3b305ff14c7dec1a0e6059295256f1858ca02b1504f8059a8ebac5492f7f15100af76d8e5a4b4da2bb994d761a886b09b6fb81b203d29c2f427f8e0e548e1a20619782d0621cdcd7219355ea8e11b44cad3127717a3eff0c988b959790f728a8e001287143447f09c6ff7e19f81c07b078f136310f007b8137edd04ef57229abbe20bf0dc0ab5c1e2e4c9aaa7063f27f77f2a06aa4327d37e4481b4b1e7706e909811d045ae2b8573d8fa8b1f6f96424c766c089c839b5bbbdc03c11583672c4eaa039836bf0c14af4a5153de5ba0ef0081549fa7082f871bbc6501e36fcc6266d847484bd518f95ede7ced54d3701129b0b49629d1cfd4bcc18fc0fae648eec475c9cda3ce2fd64eec770b4bb79fbb9c595f052240ec2749eba87538687a1cd5a52e59a643e3d86f97ebe5b05bce38aeb7bfffa9008739e0f32f63d7d1b82cdb7cab3b33126bdbe3725ad12c64770c75ae9372b7a1e10cc8c0073b7e65f2d0ebc964d90e98b5050ffa865147f7e546fbbf9c3d243b6f26b863953f3b4739425a14d3e30e1e031547f97c4818838bca79e5a7071585fc7f857a0b990a29589784fea8adec7685993dee924b80ccf4cc670f10a85166d66a03ba4e38842823208fc41e0184be25471f65f3ae148497d65f8fd667ad90e4c1a6f541163cd43f533aff5b64b886f926be27f42c38b29bf92980a75821e4114842f02d2562570a00039767f009186c4b6ab5a6615bb94bc811ca93ad4b9319e397f1648aa3b2210dd7fcff38996c94d34ca4ef81b99c64cb5fef89543fad8f064ce8f6cbafd3b211203a3c618a761a2d4e930528e8c11d7dd3e0e9b3d3e4b2e96c278126e738f0ad82c3044ec83d8a596035e7e43040669de3ecfc27d62d8c20adc4eb0abbdb2f514d6235dacb5b7bccc3226a8181a186798d03e8f42e73520086a2141bdf67a0292e2a241d82e4db53efb6bcd22dcd584f10db432d2c509963f662fdc134e3b5d43a2cef44a06f2e1c4c11286985fc2b8fd099ff841979357dfda653e66b6ce743b1651d1808ff9afc179553b71e1108a8e29a1ea1f8eb1cdb7b82ce6906db1f64c5e60e2f089ef7e70bb49d39fed2e3455746061036901893d28fb11ab006c84d5bed639a19783d2bfb8bf701f287eee9245c3382437d27077a4f28be92ba0b0788a8d0cd84a65d2a77823ccc42f9816f122bbeefd03853d9ac29401942310552f25f537e6ca354365c96da77cdfb7d2ab9ef774690fdc39a7801cf16eb420fc2b3eb6b35cece531e3b1a14d454057a150b7181b5876d49bc803f08424129c930424a13de17527c02d207b7c74371d2b6cebf4c8df0fef97152477ce60af556a38eed724296399143ff415a2714fd3995416889d7277c23a6686c5dbca5998ff179abbac5eaefc0310471d4284ec67e11556f61073f816691fe2afe917d3139697f230614e0b7305a2f9cedf5b7201a4333b2e2335e3702ea0ca9375d49fef0410b74cff452cd7738f45781d8f744637b8a868508f2e454b0d89e5f59699010cfd9867d0046a0cc7844cdd316026b832f9005f3ccb2df945f38540234097850b8607de88934c5e7dc7570d7bda65db27d340dd1474713cfc14b4ac8667090fd9ea75b8b21a395af0552ce2ca38c17ee138988c8c6723c5f7ae9dce7ebabdd6115ec9f5f873516c4432c8f536534bbe567c0184b506e03313b7520c1aba24789638bd57223aa651a08d0cc62558fe00792fc297ec8d07c9869b451661f446cc5228de61ba3a40c047c66296a53e5f0da809914238e6e65c08d034c1c696f9570e04d20ad0e208674d327a085c06be4a14268bebfb52f8688b43449511830d29caa7c3e19be1026f9bc013062b3208b0516aebbc06ed545f3199efeec08a3ecee39000a6ed5c52edce93399d6ed7c233bbbf41ef72a54d866111772e962842fcc32bfd3bcf01b9af1a0495771fbf5be487e8cbfa241975830ae184d91c13f6fbe4ebfb0ef0f1b29d908f3684b93ef3dbc02705713a4104abfad342e707bef03820f42edc6c512b78b5160eb05801be12f09b519e97ad620a0d657006fb3995f7f302115ab94021351fe310427804f72c3b6073a829deb3d3656b1ff6dccbe4677a905da933c8b50eb8a57162193b117c1d5df495f3526ea93f9fdf8494a233d5a4d8c5e003abc8fb9f60f000168f792f54c3ce05954053ada9a519003d5dc00dbd650e0aa273e6486fd7bdba05e6d4f5c653e25f1e3797b9fa87d8a9faf69862a53827d10d8d4815f862a6fdf5ce3c44fcb5b59fac79ea57eb51ca9e6c839a4a2010d3c975155657ab8e820763c576bb21f05eb37d21efab671f9e80dc235590b6711c14f6a058344963124fed0422d1750c6b2f1d40a74c6ae64d46e977450eb84a981b7f3594842464ad3fc4b2bd4e0d89f5349bfd13375dffd3c03e2a2a81a3b16a02be6eeb14052be601eeecd22618c87510f2257f6cabe8d64c1a5cd6d5bc9280c7d5b74b90086e5841d8e1bf39ccbbe821a5e65a952cd343da48973da806b16a61e22e9269c990bb9357dd4d9a5a173051a0900d6d68e936921f7928b0effa6c403318917b95bf4d3c3b9a03e69c856fc965d85a7b6161f7d7b9471614bca2e8df8b44f8a296eea8859233e402c97761ec9b44dbd4eed4a8ba11b6a3f5366276613284931bf41860453287cb76a19b7cbdb68da587edb7663f19205459819a9c19a959e11a552c5e9cd9ddb181fffbc86ef13970f20eee4f268ac0e273ed051b7f0b6413928abbf848f6844a2e1bb23138ba3fd6d0e417239ba5dfa5f0495f5e15f9fc1fa1d6c0c605c209befebfb4f02c003ba565483672d7e3383b623f07259c20d7c97e2f3598c670f38263e86708d4149bda64b3af084074b311aee33e44891dc0ade30d7e7a6e4d5579156f4543f938fd60e89f1ef0f9cbb2cb8d72f74c1a0431d3016910ac6f87cd8955a74717517a188c89e3a1001b52ca3038aae525e896c3c0fcf99fa42eba1b256b69a6cfbe9114ab3d56d0e0032571a4c7829b1eeef038bb90377b11838bdc367020e27abf9ca9ec194b3c41bebe383f7b0a97d56b50fa35ae96690713294d30b5d35e2e8f1cc6a920ffb78df234e33cbe1ff51694863c52dcb2ce223b43cd5188532940d7f790ccb500b25abcf60f2681db112d513c09dafe2a7ba8354a0a25a906ba861810c4de653b88fd11ac6ee784a2a950a77a1aa2a729d654ee16e3125d2351d86de465204732cac49604a0d75156836c6204b754a6f5b8312e5f8e59f51527aa21db3a34c5a1a9c5027afd4ada60364232e4a336d218c0a76066984664e78d9aab124936eb9263a74494ad32205de0cc08bd3b04ca9c7635cba7ebe5c8943d192bf4ca8189a690044a3027499d6497a0f5b07ef09fcc1fc1d8f9f25d27aa843c3d5d76bf815927efb0e420780682f86dc89c200ef8c5781ced2c1237e29fefd06da2c22076f2edaf80e2129672a8d6e6597df8954669065753afdca9408e7cf9ddf17dbea8522b55e986a0c650714caf07a15babb8d7fc69805bfd25a16cf2654de07d2bf5f35dcd440b6522f23278798c185ac188fea6c377436332fdc0474ed23a9b49b8edd471e4ba4ee6a51918923660c0758c72d19a4221d842bf3452ffc9310a41ab3dd6338d4592656a586f0d7bc7c41b1c8561c5fb08c542eae575f2fd87e91f008ce99b1df9e145dbe94df781bbc264ca6f826595ace0fc84e1113dddb70a06c30b970061d710502b00d09862f69c5c135714040fca921260f8b416e0137779c74c2eb2fa2242fa880eec2e69fa765ba062de7dfe095c9978de6c18d0523c896ae930cce664cb7b960220e1256e0c5e62f77f685c013fed87267b2ca5b2563e74c943d9edbde0826166ef756cfcf8a141c01ba234058999a85590f21ddea979c5d6707153feb2de493ec5c99bb570fbf191b0b39d7ec7aff3a6d587afa0abc5c1b781467f620cd1241454b77b90b94baf24daef503644a03faaeaa8759409c11a703df77a24c4799a3b09f07bff669cba967c70d4e8fbe563a91c6f3b0164e7f3429e720ab95f1519c7d8e6adf81ed126bafd9a581360c58533a0e7827e857a07f5824254b0dccb38df49226bb6dd96d4bb9b74c52ca4a0870089c0853d2e89eea917292c1da1804c9880c64b478937d76d1973aaaffdc16e07f511add9f031678d9f49dfe156ff6a4462cb5d40145d001195aadf00955f0a412b67cdc49010fb0d0441a5af0832065f09230010c930a80c51542acb862081392f05c0adfd1b9a8c28fc0b4c695edbaaecb8a7dd5ce08958e600b2d9420b5c416216059e15d354de4d0cc5c243e9d12ecebba7288d89709b82043a45c58818b23b8c384863291708425608105296ce0040f33625148316ca121a5cdd766d6c044ed1ce296f3c77e911265fa9cf304dad4c00b6a5fff6284cba7cf3967f59a4ffcbf1c3a64a471f92360cf772f7da99400eaf1784c5bd3a2bbefb9b12c93ec2b7f2e3ff6f5f1ba9e7e8c3d6412b99d473c71dd0302f67c7dc20302f6d4273c3802f6d449e68c73461aaf4c89f82f22f6159331deb86c0e30fd2bf7e06ab674fe9856e29038c0f1ef5c8937e6f61ef58407a7ef436e4cbaf423e41c6deca713168aa812f7c7ed986922aad0d18e3c6060dad1967ac2e086780a31dcf51cc6711cc75d90e3380edfcde3d1387a367983dc2041623cb2f620e6c25cf0c2c4d49895cf5ecfbdd7f3df8c99d6e29b2f1753ef95e0bd370826e189812106745320d0850181407f41d04d8140370604025d18096210f67910fecfc7cfbd416e901be40689c18981b93017bce08db93017e6de2d468232c6ffeacfe65aebfcb8e9cfeeb96ddbadf36f901be406b9416236b760d05a53cc9b79b8ecacbe765df8b71e6e2be69d4cdfec71f618ff06933d961f77163d1867d9ddfe6638f341fbed734c1f7367f5e24ddff778f49d5f101be738fbedb9b7736efa6acdea8ffab4f981040ac9b661c71a941328227b003b1a49d2a2d15f66f9616b5dbaf46db54f5a6bb9efd8edb3eaf180acb59f2ec7791ff4c11ecf73da47dd9ece6f3a08d2aeda6f3bbe171e5ae7bf8e671926d1173c6b1120e09eb1634d11454cb1250a76ac218266cb6caa65defdc518e30d892ef3f8b0b7efb2e5bd55665f7bf8be0db0dff9e8be32b9b74d5efd519c3fbc5f5a5cb0bcdfe16f43027fdc177fecf4f7b2bbbfdc6f3052f7f0dd7d8ef9c99fcbe671dfd371fadb62b684d957f69cad9f8fbecf49fc01759eff606cfca0b720fc14ff477f16df97cf69daf9fa9e686f0fdaeee80ffbec4fe6db2ab1b42b98a9418d8188d43eed58f30367ff606d01ec58f3c33d467e785eeb1f79f468d9b187ef6829fd1ae316fd338feb63e729dd84f4f02de98b8b833fba33ed435f6b1f3fd63ebb9fc7bf8347d59fecfc0bf7fc6741ff4d1967f1e8cfee7c3f1f75ca701feabe56fd85767d90fe2c4be8412fca71aa80f4773d1fca1f8d359729696ffa6ada47dd1d9d61d36a1ef2fde7c6837c1d9fba8c6750b05248487d6d0cc2286aa6581db17119ec210e718861108651d44cb13a62b309711bb7712c3698cd8824300e9160a4fcc9631022c148f9d36644121887483052fe04032c71880423e54f9b119b9010af70e8c32870b819b1c1a4f60cf10cc3cf8657d36042d2cb1967c94224bc19c18262c2cc981963254c143419e3f4193d7af42bfe754529dd63cc72b260b5fd258c14b2a5cea40e61acc47d4d57a9b15c03fc91b6fb5b8b493e03cc23fb6b7f9246933473a5f3fed20919ce9528e60a36855ccd154d5f7faff11a9fa26afa82b3d303dd99cee1989444e669669e54f3e4afc9194944aae68a7dd9b9a4ca95c8be7369a701b61ff7479a9901969b0463ae60efff2938cc15faa7bb3fb93f7d63e6097b235d342167e6ca2767485d10d9fe304e92c85cc1b6bfa4992bd1481731db5f3a3159a4e7343788cc01cbb40fd727efa4711639635d7f2f32ebe8cf47fd2448b381ece58c76ad6d9dd9fe58f6d58d418dd9f3c3956ad3411ac528f91117838b517aae04c34c314c99dedcc4d0251da3d1531f8d1a80b99f24d7a36b742fcc3dcd1f478079aa314f73c7e89d1431bdec8f48ef24227b7ef6a7b942faf9380c297d2983ef957ede1081c19d707a8b992718ef796cd37132a43343649e9a9834a53c9d9851cc6c31a32d6634da848c46da9d30588cb3947e62d2476e55e2f47749fa0b916e36233698d1683302038281f33431546a7ff46675b33a62b3193132d98c78313231e190c0df1c72337353823332195242fa9237c9dfcb3679f174d361f29ae47e441a8df08f4641ec8b946390f4e863ec182525cfe56f83d9259fc34df2c9976418ff227fbe4ff4a603869e26cf914aa35169447a1fbd788ea43f93e7ae1fe5efc573f3da5c0478f4743eedc25ce97e8e61ae807e3e6dcd95cfcfa768982b98341a8d603cc765ee43f97bd9a1774a7f943fd21e3d297fa44dfa2b9b98fc8b177f72f23060c4788de61d7163fc74f41cd5273be2a6faa4e44bb61859f471db114397bc08469630fb24cb98fd224b21db24cbd4be32dda48cf7289376c996c3435d06e5ebe23cd8255f806f369c2ebc00cfffe8cd9ea4fdf9ea66d6ecf9d9e91431fd1a03639a5c21a9bb0053ed2ec0f2e54b3ae99cdb8f98734efdd1bf6abde6bd64bdb08b4d7a61f67502cb179c94cea759fa20252625c5e4b6126b22bb223b92d9ec0e98d960387bded7a4dc74883e5c95f877a12f799f4440dee9af65931e943f1fdbf5473f947dcc7de9394d3ef4d4c6552675ea4ea9539b19d225ee4f4bbca4245f4fbbb8d97947235d44a1f24b371d43b8d77ceb41ee23f057634f3b9f0025a497364d7c4a3ece95a82fcc3c7d7edb81cdfea33653359b983479862517669e2e5a12b3bfebfd73cc8ea67dd40bc75948a01a528e53c575bcfef4fa12d7d7cd3ccda7faeac23ccd0bc93c4d98fd519b1aaff1297c3557be175d32fa0dbcecebbaaebfc7f7f5b98c4029fccd1d501b8ac55c09fd7ccaa2a3df4148f4a11fe5ef658fdea389b2ec3affee6f57221285420fcadf0577e873f828e30fe5cf7bf2e71beba8e323b7931eae7dfd057a4f3784f43966092977face13a51fdaf5f7b229be9eaa81362bf7dd7a9099ffe2088c2de38d6bcb57a9b2bada5ac9bd9b7c8d74efd603b548cc95cfc6ecb9432a8c116287ecf9ab78e3b3e5d723b36221bfdecc9539b78c2c5626bed06ab67c4b831873b0e76b9ccc8edb033ad6e47253d34c393ce109148e71bb6b08d5d6d62a9d09dba6a323f3add5da5ab39ad5cf7edb7464f56fc9265fab1b0432ef52cd130dfd8b35e19e54c655a6b6daf5bf58b3c2b366d7974cf0b8cdaef9d6d7a88ccc762af04755327b3e55555f02b65fdfb3e9a89abad65a4f1975e7e4d26c002db0663c0dc6a5d9005a4461e369312ecd2711a07ffda55b0e0024f4a88eaee26971964a31739a4f2818ae9001bd880631fc60e569d9c72aec0008cad3ae1c9d600590958772c113381eed8111319ee7d2dcd2729960057a2d2e1a1970428fbe8bd4c10f1a8fea2b5e740738a07765adc3da3edc74693e40122890f1b4bf34d79420e4c037c496da87532288d8da76696e895fa00116a1e7c2adf4a5d9a5062a0a94b7c4090ff2ebd7978db2852db0522ecd2e39e02c6123a3864bb3d65d9a5dea8d17a70e5ae852ec5b5c504f1f8569974b531a5781027ff46ea92263e6f95e761786f08318cff3d5ee799edb4eaac30b344de6e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4488937b54aa0583db2e3579b1dbfae767c5782b5d66a930614f4969853fb28b827b8a56e8943fc405b906891d972eaaf25b5a5dfec20a89d272ae5143429e59cd3d2ebce03e637f252ef028ec46474cf8d23615dd7856198a597b660fc9342d85a7b2d45a59c4e0f838483a54b81bf7b371ddbb68530873b50f7c11de7d96ed7755d34f1486d0b4d9367c0f1b59863ced8cd9fc7d84c991ba96ac933e0cfda6906b9cd782f467d62128bd5f3f5d847348d8b38ca1877dc2d5fe35c0958927c888bb7bc25e2639b0ef91801b6b780de4a82b76acc53f4fcd58861fcba3d20f3a2ab44ed5260cbb911fc613cc4a5aebc25e2773a9b8e88ef10aabadaf2bd06cb20ea6afbcd8eef46f047ca6cc52e8dbaa669da9491f37c2f9b8b38fedc74d81d91803fea94524a27a59252ba79e816900063608c8422089223823394c08811704a60e4660c45643b3ef1032ef0a0891d43d5cd66ed18327164d7a0ac2d7f65cb8f9ebfffc3bdcf3da741e0f9cbddc7585fed7196dff86acbe7dcc6a39dc65550de4ac9f84c8c067a00c1bde77ff07cdc803801c2f3f8b10601f71e7d62dff32f5ef44e7ef0e2d6e3878fa6d9f221103dac4f7e586df92d2f9ecd96efe2c52d022756ff106ef99e9a2de32681164ed3199f7115f957bbca55683e9f6939b8e16cf9f7fef5184785ceb2da32baca3769b6fc4dcf9a0a3acb44690d82fbdbf7bbd3b20410f20b3e4802ca2362fb1697911659a03c142ae46d9a08c7420b2128ef6a7fff0488fbdbdfdff403a477ff2402f7ef5f7d0201e99dfc70ffeae8454f7a4a7f1eb31d74d496a0550b90a03cf9b2e52cd1933f511d9c4c7f33d519431acc3005cab3fa9b32332a9aaabf1962fa9b2b0f12ac48420cca9bac2dab3862451428ef9b373896c083d0fb268ebdf4f7547f249ffac35b7a3394b5238a0bf6a2cd0e8b8917b0e009314c3001064df0b025a0ba2042ebb3a3112268810858282125dd734e777f7fb95dfb905bca1dacb64b52ca3ccdaf1155e6e33dbf1a7bceebe336d5b866c0273d98b6ff7fae4f78d8527f76cfff5c9fe6699e26dd29be825d010554f0c2f60985261fc974f95facd98101430089408c68d811bb648eb9f29d143057e2147212609e628ddf5f8d1dff84c35c21a97ed8ecefb7951fe56a06dbb7c0396baeccd374d63cc9b746c2235bca1cf3c5a55c817b8c31004f1849020609122448f61422912049b93e5aec4fac5ec0dcf6eb9fdcdddddddd6dc57e8a1d529e77e51855b6bbe3489f49b498a261af69458a40b24f3b1629c289dd79cfcbc7b43b3dcf6d0be8bce7b5cff5481c253207ff18e3db1b6fc41d7f8b37ea735ff2d81092a4d90e78f4993cc99fdc27534b6ddb51fa131393ec2592b962f29ded85a69d9cc5068c50d7755d289aba2e14bad99de95f768f85bee67f9df53777e8734c6c76ddd4d84b8b0b7d09cea752e260537622297a8c769a47e8aba42fc2f4d43ee60e7d9cf327dd13d33c429f0f89648b3e4e96d3d422516807ff18534a3d317dd2d970162160f0207fcea753f49f44b2e997b267dbf13fb7cf9f2cb1bbed90cf03fbd7248665f9760ad95aa80b8542a150a743a23765fa31f2e8737829c72d3a394b8cf707697f1bce12430bf1e97e62150b3d36b1da3d86851e0b2271883e1bc417c40de2d24ef3d018cc1689e2d680f998fee40ece42c21fe3e7c3b7ec74484f7d127afaa217c27fbe08eb68f7a2b7db0eec7974ba62bf43375ff4f847394615dff3452f83544d5e3b8449199a33db1266664f270bc955fcb38f4876dc443fe5e835cb633e8cf7f8a4277d24cfc813a1ded1c813abbd43bc31df9f87384d722465e9bdc872ce3969f01723cef61d24f01760c00f14a8c05cc9ac49cefe458e5b24fa2e7f2fbbdb21936c4a2985d9f4a928846121d1e7f02e9fbc2867afd12bca71bfc8729b783bb8e633cf8d6d12e07ef4718b00f725ba457241e595fc090070bc1600e0781608f8f1bc1403a9818411b0f6dd616a8ab7a852a408223b1a915162d3d8b1081133d83bc41b72fbf310596ad0a47460e4053eb0620c5edd18c9c6ffc974d3f111bd2612fd8eb845fa9e01dbfd49215bf4b108112ed82f7b8af2373f9441212df3cb9e3e7c83b4cce19febb97c6d3be6962f698e3d3f39b3670522639688468a1cf10531575bce7cdd05cc4d1f02d38baef229604f10a8761073b5a91242ccd38cad3d25ca3b599e8236e5b623638560cfcd07fc22c5b0e9e6836df1245bbe5f615f9b0fd996910637b34c22d1a00ac1ae9b0f255b461af26316db6e3ed40fc83fd9d9e6c3b5a5e67ac8cd811ea6245b7eed6277361f4020b7a6619746e9a5d9b5f6dab47bddf371607baed65a6bd25897f44783f4755dd7755d94524a291522e248d627a1106515521409c28e2f99882c42502a552d8bc22029e653271939c3d5d4961024b032dea43f4cd21e14714a1147c660cfb7d1b21ecc914c8f4bdd26436aa01a37ae017c47b6378b3189f4587f5fea74a741516dd5566dd5566de598b5d65a6bcdb22ccbb2cc43d05ad08216b4a0053b3d333333333373e3e2b832075f2208902cfc9f9c9132f8e41112059204f2c78edf81c822672eeffe8bad1dbf8873ba7916c9665b8b3189f47f3ad590335e42c19eefd11f3e62cfe7f44792c19e6fd272e6de40ce3cd69f7cc29eaf1de05e22d85a8c49a4ffaea4ff53f9686f71359c145c0d57c3d570355c8db5d65a6b3b9d4ea7d3e99834d6250dd29d4ea552a9548a255992255992255992b5278e6b807b896cdb0ecef4324aaf6ddc5355bc21faf99489c8926536e8eff309e9cfc4a406fde55ca23f1595fd5115558964682bb5d5b4ddb4f568cb696bd29fc525fdd120dde9b94aa552a954ca8baf1de0ca1c0cfacfc68e01f8ff54f27f59ff6782f2df67c7cf224bcac7b733e52c29fafe882af35132ab3f389b90744ea97c746ad79846b2dde98bba44c09f55a1e66aaee66aaee66aae34035c99833df456e56aa8eaa2acaad3b1aa8e5575acaa63551dabea58cf5e547651d9456517955d547651d65aaab25465a9ca7235b5723595aba95c4de56a2a5753b91686d516565b586d61b5d5baaed6d5ba5a57eb6a5d2d6b312691fe4fa71a0ebab5189348ffa7538dcfc13d3b998d34b08f8e91c655d2712be91869b88d5bb3e36b51da987994803faafaaceaa35665f7f7e210b0a6dcd97898fbeb40f69a5fea01fb1abdd7072a0fd7fe5ab08d076c7f20b8361eeafe5c348b594fe94b9fc7c0c8dfb439c9df9479913f79a322e52fb66258924517b5e787f267bbfcd120ecb9c59effc9df75832b8b8d1df16155ec4a82af16d180dc9f55798c955fe563b2b56348550070c15edce57a295d571a8e68d13b54e0f9de59029e2f52e2d062ca178a1102fe6ecc8d992b42260b9d2af3a711f074163cb1163599b127cd156d5a6f71d826080a6eed16016b737ea7f39cf67ce7adfe7e7f1fe7bd5b66b93bf973160ecd7796b3bcabccbf54a39fb736bd68f6546f1263190ec755e6df9c7066477f36f677635e7c3786522c033ce463d342607a99e66e5c65be5d01fe702a4603747f38b5e763256c6a0cfba34a6cea7fe5540bb8af8ae5efd241786b536d431d1ab826ef47a7a86de53b0eb6d2dabf9ea224a76f6cb2f4f0671af7b6a369195bfcf6b9d72cfe0c5b0e89a3b6a45beb024e866fae904596e3ee441ab693e7e632922b646173dc19bea91efb56b3bcca8a992b9b90b982531489b9626f19b07dee31d6125b4cc57df750ecb2dbe9db1d377adf5a1c9b9b1b5759591b56ca460d8a3aed56cb5524f7d94f7f366bdbb5d842c4b1bd7cb771967ae337f146e8e57b17e68a0646a01795bc749bad41b9e44319db9effbce8b55af225f21a7d8ed41b6799385bde60e12c11c826947d8b62a4311acd2d3ae24df02a4259ee518ebb4404d2433a2d7a918e914628c7ddd97ee32cf5e53b8eb3742f75976d66b62dca59802c117a2cfaf9150d734503a09f5fcf106f7000572e228eede75354bcf179ad6aa12cfa4fc636e896018bb0a8444b2cfa8ea8440443de4fbe688cb34c6dde4fa65b1480ef7188f4c91e22f5704181e6c639ee50f77d3e718bbaafdfc305b5437a48a735ac7a3028636d33b7bbb650ce323feb6cb9623bb5298dc954086a7e6d39cb85c258abad3dbfb3048c5d77ab1767cf6f997a7ef3bcc7c379acb5d7b3e9cf7ef63a1cfb8e96d876b2dd59a643ead3cdad8dd15ce4cb75c558c2867bc61bfef13319332d5ed775e5b061c38de0fad8f680ccbbdeddbdc6e9846118f6a45843da61aed4ac7eb6e9909f09a9f50a2c83a82b9b9aa76963e669be46ffc5d3349aafb73902f42fdd825d65d6d510aa2d5f6e43ac13709d2fabfc88644bcda37e44b225a532b1e6a3129051620706442cb2eb52d46c9198a7f9f20b383e0136b1affd591a245473e5b334db89b912a9d8f3adcc5c894f80307bbe55c236b1e777f7d2ae2c3d8d66110b92dc78293454cc78327a700695a7d14bb38c23658891510513284fc32ecd04e84112663c1d5a00849a2e0c37b0f19e0b213899045b849ed6b934839868d978dabd57a61ecd35fc5862e569f7d20c3a4109581e288915d03c38a4c6d3b84bf3bfe00c294ffb5c9aaf77b99ae08219efd2207d0422569ed6d5902a428da785ee95dda359061559809e26c21ed32d2e980dc23004e5b5b8d06f7121001550ded5e2427100061a8f6a171cab1b909021c878da288e46d3a3b9a40533e369a2924bf38442083db8f144200417c88420fcb10a810f84007ada0b24645a9e76722409222b4f8341c51626b0f15cea4d13d260d3f2b4d2119821d4782d2e231a2f4e1d5cb815a948175acc78da5351c4082d4fcb426a6a3c4d3fa10222339e86422384d08b4c88c206319e26430545dc78320910245a9e66c3a5791251021aac3ced84851095a7a95c9a651126b8c2c6d3665c9abd09d8fe490ff5b3cf340fbb6fb834c72241a8428da7e15052220a75a00fc6c1e408684882a6445641a385cc680747a0f134d2a55902214286d0d34c2ecd52c8cd10623ced050d4e80f2e2113065138f90052222125a47ac3cadc4041ddcc49ca229763c39664d9804d0f31c738b34220d33083d17ec0a29ef1e090315319e4be7870cf6d763ba254271850f40cfa53231e3d1234ee841e8b9605aa008500308dd228f70448be5b5b898643cec5db22d561efd4b9f0071bd06c5ca0832f506e10910ba45a2408b31a4bc96eb5d302d501e7d4db7c42359fca0c66bb9b40bb7f2301cb67c172c0c3753872f8463093c083daaa94ab7602308d2f25cea8db7845b81e5bf789244f2331c81734dec1530507d01a6c633a58934a601aa5064e5514d55ae32ffc5f329f0c9f5aca3d226e6c956edd97bf641b77d9aab912ba0bc16fa2e520a5d58794b74fec5d3720c738da7fa5fbc1c5e730f19bd1ebeada634aa2af0178454ed4e206ce23c424c77777797d6624c22fd77200f67c29dc5a43fc9009970e903eadcdddddddd4917f41be8e3163f206ce28490d472265cda64486d93dae64971daa7dce110619127a208c310e545ea4aa552a954ca0808822088655996655996d2312e089bb819cfb4bb896c08d55022cab22ccbb20c044110046fce5fc9a227e06aadb5d69a65599665d9e6b1d65a6bed755dd7755d94524a2975777777d3c556abd56a15ad0a04411004c1d2cdb22ccbb2ac66201b9b8eeee5068adbe793e3be4444b7e4ba147105d3c4d3fc0f0f618a1ae189e6553bc618e72a664707fd07175b6c218b1d7f4221b2d469236367b08a34697e86a71a5fd96c1eeea3bf13487f39ecf9b4036d1ece84419265350b2467666666663a217070dcdddddddd43b761839aaedb99eaedeced4c9aed786c441af30b70c300a41b3ec5a2d8088b3c11451886611882200982c080200882a0e88eb44f099b246bb65820168bc562cd13b4b63fd5900132e1d294322cc6dbff29fb7c4c4c720695304afd8a3f26ceb3499604b1582c168b35c3b02b496deb4010044110e43e209d3bddd2396795d73a0505622e3f1014dd6ab5728e1e8cb9a236846a289914abd9bdd65a6bad3da5846eadb5d65a10044110047366caa7110dc3300cc3306badb5d676345a6badb5560cc3300cc3dcddddc3300cc33004411004c10b044110b4d65a6b6dadb5d65adf5a6badb558c91d91361d5d4a6edd9b802f56521409c26462de60c79f32882c72266253e6c6e2e01669a226789a313566cac6ddddddc3300cc330fccc1c210397dae6017d38130824b5cd934aa552a954576bede40e5db26416d20a1209eb8341a7e9e1d41ecfc7f3f978729c5250c2224f78147305a384e1294c09c310457b714f723c256ce2e66aae3813f6e86f2699d6624c22fd779c0977a01236a574252dc7c4cd959c2ba96d5fd2ab9964cf97b6c3a4077152db3c9c49635dd21f0dd2f4f3f1e0fcd741a758cdee0d43100441100431ac669debe16232c7300cc330ccdddd3d0cc3300c4319340cc330c4300cc330ecbaaeebbaae945b6badb5d6cbdddddd4f2e8c1be382b089f3cc546ccd94877b93fe48a6c7da4b5a82328ffe3e1f4e7f262626ad1700c2b8fbfceb3fc5b8539bfef38cd759e573fed7e8ed50beabb7bbeee71bde34c362b5633b9eb98a34e6cf2a220d2b3e791ef90f2e81a1bbbbbbbbbb7b383993263b50099b7e7628574bb92d5009cb10499c9b2fb26ce28aab0945a18c300c4330c8ee834b527f6f4f1ecdc99c21522013f70f44bf5f50d6da5a4dc3300cc330acd56ab55ad67235b5e5eeee9a8c2b736ab8eead568b0ee9aeebbaaeebaae1621886611846afebbaaeebfa4b55f9823e25cee3607450060e04db6ab55aad1b251e481c9a9a74974d9dc9d475260f238df95ec49ff028ba0f97046e0abb3ff6f3f1540c5473240e937e20f98b9049bc7f9b3227c51fdf8b384a1f5f017105f451a250d50d32e7f3f97886e880075a6e48814cdc494ea7fa5150a297673c55a5a0d8709d5e98b51d4a69ac663b1eabbaaeebbaaecb29a594524a29a594cab8374a1fdf0311c7e7e3b7c415d09ffe933128ffffc954ca7f121559d65a1c4f3bc698a577332e95287e3b941c3d99b17ddd2e5f5bc3347b25d6a155c33a1eaa8abb94291391c6fc4fa63c9039cc07658a7283ce1f5c02fd3cfdbfa6377de2f447b23b3a8bfe64cfe73ce33fabbc3623474f45e55ed48c7cc37b4eb908179477c3ab6893de538e9e27635bd3cbd3b939dff09f1b9eabe1569d2b6ab5e3c91169743370099472038abea8fb23dee07efe2542e230fdfc0b64ae60151b4a2669a3869c3745d38bd98b4a31e192ca09456ba74b29a594d279ba9f1d9f8851d0f82fdaa8fcff17593352fe8b2b6badb59abc39e3f0da27cb7d51b37b0d876b5576d3fbc9756bd7c534ec7ef2f5791c5e0587d7b2fba95aed78b6b7aa7803f4f32d13f1868c9f6f79207134a11fc87ffeef6f10e9cfa2e88b7295edd1c838e4e82a9ce953b2a673f4665c90e9e37f9d1defa90899c4cb0f24e5ffff23ed486355ae32b51a2e28476fd5960db7bb4454ee2592c38d5b88594428c4df9145b2b049552c1b4225fd7d09eb0439abbcf62a02b82a9555559be98e56ef6f1c67c2a5930a8a4eb9a80b76b4bba5a4bcc67d3e2a32a4b6e51c9146f737a4783297bfc842c9386757fb1cbd0ccad6c35d14fcb9df89443a47ef94a3f7c97153956ac3b8137525a492172fc2300cc31494aee47e2eb92627f74d6094eea3640d0305e5b5ff3fe5e8a5a098c08061ca269da26ba835586badb5b6d65a6bad18866118865dd7755dd765d25a860d324e334e38541c729665599665d65a6badadb5d65a2b866118866136aeebba2e199b0e6dc6cdbafba972738e9ea6dd40e3a26800d4b81a2563f6ea3c036546bc8938031840adb5d65a310cc3300c53c03c793bd2e87e46ee5e25771f6fb800a8715372f432000230809bf38c143de35166bc16809494d774d0a107b74b8f92a3a767aad65a6bad188661188645bbb348a37b53eec81cbac7f9ce53f72ab9fb19b9fb94dcbd2680fb0109e06aa06cb736800bca756b3a5c9da39792a397b1fd397a9a5f50beb6b6a2d9f0ad7311a62429b9082e49922e509ecadc3a17a15fbb713fab3c28cb9d731142a8c8ec4eceecee3f4b8323eb787a70fbf33947ef5372f41c04411004b32ccbb22cb3d65a6b6dadb5d65a2d263d66ca2df3d43dce1e9039745fca1d8834ba5749edee4f397af72839ba8ace1da594524a6dd8b061c3868d3d5fd3e182b2dc5d969be586116786355313059304f307175b6c21b2d8f0eb4665697048aaf9d5c9c659eeeeee6e63d3366cd828d978acbfa8853ddfd3655445555445551d08822008829b0ca981b86d0173b5ea6acb3353de722ebce52d6f79cb5b188661188681200882a0b536a2daa8946e961435ca14a211000000005317000028100a8643b2388f2439c30f14800b6986585e48320e8986c128c77115430629438000808080c8c8ccc40902ec7a292216d937b34ef0c70a37493035e0f43e2e40018f44d3f5482e11fcc385f7f69d1fa6b94bed491bf5eb5eff8779a09c1e7e8a00a2df7e2ab5d4142af5c927d1104537a6dc9ca603fb6c74b12ba059bfd434691e5963252fc06082ec6678e285e35a28af82e051596449a66690b76b829fa9fbcf713794c929f746f63004b71d40ba00e8ca77b496ace688909d60e925d4676860e861e860e90ef6222a9b8bce2d5652451211ac347d21389a2f15d488fa8bf53262502671b86ef2095f806fd74d1b552153b5239061b6017b21c49ad32219cc2015c945f812c3dd98125e91457835f2a2578d3c88f992b9d404b4e69b0e10c2f83bbe34c700f5a6fa781250936375127f6c6a58bf2e08fb933030fee1fdeaff8dafd442817010ee4030a048c80a9c558754b86b6aff8a3ac5653276c92f19959d7f34a03670304bb07d50185053c62fd0f80d918a397ca87f75b0e860d40f134fafd189e055f28ec60f2b55cba9a89b0239eadec2917a5496f9538243649bc92b1d5b1612952476f8f1f4a86fc6a5b553babc81027e8daf7f5d67cb2930621f02accbbe865fd7f9c2d9d8e49d1dd2a501351c77891e4737d7ac3a2c111e372e589376118443e31c2c82d2dc4473c8065feed7a879e300c55d25ee2a534aaf2e731fd7cacef4a8aa455440a45f7cc5b9ee12f26847f0967020102b226f7849901481415973f225580668925aaf2b64f4e00530a02cff5174c171a31b71da3b0b0509869c9d0eb69f56952888b4ee55db401e25d19c6add34e7874acd2185494855fe351db811e5e6468791d0a6694bfaf7e66d8e5422e152257ecf9cec96b0b0ce3593718bf0e7c047830ef2bed061af890ef4d9e8604f930eb90586117f6a90fe3483e8af3a88f31884d07238bc31cc578a5e7e407ee0d4e15c033b58e231dcedcd28d64397147932d96552eea0449c0939459f50a47b8d1dda4de859951552b450151d42280194b877bda42d4fe4136d31625a5221a928e353ff22def425d514e28b11dceac2297c46d59dcbf3b8faa2ec72d13d3de48d9925dfd2ac2ccb9c455918b107c00e67934df944153b058a19872700c4da617f463fbd082173aa888022e3d634b473b093288b115bdc34aa952a4f48e1bff993abf21d7b796ef74fe62b45cef810843b6a30337ba110cc60e88f95180aa6e9792531a6d612b7194aa942b4b08ca365f3ab896625d59e47bacd4f733e4d4900e2c693b865f953cf2a4f3511e1772308c1b265c65676cfdb7a17aabb3f61bbaedaf4149be03e5855f848d13c123f52dffe33381e9376eeb3b6e79fdc12e9e08da5af8f3c18a7f33ebc2fe9229110607a90b8c51934c591554512e897e9693661d6fad3d78a8b488ecd0b90ebe81ca3c4a7357fe29d197a7ff617722750ab95ceb666f18c4a0a8dbb60b1e94f0c87bc4b4a54ba84e2892f89024d0c31dd8c5b2992bd2bc857d0dabed4955eb376669a17e41749434cbc1037a45de18003fd48671eddc87546cbe8827e03a3ebbfd029679b68982f7d05b10f5cece3b73d02ec6b3a45390873fc77a2881e7870bff32c37f30aa873cbf8e924b5b88acb94bcbc5e939dd7b3387d51fc66898118cd01f53f61e8c923c32f857dc956ec12d8d06170d22e3378e6359af715beb4ef9cf0fa4aebe90b4488af9a98986961da75dd5bba37f52ee49e46146ada98080395d1bb40d1d4678e0efb932281f49f3e4862664cf7b52753aef77cd04769c395eb3161b2bc6fd6a7b99c9bc4447b53185a7c69d040a4016dcabecfeab77aa6d46bb1c70a4ec865c249c0379c1994af2af4e52870dac5a1f6030a506d54f07eccce1aa790d177fd96294364dfc6f089a2517d0d099cfc404424dcfad1ca6d48f2c000600097ffb98efc1de4a4fae0247154b1b6ca20b664903d5911c2faad50e38f863a147ac8e1486de7b90d3b04c00adfe7c3a2322b79b11e45a0528f90a7af7b2079aea573da3fb6eec81529cc30834ef07fd8c6c3cc7d7be28a72a201d0e156d6455cd22740448eadc93c8e1441681c5b92dde7a85860070a6258fe6b17b51d3602153f6e1273ba2d415bb8094d73511212298badb0f56f92929c1b4113d34509ede190b3dcc4a692fa882d6f959c80954cffac6924285f5c9a046ae93e21461764173d44fc1f7bb1eb991a321e072e661c2e089e1ab1a373e046031357c5e45ef8f4815ae05febe9de9d25a786ac638156e9797cef1a634683fa6e0a14e0079d5c3bcafccdec82f8b7bbebf16d3b9d296ef749ea7699076fb7f9ff7625c5e0ee66c21357438a742dfe1d05d683d7214ddc4bf05a0be874daa91dc3ba74eb74bb68eaa84c6c836c98c3ef508a2e3f30d47c81d8ca3602e160dbbee4d68574926bae692745984553f7dfd996fce83203fd370f38dd9aeac77c6db7835aee4a3b287d3a82c92a634f8ca98a27f1f759bf1a5e0f84cee5a0ed1ff77fadd1ba43eb38b3ce2f72b9e3dd630640c1b86ef30af9243616c340cacbc6a7f8d413495483aa1ca3feb2b731731d65a0b71f96d24bc856fb083f9296c3fe45756b1ac5188379d4a4d40d99f1d2066116ae4bc935a6fd890a281ac922bf261b340de064c6cd6fb8a2e31ba9347a832917deb04babe8f4a2901f5c994089d0413b7ce5800b08087bfc21042bd937f21c42ddb66e649a3476d81ac481fe069596ceb67d3dbfaf7b141f94451f9b08558701afd657df7a3fb722e55888eaf69eb4dfba4875233b8061161fc62f84bccd4bd2cd68d0a72ced77bc523852b7d11904a5c250da184c0cf079e287f6dd1161fb065940bd3e28db427cd56bec4cd6ca96ac566771ca9d47b9c3a75f87ce73d7711790a77847978407204c35f4824b066482d94c7950a69b24350ae2116f7ffb63494ccaac71c4711bfbfb54db010e8e140b2456fa258024a639f1bbef0cfea22d84683987c0a504d80aa166abb9dafcb118dc3f5145373e4dbc1d2f5dbeee1a2ea6af0713f1b134261e29750c34a5fa67543ac704fa6090ad9eb03453f6d29ca32842d9832083d3a9453690d58a020c0d03fc99121423ecc03807d40a4ffc57317a0e708ea200a1a5ab427569e980147f8f6d71764ebbf42ad3695fa692e0268951cac9f818ca7d3d92e36253be33b4b32a4fe92241a80cbc392c65b3f8b32778d3d4270196a4e61ca6e17f7625fbbe79fb8da6a00bf9b3aa810842dc0dfcb66800c2fb63e7325ca6ac0344d3d6f17fdd7530d77f1d28d0c38e23cc83710c79477a473e63c0ea830f83eb3555ad492be11a147229c7f010045e8cc4205994f72220d583e62bfdc3412bb15e130f78b2a8ffc3e6e5f8dab9dbd30e4d5f150880382d2c2c41fe492f987d50179257d219790fcd684b0eba3aa1e083adfebea69cb827f093a0edb8790894b12635882d44d49825851a2e399ab576a3644de18b4fb197f701bb796fd03062a1a1538844f86c620d6fec25b81d8d04137446308b92fe7b5d318c2b963387c6771038dae56efce5d081ee892c5ce94448989c884ee0262283dd4b99d586681e40b09c73e79697b9c04a1002a78ad5b8a539fc888722ae62b9e7a9b2c7a3fe3e78fb0b8e99c3c1ab5cf10ee10c5ed63e0c4016bc87ff3c392ff932676d8688eb174c2a2b861ce157d02ed661f7bb487d928e41dba907e7ca785c8c2224e3947d2a0122f16e821f77b8c78e7213c7af86a8dc94607d75aa5eefc01a0f254d1c63ccba140ee7f53fc2f01a4cb13f353f4f752ea7888f050d0cf9b11f0cacb2ab977ccef2aa2c993a589c25d153725c1814a7d5b8ae5185b59a152513f07dff094abf8c69002d7b5c0e6f2f8c45fcb766e3576105d31f4e2de4aad483404247ccd8d84e9fc74e214d8ba270a66d499fd34995eb11c6899e1e00f0f079ab990a5ddb78902d8d0845a1dfd975c6d2ba9dad95a71b4b5cc8ab14066f1028f854beef06a110ecf29ccf8f7033e5e903bef6f037146992b9b7c542cd00769e8392a6736cf991552129c21d9faeb0415a87352bc0742e47873d5c4dccfba484218836dc49325dc1931c28176375a92c73c2c41ecfc976db1255dba1e53a91741d94b0519e14eed1fe41ac187ea7b06b7c3947ce9362bf3f05e485b6d77c60b292f43d49d6921732544fdd675cebd3e31e3cb6174d09162073f5cd2cf1a46f1d1a726015a1fe59ef31882bfebcc4a37f554f007c1e48e15548ec527d6045b2fc002b95ff0599a3f1a474fdbc3f958046f603c5568559de557787107aea45d53dde4de7c4b9a009f4f454c6a6bd15fc9049cd395c43c240cf18a49cf446c9b5cc7df6108166d9dc3e30ec261fffcee449b2c8964c5c27de690694b7144099f94aa8b061354eaf400ef14ae6d2ae484ef75d4413fc080e6214d11501d940fcc3b572e3660344d717e28fd69bb4cf4ae3387b95d495960a6d105719cef6966fa55cd2cd41a4ddbe823891d606e39f3088699893d1f11d23d3aa644c8eeee8462da370cf4b5cbe0dc9b592674b7ac489ac474cc48e3ee8ac03e71c505cbbb204d1d4a0ca67381e2da4705de96cc2a21ae0c3b52316576cf7a4b4b9a443f985637a9ba88acea962e0c3efab0420cc56c9e501ab12a6584a9504cf389558081546360f687e3cb7e1c28400bd0b17dfba721de231fb873a46ad10818545a59a04f58854fa8287e486bcb7ccdec9fd45e4898ee2f048b25ecec7916fef910c139bf0c501346ae40502ae5b218e5db58b81f98faf6cdf77dfd8ebd51d9cdee8bd4e25313ce0a1bcac63ac60291cd2dbe430ebdb4200116f6782ed32025bf51b8b774c2027527fbf5d3ab15142fc63849daccc0a9b34d27971a6b71115413ff2d5f017f02db57db88f3fc6151cdfe7839544dd44e27865f0876c4bd4f3003fc5265cbd2e81ed8f8e480b611de5553d24d8e5b83bd2bceba353acb1adf93e76c5360de91ef000fb77958280f31e19f8fb42c143951cdc91c01bebe83c3a4c0fdcb43aa63c08abd644b320fe515e60592dc886fc01f0b887b65926c4dbf6a2332db222460fd324a46b1cf62dacb697322e340cd2b39a360bd0517d570a335cdacace168f5682dec53eb1d6292faf3f70cd6ab51f652b9b8dd34712b8970d81ed407ed6626fdc943b890eb085e32a2b38219bd8b9dbf3c0abadc3ef642451340a97aed999c1d9496fae05735b07490f00e9b843a6bdaa73d01e528a84b402ca9e255fb876c5d29801b16da8c24778d465ca45640b954a8363dc8445553932a2ac7fdbe43f5aa9b0a42dd129fecdbf89abf43dfdfb7e1ffcd526757f0b76f08fb00b948c66e56db93b1a6b8886fe6fc73f3977b181cbc68eb6c9b05ac41a088aa7ccf6a34c31c13a769941c68d10c77a7348680459951d2dca0801d08156c7d36ea3497682cbad6e51526d9ffb78191cad2146bec5f026e38fb754464160032ed4376eecd9d8115f0eb08dc81db697e159739b8402ec10c1f6646dcf703c66bf9e6bed10c78fc201c61cb3f6ea9785192f178e590f0006872cabd01ce96c70a030c070361c0e281c6137b63f3a4c5548e7921ee970244b3af10f938ede8fd2a1b9d68d2b4052b8962824c4fb6d29322f6807e5a6e78cf3b29e0f3c0d276197331de70ed88667be4128da8d62a07b09ecafcc0010967fcc2c10471cc6d48080a40ea1071446447fb83c43c891affc5498fd1119d5ebe50678dc982ee88f9b21e2a849dbf2964891367642a295470c770828f1bf2bb15dbd2974fa19d91fce19ccbb470c38273e8cbb5201d166ea4d22260b5d5862eaea22b60df2df0b24178952215b9bad9fd29de4598bbef0bef4c56752b393687da8d8e20f9c510c32cf1b10a537e24dc69480fd34661e6ee43e6225c37dfc8847a745a8431dc2166210ab07fc10e1f1f09f1ef881bc5bff2cf74c811cd0524f6a0f91892c9fde5e92bc33767662e285daf829ac88caa325fe71ad6c101b6549201cc8665403d94030c06c56f58499dd7647a8593238d236868b6b93b3199f2716c9cff87641157b3139cb88f72391357cd8418963a592502982f51fbd5eda0d89339b3a9d0238a9cf2a2172df03b616531490d820e4ea38f6a24342ca014d09f939ff8caa04bea9e74139cb174d4499e471cfa985dce45651870d1a555590cd911d96986dbc40794ed56fc1edb33fc50c29f35352138dadf42f54dce4c179828723efa87b788c797de74833778bc5d16e0034e7f2f498a56d64fe41821981e09b8051a559aa36be174aa34a18ce08eede665b559f8c7bc54cfa50f41f527be3f8aa7e84e88fa2de14eb91a802eab3ae77d955770dd2ef12cf4512498b98878e5f9396040ee1d6d6c335f68343f10899556b1c60a03f387e26e947c2b7fdb91985f946185cbd82e763c38db0609e49086f199c53fb2cf0dd2a8213c4a9b339c3936780d6167f3095713663869104110ed00eb6186897908bc3209cde38cb3e20523065612e368383fe9b972d43fc362833b3e2a008b5556b7c48736f275f6d0ef6097bdcd9dfe5da9b9fc7bc68dbcc484fdc7c6323fb0354b4cb7d89be2424dc3e90eb7664f435f897b511f63f9a307a9f86addff2130e3a28c1d47ef78d45e2f58968a8580afcf056c0bb0909966feba0527099c38184521cbf03324494ebb4bae39e7d4632846774d538da3ca3064f54ef6f54aab597674e643b1b7ab6fe68c606ac435addac0789e78d277f40dad76ab67729e5d088b906e204fdc97fc3a013d27490c6f43435966fe35c85c202d8aa202df180319facb00ebd233668b33c57f7128e2ddacd0a88254091e2b5d0db122192279332ac77bc438ec65c34c3848fa2a55b28265d349a7a16a98b403ac08c8b06bdb127cf6305118a2d749a28ff29c398b73b3281a93db4dc0a2c87824c885221e9f285beaf7e708aab207c5cdb6c73883318b06b2e4a09df9fd2184a056bd4a4cccb9419365bd2894dbe4a244f6c9a408191ba0bd6822abe564dd3b70fbea1fba2ae7349ecd7f9164ca0fdcd24b2a3581728fdd661efe8d68dcf3693c7ad56a7591ebee5e839588c9962bec7a25a9c30e71159c419c552b10009c45042b8134c717af00ae7bcb2624ae5846bf77849334f5fe4a5388d45b2542bbbd285ebb63091c11e6801f54b606eccd111b68b7e69cc1aa45044b37bbfcbc27c406f54573fa97df0a287b4bb30c22323c1e0c3e1145366fa6c63f9d7abaff603ad223b04b3fe582b818f52f59ad84631835d580409303ce4d507f0688901b3967492284f1548a346d0a9e35bceadd40a9be0f2f23edadb8dbd67de0cc99eba6ae6858455d91682650eae87494c872265a84a71dfbd87abfe1c8d2cb890cd21dcc858407b81d94eff9a292c3d603c3097432ac3ce71737a958bcc8d4338c43b1fc9e2c9f6c79370fde21d30059543995469ecb59252f80f7b6a5af2e9e28ace36f4243980fab113f62182c12801b2100f1f5eaa2add43c37bfa3d4458675b16b1e01e0f7236e1494ed94c12ec17bb9f8fbc047c204ad36c23a1816e86fcf80c8ba82d155572853310323f92f1f43e6475b8edc06c7d452c28496d1fccc327c73468c0d3aee12109e64441aaa591015286a38adccec9898d9fa278cda50c6692c1cedd5270c75a94b17e29a878fa0ec4dea036a17a30945941aa4328c501679a6a3a0a642ec46d5fbc84d98417d88c04d121cd8ed9cd32f4e8dc14059533a13ef20545ac16a9195dbcc32fcff8b926f009ec6c9e96fcd9fd21da99549be6b599b9a91eb9b4488f2e8471388a45aecbda1240b7ec9dce6a39e25d9d97f57014a6895cee1b0f6db888e7fc35189c822e57a1f81a7d4e49d11f1d931651306fa74821f0202da220403e4e62b02eae9ee758bbe8e57b604e72d6d3f9a0c8bda7287af47f29ac3af5eccd81fdf0b7468c10ed6042178a0426b203a1fbc7f908198092acd25a857d00bfe466fb251e6e72ea7dadafd87d188ccf3906acb0886074cb0579c1e14359ec8e2e5d53eecd1b8a1423948409044d7b60f6d1eff56ca1cf6fe28fc61a6a7f928649a50349e96f30c21723a4784c8e29a2361cb249318e1363bd28549b7af41d2dd9fe63d337f4f5ef4a7c08bebe449d7869e0c7714415853238652ae81876d4a964d03fd290f8333c8478c85ffe6a7a60b36885f59d8cfb1121c9cf4c95103523cad763bab3de4fdab5f4337d521c06a761f4422321c4717324c4f26ef538c1d26f1030d57b35c071e1c350c960ad8c80b36c9b2cb96a0004eaaa77d181ee955cacc5ebdc832372ed2d68a68ac9e66ffe0ec21e76d82f9f2e4fde41a3329e0270824cbd1cfcf70a2a88862d78344bfc4792ae9603454a2887df3c8e5ac9d913f8edd23fa44c2e55380015009cd96b26336b36d47423299f2705b77aa964b664c91ac15826770dffe36eb18c5d71e4c389ee20a02b512b1400c9e789f964d9940a68e56e27e4a526b2b136c8561f3d3b6925412bf36bd2d82455625929a3aed8c8ca89782235f4bceff25fb194bd37210e4bd87e981bb6233b4a0e3b29ee66b294abcf8fdc4a6589ef672b93de26c5c295bc184ee6ff1a2440fac593000a2e22e1323d7d4a2b2cfdd597f1c258b59c581729fd93e5ed13f84dccaf6f1537993f7cd85546e88f0d307f7df147d8aa040bf6f1adccd21e4c46581d916ae2d52178967dc7f901ca6267e394e6f762a5964dae4a12fee64284abe2676aa183a3fc51c1fbfbfe203010d19762977acb89c2852c6e8a0ba8f4fdd44ccfd6dc4aa90a9b555d830d0896e16340a7027033207e076808528a05d80a2f7305801cedb1f624f58f5e079efb5207264a909710054e78104319a6a5b254f24f900cd2929e62a8459718c8043a2e4d4954ec68586ad4cbcb61932fa452b626147149cc059187e937b51d1b3b0a0a750a40aec2d7be421f6681c34cb98ebdbc4537ffb2d127b2f7bc8e7e9172b308c5a69c03d9cef77d10ab1f5364112e732d78dde274c95cc37d818b11537ab01b01d9842e217a63a3646434cb2c8f8c7d6ba52cf6166c25efa521daf83beb4746be0fce737e4d0440fa66e0ab4900506e370ee4e122a197add318e24a0cd00b705b32d1906af99826d372ececc193c5584d8c6fdf52be80888dfb4faab749dfc3a8b6c8bd8a14ea544e16af850a2249174a45497b6135ca4645ca5933dd9e12395ea723fc4f63681a6bf6fe086a475d7ecba742de48e9c978d396cf0131f7996f242684e1e549c467a9794a8a3c2181d3caad1b3d4be1f0fe1d577c649e9d6d86426397ff38ea95d3d895973cf52769ed56234ffd209a66c220ca9be353c3cfd0c3c16012943e5bce216ba4c7699ab589a2b55c5c6b87b4359b95bbffd3239ff40491b06f65581a432c070eb06c9ae66ac36ae3fc9f2f56f31ff81d3dc8ca7c4066f11bffc4f05619923675156d3567ea6baff39d35dc54e911e225f67405b9e5d43ec0afb4022939be3a54a004618545b1cbdaad43316930c65e84c89e27342c0dceae51c9c3a6ca786c2686879d1452e2780b400054e63fd0d001b99420085bce200f50ef073c1f432c79647acf2074a031dd314a4b264aa98706536eac1091e5ce02b369652485a8a9235aa72ed705982c4a8fd8a2acc72e32be7dd1f2491865758d11646a1874f034b335ba921d3fe487eeb1e207e5e764297e3c778eb0e287cccd7d297e10674ec622d2090cfca680c066a749fb7349020d46c8ed721f283726bb1372156b666cec43b1e669913f12071c3eac272ccd6b9a61194aae10cb2589aff4772841cdb8964843e32036f36b15b49e844102227b1e86a5cc37a18bc686f81f1d37b65c5dbe1e15373a474d4c8da7c637cd021e57ca00c1bce901e56e49cad30322ce96458e593235ec892ea7b0aafd2c1412134fc88fc17b00f0d1cacfd045316acc5c164fa0faf50ce5afbea52f47299684fe02b8fba1216ea9672bc282e5b2514338bb76de7446c5115588189d649f6e1df777cebf08ec954aca95ee7506c0169d9bc224a77084fa93d8685e077b89c60937057926b829ecfd969ad96db7c4b634706658a955f3a81229d231cd5b3ad2990d09261d9398f655021729bd705bb9a06ee11213aa395800bc60be668a8d04c943e09336d099f038a72913a50c1602eefe9557c84d83442b8c600923b01c5be236737352eb6debe7f02ab85344c75a71734d27adc96d591d6eccbd8843330146eaba4e041496d0408cd59095431715c518d885470233a4683467235ef04967fab492192f78956b7af641a1d6b694377d9ba814cb2d678424290f47d60d2909bb9ce24f312d395909ff3f42a5749514a068d295a1994b7722fe085236a0e12f8e5a4c4630616e61a4e0696c066277a9ed2d008fa5ce5c9d33c59c49280fc7a06b52b3d40e3971508a5207e6a446739e05173dedbf392eef769c20a3607b3c60b8c5cea0dc3fce7f7fdb84c713b42667c38eb89a13d56bbc2559a395997be1ef8cfef716265b0b9e311ee1327c2109bac4c4df06b59118a27768169a86dfde4f7d34cbfc0538d5e1a61014ead2a23c65cb42a29f25a9f8da94b945aadde7bd2d8a50ca4ba966af282923edf70b01056a9318af343275a9496ab04283220897e28c7859d1afb2622f2b3d018d69bd42563c83b35e088f335aec8514688671f996bd6296c28c1c5321899611781472eefbc0aac08f0e122a4761406ec99e2c94218a749665df14c9206aea886ab8e549d57b6f50ebfa8cda8f627989ec72118fcbaccb9ea5521db685baccaee058306cf32ab618d71369219d49ec221511ead929a52a2627a7f0c8f62bd2e7bde3f20817751492d02ebc5bdefdc9e3dd9d3a9d3d89bf8d3ea5064a0c9f52f669ce84f70cba9879ba1968777eddf33a19e0cfe9ede41e0a19a1958ab83773e25c09d166b6c295506be65ae6c19166b6220f05178855032fbaca488644398c094bcf45d93c9720c9a6bf0449012de955475a704a900ca4878e2aaa4597144a1095e599ba60995bcec351e4469e80635c6ebd781f997b8b58eb3abcb8b032337e904404a25e80bec4386c18c55b6303ebeb324d9549902d6b2ab170f4f3d97a1a7ab7981751ae31f8d5c5428471a43e0d77dcf160ca8464f44af436f3b60ffa4e69efe47502bb01408825983f711580ae7645f7eb3a55414f39e28b8483c24811b9a34302a5284ad2b8b2198edaca71889324fbcc910c51434f29aa46878065102ded4f29a3cc383d578eaad516da120f60e751ebeac48b8d193728dab0de53de919c4f938a1b07e78e11fd720535409f30236e6df3d146c9fd11638a9d9a3ca9dcb3897bd28160f23b96464b120c3d5098b23061cdeda15eef8ea489da4e0b4af38f29a605408515d9b04c9a6d29e0b98185c472e481ffd3a52c26ec9de3794abbd36d66f3947004b50f050a6bc6c366b13e8433f03380a30c502162133672b719c807d36a78eb83ebac609273f8c42850ce19421f7f6a69f95315e9017f303ed81fb82f81e3b318a1bdbf3c660ce0f2933d2e390ac41ec39f9dd69f4a0a5a69140cf00b996182c1caa4db8c6f438a14bfbf64b53adeec4cf0c8a26bc9aa72c1d4f7dc6eb8c42faf3e118459c47d14b40c9c9d7d40b4ae46071694dbb1e99a89d231424db4113fae302e8d0cf7bbba71867e187fde72b707e520fc789ff7b6a17e914d09429c3a0e7ddf180b93fb47e52a2e3eec30d4b020410842b7a37d9c8e19aa13362b5d585c87ef8570f05ed89cacc3567b27f7640a4606847a892efa08bad221b9e83ab58c0eebbd726b6938872986523b59b74b2846d2b9335295e285614060569bcde6bf5494adbb59c472f7a4524b4aaedc8ef7e2b5dae5102a4d9201786d0974b08472a814fc904344379ee20903e69fd6a8d7ff29f229125539acaac5f299ccaa9a54aa1017ed24bb215e40860d166e1ce5f331fbabf846e4611cf5710790181992d0d8202a36cda1fbb21936f33a35d352db9789e64cccfd59bf4ada442af3b4c57abbf5e66af62cae2984fdafc7294c4760ac47e56c8d481e5f9fe1cd04b03b9a7fa5c59ad17676b48514d240a7371ca93f3d13404b8c864287cf50fae9e182bab304eb9ad6d0f54b65199bd005f4a8e67a37073af5f10553a4003261d88610661ac8a722ef05b107bcdc63aae2b852ee0ff862567e9187a2c553b47949a5ba6ae53788bb1b89fb18e8877141659c3ad3d25758b1dc58bee1c3b6259440fc556f852a5cf9480d2c06015a8fb70e8b6c6fdbac07b4d5b67b47393864e6bab6a7a9de1a689d698164815c10f6b3a386ab5f0258a262a0415ea68037db7deb0c7068fc7b33edb3f50d3a2f7b760a335e9eb16dc3e283a9b4b4f4fa531252439ad2ce7761089f6a59fe16533cfce98aefbc4df83fc61cdca2e2c5ac4fb3dfb813593b35d6eb49f37138f81be1a26051b72b320d61f067f13f88d06df8c6b0c32607e128e89e28435bf8a09a2c5891257db05616c9a287e3135c438e7f435f761e4d470dc43f2b99263790163b6138707326ccc81d0183ead630522de0f30d1c23d7d13dc8c8d8552241e699a740b9a269a942ea102ed05c93abe145b44ff1f2c337855d3664904fe77c3a60068d76a8d6f1539e4e38983316ca4e3b1c40d22180c903c4f241be3a9eba14be6fb2e917894301f0f82b9352e9d2ac10e6873fa18190b5d016f63f5753c9bde70da00e84a2e04dd14487d4414d348f3d0740511d8425dad644a5816ab0797cd7d0d0ad4114dcada96f2bd5044d0fba9d28295fe232b19e8139767ad4fc17acb58cfc2700b6a20eb17fdc9746cd37cce60910e2399c3c3bf761cde1ec1d61087ef3f1c143d011a36f112c55ff1d17d12ab6fdcac4e36fc6fd08fe8eba1133ebfe64b501c6974e79b19ad1d7a517d3e385d2529a4ee912f0485d41cdad884be8f4736b0ec23226d9b26845a8b05de7efed9dd079f8ff0eb23acb80e14bf36b84bd6e956955c5c821b7b4577773c27282dd158e728b4812b7c16be050d736ef5d081124530ad1545475bc0fba7cb27dfc9a71d6e03d172d52aa1be0389b36921f3e36054b3571e57f73e22dfb088887ae019b89d3778ab0907fb3a3108d1d4e63521f746cc0945749e712c5d7e514b6d9b43681cd459484a4746c715608e1119b83549fa754c193308f450a0eef8b4bd83717a9ab861b2073e0634560b768deadfdc69a06632f3f6c6d51d0c222276b0aac9b656e7353de2a033da3b0a95ac92a99aa3b05e7849775529757691dba208a589b25b63443ac6f0fa48bb8e5fec2082a4311cd828dfba440da2f9cf141fdfe0685b0ae37a127e7508282d67bf1e89720985050a3753611f7669e2a976791538db803444bb9461ed18e892825f497eccee70628839964022856f44490c73c18163311e58e1a0dbce731f234154876d02e56d2057abee794bbad1a3ebb2d57be2d40dff95c30f7091c5491226ca5c8b6e6600a22dbb69fdf452d3be4eb5baee02880d9e644add2c76fa6a3e9c9e5fad4602c8d9c305909b91603351487973ddbe86676177a8f6f610b61a9ea5ad7711020f5965264f10dcd973eac6af98fb80aa2666c37f3c5f3723d613207a066087b134965e5136ff12bc8673cd57b8ac1a177230356f05582132da5040b75dc57a828dce26926f742f124fe53477bf4c5253b132414a22c2c04d4434b243e2fbadbc52f46d30feee6b13d7e0d859c405bdf24c3b8aff304824d59a780ea4dac27724c962eb61d8c48da43326e0a5e99d43dca6c22bf0308d5de3d06d81f19475e70d047abe4fe002426586bb6c0612061cfb5d76c4c7645662aaa7889e28258ea58e28ae5751a8766d73278449e472e79318676668a7ee39e3028a59f4309e76adb7ad47a50e9b04d3005e9e546f78f1165a12deb570f61dd7d2cc88737883e22c84e1429c5a5b7df1f6cc49d0fe3e0a33d0ff011232c3affa8f492624960b1f680f5b38362e026f2facfc2f1749a8944d5e789e3b6ecd161aaf76445897484eb2601431ca147c928e5113b84f2db602c61592c32f82591b1891587993b7c75ac02c400ba2498a6d91ac6c2f22d30d8b8f70a4b14575eaf41debc8c40d5b519813f292966167b90ccc8556ed370ea496b1099224396c1c18b4f6c1aab71fb8226c37949396d6db0acff7c86df0b2c7fe6c265c683f234750ba696ac9ee05491b34a91ecddff8f73984b9e879330c2d0d918d91c46188bfdb3c9429d97e6cd2bbb2cef93f0938f7471dbd8c53fec6ddfbc3b229d5b38d71e1f5b4a82c45a5121218eac026fbafcd0baa32e3755bdfa1a79941935e1054baefb04881c2caa6ddfa59feba253462245c77a09856c1f9f78a3b9c608fa09aa792133d4803bcd74b47bacecd129c2b9171bcb9b6612531cbf5e27bf12b10e03ea23d1aba92f832c52abd07c9402bc2c0e77e0de71e8e3bac20632c23ab492183a9fc51567dbcba171ff37234045d5e981255ef23bce8daebdccf0466cffff3101e4f7745fe434fb87257711f138ddc6280d21de18971327b5e4549c211157d22c30b52718de675a862f0521d81fa5b2842576ec12b7f2c1abc070e042bd32187a2f1a42d313fa228829f42c9d3269c32aaa57d83e5ce9088b09f50e1f2c1633f494395f510d15fdac435b587d9fc37183385dad9015e18cf266683a87d319e01e569f72ecc1db51fce47213e171018cd6e584bacfd00057d28242d0be42fea03350acf413ad4150e5c34a1a00701d5434f3736f74e903a5e97f749524c500f1e6661a916c63d95c2d95d91d8025cca1c81a4fbe16d3596d9098156847e8edf8b263fd95cf68dbc79af06bbec2b9ce0c22256ea28f983140882383848b4d8acff719e4241362f55305413e29423814622bf8d1db6f2c6ef5814f9a9b2463747d4da066952c97b52e94bd75f37a48ceb9303df919e29a1cf5b000fb088e9fa541cd5a3c9c9b9f0e97f7c13d41f3f05ad122fb46cfdf902b890313955a319ed8deb0e30c846a01617b2a7bf4d2f4671edd295507c8d05475681c23d70619d4042c78f983bce002dd1712aacd1a360e134fe0d11ec846cb9b1eb1903e9026d44e1a956de33f1cc6573671b9c66051eab5a76e3bbebd7954e44afdb79dd2af4f76125cc8fc4a401b942e60c5802f4e9f089a2e5f38e51f06259b4a33851eb9bbea5b9d64a705a4e3c7c084cfabf72da7e4fd8bc55e737b394f745c8f4eba29c24c4dc92965fdbfc7dad8948edafd553426b3143dfce62791530a7aa981505c0d49d5726f91eb7e754598a41a632e89c54f543a2776d426e6c7d9c6977fb48db1a56b38ffe9aebf1d8c4639b2ed94313df47881d3d5ab9caa2bf206c227ddcf43fce02fa8bd53af45d0044581a713122324317b45c47b7c3f2adfa195dc5d3c6fa80ee7b16ea67b76938a253fe94ef14510864cdb538c5fb6491fdba42d82dd2dc2de7f19dc8d6e6311154e80f27a7301e53c754dfad417c880b5f236eefe8a124bdc19e25469a87dcbd404efd8148063171cb39e4368e6b7628a63c2c61297d299d57962e3118610b0e3628d35133f6451f3559796f8c2727d13a63bb8b915a93b10c9e2c69899637703888ce939657ca3ac20e30536d73067f45b781f62f7d358e4af41a1b1ef139a4fc276554aa30ec27cc960039bb632ea30e26c1644356c569af394440dc1718367d4930d207b7e488e60dde1a2c8035ff621368625fa4f208711027e8120e083fd7bf7661995c60bbbc4970fe38a65edf5271053e221194087ab64952057506ce86dcea6fee1745d1aefea166dcebd2459d83498ee71bec665d0f36157488dd6d3af237644d9d25272285775abb87c82cec77bd605c02ad7874c4f4d897fb4475959146e1b53d2dc106396ed718ea5371707072018dab3d836d37b9644be0d9d347b6e34acdf0ff84dd240ed38f09d57109a35f0157173d5dbe64247a8fcef8e6fcb6074794688c223acfe5037ea3830818f7f946d6c511448d4c7d96370c02a9cdfdb2edbe88e0a5ad232885f29ecfa741e6065a9983395212c3daddad2d1b50d1639a987113293cd6c7e066fd3dc384a706179861ce8059697df18a3246b6138a6ba006dcd1ff4589e331c348e9314ce7196b1cec67b694a2f00961d434bd6ffd31cf4ea55a3968aa1cf7a4f2305e6a939f0b1b8c3c1057de56e40b7378b0a8da8f016d775d46bd4f04d0b437f5df8840ac5cee3bd624ca97d9e6f8fa469562e568183d0de685b4a0fcf7741299a8971a418fc323a5a240e14f020850a2afac2d966074daee9f1b7104eca0a0ef344bb3d2183bc2ce693a81a9acb804498b1dc8469df25199132d62825b91265a9d353eafaaeb2ae30a626d153cada29c344fce52d44e766636dbf0bcacd2c4b9ae6f31e37784320ba3fb7e2ae6f9fc1584473947080a4a16c9edd6c5bf1d4dac1194a89ccd6590da35d8b77255374374bb03b4b67aa9892cef64ea41e65e098758cb45c16e7a4d529026a12a65a8538779622e9ab1a6491b76969446c9808a17c836dfe018ebe6f0417f55fd67d6f562aac286b9d1810db0bb06df95559a6216d4739f68b47e36dacc549ecf364c465d63e0327e9cc2fa545630594391ddb716ea91b7d29eb64482e5c7b9f173bd2c917fee0b422ab818b07b7772b0cad4c7863ebe7b0d8f8db3a4b53a09ddc20907a8c6079f734e0ecbfaf2c9e6430bb30fc0d9ced86c6036ac50f4b15011142519908867d82b0a0242d2c01c683d0bfa071e18e27b4ad80c085a500f27a595b9c3614a709550807193c055a135d28f4ca2bbc74ab2032785f5f30ee3bd6e2c45b58a171dcb48a622e91c06e49b996b524a3d8805fb4b5d1df6f3e7cdbfd0f0641a5023d01919a4d4ccb8a593dbe86d481a0b65c11306570ceea9de879f85cbc48a0b3a2d609c72671033e0906428c56a941a691ea7b050f8cbf4544cc3f61fb65663025aa9d77015f290cf5cc0b4a971203d5176a95ac17b7eafaddbf350d1aed26cf3162fd2e718d11cd2af2d613c6882c390c40147f194506a8aa8619bc61c9f07088823711eceee155133f25f175e7c7a680be75c4883372588f0b08b09e8e0ca0c2889c46f89a16114913c6b8339b306fbe43f701208c576987cb1e760a5e81b549c43c4ae79e5be1077506e9ca0040dcebab656b1f5fa5b94dc450c2a72914af2f07b7fe0bd16a666ff480fac5166e35cb86fcb0119cf11ee23ac1d1645c1df32815d136b1a3217689bf4a58c805ba033874c4ad84283ab0ddd2693eef96462dd902a94826ea4097f61972dbc08d57c4e843b941749250a20b069df99dde32dacb1bd7bef7899b1e1cfae9ff130f59c140913ab9391539f409c0a6af1332dace4e48a7f00c113aceb50aa78991aee989b711253add09a13a43eb5c1fa52bffb7a9def60fbad8e0859b70296682eeec2c4421f990bacf05fa0538d5848818990d20eb3a6185cd971c221870a8ea71124e14e057e3a346cc17f0ac8187aaff97f4443cc398934ed2fd59faf8e8df11d02e48abf77566d72defea17ac10d910b03676c56e18d09938338aba8d9996bf3e0a2594846703850b8eaf715030cbb25405fa74aaf030676e81fd858c32c8e653c2b77d78c5a567bee016e26dd166a75454cc03ebe97c199f267ece51ac69ac9024183ba0c701d569ae9987d7f2f5be9140ea92f491d2f6056c0e4a5d2b1bd683c14d12b819eae547024f925146fe6681cf767686eedd8e42fdc71009b9987c9dc1a1c556b7c85689f253682143f0a6cc908861f10b2a2668e3a81c49c9bd944e23429f639db15e918a4fa93fbfa59005e38badf10ce47d1106ca978ab779841e78c4d267296bd7ab5e04a133e92b43c3685aead8c944502c67c00420b1d2d01e30fbf64bdc1d21fac30f40ed8019b823468ebc463f9a298047bd3c93e5ba417614dfbbbbc3e7483f012cbf886bde1bc3bf2df3bc8ba05857c0af00b2602cb7a3f07a385faa5180892fde8123891deb7e3c5ccf7c9efe0a55bbda82a944151c319aac45e4cf6c0ef1875f008f6dcc8616d8e23e891f1e21f7e67d3c54009925c590fc4e04005d3b02430b9487220d71e02a04e4eb7e84cff15608679d233e3c4a10c785d3694198fdea34c78eb189c1930c9b2b6c70a828a367fb9cfdee343eb745c29c3057a1d0831c39ee03903767541948e9dccf7a6677f1a123104b9e50d948f69f4775529882b8c3235ecb8ddfc37f32dd7cb34c62e643cbf739b766103a45ada3cd2a66b5c9a1c5063626a4f231bae2c6dd90f4390b91469470ce7ae16c5956bbfab3b4406d0d5dda81c566b8cfbbd13d1c7a83561f2bf0ea66db82e5c3ba21b3cdd5ba24560983594aff86692cca17959a5756d2ddfa382f30e0d229548c721ea6a8c6ffbc4059270054b675a4b9c1809c7db54228a8f431fac587958d277e05ccab6a39169ea1c36665ce444e1b88391f178c3c68b4237b524e0e44d46101dd83da8043264044b810a1232779a7901f1ea0cf717b607de9a4b074cf52b5ed6488a7df5719a2e2c11663692e4332ae6541a970b13007ab392a5731c297c07b5e0b1b6ca4f92fb75356e8f7ba223f7e55c6ad09fe1ea31c23c41aa9e9c2ea3d40148bb50e85e05262d75b4873a0e061dccbbc2c177909f9e6455abd89652ac4e44f0438702181ef25e554c8f1fb16034013a77c3a67995b390e99bb9a91c0e0abe14d6894f894479e18dc6eef03c3a2b615f95887ff275ef8835d63d8f767558997701ea116188ef81a5ca97ab116f569ca9c53bd597847f198a5a3d078c99aceda7b29b535191af995da6ef9c30f33da3ec9452fdbb36734a9e7bc5bce186665768e4ce35644e062f47e63441d010fa6c002da87fa27076b0e91fa1f498f59305836b30f50a7a8d5f5138369b549770a02bae10b2179a36b676330b649a829856e000be938653c4bb86fc37374983929856cf300afa740475a7884c19bd6c40c84369558fcc1a010d9276f0cba37ac2b00063b308aba822e019d3f1db85e1dde1792e3daa6706c16c7e74b03cd2af8df53c4db2aa1ad99cd136846ef33183222ecd1ebc6de24c472036c2d217e88495b3c703ada54a021a2e9eddd4a4bf6d27b027099b869b8ae46743f07d1838c48508d2d8be6735a9ab0f105a40acc3901bd917b8acfa1d570f7e30859e1d4fda0ff531992c0b2bd6a7c31244ff11dc3dfccb4cf324cabded7f34a8447ead15d47476953aa38ff96ebebf76d612a323e002d9d4a12ccfc014d4006fbcbb9bb11184e18209a28691f357a19c48d72c63a0a6cd223f125d101ea1fddf92fdb9d107bd468706227526fb91c22902f8bda86e3573220d3f7d40110d8f74f132fa154b8286421aeec02dc54b421948cede215ea709efa60aa88f1b437771d05cd4e370d44d63ce679c8050637704f4e448bc80ee32c01a588449e9583c3f0f75f7b600c7eec665a11f7620576b8c380d843c31a1be3653b54a07fdbda685e7e97e134adf56e36bb2b079e263139652eb0305d2beea732995185fbd90b10e2e547525c612897f0fc3f426b09d9106527af7a0d1674f224d5ae16653553956e6c2175b83c208de0634f6c93f0832b3cbb933de5f2614d71b1e10dc80a141b1d829626cb02672073814e59c04d01b074486b31f8cc3324aa88bf176daabd40a971b385a67e1a55c34129d1a00f076a36f3db3a999a05a1a00b47315b3756a9d3657d66c2d95aa0ebe9aa0cdee312ce9159e89796171e143ff7a08f8dd499de5a234f833d87d3e2e7b7516ef5c05973381bdaea1e276d2c7614788179653397cd8a6a29296443eb72eae7de3ed287e8403713e87abc8a1e4af48dac344f92790b931a946d839b655f03db419615c490fd464d31d0f07e46e07da6adcdefad28ff0c9e4738052b9e95cfd81053d9a9855153e6a9b9985a9d534daa1bb28aa5e0a22fc22d09437ec524ef898126b6cdbb07593145fdc4df09a04149289bf21ca5bd92b1b27dfb1df8f766ccf1afb2b8f42a074af233ee19615facc18ab2ee548ba02eda6347e50ac27c4871e90678282ce072c9059866b651666866d6db0e0412394bf509c8d9ed4c3bc636a1d1cbf50cad798612e5be2887769e25faf124d5c2aec77f3789ad3840c43628e707ebbe3f21e7f1fd731d8546210c231d14330252cb9077dd361033eb46419f6bc212b21723a9dac45a29cc6a01822f243bf4621e379d4e826be7ba01994b8d4dd02923b673819e0eae71cc423274d63c812dedf200f42cb3059a60d21e4810b24844f66e27b195218bae6333c27eef52251c4c1d0ac1b9f8b0ed4f356dd4d4e745bb23c32535fdcdb116ae774ef0f8870aa0e4297fcea43b9dbc17a8dcb34c04e2ce0b33c31d3cee0ed3931e01c8ca6fbe4210b495b438b9df893cc4922cf8b2576801048ad127aca9d4beee9eb11e18ec30bf72c60743db0affd5182058bff0b0bad4c04c7d1548af84a5d987e515b5f526fff3cf3f2910134353158d53079c5801b455dd170840a9ad0336815753ead38b5a486d7bd94a6f7ce3a234f563f9a4dbc2d3626392b54733db137cc16db63fa09d18b6edabf801e13f4e9a612cb3970029237b32e03e55863f9925467679d81dda8239a7356e416534ea57ecf2b5d03498a076ce2f24cf02dcbe14b24ced40c609bb166640cffd4fc08b85c93aaf67064be83479d204abd11630b15ee5623247a661d5759ce4afa8bc4c04f6321060cb054888703619ca80a7a4389462f040f7e836b9b9c9de5bfa689bc826162789cdc57362cf0d3f3a0006027b947534c3d019f4e77ee71f3a80cba1577260c4d8e97635b7d90d82adb85d03d96ecad02705fb071050ca1d569be593a70893cd30b7d2c9c300ac75fe2a840b04aa7db039d0e89e99ca2a485ac092c7e9072104b9f5a0d371118b45e0ca1a2a19a52466e1c9ea64cdadf0eef6a62b2a99212ace9b984dee4e1269176d3e34e946fd4ee0fb63edb0e07ffb5ed24e56e36d167b45f02b69055a69517101e01db5aca3cd13872bdabbde3f349a972ad0792c5ce224aa4fe50a1131acee621f32091dd23dec1862840684146d749eddbe161948566a04afb30962c5d0e0b90413468519ea22c8ee254cc55adf86f3bcd232a933ee127a9181f3c3ac51ec09cbe19201bdaed8dfeca06e63dbeb1ae8d2a5cd5964d08429b93c86e67357187e5a72d50141c4eeef4170fd40915c6127ecdb700aa3ad3ca6990f67101f9f9d2c9632db8c6f0995c52421eff44ae36745c31cf1aaadb1c5573b8320119017c54a5e3aca06ae2778679ed33415a16a89ec3d09f2c8283b46f1ff06e43deff2677c090156eb94cbfe3e42bf5a44721840fe231268a58daf96208475e998d60f523877c89bc21a963b9e8d39848efce1b0c0a3e0e05ccca148571991718327c40ae417b4e5c46c0ae30812352c6a11c88c479e65f8128966ea26caa3acab2cc827192d62e7053337a9ec12c9d1a928fa4a37a6eef299c5d8de600df805d95dad7b1ba9157074487b2ad2029f5266bcdd7f538d25059caa5af1fcef5446e84047bd9c62381f85a7a8bb0fe0bc4ad617c5e268e916d6b91e6c22866ff69575cf23b18382edbc1443a4af740ff4e72e60d107948765e90437c9a89b3c3c0ea2a12cabcedd28f0c091752757cdc2969e37025cd203e3091da2f1c7b536fb247270b13772e343016d80482da46fdca55001f6b2bf0a8f9ab52b4583a403933a3609370aa855899a89e74d9a95e00e02255a8df919c6308afdccf99704f471a9392ef38725baa8ffa88b3899939125e8e8681adbac91757c1ba49454ea6a3aad875d2cd8d2e34015005a9aa2771e08d4cdae393faf907f9c404addc39e8e9e67e344b1739426ec1dfff54e43302813a9fe9f2d4465dc2661869c918821d732c3ff84bb0bab4942a7f906755995fc3a92ac1b650b8eff2b30c77dc589a48f6ccffc879d15b34f2c0a5a0f96eeb75c4e0148fae882901699b48f8db04a6d614bcc0821285cd3325c3842178a844a9e745e23a93fab580d6a161dfc4e196d22e8bb5cabfc7e9fb83a6a9dc149ae85855dcecbdcfe3f095774457c66d26d7affef91e9612c5a6a143f2f088359c1eba26a167beec78de7f3c7044da721643c0bc0062a59362abf119001d8f1a59a0855b3a56cb418e9d792f8ac25056ca035cafff40c4283abbab16f819ea18d0e69bc482d5f0335cca0a7727ccf144d7832950793c0f0454856350542ad4b79948f34ab779f6c2c1b08871d3e9b4307e5314b32bef574373322fe9177be9c5b1ed5a2a0d411b8ac64c0616dc056f5135d29b42d0d019aa339fae3a9d68f7dabf0b0e8857638db9ea3b6c4e50dd3c16697a18872aba78c399e6da21de9817006f64436f1242194cdcf6aef0bb9b4b13d8f58ed28f45ec2bab6eb4dabdda69e3512124596b72b2d03bd6e31896f6f0b27cf6a373829feef31da9290e8b7375a010e4e651d3516bd33fce799efa4e116a3f3f244b518dd0e1a8259b3b006f65514bce98dda109a9e787eabc3cbc8d77bdb08f69e4adde84f54d513940f6061ba423a6262c7e84ca58e313cc3808d0e8a4243614fa8895276c9bd1d39603741cfa9c7602fe6ac6ce311272396816ba3f0cba259721087354cd78e1af2db1ca3c9ad89e96d5d52a3f83b39db7f54e6d314b4d8ed35b48de53ecca231d4f0243322766783e4fcd61e496493f48a38e00ce0a00c24a4a589986b0153204e59c15579714989c85b006750c6779458cd4e886c72b800417a890717b422420d03cc470c4c9a1e122645604f56fcaae168ece361d05a7e75834d1be80428799d99d8eaaddf4f84308ac71875ca57e98539e001458298cd4a4b876421cdb2240b82c53a4a4cff9bd6543ca8eed1a26391def16f19733682f8c310019244e5dbbc62adf6c2e4f19b55a12e7a681f647e868186cf0853df10e223d6e716e66d5624473108786c820a15e7b16dd1755588114dac2ff6e38362c3147518b1b23c665f965fde0b102b3fef7398913e7bc9207c80a74f8a558b2acffdc4122bd8c3ffbba0a8e2edcf198e2009aedf579d14cf1565bd5a9f8de3ff9a633bedf4329539e2ad5ecd454f767fe1ec3bde20158986e70db005b212783fc55ddbb215f0c5a4169bd060bccd8cfb421ca8a48e9e741e735323da23c7d2a74ec445a89f50f5bf21f7256199131821ca2f271ed7afc365880674f000771de36f7c32ced0ea88f984b9af2df0a0661ff2fee17c62b33b82a0902bfde21ec8ec32bd231026fa32a67c9ad3e64ffded12e57563ad19e8a5b2016a7544564446715d1051a0a0e4ef43cf2603824c26b623111041365fc7a15dd2ef2bd926d45169d7576524f27b1f0f1a172424097c325e2b7c6751b8fcd28c7e304cbc3f2166ada89df2f1fa4a9afd3ae881e890bd2b6c1bb7fb9872f2e329f5ae303059de42ed750095fbdaab806e581cdc144d6d325e8ab76b31058b9bc9efe84546b35700bbddfc66df77b1987e79fabec95318f1771f5646958b174c04bd173052a121afc6f221cff52b4729875ef1626f600a54d8247fdc49e3c2a0bff7a45b15f708908c0270b4252cd9ffc659b694b5e676581891b17bd5ca2d2edb861acd87822d2eca618d649b087fa713c3ec30e715fb7852125f0be672f4e435408213b56c741999215f235171b2209cb3c289675fe0d97ad6db2d8203b1e316297f124f1ebb2ae4ed1c1837d9eedfb6f381c43b6170db958c78a392002faba0e50c7c8711e28dca0bfd8ad81483dfa03fc027017a28c295f32d0aad759efc69bf341c3b61e9a0d83a2355df2be4f11271f732c7e0aa4af05d73c7c12d534b462f1cc5a44ab0eacea035f0399096b94b4ef47d641b5cb1fb6ba887083434d36113944403040581c241b018881b278854766b2fadc195d7aede115443b26fdb218e2927122cfa957636663e300450a5ca33fe7b3fd39b5606c68b063f362cdf0e60b04b52c2107c8b706094a47cdec7c35ebcdec08c194ad741c36e99564b5e18434d301c0dca6ccda83b2b09a8471b028c02240c2c00fb874e1d7c17e9b84149912ee5b0208525b8a916c8a9761ca5a46f2db547ed1e1660be12478999adbe77eed76dd1a4a6b9f9f8edebb0f21384cd08fd2dc37fc44265e086d0f85b36cc47e04c43877521acb8e36a0e8bd8a07d10718fe5cfaba07bbc4a917732a3edbe268b18f1c990f637d77f331ec9f12cee3a9ad7ffbc55e0ab8e961c70d7b5f9aacc0c6904ecd9649f846cb0751117572508f2bbc355fc3158787047f288c388dadd682284ff29c71018f9e0383ed3950fae48d17a103ede16c8675ac032c9e474f98a0978b3b91f41a42d00443a4f9401d1de4710f2d1ecd5181537f378b890470d0da2213489ede720ad72326d8a265150033e5cf0524333794dcc0ba99911fbbef7b76e39991388a2797ba9ce56e0583ee054e431c36dc3ab11b9ad6757621bb0a4bac9dbf0cfbcb8f1baebdf25806d9cc0095be168f361b4489fb4187e56dcc0362b733dc0c747d6a036cbce0ea6b9a826da6c83fe23ed9dbb1f3cc3f246911fbe968d29dbe4f88d7b315c6a3faa292a0a1a31bb93f9f61fdb9e39596dceac341f3f5ffd4fbe7457f1034e79457a543ec5198b8fab3ed231dd5a4354336fc7a5fc0529806fe92138c95f57db86d739c3bbecbeae1407437980344614d41cb6eb8f83c8a179d83af9b60edbc7c9fc797009a4399d069a1786bcbd888862e871f8383bb1bd3108b33896f21c7e2610d0a70e64690723528af7e1e1e0bb1bde64b7209e08cbc1c8503974186f194d845174ecb0d2865b7ff68ed79d0ba0210bfa74bbec4999470bf7e39d89493981056e922085048513b22b2b46a33295419385b0ba977b92344cce7ea942ca630e98dea2db2502b0bfbc3f65f9a92bda3c2bf2162fe6c6a1e8100207c9c0d5cbf27dca49a419b89f33767e85a3a52d43cef601e99a4dc3e77bd7062c6ccf25cdd8208c91667eba1cab0e07ae3b087cca685f073009e1e2e117b7886d73a1593744c364c676d260dd59ef05c30f3d885f7d01f3b562730f143cfd031d2edd71568af50fa7bc93eb830a86652a12bcd70383680b73205a017b3b34dd3b4362c11217426c5529deaac60bf3bc24131d6acc6af71f005bcecaa7ba5f035fda23d785b534719bf18c48740611ae096b7c5aeae4bca81b6ae445449aef6231c6785ab63c1acd43e9b11e4e5191089695e4a02baa20ed2ce4ac1803b0aa2207820a38e89a244b6da21439c24d0786e9e0a5939209d0c9d013ec00c42f761c92b249d8087e75108bb8a8465a3738197872fc80236dd0163239cf50ba8766655eb55c801f9a96081aedaa09b18307c7122e2616c101751441442a2414d03df74efa832633567e8074cef8ff9e9cc3382a934c7417c8129a9cf827a41c02cef47aea582e80aa59febc5ccf3eaeff725792d3eec1ae4ec4147f3a714510c13aa052860f8139ea3d57195420ffe85bcb4a458e0d2149ad026bb8dc6565d307c64f160cc003f0da8d06e077c4bec767036387f384433d8454574874e0a24fedf21be6918c5c49227a5c6a7e482bf418ba689e1332ec681206b3639787882776c48c5caccaa8aeeceafe67f5ebb821e198af74b318f56e5868b422d620482e3c2687dfb1f1e739a94a62b3eeb555719450c1f5db60f039040b6943587186b2fe9ad563abfe79808b63da723216b826b8b51fd491115cb13542632d09224706582051196da5b9db76e37815fb715b03cdbbe154ae12f768e52b48b5a5a4b80a87f4c2029a0b7a6658301a16a5033d71da33244c95ec6e7f832c5f2ce967f95a2a126372c76c239025b743ab6b69517a0378f8f2a885737bde0211d63f731400424e6f739f9a63eb357479abd99b023d69dcd4da3e9184ec2d37915bca94924c0176068f058f06ef3b93f1f514e87b79aa9d945292415f8bf8e1c0630002e0d118f4bd14e8fb6b1383644495929330b593524a9b171a496a41a1efbbad4a270308c09381fc7cc427b3cf2fe1c678b37014766b28d0f73a8ea05fb5ee88006a7c4eb41b241b2c2b2b2a2c2f278574d15129a48932cc655e21f9db536da86b6d918300f0189a9f10a24f067a3d3f555d3c4eda8dee489534506c1723d960f115959594ca3f59303e82ee926cf0bacbca11d47ba31b33d24aa25286cd2b94033b8212c1b59f406e1f87d195bacf09dc987d7eee27f4bd94c1460d732ee6dc7e5bbdde3ee3cdbdc61aeb23f43dc4abfbde440c40ba94dc61d04e567ebbdbfb5bfd25b78c3246cb3118dfb32411ed04fabe9b405fca8892e49352aa686eb160fef249b8d67e471b185c592957ca58e459329b8536fc46637c0495cc47bcefc74750af7c047d95bddbbb9ddb6194a16b629968f476d4391f914c812673dfdb65eef687a4eefbee2e842ebf9c65f1c0c186158dae68f4ba78ec4f1b76310ccbb24c24128d4623121d89b2142c655ea1941469a5bcbd71da26cf88fa38df98186812ba7c922af014501434ce094c500212d06ec571a8b46216e3a33cbc2aad1fd4927d2bb3799c1f415d4a190a5dd7ee9c18866159962de442998d8f80cac5f8f5452736278661d8a345342ccb44a2d1882ee991a4a83b52b9cc06c356b2cc66335166b3321a8d7629a5241289a664369b92b260d47d1b78ecd855515159c96c56329be5565858586cd8b071e3c60daa691a476d4a190f5c77635a442d2d2d2d2dd09b5bdeb288ba2315b3b008bd317e22918b1796b084154da398a43c4ca0efb10cc8a8ee53d57d5950ec047363801ffa2544deb7d05b1b04fc439c1119e3bf4cc92aa1e32b62ad587216b0b887da8679bc2451d781ba1bf37e63687f3f3c50e0d4aecb03c4b35d982622fdfede9c89887f7ff73b6722c245ce442446ae23132bf4a020b784df8811510448d84139b764df088b8b3256a8e6963c23e07b3a73a9f7d0f776988f5bf782be19488457e87f81c7a406732ec6430524eaf248a1892bd4e52143a76e36e457bef32ee40d68376a326aa2aa369ee5b19ba6f9c76c405ffed21181ef2404bea30ff84e73c077df80ef4e350be22d9cada9e1f9e36a6b6878fe98da1a023c0f11fd200242b400111111037e9786ee1ce03b991ebe3b21e0bbf7e13b2d01df51057c27ebe82194add9f1fc50676b6476f84ec6e6bb1390ef9e87efb42042be939547c3f0d31cbe93d1e1bbd38fefbe7ea7a1bea3956480df25bdff6ccd0cffcfef3b5b63c3f3f84ea6c777a79a52f3ddd7141fdf69350587ef684d29c06f0acd773233df9d6ef8ee65f84e0bc077b4aaa840f9ee424a4a356dfeeeec64ea7cc984de4480de4080de3c80de3880de34e02608ba2319c0759212e13aaa2d80ebb40782ebfe87215c27a300ae9309e03aea03d76908e0baaf3d70dde9005c27d35208d7c9203c70406cb81db84ea662a069ac20037028ae723f381db81cb84e46a7001c0e3e6a7a703cb84e060a0dd7c9cc70dde9068e0b00a76393e139f5f2927a49bda45e522fa997ef645e36ec7fb350bc6a2929cd3efbec3b992ac366a9364686ad867fd9b2ff2da21a4724c211e188704438221cd1773255868d867fd944ff1b44b56a34528d5423d54835528dbe93a9326c04f8976df4bf39aa839a9f366ddab469d3ef6464d876fccb46ffb746594124d2939ef4a4277d2723c326f32f1be97f63d4a849f3a78c9aa47ccaa77c4a8a0cdb0cffb2a5fc6f0f85dda8b0accaaaac8a4c55f94e26240a800c9b0ddccba6f23ab6abd6b059381bc34fc31609b0c5d4c6f0efd820948de197d9a0cec6f0cfb0f9cfc6f06f8bd2f153c786e3e7c3746c2e3f19d3b1997e36a6636bf9e9988eadf413623a36ed67c4746c36ac9521510038d7b1dd08015d9e317eea0b4795206b2b4995068f9f14fa32122d5b9665599615141414141414a452a9542a954a3e3933518a0e1d2a2a29a3179a83241ae9e8eeee6e15d5155864a152a92696d9a4fccc48a41c3954b6e65051054d528eed558a91b010dcec895f55454fd151b413bd44ddef152c0ddd919d847b180afbfc04f54de3e830d95171777777ab542a954aa5c2c1c1c1c1c1c1119154728854a89652da3618984e51b12ccbb258be4cb4835319bdd01c3c786cd3f0e0f12aa48d4b51e1f08bca8b8acacb3e7626e548c1c1c1c1c1c1c9b1bd145ef18a9df0170c8668341fb3aa5782f8d11c2f23514677487427a33b22ba33a23b2f7487eed02a54fec896658d46aa2bb0c842a552a9542a1cca612b2934cd23187477b77737fc7f8174e4dd0da5e5edde6f4ffb5d7733eceddddeedddb62c254008bd238c10c2860ea14b612ecf3414bfa1afbbbbbbbbd9dbbbbdb7773b0893a1373343070164e61e330f2dcbdcccddfc9899f979175c48f213f41343564ec3d084de53fe81f7133b76c7b5d690dddd1ea384229b61b777777777508cd0e3f6aec70806e8dec46f22c7081d72fdf3d6a0efe38bdc688b2da47cd0d87e1bd3edddd093348c6cc769988596777ba4dd1ddd9ba1777bb7c3eef6766feff6d8ddb0dddddd1bb6777b84dded0f6e6ff7663ef08217b8df93674408238c314608a315a154430d35c0f09a5499461a69a81ca7f6bbf5e2760da56b28bb1bb7dfef37b700ceab57fe01fa3e8620740bb61523b47c7bb777b777bb5fef766ff75401d759ab67aadd7bef3dd952bbf7de8b52ea33b477a376efbd076d4429a594d25ae928effd0c61efbd0f50fed07bc242b9a1ac826129d36a729126e61da4aaefa2b59352ca33d618bd97499f9bd0d5e49a9ca876524a29c2da875a3bf5fd73b206e5bfa494328a9ca1d06c2852b6cf2461d77b292115ec39914e283f2796b3602f3f243b8a6419bab64eab4fb619cf09e5efb0c7f5cbed7de00dac7d285f7ff519524a7975940e03e50f7d47a1fc57d31d256e7967507ef9ec626a2969376cb88876631ed759bf6f75f25fcc9858ed767dd7a14f779f2b4608238c314608a3156194918372f6637e1816638cd2dda10f7cd83efbddae472bc60bf3b87137621d37eec6ed28ad6193330cc618a168034cac1518f6b333a247f728ca305126f28f4c83e6dc2b869c38794e9e93f55d8f987b9434d6bbbfd6300bddbb4ec61e5720ee6f63f6618c113a84104208bfae5bbf0b1dba432a2d0e49081dbac3cb033e9efa82a7ea3b84103a7487fe1990ab3ad7902910daa57bbbe5eeeeeeedeeeddeedd0bdddddbddddbbdddddbddbdbbddbd95d53c2917808422b6fb777bbbbbb617777c38edddedddddddeed2b2b2adddeed515aebee6eef6eeff6dddeedde7ea127a8543c4eac4ab0fae8967316580f7594ae6c6b2bf261e7b5c80aaff3e9c977d903c567c8d2a621cbe23aebdd72cb0a7170c773429f94d2b276e9c2ecb39680692e599098e672c5f76d3f6e42fc1747a22e092584d6c5b56f10863808a10588e0ea9c4addac07192ae49470a0fd218470bb1fdcef208470bb1fdcef208470bb398e46bc23cf7d0b5e0842e30cf7755f67cc084e7781bedf4da3cdf0776ff7e682bbf7167cdd9ba99840404040404040404040404040404040404040404040404040404040400ea3254397bc1c464b86ac900fe7f4388c968cd261b4a015f498f8c0e831a839a87fd87f967977432f74823997bdfdedb70f7fbf9701e97d61e6377acc16158c58f53c2612980db71b68c787b063e4f8b580ebc0e4efe05b50c27d6bebe737d0e7fb7ec41fc7c0238431c6087d9f50e6f82f5b9979991fcfdcddee3a21e6cb711273b7669907ab6e47f83d265a0ba621fe5b89f00d0afb19b77e6b1312bfe3740c723812c58536a404e3e6fb06e1d661a0c6b7bedbbfb80ded86acb85f43dde59498a23f07a0cf78f3fb8b317e7c2782ab12ffcd4ccb0d811f39201605b92074686ea1117c841d2661aeaca8f8e31a420821840ea1f783bb103e840f61c38d4ca82882bd9d47c5ebc1db793b4f50116b7c08638416d78542d76ea83322c4c917ad8f9bbff54ae01ba8eb21df76436bc9f82adcda1b09befb514aea0e3b5aad8f5c27a5942e16d769756561f6dda1fb478c4f6b410eca4e32616e0ccb49a779142ff326bbe3ef76e4d1d613def1423bae78452c4963612b02b11569612d3934812abf77b9e8c34bb580bf240256e82ceeb2dd35ad9b93dd32ae0d2943d61527f4ec69a11ca1ab3b0a7ddf7262bd592f87c55d111475938df191bc027ddf94a4f1c90af4fdca2b83bea7ed43df7b15e87bbf5e2e6c7986e6fa6e57d2ccdd4d36ccfeb56db5ebee5eaca94003f455242378d412ec97648f64890c4d1b6ccd0fea0d7626073b77b034cfc7b5f3649a6950fb81307f9b5b343f8a29a0c42a6a7fccb976e267157e97d58e53dd4543d9866dda6603e4bd1d38754a5910d61b99e10755facd8694b86f18cd0774073e735ab68f14240935a6ce4e275155c8e9b4c655610149f1905af90eed9ecff3f1e1a109285241523e78fd82949666ea7c0c4ba3fdfe0096c6fa19397350fbb58dc160987e8b9fd4c7f18a573da01da7e2130bd3f10639429e8ba9e5bbafa71d2e26295b282d69daff7b3ea5dfe7d334256e1be6691ce73ca01dafe213b51f86511fd7c1fa7ee34106712aa8ce74b234738aedd7caa062744da89dfdaec442746261fa43245a8a391bb3038a7119d7954853278814b21629881248f049c80130c62e52102590f0692b7680d903b6513284102e9f8a683d743bb6a5b1dee2620ee446a3b7714ed3cc2816a6bfe7143ab567cc41edcf9101b9eae35c07b4e314a7b809ce310076f5dcf88db9914366733dd90163d9b6b27cbd7a6e1859d9764f3772c87c681d32215d6ffcdc0c88232f60f2012e24a1c512254401b50cc3f22bdb0daec3bcae7cb6fdc86cb21f6d6353627db615c1ea8bc230fd2b5b67a48ebe6636a39ff3876732ae595ef20ce959b637da9ecf1434fb1f4c6261217dc3b070570f10595199105949ffa357fe073f1f9e197dff8bc2332cdfff7eb2ec716441b6b2b8a98795cf3ee32e8055d20a87d54c32a1ddd5a3b2c93d8dfeea197d7744d4ecfb53b6dd13e96b064456218cd4ec6be643d794bf9ef04c0ad719a9d993b87ebaed9e46dcd5c3a77ed14fedaf9910af19773d416536300a9ffa4d3e7ceaf71cd0eeeaa9dd7ff55c4faec7b64b0d3ef5ef90d93cee0a8242431fbfbb826a7f90ea4302b06d9a45390e1692de3faf9a8653a9204a34c1a7ad3c06ed7f3d34d6e5b90249dd1aaf3da5e0939382241185099ffa1f3775ea62c102242a1f4165ed624eedef664ed35852308d44f567b22660262013c27546b131ef3de66eaa6a4f26b5753666ce395ff269fe663a5bb3b5a79ca20a9dad797594a48e90a8f38bea845621f915f07e0ec17609eda6ce086774022154ff8eabddd4a9fd338afea9b335fcfd5b6857d49e55d49e53d4de1a4a93b1bddc94585cc745e8292c47a811ef883ba74005b31f4208210bf1d6d07e5d0a1a6be43aed06b47b3bebc3c4661f69059e20d750f8c4bf461de271308783cc48620612ec8977218df71e331a38f28c207787308d2cdc007ea10b395d50420a27e8429226dd5f98ae042b021450a45c83811a4f04354f880ba024f0008d81b39bedbe67468f195fbcf798cdf831a397c023052f240f1a523c3476c03a8fdb99f0820c49299928a36a7c62660e85a410672471cdebe26942c7af154f135ac41823864d2048296596d160c74752bc4d06233a1a41d173c516642469e20418288952ab89c480482924121523452525c57710e4437996e0426545454587878924dc8787891f545e22082b2c2b2b3e86dfb88fb6840d586cb0b0fcfcf0bca008ee23799688818d1b366cbcc004f5358144d5f8a4a2a2a272e346906ce28817a8516a299530c993aa028f125eb4985a5a7e4275b550f244a52e8f1255985c4c26ec06a37579523fd2891f2c780054aacba3448e0b0e171c7069d0048b284bd46e1b3ca84d031c9e256eaa4ce1c88103c74e16b4f0319e470924395e72e4802235eb5ed14409bda2098ea351353efdcb4b6603fdaa7bc5163f3b68a073451465501e27562926ac50353ee1c08103c7bf8d24bcbcbcbc6c1b4b5d1e2684c061dbb66d1ca7c39344106600a389da61953b6b55c45a552e76767a40450f7676eaf3d9416247fcde6366778f3f3126f1247edc8cbabf3f43a4182dd85dedbdc7ccddedee4f63fbc4c8ef2ef0692e2c4b0849bc259658820a73ae124a28e182100b90a0ef31f3482e9f20843146cdb22c26ac95b4a494dec5caf7deafbb43083d7a2a460ff878ca53af05d4a5bc241a8bcddddd856ec30b76d427b553e55e7617cc39f7bbb75f77c3dde67edf7508a1435fe87137d8fbef04f5bdb8f97b9fbb0bbb77bd9b1f4a31e7e6784cd688d58f66ae0013b67d30a4245cb004478276b27a0b68272bf733e9ac15c558f45eb0057dcf9d0bea7479287741f908bf1a7ea5db9f22dd4a7d2e619195caedef4f7dbf6c82e92ca0dd7af1b2f881816ee93f56406dc062978626fe22c19128f8210b7e681b010f945b9665921c4541292d4e09fc1ffd83e1364c06e8b62f99deccccfd9cc0d6223ec8dedddddcddddddd01b7643e7938761eef22e6b376cc0ef9865c33033afa8a490e8489461f30a492b426fe6e55d66e6963ccaa0f05f7c32ef278f1e3e307ecba95205ca19ff3e1411edadb7b43f82921072534749e99d0a5409cea34aff5e2365368fe70c0393faba6b676766bde869c52b6d3af0fdd5c33390736a06394e5d3b97153c03b9f7c3a72950eb55b045c51d32341a1e4fe0d1a347cd18353ea4407de02006c5a100500a904314680e3a4041871f4fa0d6336abe7ffc1ff549e88aaefde4d1238c1e354ea8f1d1046af9c0a10787023081c22f400e4ba0f073d041093ac49c1f60fc58ad56abd5aaae56ab98e349a0da5b4f7b00c007bc729e0fc85d378fb91bbe9e9051af268471810048cfc678edae1eff82aa316faea0a9b335f0fbd9c9d25c410dd3df84aa8219c5c64c1bbca9821f3c986eea004e9d8d81dca5ba763875edf0124bf3ca783e9c7a3e3ebcf22995302d8b5fc25a329bf8da765d21359e8feb0a85a1f64f1c4266d4fece2504b4a77ec8c3551f774d774261edae9ceb72c2d258dc948261faa715397552e184761dc2ab63beca38b5313a5504eddb9ecf7c3e623ecda378dbc078ef07092bbe82521bd3d9b533c4e3d59c39338504da3d9fd4f3e19968822dac20466d307aae9da0a6a102a7462b92d421844c6e88352d7edc33395e5d3b8b83f6fd57154b737de0dab96eea75d3341a17ba70faba292366bcda018d392e4c6a0c3befbba8aafd10c53e0dd37f85b1a72b8c9db9beb0a7be82f834c19816a7be10c4b59baa1d1e0a04414c92a08c8854e8a096a46cfc08990fb03ec84ca68e8e50135b03835da6014b51fb633002b55e7b2e28ac4378cd76541e525fe4ae9badc88e3a392fe8a29ecaf4b8b7b363d3049ffa39874ffdde05e5d5c638b134ec6461fa358d1480374fd809bb82b278c28a2b876766157bea9f5edcd47ee7825a7548087458638d355016f6059ea6c7c51c54848261fa7d8b11c8c0f45660ec3ce153f730793d1da722143c6312021ff7c8e0537f3f28911424093260ed38f5a034b1f5f5d06b8b2a7c76b0a151a769b40f81124aa5d276d78e539cda533f15b4eb6432a9709e814faaab05929d4a12e38bd41749d62ac3b25e16e86ae12449e5aa85139c3a77a615b55f009910ae4152aa186c0058cc0f2194f63f98574da37d6ff6c385d2b898d3847653e75283692c9e596cc6700c16da28fdd00a338410c2f9bc15599954704bc32b01d447437d35f5fdb6355b5f57aaaf2385eafbf71ed75ddb8573dd5c318721c6a914e4302ee6441dbe211567c0bc0834d6211cbe378f58f185e713337ade8a6c16f57ac991a9fc65059f3ad5bd9b6a9a45a152bc721e7aa9ae1d3ef56b41bb6ba787c799e0ef00329bf973a988c1f01171bce213f7f00dddc3330bb797c3272872164ac62beb53389f4a9a33d8cf90d9609c3f2ef43f3a8464a19036c9ab8eca605e04dab5bb7aae9e1d5868738ac33317c73345368beb864f174e16f47d77ddd44672e1f08908b4bb6e4c4f67eb93020bfa7478502312cf84f02b5e0fc5ea6af1011ed4ab2ecf154c883ba8e8173187577149d4b1e1ba0ff398c32b1a306d8b5044299e8fe8c4caf4131bd3df7175b169f952500dd8527f1a329bcb06ec019936d450c30d7bc32c692d6f7d10a52fbdc515b18488c67d11a6c79986580fc4a2acd7dee28a30b224088d2ba2f4d617b18448e92dee08aa8896d79e88f5dabfd738234b3823385e7b2339de5a54cb2f6abe6c08217a78d5f443d8c01f62facd4aa55fd45c1a4d1b346306997eb0bef441585ffa224cef5bbef4d607d1f2a50fc2e54deff2a6d73e4628f8a46d93098e1c2e2da692d6b22dca655b54695b94c90a1a75624e4f505008088eddd9e1819760277070aaf42def711a905586b219ecfb27cfd628317dfff4c1d268df7308b53ffb19c427a2927883a5e155cc79c24e4fdc811040b8cee757af6ed17ce6b8ae562bd3fb966dfbcd1e18adddf331719b9833fd60bdcb07a1bd892bc2f4dabb70452c21627a4dfb2274bcc599f81765fda270f8f492f4106837751e4e56570b1040a9b22ecf1539e8b195b66d98968d4766b3d9d41102a5c13c08b4e3158fcc460813ff0f71f99709114d3a3e88d7451560a04cbfd9e38058940b8704490c8f24c72301c023d91ec9cbe3100288452141627de99168dff2913331374407770465e24c8f33fd60bdcb13b1de8533b2e4bd91d25bff38229a9196d7fe08caf4def48bb236d37b975f54cb667aaffda24a9b0935716c9349c3f4e7d8b6615eb66d986f52fbb755ede77a6a3f00a0d4fe18a64f0c2f8bc2613364ea344cbf69889125444c5f7a23d6bb705b89bc2eaa5002aac419d1dec4b915f4fd381068c7ab2f40c04960267018bc7a3eae1bcee1317af4e8d1a3a6a60687c5e1e646c81546ed2fedccd5b3a7fe2be8f9f83c9f2bc8e7fd44260f8d98f3839c95a874cd59e4b474664600000000008316000018100c0a85a2013dcd82d6fc1400115d7c4a645a38120824d15810c4300c62180a30c620620c40041985a8468a0008a5404ee7e9fbf778161c25a3b31eb41ece4fb5fc4246f9c6cf553c9819f1bfffddb507c54636eb10a50955acaf145662ffbc2308747e6a5923736e6ff8784aba00d302dfeb04d4ca5956256099e0aead3c0f631a45b2cb62a421018216022960460991cc672176d41cea05ac6a6a6d142f5cd97537da51cf90f3a99508117f2b3a1530d5497436f0e5865d726d98a311610b1e0f20ed698c56e0464d715e6a58854dd53213688fb91184c661f087080b1a7611757ebf7573972fbc6a5e8a3f94bdc756b3b571929490fc6a864f42c7956474a1b8f42b8707c9b4cdd7859760f24d0f0c14cab2203e7499bc6aca6f203058670559b876eaff08c6a61b3bfd656951c3eebfd1704bbe9b2d10c18c2d567230d73d6ad32e6ea83bf64ab32873a50b83dd26874e6e26f1d28d25839eef9161ee4a19bf2c23181a1b7a0416c8f6e22b255fc6ebddb465bf9ac4f62575b4e8ec4b69d63a2f3b0ff3d6f2d558ec448fe966da1dcd6e4c9ba3d14d9ad6af111b58e560be7b5193468e612baeb2ace033ddbae92c625d51c4d422fa7d711839b25b5248af5556a0c33bd624511dee040c62c048daaea0fe8a29b1fef41a521a54ab0aa40337a0f805dbefafd0e5c116d82017ce10f81a41d4d3ecf52f868f255e153fe21280f15055bd86564c34b39fc194de4906e985a024a4d09601363ce764d2d92164c50b3dedefed2bd3616f2a5cabd77cd0ef31f1c1adb2c1a1382212f11ecba8ab92adfcc7de13588442adf372ca9c20b43754e180cf6c8c97a4d09ce853a3579bb1a720028b392c65d67dfe1d9c90773e31bd2de327aa080349fd733623b9234764f280aa9400d123bffdbd41b93aa33e862b6a90c40e6963ab200ef9194a149e66fd471028791a6232fcb394cb312f885c6080477cddbcea68b59958d812dc0be91109a0d3e829c30b3e10541cb1c99dc9ec19fa252e70ef315c5e138de8b86c76dba7ca6b88515471042b2b009416d170520266400d691edf73e74f8a71bc69b7b37381f50db83b48da0afa1dc12cda27d743b8911930919043c624e7260cf68f8e18c25347e45b806a00fbc8912ef97320d63046019c5d3200c11d886202d8935f1c361c83fa4c162be9ab79d4e9f7fc5d1b217ac9edb8cc98c879e819fe7a902bf03210008d4a7294551738a83732dcb1c7c67222cd96b7a55e53780a9715b3b5ba67dc202ee798fe53d679c565e62bb5cb7869e4ec0110b83f705fa8e0f4e0075a5b211fb6a08e044a2610cb072f5402b4e3b770ecd93c1b80d98b31a20728b0cbeec2d8af4c6e2dfb35c1e2f3efb27bce91dc872f1625bffb287516d9fd8fb404e97e8515cb7b08b0c6ea03c2ba4519ea89a989485db97c0a95c91c42f09b4ca83a335283e789014683d4cb1382f810f50ee7ef1258a38ffefdd811c62fbd738a34316d1a6881ea6bce641191b7c675c03e476e7a694986e400f4290a94ded64553fa449c3fd1db3f5ed37a3e1b8c42925bc490b02bf5074009fee3f05ba4c9615c04c49310f0fb02029392620534951d5ce026dc649e6975d622203c80ef8e77ee350b4e2ff583edb8ac610ec5a9963695e96e0c48d5577f77431b53a8eb0e2698a9313901a1a8da16a348858dc17bf277bfb4670397f5d2e3e95125ad121ca34668e61e7f7711701b2a3975fe7e65ead70f19bcb87775e24548abc1b412f8d87c96394f5ed7b20d4e86ac089985979dd6be03d1a03e43f245da4383b194c4c7bb28842cc02dc7f81f34b137abf814b015b124829941e41ea83e1e462d6f29ddc566619b2c84821f4feb418101ec04578a8634f8e7f499c8dccae09d5bdd10a7651a2ead719e33aa3c2e5833a00cf46234ddc58d347e7dd57c2a5c4160e3685aed508111f609a9fb57bad073404e772907be94ee741a6772c025912aaefacf33088c3120428903210d5d102e60e0e2f952dfd96df7097979ad461087f2bdfa3dfba08f0554b0101ad18891dc0b3a6af15755000b5b7196bd14002ee02fdcdbd6d04460d22ad75f121874a4a58cf6220291627d2b6a97b3ad1c9efd7544bfa61aaf406f1156ae48afed831ef655a1bbc6551dcea0030293c8965bb986e272a82786b7a8e3773d3a0c4a6bda0cd87f49e0ef6753e058934561776df5d6e5053b33c8d65d61f8ed659e0fea314d84509868847b6ca0132b7996e5c0e14a757b8735afc9c8307f1b5943e54cae235080c54ca04c7ede4572c50c1fea2016f43d0690641ae1f055c067e30cececd45322ecc7d25ffd47c60159a1259fc87428728a76e96910a32aaf88112f1b7b403b0280ff77b8f03cdc070cdcddff14dbf7c364e62555dc85e45916371b0ee0d910b657c8cb5a8c8745ff1a70f18e3bd074f16784ef0f79ce35f72e389fbaf56744c71376a3abccfe3eaa31f149aa93034bfc54e4349c12b60fc3caa9a2a23291c608b185315dd1639cf396e7172e4057e700660fae3d8511f89b3c2b5ad1ab8a85b18a7348c1b992c13cce7f6d21c24fafc2ff8bae1e8fd165b3744c74a64c3b35a405d6d7e34e37081c898d8ebd2fb5fdaf147f2e144324501eaf6d2ced3f381e5a4547c70c7f2c6044905a834eb7178d22744ca683ec199a0b02c0f9f1191cbc1aa8e51ac5692856c4d48325286f2050d7194f0821e76be0b97ed32629a362770b08ab071949717ed4bc477155ce9bf5e2d178a5a9f7da2a8bdcea8d512bbf8f96314cc2c5185f7c4147df86fb9593b56fe908d01db1f032c8a581b32ad27142707bb542757842275cecf13ffc626e2667274e4341e056d404b3d6009804e2968164f05865fa7a834ff902915e963583acd010d203ac6e24d0b2ed21920a46d6f52f275742d06d488bd81d80f0e1f90657001351ba103191c391e6b0766cf419556287d19240b296ba11c865c5dd717efe189405294bac23cc89df632f5a407d8bf216da60a6d7cfe400a2b8a0036b8bd5c0693e16efe89a9c5fd4fc3ca26b898005c522faffd3ddd359a075e8ba30097ae37599faa0f97d114d0e3cfcc11405eb4a159d4ecd98c9689ae6c848df211e5ef4a50f0c7a5e20476d241a3aac4b0d55d1bfef204f857ae8e8b64b69611cbe635bfa88fc380e2e788abf4032e1db274ff74706f7813e3cb90ffd58a236c42cfc6a066e3acde1e60b6478259606feaeb4885ef3f4801187a6fd4ba1c5e32bf3075d2aeffe55797b552435f3e785eb14ced20b0aa364c9c10d556ef72e5681d4a2aede5e600f55faf626c073066fea36aebff2f38c104ebe4dfe8834c3e30cee6783fd5a49a1439343394a68a18e14f2ff0c52700581a65cc35f8972b6a1a82ec2b2e2c66ce7b7d6e1184952e00f7b9cb8fbc2aa79a2191caadbc2322c920d03ac7bd6ec0320bd676953f332e74eb9aa513fd1afef755631ef85dbd2b46bc57b4155a1e2b7377aa06440b8885d43716cef100192d3d4fdc7977d83847555b985d229391252ddcb401e5f0e12161ecb2199439c95211a3d3ecc4c407a817876c7132201aa47d2ed2d4194e53f9e6be9b491a234e1b78388c44d6bbf4b7bf38dcb984e8d0115e0d6de7d0f055d29f8e3befb791e575e82fc82aaed6538aba5d4c3250ccc4430ad94638ae173448b6931b31f1f10cc0a858b9f1aee8ed047ce9a09b120305d812113e8034af8446c6cbf129586ffa57eeb6791358fc15fdff4b3501eb880d936eae0bbb5a23e7cbdc95e34704ea6902cb3a663d9cbdee05190ddf96b6b7998e316e1934e29fd71420f362053fe3d18ee2ebc0819b87fd5e453d908b9525ba85fdea6a595829ee6d470564f88599dd1c834e9805e0da9703b83748e8823854d6b2130db0d37b18b4c119f63ddb65d897ae610f988ff052302f9260a25b8fec7d69649693b6170b1a0b262b7364d3d9fceb6d18058e1f5d39a841377871020df5596f55dda13161b236bbd74ae33e98a80b769f728cf802a891ce7b728827ec54565cd6085f7ea985e827869d4ce17ea8d9a1dc6fd0f9a4b98548838534726ce1757ccfa15023e0540cbacfb5a9dc4829841ae83acdcf51dfe953d17d2c4dfc44ec8cf382f7945681ab2a7154e4bf8303e0c841876a86a6572dd52a95f261360ebe67a3a8977782d9e742a437bbccfcf2e496083bccecb534708b8d7b5e27ec5cc628bcfa9309c753120900bc50d19cc853b49424c2e81f07a4b5ef3574767bf7429f5272479a469b98c6f46bea7e7523fb11f2459af1218252bfefe391c1f410758ff45cc04ed9d43575118264718da0b0406047db545aca037c4cf2f3cc70d81d0a1dbb2cddf0253c8888120b65ac4aa7a12755bff24e6f211175daa11f65798d7d1e96cea5166ffc132e27a063575a644dd7227f388760091b2b3ff6d592c6eaab63ae442f393229be5785178dfd36b8910cbb132d113c6f2e08f48fa09feec771ec1c30ad6f1d2f1b55f25fcf0001f6a85e7d347c3e601cc08624fe6f69126ec058ad0e56eef65bb5907b30e38f802ad80ea33234058e4e363ad5ac537e9af971018c7185ff0b8ac10847446bc946588ee3d250ab5ebb6956a28d2eae9ced23b7dc4bc68757bc9581036f7b818eb9bfdaf601c17cd7836262412da810bcf224a509e1a3b29c20984d4d17e8166c125e8a74a5f04480064bc63174cb50d4107902f718f25e7a8b1a310a8987b21ca7a1dc9700735e310bfdcca1d6d8c10e5170e5df7f771bc23addce22aaa6537586f6ea6d15dfdd00435ea6538dd5cba55d12a4eb263951e4be1b642095325d119b1f0be12c7e555e04649f7f04f03ac80abf57db43ac40bd12b9d5843bdc621205a8c872e6dd05bf437aebc34e05f078e0cd8b10df9a17e0920554635dac8005e3eb159d54f8d62e320f20d9f136ad2d3f36ceb3a00e1426f9b6ace6d5ecf60ec64e73f4f2df9ad829a1e7992cd6b2a564919cd71c1c0a558e895d7158eb1662b0fc8dba85419247082266ca7c90eef12b9727bf89626529c461c186899ad92ce47aae2611dec2c7f484d89da07a30f7749e520bd4abe879cbae0f5ff8fc8dd4c275414420bf22c8102cbf87e50498b23e9ca105e8f39d26990612620a049641e29c71570bcad3fc6dbc74e0cd92634f6334c0c55ea7d716a44d4e0d08e7d9586a860813530d9f72af592d8e7526706bd6d1fe67f8bbcc44590dc83abf11bcf1ace96b951067c884580a29f76d6477f5c91953952fec19cb813058c4f380ed03ede42472f8440dc51e0acadc5f1bc4780a0167f5e9c23d04b79ec75ee289bb35770ee4eb20beda9f42f189e7d9c28bc8426a0d0eb72ba030732617358cd016d36d43f8640a26c25f8c507ce5dc47a0642dbe4667681893c9fb86763a1294f9c6391a8f5e0b16bfd3545f1328476a38229b7c6760e8d0da9bd4b6668312df4c2bb16c9c518e2a8c4a216d04df70714952eb6f8a8f7f089d119e6af8bfe04d2d4cc1f833f6850b7bd1185379117113ecdf9975ec8384d4d0a7719c1dcd63b087a49ddcd8856c8dd8f0d1225221ef37b5c711cd21032dc882dbfabaa0f52c4496be71fd9759ac6776e582720d8106f429ac6b601ddfa19f20b556c57c2c04559354d6f02e78614db1e091a9618422a84a09029cb706fdcf00b5820e1adae8ce8188fe4c01a62d947ed57ce993640501daea239cf5d07c7c03eb2a6278bae3b208ab0d1af1cc12b6b95420294604efbda8ab5dae5c3b1107ca92e8a9981c962b73f2f57b21e9d3d934854da7166bc976d664c1fa492042e9a12e37ee8137c55086fb915a3023c1fcdce6f149f5747a4c98a4de71df36800860ea51e39b88ddeaec3a1b189fe4d6840063009f79eec49795298fdcbe34fc72dffb45217ae62815869d62f52705c958a1b32967011576e372cfd31f5fecdadf2fb6eb0877a5ce437baec5b0a7e92c84a1a06b4db22169ad07b259d34e5206ecb3e12f2aa3c1d9e7a7d988dccc2a9fd862f11b929fe240e6056acaa43dada773fe92fa8549a907d64e84fa2c468dd4b5064491a5401c55a3dd0dc8ba34e35b75fbd3772307ddcced47a58aca5700dbd090e15bab432c2e094027f9231eb25d06946f559a80a2a6b2938699cf50a7072e3febab799dcc40f2c9beb1a268e5bf1896f32fb0cd28bbe6b0b846ce32607980b1c6f91195351d971f82e3825b4b4774f1e33ddaa9555d9834fc8daa40f6fd0a6855eb1cdc831d51e244bf0351c70bfec8d7da41f14a2828bbf17e87ac742196f4dd7bb0dfc44356abb42f02b78ef3578c9191944bf99e5af2d5ff4edf5af2daa401a010a0c154d20430a3d21323701b374ff516a397b99a70ed137709fec89c705958e23b7c32b52edeb6411786840c94cb63ee5469917504e81433de73d0a42494386d22b25aa26a2ef8bd1a2c5b52b021190629fffcea4e2d80fc1c8c7288f3cfb8917a4c20820b4e22851d6a9f10a1fc0e85155042cba0c4214402f43042c76fc73189fd0b8d3b4d84982418d4518fee525883540ea8d5d7c25790a07a593b7de3065e621e1886025311d920d3ab4008471dd85703cca36a395b21620beb5be5d226ba1d51b2907e90c1f2535be57865997804e99503bf727f37e8cd472973927c61a101d84ba71113f93b81ffb18b9342c9ecfbf7900aacc4340497401aef3fc0bc1e0380f8c74fc0fd2551dec0e826eb9d815bfab831a2def961a56e61c8382be8890fa534923221e2f6f95cb17e4c9a59cd32516c5e56bc49f8f5e111e0f39d3c85190e76df3877abc0021b2a4bcef3d995db1f9ffbff8a301e172024c0305dd28fc735a3527632a2a9e4fff8f6e5581617e68dc0883ab25b9c0cf2d22a79150ba7a47743ccc34a7cdcbaf3e11b721a3517e56a7037021266391553f4d3166de82c7093bd69a01137a167e39819110ddffb1366a1c08cef237901a8173bbc905f97bba70a1d8a91c7cd67359b6fda852314b12dfee4117cf573ff529a7f011c90c828b4a358f1a058e2e9fce8c21221e73ce52d4e994917253d60026bda8503ad416110b7aacdaa8f1b5a0996ea6e8beffc17b77505641f057c29caeeb45c07f08776937909ae3a88cb00bde25a9947bdfa3bcd4554370973c4c7411a0f2975a4a8a6591ac24a600ec6f7a5ed1d3f3872cd8d205dc462363af96198ff21f297407aae04789d9352216175a2fc4ac3b00a74c386aa8f48c855bef19e4c9ac2be63a1b60dd83eaafc0a7f2f048860ee596f972eb879b3b350c91c5593c468021c312f8bed4e1afeddbda02a77294402ceffe866793b4c57278389c5c2490bbbf39b5dfae52c7ba3fbe4f906cc93a2fc7ca99a3cd46bdd2c89e34e4d08d250596cd01b1d00377e86cb8e87fd0d7a51c8f71950d0f7a46073f9e19f3381f58497766cd1e3fcfa46018d519e8ce1d294f624bb276eaa472da022dd82d0a6f255019d6349c2070f3e0c63e507d9237b684b00f60f40e142a1ced23327eafb48f85401c5136e1e6e765ecce71d2a8fdc43051b079e0dbf5c190a7b3072092e56a07365a1b733842510a7a1251f35e505d1c18f106dae059dc3f14ad131a65aa4ea97697329269ede820c77cda75edc4c09ef808008f080ea9ff02860574eb19fce93aa0bde1a27000e1df6f08e2177bbfc9405bb755ee8add902217f0392b1edc67bdfe936f937b29504fb2a32679288b4b9d8b4719bf5daa0e651b9163b809b367329cf502a1b95341b9448fd84be73700706470710a692418884f9c5e1ebe71cb31ee3372cb4f817d511a1974c2c687172f168223767cf0836095149456954a0cb2232725e3a184be553f8b4c9801eb33ebc5e1bd326061da8be6ab460ce5977badf37781726ff559d1387c719b43fe562a6af69242134ea5df0db082a7cf73314a1b947ef43856208faf1ce8a6b78bd116b54e10cf1e730d96d8aca445accd91e51a9c65c44eaaa05ed7dfeb5c3f482ad5e7d39232e0286e988ae15446a697137be5c38262c4ddcfd1acde0ed0a67fd995b3c2e850e836485c379226306c20d7c591919b38bd7e64ad86602b4b1e9ed8a1c865ac6d23758df0ddd0f97681f0e865a7d4b984693c7b4bd3daa2ba631bd5cd9cc7f6c57d0a3ae4d4009e05a2e1a10a6eb6e0f0f55ad40e39256a38b5a992c12fce52c5b0d506406b7d77a1c9f04456d4f908b699c861e615667c4f41f63ca97e58f8c921f9324eea417e6a76419cd891539c744d01dce0144e3815d866aff847e519bf041c007184402f5396200ec6c86ae108fd63f7487ad56bc63f55e1a457ae7247ce1f0fcaaa1980c367935f87745e4006decdc04cab26d9da36e0f638b3710f98f853c501afd01d0ac36a2b469ac804fdf7912a431dc57e8bc93cc2b137af28a592bdef2605828531f0ed2191f962a7818813c29a72c71f471a0d4acb56769340ede364f8076c76cf842d6ef573fa09780958a0d14101fe3421eeb54b990b19f5d32814ac471beda1114e9918ae36a9272cdfce547d18f30949d1c4f9a6ff452ffc50a18b48c7409156321b5f280c872265c84d9441184ea841f05e1e358fa6436240c24e984e5d4fd506ceb70187a9f5c68057281289005f547af5446df45bb0f5e3944c6d4e1ade77ee64a5c7f46f8fd9edcdd7fb3372876dfe804eef940b73ff98e561e504500f351b85479b7250d2290eeb68e33ce3faac259c0d83b1e085b8084bf27f67499209e3d55936c5095fabb56ceb8e92c4437d74a4243fb571e5f440e0961ebe4f64348c8555f2baa5cc89339b667625551aef428e6d61601d1dfae59957cc66743412a352c9635e825ce6258dd17a237fc4bca0ba29d1846aeb1830afc834f13b7ad47c31c2bca259aa89a9343054ae8fb7892b9757df6552340da4e09b957ae82254551ebcf3c285dd394670dbb65067926d404c848710b7cfc07f98e92622acb130b1076c585818b4a586bca1bfce95ed5eb9f112e3cef5c77f99c601867ab22bb95c7d024eaaf5b0f488bb9fe61ff255c09ecd23f6e50d4b61e01f2cab2ecfff45e659560c6e2f9db968ebc449f13626b95fadf1d8155aa96dd8541975e326536b8972b3c32f9674bfa91258b5885cdd7c2a911acbb999b5ffb44ffe613ffca37dda4fffb08ff6693eec837fda0fff6cfb9982812c00d50003d51882a712001ebe511f05bacb7595b6aeb4aa2fdd9ae1e581e47e2b73b090693f4c8a4492f23b007885a50f40be53035bdd13a1d45e359e6cb3ef1bffff334431a7b8fc44d3f3186fc053b89912b884f5d094e1739adb601642b9ce5ba25719af3f4908c22217906b712793892fbb819a483bb42edc23660d9c0ded715b5161e89e380d5bedbf96ba5db66177df63f0c99c9f3771c344ef9176e29cef4eb0c057673ec28b8b7cadf4f4a9bbf38924efc2b81f4811566a4d598423a65cbf0d38829d605b83f58a7dd4d84868a6a6a3c2a274322308fe0e96770dd2667dce331450e592cec057374017a907fa04e522f98af830c00964a3fe60a58a36eb8fb57227a3e9787c1c81dd5557154745bc09415a7da731974aa623d20aa733be8dc6b5d9c1cb11481aa0197857949d5120fcb1738ebb918b6f02ff965128a845a3a0f982735cf08481260ea7736db1f016afd152f8558debf1bb715dbe0946234a04f4f0d4fff6acf829ea0f83668a3e51180447f597f9f9a671ca4077599b7c8dd5b939bc41af5fa74f117260bef5cdb41fa82bf5be9b137ee58f5366238c23e60efdc49a65fff3fbf424174875e7d97d0d1ebd39f44dcbc453ff19943447d189a1c03e7b277992df0da58b424e11e771f63d5a6a456baf353dc1b3e4d40088e0d94656bb88d37bf41deb9f39c6d791994ec14850285f80567c030aaf322ed70178e371898ce56b6ba114c317f1023881b25ce5768664292af0c8d0c7578ac95aba14b8779f8cf9e65d17e7ecf664b458e237ebc334c9b8c093216603adca71a444c992d8f3c35b9530cff631a2c00e36b633f5fae30225bd732e81d0ae4913e8792cc957e8ac9b129685eaf6db7947b859b68266a1dd174db3859c447b32126137ca4f3c3624dc49b0e6190728ecd18ed88bf4c93cccdc0cd083a161cfbdbe4e252c62066e86b7cd53a5fcb7912a089002c65a28ed7ae550703edeced8f4e26c3a9a919118a2b4508c56b48b7319af0b8429af70af3bec7fcecc8bf93097e236911509c9cbd892954b59178ce1d0e2ac8a359d74504cd2373f4c4e66f1a29740e03c52089137a53153e01fd9d0323dfab5e95cfe85060a56a02aa9cdb68c807494d5ecef7bad3f7c923d06eec4f704e5cf7f0ec8c815bc93944dc229ef0a804e7a6171a7bbd35f04e3d658fc22cc48a359cc41b3beb581d154aceaecfac308a8806902a720a7b6ad8444478491e606e88b77949eff35479c984be82bec508bdd446b62af98f7fefc04cad1367a1e7d54b381a63993c2a2cafc185c2cba2b5867a9e91fbd90f1023c2ed7972c3635113b540807de3d4bb0fd3b60b54f8f4a3391678f667af53bf9f1839d6f7666955add71e6356bb1320117ff0138fc4d985229e7d7e2d672af14f44ade3abd7fa480700f3cf23f4a9629734fe14f7543bd5e26581dea4406cbb62f0fe44b3081556e51fe212a74c20ed67332815b0f096f6dd8218639ddf8758003945511868f100ee9308dbd98df55cc9f5dc41e5916c3a87a0c4717f13d29eb5eb17c9a2d9181b6ea39f2e5b615d5aa53a799ca3af3e1bbb0d5eb7649da9e4566fc781a766518aa9e1a796f4767baa475e709c78b245293f9c4ba3dc1404f0a1523e0021015bd0122ca0c30a560f5fe9d49ffed6532e4dab61a73b29672d557d1b67cf7da8c549cd92655029146300e924b55e8d51a6ba97d9a536f60fdf2b2c44f18be71d2946127a029b6f2660855f10733cc772ff7b64411f4a130ba5593a28a8c24a5a6de285d5ef3de84f73bbff057df0489f16087ebf68498a808fddf54e97eb203391f5a02d283cf9046124986ff437ef08e48fea1253ca972b0c79cd7ce1c6e78879c4c0d65645b6c5c24aa516384798360ca2f7a5c2d8b7954bf8b140388e6d1b0c19188be60f873919602a692b04c693741e4193f6b4882b8d4bbca34496d5d9d00bd65e8737720ba56ebd02d363531d91200edc2b19df9fc6d7da0116833d17c9e20620f2305f41aad92e067ff2f4e71d17c54d36db7db73f484195d1a5ca2d967c37f9060c72edd03ba30523878cd5f79a750b90587c28837cc2fad11d49859a0c52326e6fcbda901756ebd630b29384a8734904ae2043d53c9b2034119df6fca258c2bb8034799cefa1708bc05cb18906abb4b694664ed685b99cad90e75816338dea5167af3becc3af9a87ea90291462578d244e0064965c752102379a484898b5c1c20bd66a694dd625ecdb67753ec7d24901fc3099a775f494c16eebd0ecc236a0004b9de9b244a1504a134017f64501a1f11a58985846b88175b00adb11b8c2efcef9e16a344108df48becdb3d9f50c54d49616b8ffe4940876eea581deb7e673ed20869e608397419c15b43cd785d605aa6ab74fa88aa6a363f8c714dc07a4ad232e2befa161ae241d12bd8c8573c2cc952173f15e9a7c1d42bb4878715005d2f24ec167333e4ba63d732366c20eafbc92ade0b544de2da06eeaabbea7186ce3b83207ec49f41818cd4048c3eb1bc66c6886a43ea46832ca4b6f905fccee56beb658212069de50c9407cc37d741a0c37f7400a5427d549d3dd61326c5bdc2c16e7ddf98f67a2387e67c388e7325d7f2046af534e0cdb9dd08570e35924ee5c22f0c1581f6ece8df28817ebfcf121729f16315695c786284ea9f44f601ec38dd12c2ed2e93d19b431a2a29564690a51b6374841526b8fc05a4875324f756050d23aa54fa4ec76221056765d001f882eaa2aae27e6ec4c97e4734236a01956da8163a3ac6cdda2a9b869bf1ebdd00ad53b4f154eb45105e8d2344332f85c155f907017b8715e8722a7b25ee4ff3bcfd05027af68fb4d4a24b923d33c6807145b86880809d6abf9b684974ca5beb69426a45e6b2ef336a357c748ee5666514f510e134dda51ddbd090b9eadab91d7269dca7652dade2a4b10625821324fead12d5090916abfafbb4e482061198d94618bfc06b33c340e01145438cfd046e38d821443f63867428a922c8942cff073909be1646e3e0246a9d68c47af1d214edd235a49af3786dbbf15823ae111fa76ef0d5d0fa6f51149f7608497dd5205e04ed2b1d55d9306616bf09575273b71843481b4ec62153a1428974a4e955823ae166eaa0c857abb355be09152112c26cff888453aa5f3c1b322752db012fe2a7c3780802dab155a8f1927239e867c685b444cb66275f77c4beb1314824a6e8f3c1402cc56d398899120d1c608d02b7ee52ffe90557c402f804d610f87e8a46b8239ab3218dd83eb4aefb3226eebc5168d5abaae94fcb0f03857cbb35f731a1eedadbe57da8d1a89c6900ee086449b1bd7b103f1ed0d4582b64c5f7fed585f8289ef5a6fa28a07a5a4f981c7f51b8ff50726c3e61100b435f82504834e55d13c666c082a5e8cf4e846efd59958fe8520100b41af37be08f1184f0d90cf53af80b531024948e722ae401b6840f00089f2c65bec2d04f61ee6ac10979370675eb944bdc55b26d5910ba50d9696de2f0729dba3b26f7ea6362c93b4e140d18afc5b2a5d0ea274edf20f0614d724ebabfc300844d02eaf2397921faa897ccbc72958856716180381be179a6f0e50ce6b7e89bcfc57e5c3cdc04aabd4232d964a81d0846ccfe737260c4e04e8e82ad1dc8992abfd9c74ad4be18e99af9425a3b90eba6fbf4f66d252bc044517a95ddeed3318cccafb5acc69cd8cf862b3443e0bb0469d5c205453478fb668798a7cc03f8d5da96f2eae40ea4302b03ba5814b230f7925b6a9fe6158ef14a2a0c35a66d3d5ca812a36fa62da99ea9ad38f4966d350dfec5805626eed0220af305bba8020ade511f7492e157c2d8227a0427b804c1f57944f57b2ebe2c4109ba98cd76b5ad19fdc74b07e30d5a0061e34466ee9e4768675354de3b35a13d42c7276dde1bc5f562895c487646494b15cd4b1ca7fb2c822863960c2c82908b7061fea3d63b6b9ef0da8428862839993981e65d741d9b4b8ec907a7c8cb17a5e851569400db53288a7e30cf8f46892f7d4985684622665202cba500f64a09f13bd33666efd7090d7899dbe0acf16e1be765a78093b0b907b4d1fa369acc46df1a2b56912742a5efe6c8b252df0028ba9441037c3aedb98fb2b45de6b339e20812516d6c6820474a9da7c06181bc4c48660c45f468f1fbec337e175d54a327c294fedb07bc0c5e57b309475d7a299450192301002ec867dd1d6823fab4378ad59ba3324295f02aefac7a821680d330852c9a945a1d12810079bdcb1baa13a9b3491c2840ba355bfa26286ce9dd3db3386842373d687e4c989f0c861a6bd0ef0fc46dc392552351ffbab90ac0597154b30eff6bd35e284106ba6d0c16fae0d733592bc2c8ec0e45244debbd384c15f9b58ba00c054f698af5b831c159fed11253d5a50ff985c2d4295930629474ed597781933cee37ed3683fc287e6b20f23c62e33333f39c810a9e9c1ae16d9d924fe51ca3cc5086a51200fa474c9399e604a677c6e21092a1ab45921f8f366a36a93127dba861e2c07d152d3eb3d54a99c796f4d69e337d5136587cda6c24a43db96c157c23cfbb7890d59e362b3e33d09bf32c27b32d080cb8a8f8f0ca58290500ac8e1b0e3c599e149fb90a40213ddf3b1e13c0311cdb43be9973b453cc8512365db2477c66f9b3b75e47111b1c0f7fa18b945987139f79e6b5a4e3283c831dc4fff153a6d335c5a716981e44634ef2e013af38abb3f4f80c4a7c44bffe15eb9f4a414958295770a3d34e0484030fa030ac297c16dee52a4d85584db00f012b2c27a6cd539ebff5898174d9b2e93390e03992b42ce5d8e1302d57464fe93cc03db279da6717dd883720bd138ce9e7fa4a1efebc175e8cba1442ef3d0a30e1e3b6290739fd2e5711651d579aa82ea3931642948396c1eaa98b6a04f3c40b411e38773500d3c833692a79c721254384a13adc3733d9d25d584dc61dc4f76c2f0c805e80239ac36134c860f841dcdf30e6b11d35b0486b88c97ac4edf9c870572997e6702a58007c68271fe1ab9c130c50d7932318a3a592ffb6fd864e22756b8c259ab4a572a42bda77e862a5adac88bfa875185efdfba971e74f5e02071bec76516230647a5113fab45e454be8877a67574f9e9a9912d6d2c7114f3179242e9dfe915cab01e927c57e2ba9c0dd5ee59300a49711d58df5a160187c808546d8749b2e3c597af03ee83b51f20190c063212b478431b14eec8335e929aaba40329bcdb237c78a41903eeb8342ec7b931704496c505b101e59af84cfea72e2c8598073065c914f0ab6933f8bdfed267ad0c57eb2537534a620d1ff4ea02c9158bc88e40c12195373379f064858424e67ac6ea8fb1d405152f3b1c541e7037549d59a5a3e224dcbac8852b43a3086354d559c5664aa22bfb397aa397fc3946021f5eae30327558ec07b8b7923a98208ac227a2f90586b39d4c3d50b2cd3c67ac44aa96de74d4350db5e0e73801f5b792eaa76b85e7b8b8e58028196dc098a9b757242ca622f8bdc5bb56949706d3844efb3147e3b03396becb4a18d299ed3fd77a8d39ef84df512706c7d2c0e90558e9a549d895927540126e313b79f5b4edaedfe84ec82a505fa3f34c368baced64a4c103928f70fc7b903ee249c3ac02179741bb95b7b257253c5f7cd8d5b5af238f7ad628f781c713ea70f98b41611953925eac508654aa7322f06177bc0e9ce0d3924bce64e7fcf50edcd4be955a51f1bf513bc36b11c60f8cf1dd4e7d7e959b2474d95232b3c82f8b649744408599e0d32a8b70a868c3466de35bce74fd7a85759e279a869d5b81b1c446d0f0d7fa76a604e219c8a040f6338ca334054ea519965c11db33ab5cf7c58b70b84a1161a6474ab5cae3294ee2353fc8509d8f64b9a1ea0e42d3ae22bd05c4e27365854735078b2cd8a06eb1f5f1fd0b08e5ed07ad630bfe17620e094c69ff3e8ffdae53476a5d4c48b5dcebf9475202b6596a3888804b01a57aeb85eeefb5f3e83ee333af598b00882313b7b4a052c8547b8ab19efa65264f779a319cd0f174e1bbf421d06973d8a32a4ce952cba6210eb6c1e0da4c547f0f3bbd8a73f492d62605a7492d8905fe804ee626c95f9b341cd692061707d47055a6ea4263e4b476163276dbd593ae64c2e0a15679414a2c7b242a5f34c85bd58efc2d666236b70ad77f9b16f514da75ab5497cc9388663ed39508474b938d5389aeb5e0cf553594c89d0fbaee1c61c42169cdc68ce76d4435e2645784ce623318ceddda65c719ae02723d6880289e85b8e59af060518b1d08eaa911d89433873fd0f2828d5e42c0fec0492deaa1cac217bc269ec5cd62400b79072953fe5233d4acd84ad303a5a57084c1a0a084319f470262817cfdbe616129c7dd11ae542dfec9a2302377310a9f359234b7dc75cc230eb8a4b3fd2d6bbf1a20c19dd4b0ce213e7ce35150f1b79dd1bbca0a539f43f180e54954bb0466c894b54b08482e1d2a926b3a96bf84089f830e868a330d7c9685939b0c085782478d261a76dbc891636a86340a322ca389b667c4c512c9777e2a3c509bbe16593f3d8e489686d2e6f542f9266fdcf7f110315ea4510f19177da856085df06f0ee49ff6e93efaedc245a0362cad1ef5a84471dfca56585b3198fd46797344eb00a3ce9518c0e7f7e9079735dbf393cd9612c8c1d8f24c8fd99be39731a8b9371448488a627996427add2c9190bc8931ef462e8526dc214b09f78982ee9a66bba9005180d969843b040a1ab44cc6c4dba3414060e03893aa8deae962497d36a3a011ef02276bda3d7db7f313311834a732a0b619794eee73da91ee6143757e28508d1ec7001396372db52c9f955e019ffba699ad698f5fc7364291f43198b0ce6c2ea69c64aed3237c033353ac06b0f3a9b5ca026c5574ee5effc03a9f5602fe965fd9f0b198529cfae9c6bf90a382a09d32e826c533d8dd523352e0816adb718bc093253f9c5f7c82780c5f515b6de164835120ab902f84247bc3ba4012963ece7d180aa8731e827188c067c620e504699df3be423efd2ff53b32af05476d2b87ad5a743c07d1395bb1ac631767f227740618a5eeaea0958aa27a0a6870a4965c00f6d4b965885e71957cb707642c4d51bb1dc62386678b2410583e288e4581502decdcfe1b5dab99918ae33efa9c6891c137cd129a20450697488c4f047b53fee115c4abf69d00015a5fd250c4dbcb6e1ff0245ec85a3e89839bcdbf2f9f009e45f3a2681ae737181e9303ab5cd57546ffc80df6c212f2384c972a982f39a274fb9dc8667d86224f5463f4e1d4ca876bb3ce7f99957af31cf5cbf3c68971103422a44b00ef8e7bd0e0a0cc481f1ec08784cea6a919a5e14960c03c360ec229639dfa884e05017e6e602221a86351223fad71ebddea5668546da738e195f4cf2af569fb5f60ea51c55d30b1f9fe972bd2e1fd9643126201af561cfedd23a486af9a9839c77c4d1826824a3d2acc6047a6cf910b06f97419c1a8d7cc701c1cd02a4ec09e2ba3ca20f9aab05699e1635e9b3472e32f86cc04879caced6fed094c1c7fbd5ae0c5338aa9f858dde86752a464a6612c3e2b6835fd108d386bcb7df83abbdcd021c03592f28057a0370e04d026a78306fa511af24287b1a29956976d439f5379d73f1503ed71b0b28dcd294de9803c069a3ba9c1bf9076f147980501cd12ada5a05b7a6e4be1c2255452a31d315670498892a45bad2c3c912a32c76848ba41d430100fb5773a1d6a8816d36443a101cd5667ada060d927faaeddf7a27a600950afb889df289e0623ad2cf219e518a4be11686befb2db31342619945615df4a1448e3ea9e8e4c235f5f8279f46ab568ae74bdad1875c2bb8173fbd467443829ff201b563f8e9875f1f03119f305a4499357ca9c941d67a3ecd2b0bce711da6d681f51e2a86e0843a1f1623c45c41efcd970d36b2452cf08b3dad1007cbb854dcb15584e2625874b31cb3c6104cd80983c8c5a5d38d9c0b28bcf67156d026ea167ef22ad63ae09b5c0c12f5e17e22d384595971577146d31d22613919759d28b23f6b04503fe94b8f116e5bda0f3000012a162e62d718efad2cb96c4de35fa8293c772dd606f0cc80496a3b9d0c75ea86680ac3f032c2d11db58dcc37740dd4b77406e04896c5086d758b95cd854c630825ede8b54494ec0771c49177cf7b7050f051ddf0aa509ca85f0e92b52ec3deabe22c5906fc4b972d0ae59102324aebbffd16f126f0e946cac326a49522ea3fef4e3c88ebb3848fa43518232c82a0d40a90274768627d6376f504280b7d6572a60886f2696032a19c2cd70051f86bc24820bde283ec4dd01c3ab05dc5ef33f727a97e1cc6d4aedcb1bc85445a879c89d0bc37257f6987fbe9a1ad643902334279a1aa29e09f21c730afaac7b07a57dd86071c24614c0786f630327a767b5521c6a121278c21b54de96ca564a5077bbc75950b23c065fb0515f21195391a5f15f8d9eaba20153454948f59301f19d740528e4d81c87d501d3a621054bbf00c472cb6d03734ae8cc5385dbc9bee4636a7359fc85170089a3ca299d65ec5cdb10b34b4480bd265916afb25afe720ddcdc4a2b1e3e5c435eb00d48476c46908609f750f0c9c7624e85c1c395ad0301bcb813a302b76aaa5750818ea88fc37d50ba0332863d177a2c355de4003f1a7e8dec23ccd18c7b7428e4dbc46176e7a6386ae55fc5ba12924ea472d9bc4047d258943ef5a9c1bdf15203ebffe53a92974cc824a15264bc9c0fdc13ce105908fe169a945a5ccb813970010aa82f98e66e8c3be7146bb1491d6dbeb898a23afc7b3be15c610a2d32c8c9606b45b5bbf006b8a0c7d76c5a339e125c8a4ab4f9d9d7ce4b09736ee47819daff7106dff0752ee23dd96a72b30612a9204ba78646317b200b50aba235fddf444df48c988334dd727f320e488022470d5a845ce0e74ba37d30480e963dcf87528272ad1074eac00dcef837499d9abf80c90b9e30198c0264e9988a01e9dd389221e8fa83c10287743a014d71d4faa99cb94f64c0959c9889994ae525feb0fb53d6049f5827d085241ce2f68360933e0d2bc3179438020fa335200ee1f45d0a3a91e447ac3a18c300e781da598d17feae6846109cc2474823adef769ca4d874fc5e0180e390a8057b8025cf0718a56f6d22b66750fc38362fabe65ea2c5fa8744e5793861011e07d4ef4469c646c2a14e5cca567283157c0cb6be51e881e23b79376047918c24a3bacdc2af1b14842e95ed779808cb7e3dbb7ecf85c058d73274c4bcd2cfb4aa16e1f9ab04e99b62cdc3d57259ad796488cf5ebca609cd7f85b4a66e07733061b1bf450afc6c2cd6eb86412c96cf5d56de7bb4a2e5f259f29122ebfe8d65e1e166d41775f48d5c070c5a88e0c4639ca03025491b92db6c054130aee5873cd84a81423d95e58b24001ba6dc04091260d375ef06a3b504e54c2faca6c22a362014660dc5f048bc0c3ac122f3c083e07a17e4ece08e69fd9877314d3ffcc3e19c9108a2fc0bb0fabdbdf13452f5ac0c969ae5e55582c7c00201ff2a10164096b9e380247ae763936fb55f80536cdcee27bf2286283a70d9b679b3c70aad10a9ee79473e1886dfd4fdecff24a6e7049e9b0df35d2e65014bdc52c48543f07d979592fc3f5c2dd8ddb8930fc7ca1fb21b71e859b8322ff115ab31dfad46d060331d2bb94d3a97f15a72b32e7fcc2f14ab70ccc260fe8ab6b738f247ca293a75acf0c52a62f9dd930b7c789d1793f8cc05756f51c9e1cd97d477062e00c4089a0466411a49364936d6592cdca82ac43285ddd5df95bf8d0d24f84ea75204153b1d8b7bc841f00c943bd925139d40c6614fa4056bebc3dadede29d24c6a52024ff9a62589271ba7954e4d1b424db3fd637c2339356a4f57e413ab4e4c36b9902343db0afcbd45677c2ca994573f6def7cb1e113e528f8324feca99f46cd842528056da5fabe38a4166cb5baef509f5f74350a3c58cf37eac78c65091520a2b90fbdf2fb90ed4bc271c56eb83471c9ce08dbc6058ba675262d16aa13a5a352d810b8bb8b384d601806b1cb6be4190d4170293d8cd74eb9a8d41dad870422261189ac0e0a4a6e7f35157b031466074b70ba76616feaec9e5dbcdc101f1e7c2ed5392b070272d3050f631b748d47208e862e5e49611ba77b1272397dc3f3a329c8d58c3ed5eae035bb4fe5d146c7abb55df05f4a0fbc37f8a4ff24a89a257b4a42e7c68f7c2934bf533ba23d84d8816630ba4106d049e0de5e5271d827c97b8a570a75b7d424537070c78f74f4439f0b5002b548571ebc7db838eb4ca98991f2e7c661e3eedfdec3c8efade670a415b5c6d686021173e8209621ea07787221364676009eba27cc5cf8e058b2a81cf7c08d857bdeaa5a6fbb474f8dbe2d14eac366374111c6b0fbf305ffba4ae17f7b1c8b4a7b16fd343d35ca5fe90d1546a10db741e54d13e6de6b26a5db86dcdd2953517f01862bbcd68d98c032c2a9af18a6e10320bfab0d42204863fb5d709bf7dcc65aa1e5c832dae9730feea39612c19ec854692ef90f75d00e5ef051216897791281479b109d2ab8d635d226ae507e94af0d08a7af3534e8d696e457f44e10b5773fffbafd431daa5969739f6feb5a8e801f832b68148a95f93ef1765446fe5b000bffe66491207e3236d54ee01dc87524f70fba91a648cc3526dcdc03cbf6a1ea5fbac41b753d14006a10d94a3d7117e71265600568acb58aaaa8cd7cdff11e2269e22eb60aff64279dd01c31209205897214e5b5e821a30d9acaf92d32ba03dcb7fd87356920f9363bcf9d680838d0d40a2ce21bfcc0ae5346d0b651f0064f11ce5214a6d079f055ffaee5abe01e7faeeb2c7cc2021c3d1cb312ddaaf8d03dd5abecc518ee4d39c6ff0227ffd535407e64ef7b16f403d7bc9b77623a9f2285d1ee4b60861ad2eed86346ab3abf101c564447302fac6935a1857843edca484628749104b4e70fa67dfbb92b24c1d9eab43c800144d44c3834586034628aa749502547fbf2687f9dfb290cf9f5db2cbb11d8cdde0150c5b9d8c3b98c9e80e381b7907e969570127ad4248e4a6012a6db2487dc03d93a606d38c06a91d7d130c244d42aa6f19b1c9b361b2a36c867d04945169942aae72046810e6c0abf54aa7e873e512cfe2655cdb1a5e9aa6f5e0e5894314fbce1128e2e44256588288437fa0c80676556cac2e9d58d95d7465de71a9070049adc4f59bffaf8d89b8d0daff3591b7c00b5ad38914a9cbdcfdcc7488b9c80e03b03c757750dc175266ce05176b0268f40969d15894dceabb2df6b991323c1f39f464bb04ff74115646e2176dc1c669823fd23eb8b079a3351fec86831df2a2910000013373db98ccba6d964ea1f80a7526a20f1b17c292496e133c58668fd102b41c7257f3eb183a3b45d28234558e9c12c3d026cc80a12fb447dbbe52fc977852ff2ff88e6cfcf03dd06f0102e921d8f4bb6d580c782a7ab24b59ac79bf8e4a1ed122aa30ee06df0152886d5f04a00c673d12807c2d7a2800591a7358006ad626bc111a72f311a66f6b2dd0169cd60c729cc7ceab3ba63c2ca92766eb13416dc26666ee7872b02865f80d1759e7386c4fcd61474a50daa817e739006804f7245dc54e5677d5bce012db02c74e0843f9bc4cc1f0bfaa96c53201a8f0d4d5b6cb5a429bfc7b79c9ea27b37f1d68d76f857c39591a5d8a314d7c563eabf6e656e09ed37594901876b2cebf4bd44280492bf776a6c4f7abe7daba22471c0d758c4a1e7b4897489cd730b1843e1967066ba884350f6152e480fb7b4b52f788fd8d544b00eb7d228dad3968efc40a5f1b5cb185146eb0db2dace1f3f58003cbd198250c3edb13b5d698d8e73f8aced95a5325dd40f247997873c07c426bc0b2244570d04dc48d6b239e5c2bf2e108aabcd3cb091f6f772b023bbea507a10f4467ba4007a30b54173d00ba967e8a5c5106850ae6acf1bda732239f41974aeab87249352832a9296a93d21148fc81924cb3091a24888b5760ed54caa3d4d12eb0162b164add6cd4df341bbc8a01081b056ff62928d6f3c1915ab4d41a9a9b94c8f5d6034c0285a58267d2f1a214b11baa4455a9904216ee860654170001c33fe5e5e495df28a68faad9925973552b070013f9dd88cd301dc2aedef58fe8b4134eee284a8a3f0eaf4fef896f50bf1f908752112a8b6bd72fee5de708bf16e5b69fee0f7991124ce581bc41108be8df4e4230f5f05bc278d88a089a850cb7dde60b678af98d5372a88f163016ef26fbe9396a8a8208e8e36e3f01de61bab10076ccf96b91c13d7d41f879067ced15e0b8b47fc15d737e52a58560a01582992b5b361eddba20b26d02becf2622f61ffd7b8e1a7b441c8cd70902d693cd39ec99f7cb06143ed99388be50f5af00ef5bc98d9d0065a3f16804ae8b4ef54771d101a69356e03a6800a3833e1585255642068e98f019c84d800bec0982cf0d05190849619ccd09a72a08977c16ab451b2ad8585484022ef3dff7bebb7aa972d21ec37c5dfdf1e25083f53a5fc261bf05acccc6457df267380f781983c097d10b475176fcde9f3875a764204101d4802f3f29a200533728e231fe0cfd34f862a4bf845707fec8d68a4cdaa580f34026906b89829ffdabe0ec4d0b744bb132abf03f88e520293b11c08c65e7b3453f9ac70a55d0c972202f46b1ade26bba1dfe180205eed9142309d4a4d909606a394fd08977a8a02585942d9cb150cfac40e97aca83f261ab966b1385d9094f35288053d26926d175c5eea93485e2e3eaac927565bbb26963fdc30f896b1818f0f2c42c316f5f5f5b3b4ea86ffa62e275ffa15184b0f0dfc0739967a67edc23146feed15a81e05c14555324cc9173a0e3a3f8c43d8cca3dc9d03d765cf7c0bbe924d42eca390db9551f9807d2c7c1375eb137ceb1d449aa6c6943fbfe3d3c983fb5f1f3cfa2693d16fc2659d60199767b6eb30c48ddf3be6f0d7b44ab683e356bdb91f3ead7ff9b9af2494a92cff0edf03bd4a0c5a7de76c5e32dd64a991f9de1d58a34247551e83ba304033aeb93b8c055e4a1205d767c39cd765b77ef81e2446ff8a4f7c02b6776ec3657653ad5755e7d799ae5cd0c2b7544c2c44c86a5ce9207d24b9211681e6964ed221da506918775ca0ddb73057aef51a87b3a7c57b7cb2ba7eee90e8466fc5a4f9e14e83cc9662ccfc5038a7a441a7584234f3872edd6d0c48ea45c64a11fa0ae53f47624f43521296746c6ef1ee1607ecf08f0c247ac31c647d0d8e42392d3067aecbc4c8a5e8d60a6f200f54bc0c4183a2029387b79c46dfb34c1f0620f54c2adb06cf32033cb9130355bbd28d2d86db3d58f7095b1560565e9e535a2ff60ec0356a65ec3bcf16d5ec399352574dda7ff46c9da903b25c8a0f0a1815acb495efcca1fb25c4b640c8981fc5ad1274c150624fc246206c684ae38100158ab5326574eeedc6a8569e1a4173bf2f740cc1c0c2c8005de0fc5dc0f54205c554d3a493bb1e6238d37a6583092b0a4e7677d1ad804f30d19492ce416cb301b56f7c00fc0f11251950b0a4818436be773ce4bcd3e1d3ed7e96a8672fd8917eb5e428f0bae7afddf964823d208217b6fb977fb0f360f990f1805be6f2fef5d14f8ef1e0ccc439b3b1488818839cc77c47c3007bf03e6e0f79cfce150883d8987cc35de6570690ed6c34256fed80d51f30e07a9f98783d87877212b1e16b2926b30b5f17bda0591bdfbec7ad8c0e1869398b94fe31d0e23a6184e62e6d469bc3b05a44ef3d82920c5a56eb844a6919797f6cc34e76449eb8208bb7706b23704cd340a08bbcb8749cc9cc2210ea944733bd3284062eae190c6939899a6060e73320dae711ae77a5e4e736bbc5e1ab9c66dba069e2f326f9ad3384773391f1a97eb9981a579c8f5d00082e636fd923de69c1c62cb32effbf29a1b0ac935b4bb79a171cdfb9efa6cf74198eff00e835732789953f3ef4a99dbf47765eeefb153efd787432da73e53a781e5513dbc7fdf91fa8773bacbefe8522fbf97ad009965709097c7f478c131b79935d7dea800529679e907d898f73f1ce6e4efde0d57b2776bc11bfbebbac796120606dbdf83200ebd5f213975ef7e770432cb5c763d3acbe020fd98771744f69818cff3ba98dbe36849e6c6c45ce686327b3919658ffa0e3e275b8c82b9cc737277ede5edfacadc1ddde5616e0ff0eeb0effedd1e165f764078afb9cd7c0953e75e73c325720cca3baa47f7ef3bba0fe764cffb8e10480eef5358c84a8e59c9fdfb9c1c23f3cb8d39e6bedc66bedcec354440be27dd5048be94a6bb3996b6f44b332dd11148172a776b22037bef3634038bea2143d4046a2541cd22138afebeece136b4636b22a7c8afadefbd174bdbf7d22c5baeb090488943142734d404a3b82422a039882b2773b2447395810db99ea35ac4865ccf572449ab62e47cbe87dc0f6724875c8b890c88e4d824472645820e34d43d41f4e5bb1ba4eb80f06e2f7b7838ec8f40e6ee337ff1eebef0f007864f76372fbeabb67ff3b3a755207d1ff1ccdc7ed1caf3d8b16721cbee71a85faf9316f1c69fc89305797693a2c8dfe2c6b8bbaf4c0ffbb28b703d1d96dddddec3963d53b4b82dc9776b637753e336dd47fdeaef3506b6c6bd0a03fbe12d497f36497f9cc42108b21d325bde246816010de271366ae050e61a4779a8e130099a6bdcc6b91ab76ddc2e7ac2768ddb34b79a469a87e124e88efe11310f0aa0f9cb6ddac6a5b92f2a8897f71b07a1f9cbbdf76d27fd75d8eb4ebb9b28506edc2137cef94c70ca9b4a5dd2dc50669a6f40a6cfb9327da61c7d5a9ee0c353fec0ef8b0265e6b1bb8179ec6e62bcc3bce63387519a83f50e83fbe5dddb4feec5f46b13ea1898873197391773fb48e6f6cb9389b9317bdd8d4cc9fb7c1fcd5cae8833e10d688240544fc15c50e783eb4183ed775f3de4a4d8603ead952edb98c6616ebad5451521801b17c04f7363ae61e3e00d5b8b3c4fe386b3489eb717099ac3f62ef71a3bb8a76ed3369cc4b08df2bc0d9a671234bf7c763b5e5e4a3682d85a496edcda2380bf5c11d0dc3808f7d46d5c9a39d5eda22e6a55b809b513d58d116c8d2be29c7045a91b2641057051f2a66f42db14adfacfd011728f4e14789043cd091b6e40291cb3a70ef9348995f8c66bbe5e9f77d4f7d9dc4fe6cf3cd25b4c2279f6d1ec993ed388f536a0edc8ec38d9afd7abc7f3f6e435b99fa933947bbab7a1b98a31c6e885f43dc04071453c7c7ac1e2e2a17cb7f2505ecea7bf1eae872ba25239d7137b389fd9c386dcb53777fa9b9ddc9ac8ed555f60c36de828cb6f4344527e6bd2df94f3ddbd5df7ad49bffa83f93c7d0f6dd7e110066f4443fdcd701beabed9b3454e4776d10e17b697945c4fa8f5bc26d7f33d3c0c0e531e0e71e4b05ff7ff4a6dc27a0771a87d38bce57a3aae07077da2f405ae88776ff8d9dd745248296b3247dbddafa0dcbdbf1d6daf563d6915e9922b32ad7099f0aba7906753916717b27dd857c41c2df7613e6c29c478d84bb84e9267d84af2fd3f37ce4983f3432f86ba0d0813d5c891490a8ce47eb50a893e1249682d4fc266ef13fccc3f00f537b72301000000c0b9b560b6d606b4016d47405082208c4ddb1b00976f475ae5b2b56a7777bb006dad564517dcdd4d00dedd0d00de97fb817312b38833f33077c625beec6e665c7637f87d37dadd7c381c92bf7346361ee2a079980abf87a7540df83ead98d4e1bd7128e487dcfde596337ab95c9174822be29c34cc6370a8c5c87c06cf9c0687a7b90d1c7eb9c6ed2771669ec66d39c49979eff61c64cd7ceaf651cded2d7e260d0ebf991f19fc13038343edf50298f78dc41c0d73b7a3262c38e3f27efd42ea6e5eb0b4f2e5d28c45613ad62df1030b499372cbed1dc499790e2b795ace4a5c1167d4aad80100800bed3a29a5149e10b1620e6c18aa228b17b9e00544a668a2054860cdcb27332ed6ee4f4b224794358fb6577fdbab0708082866318323497002c8891b702074440b3a5b08210b3a29907db3ccd152cb4de72161cfdd1b238d5f5bdc8376f78821d9e2be794aa02352220937a00da855520570a0430d5e37d8420a39c400065760220d3a433fad1f4ec8018b1cf0600c3da843019ca8220e403500431ca460cdcbedc8d05c6daf6d686bae677bd172638eb1bd668c2bc89c4ede8ef26baefaa7b7578fe7eefda3591c6afd7ad12d37ca58d39771e7a571a646b0dfb20217433c77786b6d40fd63a493b42ae48af24fffcc6e714eb822ae28a7c70d4e0c01084b8ee0063394dad0043abca1065a1889030ecab006298844e1043c50a1811cf4a00b4c7a84a00528a4a088007264b27345ee57ab20cbaeb99d29708e4c76806af63eb989baa7f87987715be2e7bd87fbf8793fdd95f8797f716dfcbcb3dc52fcbcbbb85afcbcaf5c1a3fef2a37c6cffbec8078ee5a72775ab12520b46cdf1d10345b7c84bc54053976de7374f14049e67eb922fd4dccf9703dfde67a5ad5cfddb567fb26c6197bf9b2b89f743d31468042c70812da400738c435ac410a1cf480065228028624fd62828222b9e120575c8f04b38839b6a1383373703e7540c14e8e4c7e767cc8910a464bb21273d54f1a9cef2d56804525622393223eb92bd2d32f174c31545b606350644e1d27272547767c767a6ca3fc4888fee6c3de224f943381c11c32d7571ee572451a9c3dfd455665817d779982bbd9af8982b9124d62a5fcd4e9c9d3ddb124e3f4fa36ddf88899b7579ce9da08aaf111fdeedbd08e98fba8be3c176d67258e71a6bb4d47dc4ffa9b8d1b8848176955d82f23ade27a5a255fb327cfbf7ef2dc9a6cafe8326124e13694875af58aabd9852b54c1051d2466a08235df4771955364480c423048c21198b085b8cab9410eb4c04313159c00083960cd4f9eb86a400bb270848818c0c0843ab0e6fbb64f7f9dd6f54b9ec0865ccf51d83d73d52faee749af226bf258d24b2775372425e6ea4783f357e838e18958e4f90905cbc3e7c7e72776385cc96174b5ec10e254b283ed6ed3ede0e103e403347d8ef0f0016a553fe6d8f1f001f201e2e1f3c3c3a7d54719a857fd9ae0f431c244074d72188f98e8c0490ee3d1bbd5e1f63ccfbbd73e497c8ef818f1f9f1f9f181a25f3c7c8c94ee8d6bd35f7fbb4268fdecf6b18e3e3ffdc56ca369d69e4efff74d15d83ec193dcaf56452627c022cff793a93377fa3575e4ab5faf16f4ab5f793eec17f7ba4b740993475c6865294b730a369eebeeae28fdb9d27ada88961a9d190eeb351c9e349f39b19b44cd3d8db3a28c680536d47a5a4655f6b0359ffe7af2e723b1d6d39fd47a72bdd6e3d3aa58874ce78f3d23ea2fbb620a363c658cdaf08efcb141c63009479c11cd9564650fb326596659508e0f4fb973467f6a9594b9459ec70f17f9281fdec8e1716429a7c892874f10bd3c66e0e2318325465a11294b35eba819e94f6a3ffdc94cfbc9f21916adbaa6d329d822871a4ff6ca5e59f627a3609fed37e7496aad8e09d7974ceabb4b5b0a0c19572dc17e943d29a5b335124a0f9136d6b267cf9eddda741267a44b5fc1459750d3c95405963ed25bf3a6bda6e0524a8c87949aacd5a5023c640c87b1a8d6aae1fac3a09aed2ffb8368d8e2527f5d55da394dd334ad0706398c45da7968b60b42883b73ec6e78f4d73b368c42407a68a707398c453c8eb094a41d45c24074265de67e77777777f749987679cc6009029a5e0322767b31cec8dcf5dec0ddfdd3d4414119340d082d3ac1167278e2d1d44ebc235f2dc83a18d78252899352b68e4eceb08c5f3541eecbec8e204b196bea8c39eb14303356694e6e28f46a077bac486876794a074b1f23ab5e99b18e47a4b8d4aa428c31c618638c31ae808b8f2e933bdd1d31cb3823e59c73ced93d70721a8538c787302198e5e966294392e6a4bf7867d10de57cf144e1899e1c99fc14c957c8518a1bb4b2ad3e79126989e0944325747474badc0f55ba58d30f514a39ea888ff5a169c699f95a3373fdc4b273d90db1ce316735c43ecf61f7ca2db21ca49ef6d7f59c2ce5fa1a7354497bcea6126b7df9da022eba8429b27d5010bff9b045a73714f4d010d743434413d3b02376e610fb31757723a3ddb63cbbafe86e3825aefe261774a475c40691ede494cbdb6cb09109148ee49003026a15ca37a156d9cf73dc10e7a4552b9fe78c620e179fe7d410756c3f916bc22551c2b9b82579e3011bf2ec2b4a1bd751232cfaeb24cbbbbb6139e7c9ad09a14b86f150c6462e460c3c04c787c3c0418213e33de47ca9ef8ba8c7781132def21832300e8cfbd012e33d1cc90f18f7c1a6e5f270b962bc87fff0e13062bc8717e1c361c8784ecb7fa0de72f99696cbc0437064fc848304a7e5590e10238888885042c9ffa8cb78112d3fc6f95b2e03e320f9718c73ba8cb7e02143705a9e1dc98fd3651c855120b84a4c701e7589708392ffd1f2ec3f64fcf4d8a12426a2e5d98b90f15365c2e5f7f3e165a300f0902372c11cd0047df0e1317eee5ec99a53468cb7c838d746454b38659ddc42e7087bd5b1a1968f5a73151343ee2573ce05f390137a79c80d7d2d0fb9a21c80879ccccd1e734f87b93d1cbc30de32e30170f9cbfd871f3b9b96b99115f372232b0037b25a8c5e4746731559f2c5e1ad68234a0922e2b81523ad9278236a17dc0de237bf11adc04ab911c51c5b1eecf6a6c20abe20314657603d105f3908e9253a042b5fda8842ec67333a5234054b7be826049d9ad026534701630b0a8adf3cf613412c8aa048f160c3ed482bc599f993146020aa42f7d08fdcb0faed862fb88b84cc21f6132651b996de8864dd88e66a3bea8d48d6a3b9924678db69288c24f6e106f1e37cfa9b2f021a66f0622d51dda07383a8da7a103f9f566d53e388b0de5c1bbd83954164d876fa4371f77872e8f1d4bbb9fadb82b6b040f3746592564b4e8ac3d38771a849798dbb1bcf1296e34847a42d485b64d2519e1c9ee142d360659779d2543fc9862c8de2370fc2c4c4c1481ca098021c944c010e495e4a5d678e4689da21cb1a255a07a01c6a3f366e68614d97bf893342023812808a0eaad51c867c8480914ada555d57b1e9a0fd864e438f6185430eb6bbf6128e013cb1f4dcb71c71b03974c041c70f593414047859eda447b1511577c2a08029012342bd00a0582900595efb64b81b0278836d1fac091811a2ea0871959d84410113025d9d2e00951b6c0f0fdba77b693bc20d3a8a2884b8ca9e83a443fb6c25e4a9f520cfd3d5e93d70aa551bece93b627e149951c801f9481d51d684346339903a361aeb0a0716963bd5b62ccf5d5943654a9d00546cb0aad51a2cf755182e3e83804c50ead877f726577a2861dcbe8beda65befdd957757e5a59b72eea23c76360dc3dec8e280c422203d601b168c030790b942c51b3157a84822619cecf2248c83041571486f8c8a8facfac89a4ac8bf3807669fe5f1468d42c12a21f18e1c7a81a38de740c4d43666c146f94577d3010e4427d8f89b2350a73f043253965396d317dbfb3bf5f22c1875c23e4818c59291fea34f1ab2bdcf827fc8934ec243eae545b15c3e87d517c582cf726279184fa717e7809025795efa4823bd526925d1aac884073d7227cfccb3335b4140c8a59f1a1c2187128ad30b1620ad8a4c96a024cf4f004504e9fd1fa4371e8284e51c1ea2fdc82ef110ec190ef6faede220f9816114cb2b8e86512c1845441f7b11f2f518bd0c882c17e7b05b7abddc49577b76b7af5cef2ab77bcab547b9a6c7ce870bbcb363b56fb7e96c02fd4d8d2b75d3742718591c98e034024824aadfd18e7df3416ae96f726082f3da05c104e7334cf2e0537fda0f5d0225a7a91503175dac247ddabfeeeeeeee6e9296b9b0240babd736edd9f2b95f72d2e055ea8f4a1d514a11d4520bb965155a2ae9cf2583aa8e95a70ce408895247eb84f1c5611a8771dc16f1e07ac26d58d564506e4c49aba214762092fbd2483ee99564a2482e69558c421349726722e90a6511d723050b88e45062219be4be8661a52875cc96ed61241cfe9501214692557f9aabc8526229b6da2bc719736273e0a24ba8fdc8a8f960ada7ead8782073255912281f49622f70d2c26691a5bca81e39995e1e1192304a74b05128c79c814c504eda041b5f078c6258c52a95328c2e3a85f608cacb879f4d04a58de08d9f3c76b548e3274f5d99a632b5b9e223409029105aae151f3124534ae3c0451a3b5de67c96691a86c3e7ec15c361a645fa1cebc566c723865af7a30d53bf11461c3fe4b6e96977a88ea6d939e30b0662c873626a69132eba845b2b63e7e61312083b983588436d84bd326171ccd5ca2ae5d8413057a44b1ff973a3532cb2c721812cc6421ca74894431cd839d295ac36c28c48dddd2a244db3f674fa81e67f3a613dc878714261e15cc8b8a4f770557eba30fee2a2ce7977612a9da57bec6c5ac68d2c14ae6729d21213366c9d8c9dd348a4ed1ac6d1be69df30aa71b693481a772d499b7d27d8f62143a23ebbd15c2169c1304efa0eea2a9b760c890f3804b275e66ae5d825d15ca9fc855155fb0fd2b5d76b2ae77258a13c6a9e870dc43dec16f663b1732b57b252aed15c6946b3e536bd72238ba3496c6711b1c698c8586b91b114adb3358692fe30970fafaf3ab68d5c8e619f3a333e7beee35cc93800ae76979bf219d7c5f15d39ca4559191765cff27b5f3c769185323457ad8c1deb21ac8932e603ae1d2475344fc6ce65cf2816f626d2cebd08d2378cb39d740ee320f9b19d84518dc35dc3a88eacf7879d74bf09622085820ddb2863dd4dcbe56d2c6677d36a8833d863d7467106934eb0f208548c10c823ea6dbdfd112eae558c8a81391414ac246f07b59225197b07d51fd816ec1c8751f5dc86b9ffd0cee121486ac53f526a46f9e0b6b7dc9abb3b22089963bcbb9b9677e703e5db4555eea22afea17d7badf847ca65e0212b4ff91017d76c6d4992b1c708ca5895d8eb0f6ce796db59fbf62252cec5d88c5c544bcf76512d38b2a812bb01c5c0dbcff693311fdb1910591b46c5f8f61c560c8c2282f4ed3f48dff01024313e04c6498f817fa80c415de539ac964bf3ec5044a09cf41f2827e121485a3e841ee52df807e92a78c83ce9724fb9db4917e52a97440477ed4570d7300e921ff3db71e8399517b13d05e3cc6fb8e5cebc7251f691b572171765710fdf79f11d1757f9cee93b2cdf5979ca23cbc549da5148476d8771516fc280c8423997a2b2e282e5c5a9871e5edcc862b991e5e246d60a2b05e5eeec98bed37d873be93bde774adfd9ae59dc12bb6c72fb3541eca48b7dd3c1def964ecde4f9e4019f358a51b59dc8daced46561b4d109344fd61cfb01cea0fc34e9b601b7bdc5a39ce5802e372e4125a4e6b3e14758c95621806278e1733fcbe9ab8ca9eca0f0d901fae561996690cc70643955cf17c88ca33c6181ff12c8a38babf3cbb25fee2908f59e3d01767e67d60676327c85c797ecb348945891a98e7cdb3077a8a528f25aeb70a393c652933976ca2d9b41ab1b43f6dbe92e0a24bca0a653047263280227391c65a9bee06013db049fa9b4037be7a68b3bc5745c8cabdbc4256728642bd879fce8414dd258cb516e6864b64db9d6739efa6acec3af9eef6fb6d2fb3d7ddfb76b3489e4bb24d77979bdd4d2b91e5bba5779b9e45a4ac324e0ffcc0fe776b640ed3751fe8cd783804c1cbf9703de041ef9db7247bffe214d9c3611275067cd85d06fb741df64050a6eb8ec832182e913b1ce6e4cec6c4ae8b19a286acb1ff9e92359e5743d678ffec3925c0739cbdb3487ff6880cfcbe1be3dd3bccadb9bdcdf5d43c763735f7bacfaeeb5c724df7a9d3755dd7c9bce66e2da0fe8ed0f80c0e7fc8339f5dc90ef635573d4470e673e63233afa191674e13bb539c9939285343032353430303f39898981a35700d5903731817879999498129181818989973b20482b846c80ff9c56756b7f2c0a25a505e77208f432039ac17b292714ec6180097dd8d0ffdf2d495b9c6532e2761345ee24eeacb70defddeb78379df9a206a0e7399213c100471282483e7fad21ce6cadcbb3439303db63f76d6c2d0dc6eff2ff3cd7b63191a181c0ac932cfc91d0f5993ba4cbd461feb0fbcbc27f37ddfbf73d6da98989898980e06c67b5f4af39ad7d05829a5f576c8da0941e3fddaf1f80e805bf3da2d20ecd7e0d21c6c63212b0078ec86a0f10e07a1f1c64130f062212b99c6870581dfc75cb08d370e4b98723889996bdc468da752af914a615a8994c2c94aa9948dd40b7eb98de3c39cebae4763981beda9fb72d2b5f1ee86e8fcf23e6ad50b9e1a4edd3e223d915d8f2d7643e4d41f2b71286bd7a30f2364a5afcc12e65a7777c7c4d4ae4256328c262f31ed82c08781f9aeddeff682e7badb61adb5768898cbb4ecbaced677e0ed77802ded6733b5205a9fe3ba2bfbdd757fc7d7ed88b9cc67d723e63252c65ce6323128203ccfab5de72e27d392bc30d76e04ad166a1705c4f7eedd777c384a8e96663704f8987b41808f790cfe1ebb0ea380e8defd1d1db671e67b631b6762d7f577d84fc3e11219e6f58d85ace4e486b9daf1533766d2a519c60d85e40a002cad0f8fdd8d0f34b70fbd8231de886a3c06872b39e65cd5818539781aadea7352e23035039b7aec2f25c3d51cd89843a67637e00d6506a3ccbd542a891ca42fa494651e96b2bd0684fd0d4bddfbde3753e7644946667bc95c76c581fd2e739ad6c9343d51d8c9354fe4762483b7d7f7dd50e6afcbdd381452cadf65f0f6e4366d7f792df692c87d9b190ec932787b0929e50f6f4750d870d36404fff2486deadfb9d4dd88bebb0d35196ceae136d4a71bc7791c56aadd8d8d3332c7ba1ed825ee3ceb79ff52f76eea3729bc0dd9b81dcc392dca9e9e0d0cc2dc3087c6a5fdc53cca98fb974b33792691fe66bd81ad36b028d74e70bee56afd75cf1f39e470f2d460985b73f06e47faabf19a4b295e329d8ccca5cb6afdc1fce5a88ba239ea329f2e8ae6a7a7ced9b8e0fba6fedd7003ea6ead81fda6c9a4b8c4685ac931afb96958cc8d398d1be6641a97dd0d8d733308fbee395976570fe68037899a2bae216b62685c178fb92cb72c3f40301c14adfa0edec68d20786e5a7bef3bacf79c6cffd590356006c1dbcc98bb0181b7e99a1bae6498d35c246e500fe2f414a6fdc1dc66c2dcbb9df24bbf90a0197563ae7143212b39fbfd76a4b9959b7ec9939ed7758fd749aea77decca59eec2e536cd492e7634381c9269de5d8cdda6e71133d3b0d0a49e7a67adb5600da923d5653085c39c9c3a7825084a093e75b18739b2bb91dda5719aeb028732bba07196a768d0f82cd22a96d338a9bba181a59d4b324bae216bba50e695302e097fc81277328f7305f31a524728738906c71ab2a6fb6baeaa0d5c0387276f2749ee2147a11d9fcccd5205a246e64f4331535247cc12cf22fd35ccb1590408b97a0a4a48e33430ef15e67a6ca06010c709c6f8f2186b3cc69a733d2fd8060eb51a38856b70cde5bbee3237f57e4d0dc4384ca266f032ff707802df9de696e66069e0246a8e799844bd91ed69621e621d96b9ec7604e94e730c0e023e26899abbd33c4ca2e6ef3438bcf1b215cb3c84c14974fe2e83435a73bf86d401e220df636edf5d1031365583c39c0f07e95ef3ec86a8b9c335644de322399435648d74717959cecd928b1b5fec65b7c3bbdd866a6870a88138b4127fb7d7d364623859929930af797797e5bb9d652eccadb9e14b0da923669667b3484e061f23435303c3f50dd2ef1c5efc1d9452ca09e49ca0dc7537e6df8d30d6a6fba793b5f6a64b6b6870f8721998fe4b8e1097ecc91c7343971cbe5c884b26ddbb614e26917eb241aa21f31a191a97a15173991a34f61d730973793904f8d02577d75d77dd7507caee1ef362692c4d9f93b73726660212a3602effbdef5d14ccc17b1d0cee11fb030fe27002d9fb87c30964896962ced1d0d470c91e16e292696afc855443a66a9eaab94ccd656a6464646a649e929149c9d090c1349eb271994be3f5a668d090b161659e3a27939249c9dca66d90fe9d93f6ddb521697763e35cea610b8d872b35de5df3ee5ccd9543d03cf61703f39a2b1f733d19ed46ff905b055ed29c477fb3e6cadcafff74ea3ada60570387da69744fe1f034040d16e2926dfce51607b1f1cfc6e7dd686d74df3b181ce6641830a61fd392bb25d3bce6f83437f61783c353ccc395540ad3bce6c6fe68700c0d0df897c7c4d84cf08613c831f72e8cb53848f78ff4affb2765d75d72b464ef177e0f414e96b7376c7b7b1cb411c61c75f0864be42f2728872f8fc1425cf227c4a5b361e336d3c625a16e985324bf1cdf7002f945e6c6cc6da7ec94b99000703b8f74bfbbdc98bfcbc8212f979923dd3087eba181953bb822f67302b993898101afec7a3c836067bb7bf7cb7d3b67000421f377995fe66397f2cb63872bf9a525bfbc9cbe3ceb6e5efae57d4e20f763cc2bc2bc62cc5cf776322417356e970fb7ac9cfa9b7fe9724efa9bdf8072cc9b50aba6d882ba756890c3cd75c395dc195e6daf15972c71cc696e2824d31ce68632c3d4c89cebcb61980f043f9adb1b83c43c6b191999f0bec6ca5ccac4dcbe361326ccc9d9696ed8bfefae47e7ec9fdd4d4916915d772e3ec076b73194699e3a1759360aa9c09569dee78290b9c669aecc9f07414e62e620a9d33cd4f2761bef9a6b3548277bc0bcc1f7e58e9cfcbdb3d24afb61943daa07f8ef3bc0afc777fb1d5f8eec0e731350f3ef0be82effeeca04212364880edad48ce82f7b3bc9d92b15566291b3cb4bcab1db519f01e92f7b86218bb09a051b365016b12c6259c4b2d7296cff9345facbaeddac5ea1a885e64a9b60764db3364e5994659f473c11c1ec35c8d977903320e4ecb1933d712613ca99d0a6a31991e6d448e17b44d279c41c5223655128ec219348ff5c752769f67423487a89a47128db3389442291488f2ea427a82b6f593663ccb06049d8ebe9fb1722fb761e3147ccdb7bc41cdab7edb4b56dff5c79df34bbe11bc1eddbf650cb1bde708c603880bc3d768f33dba3d0f6edd165c341a8abb19e1c5bb5a9b0344b1c5da2aa3e3a91923a4a4c907297acecc69c1357dd0a922b904e7037b294982b0844905e7b289d2043a6e70e3457a7222dbe9ee4eda27e70db39ec5d14dc6db8cb23b268108e309e5665cfb2ecb58320579f20108e2830a18dd0ddafdd4d03f5d747ba45d4ad29ac0c3fa43ffa2bb81a88ba828866c82588203d131a0b327d68e5134ac419a08cf5d42e7581f4d3fd2aec9459c495f6146d9d4ca516993e3b8eb9d2b034aa38328d33d268ae6e8a0e9912d12c6d8239763eb29150e3c8d228939ae2808b2ea14927570cc3302ca262cc84b2236da7575a51d62428573ae4aacfa66855740dc1956b66946be7720de10c39ccb6c83523ca357392eba38675697b7c2ca1c4fe82ac3d9dfeaf35c1fa784e49de6e64752b4ecd0b3868b1866c5f42ba8188100b09fdbedf5a2e6a9a16856890246f57b2baa569d69e4ebf16390ceb6e304d9b5558ec3613bb3d5f35ed9ee679dec9ce154ef721a81f29df9e825390c37aadef21aefa8908d65779b403a05c49f74e93d8ee0e59e2893804b1ba635826543f04e5db7358b2634064c923948b2a02e5294fc1cd33c17a142c8d265875265833a18af9e47aaca755a6576bada6699af6d8596bb23729c9a667dd8dc93eeb6e2c969666ed58a70099b19efe6acd70e45abd978ea3551d10a6ec61db8dacee8aa0095ee061957004d12e5b19ebdb1a7d164b283c68509f493c640c4b2f5893ce12b262262ab69e19638c311af5974a8139a4aebca2564490bea96b8214f563bba822e8372a3441fa20507a34e537b9a23d13943a5a0708c3c8f451d2944cb5384335adbbbb4f3d4054c3a1cdd829d37b3bcb0791a75be8b44a4a4cce170e49b8ea607ad41fb5597ed53a3a3a3a3060d12622183302de908208c6943c5f7345b588203d139962f3d5d1a3384331a04ae9b71eacb7297af23c273bb9559bcd2a6c562a65380877adbb2ce338cc71dcb3db4cae74ab15b4130d59c2480c5a2cef1cf7528905acf9eda27e6cb7b77888fd247d763724d9cad94b9f55d8302bf5f5806ce520a5c78ce37d08ea07cab7a3e014e4b0ecb7d3249612cd1589351fbb00280fe9933c2916795227f9c86a27abf2d3ebaf09cedb45134415618f72143c7570174d70f6d104a7108260434af49a730a1bca5677d96a95e9f3480ee9fcec803065d3124399bbcdf4ee08ae68b5585bee642b4876d9cadc0d658bbbb5bf0c0b91ad5c1fbb10845c31121bd22a58f99012957a64866d34a0420eb0b091e369441df47fa4420eb6c8510a28004246550c449665628e9b9aa9c9f156eaa0b88b353d717fd2818b2e61495616c42a5934aeb4b9229d3211575a75692ca835c8f4894cb54c6b50a61528d3daca5a9c5e149206b15e641ad41f9598b62608051b59f221356a654a872648872e2d9a203d3da25bb42a32c1c14ea6af403549af5c0cd59d56452650609169ab1639aa3e99ca179339942187f527d36d08074572588fb0429bb1daad56853882865cad0a6951a6a7a7495a15b9b0851c522de4902ed1893964a6c7418be64a9e9e0e4d3a24d32a296c488f327d6324680ebf4c437a84a3bf1a048b4ddca5d66c92a6699af69a655956b1ac6a5957acba3a16697d1f33c43124dfff718202713b66ce8632a179348d8c62a5820d65388db2a1252a3a25ae16c192e24a9d82adaf2d1be515b96224685d39d925764b79bd529e4cf94e71c51cf2f395083d71667e72384e70563cb326294e344cd3663de7532ff7435f2f5ff13ce9f51ce9723f720bce878382a3dd4dcd3429399f9f50c32946294429432945fdcd9427fd4defc8c7dba255269db0947d6ac529af149f231ba64cf1ca33f48e525e79ce942725ef48a6bc525eadeacbd6b9411972f859993245ab8ebc234bbda309ced03bcad3aa70434869e5598b605140e44ee2cc25050bc307cb4ca25604cbe578d93180c4f28cf24c6925818b5be6b098b7750651d6561379befac8895a8565398be615fdc926ad9a93a8bfa22858f94994e92711d7433454b34cca8a433b0319d44f4ec6d8b1b923799e9b5eb05148367439a0febe2fc75a043b73c5e129039ae0c47006345799d00467269409499109e5f989279dcf88f29c44dcc4563003084d5a7aa5664312850d304359e37ebc577db4535ec14a4b258d315e21b116c166747b65ad6e57e67a65ce5c364c19c247337898d859051b723d5aa916c162a5193b98e1d32a2c6b335ca72564ad08590b5158c610575a1aec1bb28659e890b5572858d2490f5988588824e67eb2562a4d267632a94fb045b034c7384127d81086110ca3c3c0a2ae588822a8bdd6674da24abe3e238af55951565f59c01057f8081f99216baf9c0bbbccba26addab22257ca90e92773f509da67178575820d67f064ed33785a25af7d0611ed306014657995d65c49164b2568ae224b9ee5157374599ee509cbd10b9d563961da4196598e2b184611d4be6579d34fcca192250c36c4d50c9f096ad760c4216baf4aec0c9dfeb4e3a3193eb50956862bd7201ba60ce120cdc5f1c419edb16340b398808fb2f6193e30284f0e6118a50c65ed594744b364b826a8bd2ec186269d1a64ebbd577fda371c4d3a732559da4d3c291a146c682292b57bafa96dafac1d862661184d50dbb4cfee0686517fda39184652c66bae344969e6cada5bca78b110bd8820b164bc26a83d94f1ca1a0ca3ac91ae6924cc423441ed5509369ce193b5872c44599be10333d42e45b727bbb04c63b462047118a908b67edb5a3546927c6300f54781a839a5c7c551126c8c9eb94ad1e9c9f4306200d152b4734e4cabb54a6c4e26760e31b193c9260510a0c8d548abc2149d9e1f1f2341ad0a63f4fcb42aecc115a348abe250aba214405b64fa18477ad52c1a4349a659c8610c2814405378b6d36741e65a9f0de5edf56136942b4ed1414298a293b2e1149efe84c21844c835898d52f8e027872e8e60842e8e327d3d824dd1c9f4284731877ce8b5b622a170334a29e293319cd2d39f11600c6158e693a96b825e2b0ecd5576cac4d2d7225852c700122b8b011403688254e61845769b9e45564c2dacbc56157218032806d05c65a7d784bcd6ac422cc270e831b1626ac16b651af6e0caf4d94de999206dd9300650fe2bced0bb20aa44b0f4710ac51c31d35a5dbcfaa3293f991ec32e4fbd4800b1436679a4bf22fdc508ca54c600aa43b0a1cd610c5beb45a273180328d323d1394ce9d9b1230610e20cbdc4294f5019a787c5008a33f4184ee98933f4f9f260188661b536c9b5c600923a62a658a4f4b8144d152f74b75a3d57add39140775ad54fc2459790f66cb922d1ac3d4da37a032bf1ed4c7b9010b99edce79e2751cc2183241639cc5cb933a08e02d0bc4d6b7335df134fa209760694fb1910d723bb9de0a24ba8e2caf495e678c4d65c8fd899e3e37cbfe77358a1cd3cadaa99bed4c35322d21f2df59478a60faa3341fa2a043b1f967860c028cdc1cea31c6a3a2196433ab3a6d35f14a4d720486da73fca71259e1211fa52107d69097da908359269a927d31250a6a556a6252599729bd6aa903b2ad1129106698908f46149275442c3340dd397745a454b3a3b94275fbad31ff6a3566dd12a0c6b3cf56a3a40d029f1947832bd8a2bab02276592202c5bfdd587b26524cbba24ab598649610722b24787c8932c659546962cc9317774513548a10e434d0835d184032c54ce0e71a8113944c3e08008f6e312215776252f25d9660c27c172cd1c98601bc9a19ea2486258ad35ab533eab73665372c1865148081f970d6456bb8344ce63ef29310cff60d36348a6c7d1aa5ae7c4613371a8f94821872fc278b21b33113c5a352319a21533f53b58ecf3218edc40b2ca237b67f4d8fb071b1cfdf5e91696c774613e7210ec4234b0e34cadb8f4d7b7426359bd4252f9346dd6d545694f8e08bb761a8f48d5e46d186b92a5dd18412dce49399ac45e801e88a4923eaa21532212d6554bcf459b9282b51e95db571d4be98d982b1829f9837a7cf570d4c50e43fbe9665fb9a8eae2a22acb45d5171755dfd9342a4581327d8823d314c591a90af6d11fbdc53c56d8c3928e1168b9fe9463bda9fe28cf736aae50f6261c7385b218454496611cd349f74c2761148af70ca350228b3e5a7b0ed853abf268530e84628a72e37629142c07482f9403a198daccbede094000489ca191282b6129a66a5fedeb11d8b5ef905029d88787512c134659fc03bba71dbbc53f48f7eee12159ea4683f4d8a5a938435f7f60edc354a62822b07b2f8274d32d0a45d947967751166b2858eba1ef0e458477ed3fbc6b780812fb21f3de2dfe617a8687f44ddeb36b3a76b3ecd88bc88e611c243ffada71e6338caad74ec2387d0da3aa4da3aa77513b3ba4673b2cd28dfee88d98f4da2bd393e837ae44df6140264871f4475f71aa3f4a4f9be06367be4fb51cbac496d3d4640599755a86450c0332012933209f642925912c31ad790821bb2b04027c640d7fb9edec6b73d5bd7df07804fbdd8d1104d2251c89b85abb9bec15011c76653784cda11119bb101fb9d6acb54c6221a9dcd77210f503a98cd59d2af49041fe943abb22a6e6ec69a3f3935f7018a2c21443b4ce2674326dc248a62ee6a4957e52da9d511c6462b472b5e91b07999f39083da5746a326b6c564aebc43a932433f4c4288655acd2fe2a903db54c8dba8459d16a634929a5941911cf3c7a8dc266456488af58bd93b492f1734e21c4883f196d76eae382fd6efcd0aae6316ffc247b6ab0841c5e8b01155af01272b282f5a415c3b22371495c32052eba70ab946b9d56fba85a895a75054fab8a48273e4fb29547add3442ad697c70c96489f56855f8642bbcd4388fea4103c1090e303cb154c8ddc8f3247ee9495ca6ae5fd1b7374efaf5c252628af72e3044b4f99f12ea30e5944d6c86f0f67ee6eecfae86f89c51e46212180cc95f4099245a40ed944d6c89fc293b525d9a488cc324836d92e3bc8ca96441394d734229f2ccf7557664954ba8c51c87942ae3f9dac8d92283f73f73a7c55251c620e871520555578735ba0763d9e49241b04d44bd2b9ac1bdb2020a7bba9614ee62144abb2cbfbe0babbd1a490b884a282e80fc425b9e2e8b24140ab6ef427bf5378f95385d63307a54b6a905d339965588665b9d2bd05173f65bc9da594524a29a59458a52e2bfd49a961b2e930ffe22726b8f779284b76c2a1f4e1f0f602879a56719c200b8e46384e9062c9e2c0d4347bea233a4fc9823c2513796a21bba33ff427848ffee64f98c7595e75ac11072608e62a31ce84353b2e1d1775713a1969c3b8d2109109ee8d1f5243ea116a2b7ef3b1c8479c995b6712899ba9d46694e998a07882054c9cb230c1a8aea356a18290ef4b5c8f92b004b52adc8c481c4fe5d98c48242e7b6d254a445f291a7145a5a0ae548e39b56d25ec94624af26c4924641ab2471467601045e1c5a14c47531267e6a5d41eb2b478786a5e2f6c2b65a4d40d6fa852af8aac9298d229a8d4765ca082c82e2f63d6565aaaa49cba2c0b4f6d833ddd7098e270f8bdf40e8727ef2c7827bbc09917c5b082431bd1702ae130bae17350c1e117f190537098922aa83c95a7495a86d594a88bba620e29329e2a644e0c5197169e15d10445cbf4040b98c8429a7e4c40797aaf2e3cbfd6993ee6cad38267855734860d888ffe3c2294bccb73503ee33f503ee3f23366dc050fa99f91c39a07e2c35e1c9747168e7dc8c2934d37b25caebdc987e90c882c139e713d14cb9a81eac15d5ee6642cac863bcc6084fd14d71747f66e1cadeaf68622781ca91bd953377084a0bbe92370cc2c45e52a2d2eba1b157ceabaae95bd54eabaae2ba5ac5cdb5f0a0e6ad53c8c1a545b31673f4a1806020924935db0fd4da5bbd9baae54c2309b3eb55cd34020532e6f574a4f4901c1b661dfce21d1dd6c20e878c4cd2563b7faf437efe256286efdb9a91b17878ffb03487fad6c43161e1fad22b50a8a3ea2bb9191942315607086dcc9005cb3a7bb5457f53215c855007011129c07807ca872e9873433b4870140c91ecab0384a107bc892c34cc784a3cc61a6c3440e4d4432774d45486dc3a167594e190e653c001e8df48654398c4338521e8b118e105994c0d284787a86132d92429ee76894a2cd4ea3bbc16e83de2851170b0f0f0b0f0b0fd1e919485a86a94a9d6d5aa5ea6e6a92fee66b506df52b1b6c585b39a8f6f0ae3af60552c7fdbc6d22e6c0f6f3910e76e70471c60d27182622b43c341d41c6435316623c3471e10f4d6ff0e1a1290e7547d6ccb338318da1aa20ce4c1d280c21cecc87a621549eb9da8ca60e34cd8713119c57753b7ce24cdc6e6752e7c263a9b7d7f4d3f50ee3b21c75bbb75c1797714b8f7157fecbe1fbe2d5270525875a66e1992055226b28d104e92422a2ae2984ac994f4db0b6664d75dbed5c7d384ea5545a21bdeb5c644aa40e1eb266de0a4fc8d3c7f3585a7355792a4fcbda26e2ccfcb52f30bd217ef33e5c531ce267a24304a7d461c242d69cc00d79de544504e7f390e777f2fc189ce47919d79485f8cdc7b8262ec46fbee59a8e10bf79d43511217ef3550558c83b5287690a59336f524204a7e9886419826908190aa618c46ffe744d4ec46fde5eef3541efc84483589d58419e7365d299e03419c9f3619775a069d6f680e9d1abbf9479211ea94395c821cbcf26b23c0f1d94d0204a44142404a5291ea954144ac13c96ac73412aad684f54aefc0b9f9ba3ba7494aa8b94292191324ceba124548800a568fb04e86eb24cc7a6bbf9d1dfccd660559e72ef0b5a2e79459e132cfe9aabbac3d3aa2ce67822e6e83ea53657d4253cad44cbc2b2425db0e88dac14951415ec0df5e70d1520257b4a12dd4d23618052a66323532e82ee4686c0c3487d0096569c99676979448d61a46dc348f795692e9aa70ad5a195214ad1661fa2bbe1309656ccd13dbce3986e8f438f22c274fb1f26ece11fd6c56377e362db224f6ea7bf95cb6344f190931cae78428b65c22b4760c08a2c24f34fc41c9d27e69e8833f32a18487ff329d8471ae2d002642b53123d16225e6901a47bd8bb938054c760b71cb2b46c64eddecdde274177d322d0aaaba4611be936a02473e9367d0410d101a51f1a66e1910f59781c5062e1312931f2e2a1e9487e682a0214a1a9065147f59135f30f4d37a8aef007d3135e4a6d911e7a76c03496561118a813a51da9a3fabca1e482a8ea3e5f5a4154713fe11214251a64165c52810b1c6a74c8b3e3b6c8f35c1a22c786a84a712275d496acc90293a8225d212e913a2a8fac992f613460cc5541851f72b819492a445d2ae7b80ef3bc94526ba4adfa442da8218b5cf0c9f3d5555bd555d3aa3cad56e55129792937e2506ce280521d83a53964693da0c4d2e2329247066f8b4b5dfd4d8d844f59c3a7ce1b52831d8264483dc5dbd1b98c25bb5ed1f548d7c3c27b5d6f68821e51e64c37b2b2e869518d2c4b09b3a4c166d7300e392331cc747eb42aa4ae0c44ea489d0d793e4630e4f9308e21cfc72fe4f9eac46298a58785273b044ada6d08743b2240226d58e6435d5d5d1946da284081d20428e01145cec9054a17281991e968dc054a998e2cf9a0b433b3913893611696567ff259489a390c686003a5ec460d8461182406c9b6084b2c3c31470bf13106db398c9e07628e8db228f68a261887e969919a2bcfc87b69150d56c335a8b6fa9b67b0ad232cad23b266b2384148a98ec14eee88238e402222a14191e7c338b419756e2271664a7a457562691125ea6f562296232c4e603992612c2821f14a5f46a753b8195557cc214f6ab01e1918405d5c89a5455dad96c671a5ec0428c85690b920ae5878321da923256ba64a3c1749a4adbaaa8ba585c33593e5e7145aae56cd3c0b4faacb210b0f0b4faacb485b9ce16a240a814c2204498ca044374dc31b169b91196c8c433a9b11038cd080074415e9f31288abeaf22175b0b486cc90e73912947a04dd8eced9391294b42b3152a693e9b45a795ebb9db70c2395a0542fbd3a472ca193e55f489ced7437994e19accc99ce9064694175552a5c2528459bbd04dd0df6127026284596acae4a45a543aa14b1667e4a21cecc17950c76330aabcbd38215de90b706364455f6f9ed0d51857d7e8bc3662475b0f03461b4d921cf7338a568b30fe96eb02fc12d81d3dd64c7c989393d3d6d6e46db1158785878f2b4a6254a2f585a73454404e7ad0822832b4716a115d422cb5392b7b38f175d867d784351d87033c2489b6c41a9debaa4c1795aa7c8f392a70362cb95ab63b0980bba1d9db53711cf0a6f0b2f0b0f0bcf09c7e5926d22e6d86e7ae81d9586381c7a45d933e238ca518e0b59903a38bc847b681a82111de4f9828726251001d3c08918e4596513dad0e9661429de8c84e28c345529e2cad302297b434d94ea18ac96c3ea7aa24493584f8be85911bda156959e20b2d3de16ade3d9214f2f8b3c3d357864c8f3550c9674138f49c7ce7b43445ed15ccdfa69c2c23485d4e1614ab4f3d09407131d1e9adc80824d4eb0690cb88a3c7168c2421cdec0852ce4693a429e2622e479d311a98312c99ab9ca9a58922714e8178650244f8c43131479c3262399ce04e7439312f2bc371467e6c3383454df498fc81b0a83253df4865e508a36bb7c414fc91573b413a5ea8a39649e19a6f998ab4d0d46daa605c744de8ce2ccbc37e40de5f94c87683691e9e4c9655286d514cb10ca123387b444e748ac8160032eba84deabd64c8ab8f28e3d0b6a1597b1674a628e986756858c9d748c67ae3c9c054d103b0987dac4a1e995b167417355b38820764c8749c6b4c8184634416c6882585058873256b960b52a44e99c730d7215a334923a5ae7d4279075c8d8a3c46ac4b86f252bb178bd5e91b932a1150ce389333cad4282b2410db1063b760c3b663429a6721cef2bc7315de57d1eac64ade9382bf78ea372d37be5de8b50f1bc224c5759c13012a52828294f99a55312a96626cfc8cb843286613c3844b9f2a820ba201d4669a90a5b4f3b12ce5cd77433a10962f76e7751a4c75cc25910182c876dfac3be611cfd61276197189609611487a78c499c05f567d39a8665412d00ec2a382b73b500b087a73c896c9805e5a0cca51565ecb3cb826ea6a43fec750b96be3f251694b17bafced1a829061cd74dbbeac4eeb23b75cd15b58224946d16e893fe6877b78cc92b6fe09038857577cb467060aebc9b28519ca11c256a15129d8d38434f23d65cd1ab1ba90ea770b49b8e43baf7d002218a39b66ca3a4e398ae911e5ad3b51761ba46d26e7a11da4d26922948e9dcb939d850488e925cba0c22cfcd901265ca7152e6d895ec50b2833522cb872e466c2720fdd163981ed157a43115ab4ee750aa09f5647a231a073136924c1b09995e8621ca3b507945ccd12719d82632d528a56dc8f40c990ec93224a4948214b1861ee9955ce2dab21173258110f4864c8b9029c5301b1cafaf57d850129d885ed36803c519497de6ca3bfde976b8e20c3da5c274ef38dded714cf7e8a3108523d9003946418a3564d9c973de4dc7b1ef8ee39dda772fc2bbe936ddddbe88ee160f41f2c3de7b11a67b78c8090e53b88210cbe2ed096430c28a2c24f254fa4c90debb9125313dfd606f8432594a975ee120e26446254f103e64ecd8953d5734484f5b28259aa7130e526c8d522a89c0604b58ea28f1051b9e32b52b51b046242c89a486b5aacd1c8164ecf2ce5326d2346b4f922873c9527b4624e4d32e4a9e66f41851f682b5c138faa3380640b590298e38434f44d4436a94250ce5ac36b15893aebde992feb209642765240d487f1915c2d4d55ff62cb3d90a99bdb32ccbb22ccb9e6537c51cf3744876b3a1d5c4d61c1f8f4a10c15a924e88391a073871959a4a0c8939a40efa503ee184048b444bc920d5442a05b20a0101e6c0e72b51fdbc40ae114a0c9958893843858dacd31ca2708316b0427b24ab4bccd197a75fee4e62524789fe52d50a5b1f9a723d8d931455481d99628e7eabe2818b2eaea642084d50d25c29e6d15f5fe2da05dbdddd465db12a7b4c58f264c7a28ba7b3638f9ae91249a422e6984dc495e5211273d03885e8848884930f240eac0c72adb7e1e163ae54be72d3b95a5239779c956fc75139473ad6dd901e79240b222879b8ab1c67fbca71b8ab1c45c4cab717a1728e88ed2b2f62fb0a1e82e4c7ca551e27c85d65059b6e0a439093515e92d79ad8263688bc3d27514c2693c98463673299bec3bb29c56432752928a66ba5cb1bb3e996eedd23641e90a035031db1884fe2163cae8f09d66fb72240bb365eb019c6918a2e6be7ea0211ac57839685d522d71bc1138b783457a52417773344cafa5a6b25b2a46b51588b250f8f66794e4031c796eb6912db48628ef9da4dc4159036c4d5694a238945cc314f3e681cc8e0d429b07738c92157bb7d2c24fdee6e36ad16c07258a936b14071a6be36b17d0e2b5197c541f2c31ee538a6a71cc71ee51228e600425c4935906cee80d87263691467ea29151607c90f94dbe3a4dc741c94db87a70ed52fc2f49417d1a11a139172d38b30e121487e986e5f040a963e13acb778c8290b1eac218865c2da046bd5416b0bacc842d29a66edbf4bc95385e54ea4bf5ab9c72e88205ecd12db418f1dc311c3b0bbc4990cc3a81d3163b8f4f0cb8d43f911c81ceef2dd3d42e601099aa5d15c494db3f674727177b5e450ba640f4fabb6d74b22bd925834585f5b5a56563a2cd12c97b4cb49cc31b529ba495f91eb25cf5c5156f5913c5bbd172c094b9dfeea35ac447ff5b50b363ce55a0fe47f7dc48143c3214f7325a588607d15342de46a45ae2ed2cfd6760d5e51aeb589cdb222c415f6fa0ca8555caecf8ed46c09b93e1ecd15863320dcf5a828d74a86fa5242cd5ab956a109d6ea9a6005aa2e490414d6a35c5fb960e76bbdfc825cc50812491dad0307b9865c1f6528cb90ab9459862b06aac2d2772767272fbb0ca8bf7a79b3235bb0f37d2b22584f064d0db93e0b491467ea8f50ab57846d3a39e3a8b0940a2b678c314b92b3cf26da10571f15b1857a8a98634e19c48983387df0cd147c77f8e4703a830d43ceb2572d58ec75c866a72ecb6382d9bb3bc20079e02a1536adc5a814ec93b6c1a2854cd18c0804000000b313003030140c89c50222995452e4b07d14000f92b05078589c46494e296490318688000008000040200040025b2161d1380e1038fb09c9640ba5aad777837e73739c09ce6c3894e01018db409501a8eec5d8c1b0e6da3c9d67ddfabae7ee31525e0bccd2b51dc7a680f58a468cc047982b2f57c849c2909ab0eaf78cc92913730cad8d59eee1e1882101bbe6d2daff5370e655ddc9bee6ed85458d4ff00d3a03838edc20dd01dc5eb2cb2778c5837c2a8e3a281406382131a2b1d54cb31224a78a6251a85039714158047ce0ecef86aa8e233fc704dd36a99ee6c8281dcd4c1cec30f495b2781d5148691fd108139b8e8ec8bd7b9b7f75d1801d30c33ad1f4b83bff4de4a910724b61970e0e3c6d37122a33ffe8f174b6bb7e260a36c76c24db816ad6ea87579132b8a1a270c3d5d9a3b47bd6e71416b8bd19a2724f81165b0575a9a13377a3ec17417e069f12187eaa929ee7418011a71fc3025209b8b8194307db97a094761313128b6994ce3877e9d8fd25c7bd7cc60259e5ac5908c59f727c8828409279404f9b5ba5457be96111371c76b54a8dfd4b88fca5403164f76c5bde6f53143c8d7341898d68297ae89e2bc46046d7d46ab6c397d3d29469c1bd02793d9a4f17619945b6ad6782694597d2f0ba94e23d0212ef36de3b32fd6f06f31874c2ece0535fd70366d305b9685e12adb01031d0a84abccb440c9a1804da02cc13ffdebbf2212d1d4c450bc6baf2a3031da924a4d3795a1403eb29218eb7c20808f21714b89fcd567cc8050e52f94d3e952ce8650d509665bbacad33b6a31515c79c2f1f30a04bed69096249b4fa272891ff844820ea1b59f609aca796935884771f5f409dbd4dc792219e5ed9e8055f0a9d72c4925c232dedf8bc654c85029bfd8f09faf76119003a947b7312379521f929d1826be9fb8c5982fc21cbb46f2ca31eadf0c61c9d18028adc5363e5f4e81a19372aefeedb214a3fa5def1936b190552120075c475672cefe03567ad0adaf41eb4bf2a6de9ff82854009dc9dcbcafd9d823bb520301f00e576961a99e41c00a584a2ab5404e64475522b93824dbc5cc08a271f00f7a53994472ffe420541db2dc0a97f0064344e4a83ce834dcc70901cc97086a815eead80f689d96860f2aeaf11a45c1c0d2c27000bf14b60c8a221102fcb214030ef6d421e191a7c3f5eb2eacf551c861bb4a08969162a633c4ba2e924a1775afec97195bb606daf33b1565699cb73cb6a5dd24d0955fcaea01e18bc2192665ec0ed4be513fe463b1e1172530e417e0777d6a0431d178e58c9d66dde23e90d8c150852585cf74b9e4bbb8548c0caa8e76b332553710eba31d32be5313a7bafdcebf89af0a2a2cd90791ab41ae74eb503dc650a5e05ef657862b5671451335924dd1e75c466d44571dc5e6a674cc0f2a5fdb241f2b2fd78fd4b1a3ee99c723283154072d919432156d5cd978898f600d1aee83e23469a758ca4fe634b444dc19558d20253c43aa3a4408c33926d65b81702b675366bdd090d104d3f1f6cc7c2070c964ee63ce8947473030233ef08d6d3d862f88bbc136b44393b88a0d1fd0ae0b79c98d36d2163785d127800763152112a9ba768ef8bcd26052d758bd3017c82a74309097c4577480aa1adf48b51f8e67397a8990c8731d0c255ce9394561349c0dd195feb8701d76f67ebe1414ddba1f822823ca0c5cb33cb740bdd281296afbfbd7eeb2e75e5c308eb8e22fdf06f3c8c55cca5692ea6709cbd138247adcd31c347be2e22bef6106a42f9dad49650b973155be2d67a6c36bfbbc89a00fa8ee6a801f3861d9ce654ff186ee7ab344e202477818501542ec7f94cacb757d57b03b4c3a0bef4d67c9d35416f45b812841938faddded2eac8807df7919b17693b9397a109c057f012c0f255a8f1f5c44a633601dd9530128c78bf89f4f5b3e6238f375a8e9670b962051b3889521937fd231129895bb8670490aa3cee65087847c040ccbb9a78345929c62df87379f49799eeccc1e18315a69fb147f745931ea22d4dff7769a7691c6f309fdf94fd8e07bb0615cb97c5eb2b5139d2789ded61e9c70fcf76b332d7d90e00736a7c541f5c84a52017fe79d085323694f8feadba489ca8d93480560eddb33d2f4edafb675d6daa87462f3c4914a481789dbe676499c79a540913e6425cbc52e934d6b074eaadd1fa23ef98accc280e7c5806485c0a1f2ee8d72fd93ef4871a55279fa0f268cb8373dec71d5ffa4b40956314c97d45e93cd83645a6fbd7173293b188a0bedbce89b14d3509c9d7d44ccd53e4c8923b892342bbda03c48e8a8841aaa94e2dc22c9281449860d3f6a1a218a8a25a1db79206dc486192aa2a0757654565bbf4a8e2a59686f26769c829645a641a2332065b64ab859d95e88cddedc4a9c2a41c95b946644f14543d29b0a730e6cd0d7d1dcfea66f72149b3f211b8708ae30f2c3e23c8d31628920c95bf02a4abe5b52634b7a55db0ae44f67898efc47f37220689fcbe315a7e00051cf683d0bcb9fc47d5244d8e7a4257248e224fb05f2b1b7d6c3e86871f599d22e4129deba44fc7b50145dd589e994281a79cdc6576341df38301fde60858b273f18171b2f9e34f9dda9a521495053909c43079fa77bb2b249fbf216fe178cfcdf3fd74eb9554bab3ead67dd868558959f117786261751b47e0a2dc73bb55099b572ae71412ef5a6b08b2f006965a355485f88f8b4e272189e38ad21aeb6314871e361a8bda21810927b6d5fa4a948e41dab4acbca3ffeda4e239dfd4a224ccd96182b6f574a53f3d0570189a8d131412780d123eeb3664407e1495fcd42a5e0ecea5d2a9f6a2c2d30abc880ac154b8743022a1598a5a4cab538440616b52dd4f11a027186d11eccc605c150337d1b7363bea09f36943795381e1aebe08f1f1306282a43c83fb9804cbe5a0f3a7d8096a1f68e403a66e932a02b069fd25b31f58248537f00faec58080fe4b004a5f2acc557e11b460b83e1416887f009cf00232b0d3d0aa8cd8684ebac4ee5a46894adfdaa69fe9c1fd1a9e5ab643061a22b7726720443baf0f47c27c1febd084c29f0bf98fa9d1086e0b1516a0ae12b38e987b401124ac8f1135ea830bc8df839252abd291f1acf9e31f091e3f46bbb5712b6497cea19491009951876910955c08c860c53c7fbf1631f7f08282010a99ad267c48cc451b4cbb2309f1f763d87fd68cfbab49628334885eeee6e3aedd8a68283ad85a64d5b39ce1686afd486174d1698f3072734a6b574745888751b9401869b7ce2f3777ad913d8ba8295b3a800799c9af1601a3980790e091322a13800ceb907931f45cd804b38e59d488e84e6d255ef2cb63f3d7dc38f6db4e378025aa58138e8824c2b278ff53b07fdc1dc7299b87a7793a56137130c4640cee4fd596ab0102487134fd2e7a991001ca0f18bb6b23820cde1e176e81823c05c22177351c8b7c8ee385277868920cacd5608cef8f097ff7f2e81621e7ffa8df834893321b9de208db78d154f4c28d48c80e4fa8e468dbba5a54992346f209156547240cc32cf07c823a09c09641976b1340203d48c459909156b446c2fd8199bd50ba9cdd32f31f4a386e51257f151329863c2a7e0902dd12e768577422b0b7f719acf46f4d33d0d73f322ed00afd9fb21ad3952189e9da7ce4a663ccc3a24297d26480b87dc14ad606f9f862f4e32e93df01cb7eff4a2b1d52eb358425f1a1040a591fecb9ad32ba7e8f5f03323293099b088a3c7333704bfb3a8b2f7e0e6fea9689146cd8047c55573073e65036e599e8fd7c5c1d4086caf4866c0458e9e7cf85bf9ea3e8576df3e6fecafb71ce7bc878ce79c097d29798b708ad7d2223279880980994627c7eb02a5c72c7cd44c9730164d4eadcb8f3bc8fd20dc833a5c15e22b6e47078e1bc7d76f4dba9093061e28df5b10c205664215237c302b0e46b6aaaf3dc86bcbec718cd0d71852bd92c9d8778824ea2184106d6e78a3f5244a602297b2a689a83e5dbe57705c5ec340acd27f6ec090ca3909be65c5588410c0f131231f22c0a406ef98a6966ce01d94a9d76ef70d2aad50bbb17e18246851ca9bec7a96a005d6824c6c675d4f633a9d0f885806c84711f97ced4605b4901e55145e0cdd886e4873540d11c04b0e105b742e6b9a7c50d20dbd847f2173013c2c68a47a46db7db483741072e33d3d603b779b4eeeb37ce4bd2473c215f12e6c2f3701970f0d0f8136350749e00d665000873f322be603ac833dec80ec45237d843fd0237c224d89e0dac6f35d026f4938d3bfd4fa482a232fd2d0cc44b9cdf0ca5aca463bf79550c2334f341be02f2b772f0bb0d7c82cfcd0d878fd39ed93c784d7aca9be1e299b9f2ecb172d579929f97da867b75d6be59ac14d0a22c5985dcea620708110365be4ba5188381892c940a89be78d98f2697744ba1050a498871038d29189afcf748584c7afccbb985d5ec57ba206d598490215dcc74b9091514b200ea11635a7c3ec3af09907e47419699745678c7724a84bd84d56d2f06415f05f21da1c1998b74ab7e1a6122885551560d70bf55ac1318b8a9585dc46b01fe13c24b26e13b777e26c1acdbce714f7b23e610b037f0feca2f380074c4b0cb6cd3615be424a7d7cf1b518e0f5e01fd4674fd255e69c8db612604fc29d1d08c84fb30112d00670098f2c30815692abdc76eeb4d661de4f1c0388e45c88ee2fb7f8683e7baea7810152019f8746345a85558393cd5f1fbdc3da4b3fa2c3e331a78b7fadc3061784b698cca8b34189d17d92f857f3f7d88991d0fd0c4491ab7e710ffb84e54ae642efec964afdc7dfbbf90f464e4d901bfac59fb35f530376cbc8ca6fce0ce41a3e0e77f76dd0af8ba853833c4ef583c8592504789fde84a934161b57405a40b6c254a621c42ad077c84c5f876e19e4f4c74da4a167390888f4edf8b7151b029d10cc95903d06c56e614f626ec6a7e29bfdf6282d2a55d419709633acbc5d23e3b13ff251d9468b80e37ae524bda85472941cb081fafdc930b8c4601f91b2cd23e82f39f878af7bb702c81e10d3069879cd79b15f14344d291fbd00d75edf34c3ca24a3a3e040301d4099e8e2f1733ea39b1580a5470b355616126a6c5d7020c7c044d170650537eb13cecde0364ee8dc608e9bc7c1f70d03d96fd49b9a67d165745a4030b78121ec3bf205573abc0f7d5e490baf1358143ec33bc48ecfc6ab7cee83ab7bb49bd8b132336b868d025e2d8f8f623513097d9d88154d078656122d5263dbe1c41fb8c86a0508e2c5cf02c822ead042bd582952db6b35910e242673d367411252e11e5a22ee02f5ef988880f8b422410f904e885584634cb07fb00e9b3238b06c21285fb030c078f9716015bc083f8934df7e1c90c48cdc0fdbf011668d018064f64e393a9c66af87f095a313c5705814e58e2372ae4d7c434cf3f49ab6398aa802d466d70a51df4455ae39e94916f35740b37c33099404cca0c8bd9f5337e77c1c11f4965c935fc8a9d8dd1c9b09941efdda7229987f1828276287440613890ddd4ee013be092b322c34a0ad779a35b1c939c2256742ac3fb738bff301fb1037581fea6123966d26cae24c8716fa1dfbddf2ec4046bdc53fb2831c36faf34814f98a2a85e696e781da28920ed78909a671e412da8248604f6a1cf1fc6a0cf70160affba98c7975076f7dafcc7825904f26c0328598894708d8ebc9e4cc56fde30e5aaa48bb713a8e173cf510f89c98527444a15ddb5d4e2993353919930403163b25685678903b19e5fdfb723caa702fd49c2c6899e7808a0aafbd8bd79d59d432b92523a00dfeab1f4391d16579df6bf7b72d880be313d2d012156fa336c6d84358384016c430f58c54fd0c5685bfaead348eb2737604814d228a6a397f02130524f9b022804fb425ee23a585b3c0bc22bd0f8fb7a73b042d8ccc28c8641c54d3cb0e00fbc20706b403d6b85efe73074827a92c5d11c6dccbf7d861e0c8176804ae04c39f5054531915ce8c388781362671c32df00f12e10b7d6b62719fb20acb7651651f9b4ae308455699d505310160a59c2bedf48ea3f30bf310f5e6106014ec0471b8b3547af6f737227886023d4c2a42a5260836de121899c02f3456a61ad9632302e554e84482922b5821f25d0f23012a2c6083d767b69e6f24c007cf10ec1727cf34d6ec59ed9e01c690017e31d9fddb4207a593f288f8955e76ee6b4644240b2b75801fd287a119c97aead3a716f1cf3736a805fa09b40f25f15092e01f7f53df31c830a61ddd6bc6876d27c15b1ea6a4f0db21e889428d825a3a856a1fb80f0a233e2c8d86d7fa440fe5ba4f34fbc77b3c9e15a40868bfd50aced44321b8e113f489fbd167d14b4a849b481910240888185a802a30d41c9a8244f01b77797e71fa93dafc5a3156311e6c0810388dfaa4e5bc224373ba0a2a53999f8cd46ba816e155ea27c23b0eaca0dca071556be722c0433057c14a844a1469aec86adfb1d806243cfbd18f33f31d5e0f2fcab4a436acd895825d20eac09e0fd8bf76c374e29f58d2f1847d9c26073638469d014c80ddf868cd7bb3e7a64fd0da1a803fe47096d18a281e0076ac837e6948c0a6e8bb052769dc55842771d37cc8a7af573b263ec37b2b0c787a9ae0a8955d1f21b48c71bace435ad03e71131c0198e47bfd7297400a298b6a350686c6ecfae95919457242022a87b4200ff53a3480e9b2dca7faa57a0a8156a4b740d66a0b37a08f11db0dcd7056002bdf5ea9ebdae99c612d715f87d5de6b23359489f35ec3053f575d15360777c61013d9deadef530e053d4bd2c29a09e8b8e9e378ed106d04736a32328be2e3d7cd3cf63d1676ab73bbdb06792c6b57e8401380daae873c740e15b603d5d84ab50d34711a064a1e59146126805d310083db202a0def5e83cf7fb595f6e549a502a02d99543368d3e5153a4a9fca5901c387673d91cd84a5303c1e1a4abe31acdb470e2c1793a066d8df67a1e8b80c5744daec8fdbabd4b47475b6631e3b6f98a439718c8d8326ee15c7d317a789c3d09700376f6797e28c5388376cfa0efa71f67c1fe90449eebdd80782f8daf79c1f0056a78b268c43052f54b837f186d08a3c189057f92e9020aced4ec09b4df4e89eb770bb8fd098e46accdf52ec87082df6e0fdf8e66412c8854377e3c63be409a83eb2b3538493bd9a5ba4771922e16a365eee8f68e1ef44509510935e9516dea9444eee4e0ec8e6d065e3698503af37ccf813a0b0e91bc366e829c8acbe734a138dd7ad32e41640ecbae113b10dd237b498676b0fc0febf226d29e4379e27bdb87980ab589ffd79d7f82e0614adc89225909f7484d18075ae1d9be7e754c431fc4d5e13f3e554af47bd5c4c6a706c5ec01201fa909d5665b59caf654c89448bd2f9a80006bc22a0d55bc4c8e6429213a26cb08abf051f08cc5bac7b5b87b60acbd691580e03a82df14253bb4ba02f6f603bc037000ea2701a4ca2300ce503cf29e8dac9117242f8cf530b133fd26e923d0b9a0ebd142e7a2b806e05ce87d9b24ad9fc6b1b86ca810058ffccc9283b847860f0872888dc72c27a7213c0a907063527a0f29e4beade8d00e4e8d2296d76d0ca4821321c24040d063549a850e1bc6596e50a04d34f4f0dfadeba10635896120a8df4e27b4b1f01db4691e8ed1afdd716319294f272fdd8dd5f0c914baab09f06c98db326954a18f52200b6ff86bd293bd36c3555e83a399c0ca197afbdfb5a0473c0a3f987971b07646d0f84462e3b748fb6afa782d26be74b89808e064d010c5fe45ff09440834ee3b9c9bb991c8c5c72e7a190942f4c51d1f7fde3ef1460ab0cfa5562884a112bdfe60cc31926ac078b7f47b25517eb16b12fa0fc274606b0c8f0651931c8e05b12dfd0a11554c402d2d6823b2221e659f0a41aa0f78a3c79ffcf86cf8ed615a939ff69e68385932ef0d2b28b894930829dbe0824d1e96f85d70d1e8125cc67488ee0a0c2f2345c54710fce6b7d0e437c1afce210f6f217064d86170caca8c5c2fca6549b2cad037d2a733b4599cfa7b7d29d8015f283ac3eed3f5ea1e17a94424abe64ebeb18312b470c8e0bda010f0ac93aba3f8a2223ada6e96e55833720986d696d54bd44a0e0791dd69e5f76dbf7633afa7a4f97ed4f6fe92c1fb2e09b0485541b0d24effbd32d3b01221ccc95d30047c850652bd2be5abde3ca249a733a1c6f2cbd6337a3c99f0d94590ae0a2c2cc08462cae9690aee17d871fd1dbaf3158e3a7512e4b4d4dd747c097ca22303e27ba7bea5d520d08c1618502f3d2251caf6430d0914b2dad5b962320a753c07148e7cd3cac8fa3040e81bb9729e84138d30a4fd4e148c1844326ca812d5a832a52663335632d60d7309467efcfecaa6131daffc14040364c259a28b55f62fdc0759564fa3395692d7f63b4ef9d3c02bf2786111e6dc9bd395beb257a86ef93066d332479e7e098e82a3165ed676e2cc94fb8bed2d10ee6f9d2a6b2f895530c3798a6a8271b80a857e36be79d36194d4ed9fbaaffb4792576854574b8c395e2bef66cd698c914e51aeaa4631b2962a86958b42c1c0a35b72f2717460c8fe19bf7280c6a203a160b060bc91e896f3347a2cc0cc19e8e6cf8a2f40987c48c9f5792cc6cdddb0f3cc723555c0b4c8625c6f16bec32f1c90729519e1950e63b00aa5d1dd5bad0c91403ebc67b720971d5207cc35e0c7fa16f2025a43acba1d83b0242c63a867d6cdc4d8c3e5cfb5035f521766f44986d3b802524d3a25680ade51343c6c72e1920c9a450ac8bba81d0ba8b81aacdec3a56e3c9fb53dc958e7e834d9edf0a27640060ec43e8043ca46a8ab52750b42e6e504ce03218321c6ca32963d4cc9ea9b0c44737972e34402ea14f8d8921136bf08a6a0e952616583ea841cc805d19ccec60d60f4e3cb6ce69263063318a9af55da902b387df92a7e5219029c3478a66f5b5bbf8723287c165072571c6a876072725db94a09ff35cba24d8060be7bc0989fb19da47b20700e6414c88bd2153034089c224fb86e0920e35ef57b19e4377eefe6d61bf60f555cf72a6550002b70dd2fccf51a6244dda4da936be8447ed58efc35a833ce9e593ba462b450dbb71b797c8ac0bf98e0e176bae9bc37d06aa6cc2389ce5edebd3cd86113cc5a8f74665bdd72690b05c4308eb82182663a6e6f68603590bab88e1de3245a5b47eacdd388338c6fc9d5601bba0590639f0f8adee0c323708f5c5c5e96863381f94c82240df13356badcf1f05434c1434c04fb301341530556ba958c052dda5211c37fe39e08360fc1090c8b358e8be96a49ed5d62839f88b4a69cf54bd47ec0529d306418a59d2964bae0170b133252b5a517b822a346e493c7cd6066d7ab610bb1cd93a82dda196296950afec4260c70a12c0702d6339f3e43fda10932616d307386082732d3b99d35b2641321a5a5c036726f0631bd17a718ed24834fcb551c78a852b49ed3961c8480fe8719a1b568106bbd1196e3c1aedc5c77ead391f70b27b55d6722ed5041d92fc1bc3c477b7134295ec0114fa32f0a9deda1307a6447dd88073265fb30fde348f92828c8a0e4c971437d025263f0b7e7e639d0a1865df8bf0d5ce9d64f8cb3f0002a853b1504312b21fe3493f7f41f17415534b0409e43b6c43e888d3601981d56a22a7efa410b2bdb41858f5b37eb23ad82226cdf9b3a88fbb89f170b5bbea4975b51721fc3ba572052a4d17626676fb16618238947064030f8b2361e357b5c63ccbe9d58c6c35dbb8f2da3f63e7882e6809d6219357148da08079258f68e58e0f9628918509c1d2ead31196c75531280071d3efc79701ec1d803ebb4c19b99ee67f81c27e6e56bebe4ce17044e44fbb42af35402dcc2e600174705a505b00345963099fa3db26611b59c0ab1711844e0a5e150893e19324e7fd0c7f82936946f03b0276746789f19f7874e9c26f370bc2e70f019e43c20d80e3c78c8e0b8ce78d91ad174fc1475174b74f313d597d5e2f840baaf44445c2e6e385b057a6d334ff169bb5bad8e20d99002550ebbb883fee667b1873aab0542465c78449f8104a2686a6e0b9d5129cb0b6f68f7f4546711dd0d077b6a5f71d05af107573bb97f357d5447a10f678c62368f604bee0c5adf03d44f01a140c6d23bc0358b2d741f00c2bd89bdad7ac9f9e988744cede115953f949750cfab2a62bcbf2683b90860a0bcc002de0bc9edc172b0a12c25b5631f5fea3ccbd677c1bd48cef3cfd97db8b06964612208eb1108e789c80ff73e3bba2fcb90df299adb90ec37ce4c1fe1eff80725ea9b8f2a4d4cb8c8251cb72623ee8e448b224c2dd364c4b44d35788a922490f82f7a4d610162a698a9005d507b9b0127a402d76f1949235ce7754686b5edb916c25cb2473253923e45f20fb1a9f8da064296d61b0a520c22982a783fb7d2bd270ce850752f8fad84057059bf1c10476797d82c6c69a61608e3e5b437b63119a9c9355e05efddda38052d7a2cdc5c63223e557c5fae504371f85241ca51d107159f14cc985b85078c200583ba74f677e2fbfcadf6328371632881c9f3aeefd4cc2f89624139251021da75c3c59446a18b6a220bb2560b0b6ab82afdf11acbf5a816d49bf8dd2191698cdd6041d7043f86cae8e19a0bf99354a633e43e8c5ccd339235a183cd361efd55058cdd4c8853e4050497b9fa4ae899e4fa4021e8d9fabc186f2e9d4b525c0fdb3012c0cb365a8378a4c81b3c702b8552ce3474092fcc13090f6fa7596ea005ab628fefcfec49e40e72867b4b67c78546c40ecca88595bcb726f0e24ecf96efffd888879d9f801152fd402996049d1fcd06b9a1c1e5302676e1562557d82d5af723a71e579993fa74f5fa57b4f6300bdf2e3a7e1132971336a50efa37ad186227e9a5dc94ba912e903a4b65f21733b3bc136307249a43d85a11e0163497f13a08a3c77479086b0415be5f50166339838e499654efc8cacd2d93cdffeff27b52ee368a7a9a92e7fd8117b92e258ec4799c295b5767b0908954fa7eacf79f043054f0ad4d39437640b985b0f8bd5d99e2bc007dbffc4001693933ff6b86d44745d5c84fc1239dd874bc2aa3d995b472d53c6ab525b3741aa2da52db9188b7827b873312505a4b1a5906251b8c2cf151a07a321e8c881b22c672e3de630a7c9c965f2f9c6522c85777357a3bf2b9f9456dc60f5afb465acabc9ac4c126103ed801a71f9f0fec4fe4f1eb1c66abef5098174f585c157e137150ddc2bec2f2374449360da2bdc67122e9f09347ed4e580809d38bb78b9af0c93bda3ec006a5378d936926e19c87c0bc3422b0877e1d224481954cd714b9a130849eca6e5e85f08bb0fc893e081c44b4c7579146acf27751f6e721fd6a76e64f75fff817e0ee2f4fc8743d887afd84d2064d4faaba5f1116ecd0f4179a75d5304fa450dc12239644f38763d284b583e1bfa3872c47d5055d9dc78185266c4eb1219c96dc7ed2dc9967b058cf54aaff9531a54759df661e22ce694aa827e2529f50ab9d31ac2d56873de457665de242255b1ec5ccdf038671c2554a0d8cc7c377d062f35c747d06dd7e95bae4e817165424be8651f3fc9bcab59855b995e223344e80853a068104631f77a04afccb1c896c7802548ee2b332a91a0ed81b324398385f635c7d0fb8a378886373d16e7d1f343b0131581849347aac30ea4ac82ef1c2165dc6b9183495d245b219f1a631e3a121669d70d10e54213a450191b0ae258d4c4da68f4766018777f3f50c0db76969747f0c5be5d7238a834fb00abbcde4d0cbcd4d7b61b837100ea1896a706055e4350afa6dafd528426776de887aa93c08d3a19ef43a6eab2837a879de4e3080344c427768353164e7025b92350e6f0640e30644ee47375ee1fec80118dceeb70724e9244b8639de51439b1ef22b06253e445d498070a31606892514a79720f41be4c9fc1fdb477620e5b8248ba9f9ab88f151c653e09496c0b70c079b41743f3891e5e5f963d8fb128a10a64f1e7577b73cbae421c3dcec4c4e88336bb69e6c8589c02e02eab13f4e70c1e21aeb924525ed3fa9a687998fbcdbceaf9abb07ae1c7aacfc8175c3eb7e2e3ec9612496d5ea00eb54b454de3705455339135be670384c4411739dba8ab3831504e9b205a8208ddd5f1101a609840228e18411183e86227ac3c083515bcc72340702da9e8107893151c184162fac0d08aed84ce8b109a28a854033e2fd1f3cc0cfc71814708678e447862cfa47638dcba2f37e286a326c113cadf1d35082de3f25749d5b90981d258e42ef158caad7f6b49dde3941b074e391cb4e1816253fb4972c5d27b612322660498a68d92ebfb8fe173555038f2da0d55094f47683898d484cb8f58d8912f19c12c5123ec56015d52394b5896e070df3426a9a6f907450d05596dac5911919533080c4ecf05e2b0a0cb8c581b3c418454ac46e28e6c217407fa6d234b4a7124904cade88522034acddb708045b650c2683ef56f548ea18067da90385f72b1df1192ec93c8bbfe94bc64df424aa2770f76ceaf17e7df2f6012ebd5fa66b3f7da78251a41fe6992d38b7600f309b88f9f95f4c3be256b792b3602ee3f9f6413f87eaab8db132ba13e676ceeebd44682c24995162f60d081780671fe0d05cea068d8ad2a5ccc6aa5c73d3e4f45ff566b838b7c40be78f5e7289032a10b1466d4099986c07bc884a41735217e9e6d752b29f78a81d64edbc0dd1ee7ba0aebcb9d8020465c318647cb098d8bf361299cdcb529f9ff8cdd65bbcecd6a197624e1d94bea71246154d634f1b2af3ac3aec2bf7303a87cdf8515fd1e9fa0b8ea24223c157993565ed3ea5f5a4b803bc7b741f6ac9a4c71d8eb94cc128048006001600ff7074384916c07c60b0f1cc8d48fff8ceaf77fae25e449d189c5a98488d936f07e31d32409f461befb389c47ec720c3047f4656308408e618099d4bd113f10dbed69d69201556da4d6d7234f4567b532b14b8f147185b8ed4e76e6b75935f27f58551819bfa477481cd0ad87cb7456909cb5d73fc7dcb71d1b87a58dc3a3bfed4110db6714fafc9b04f1a50903dfd2dea859d51dedd420f567241367ed3782432c3eef8d198c5e686abf18460a0bb33af3bc00a7711a18673bfecfbd10cfb52a81486f7cf68f127b3dbda3ca966c0720f989dae1255a3bc185d309c258425f8b090cd2a4e0c3f9d8d1dce178f7127423a791a3aa2e41fe11e3a08c08283269e8ea1facb0cc7052040deaa15e7510a58161a8cfc8b66358412a467f47c1f4a52219246d1796882c57d6e7dcf67905fc966e78a7135e7603c4d158f9c3534d2db518c685c71cacae364052fef007de4b7b83375d7228ee197fab80b14d026725395610dc087686331303fc10f08359db47b73dae91cd7af5e0374a568eda544f05fbdec08c062b6f895f698e339be7350b4f79529964044e3e530d148a9482540bd2a36221290d9f367819277265d8c780e971b6ecfcf29a6b6fad2f863558b790eb7746859d69ad502d757b8ef62b133e1e82cb2c182968a57161f2b3fdc3d560e3c6aa038e05b2c772368cbb79582ca56aad2dd654b2b0112a11cde04b15504cfd7475232a814c1da5067a6adbee8595f9a02dc7783971e7a82dd8da5d95028273ecf99ce646705fd258f3a90658e25b330e7f95622fe1d23d9acdc97b66285da352388d022eedc6f22c1eac1263b0107b83b9896cf6a2999b826ca7a0886c550d3ec063dd9d9f0e0b7bd6c29fb8d7e7e46c9742fd028b98684224444debbc0a831a5e0a31731a4626567fce8972c9987b8711b3bfd615714a94c68c730422cbdf93b019718b3a0bd611ae4becd113196a80e77d39992fcdafc6044df4aae3c05d76117e608525ff48667b715cff272cbfb26997d1d71a660c0f8a06f2a27550cb9f043eccf5a2e913ea6620056125490465cd40872eae4019ba02001611606b816df2cc3f07c539910881e994ef8c7331a7ebef0e32191a21f4e41e5d4e50cef249935fe43236d0331bd9362f00a0997e8b6903dc2a08eb1e65ebfd4cee5ccdba7f0c9174de764f4b24f8044c9c14d96aab5e3763aec976a5c09ac1fe77fc146422f0d9c2702eb41347a1a180f755eac0211e828213369ce32394f822546f8fe835e53bf638e0b0bac69edbb71e750d11bdfad7ce35799d34c664dc0a086c77eb7b9a2eae3d70f9894427ac2fea87e8c1f9a1dc1156ae801820cd66c933b1a5165622da3875214bd394efb4766ce6535e8d27fd0e1f4288caed116c7d0a660de398a4221a5d63d475d76a1e47d6837e8f0db5c8eb0983505ddb69c2f8ca811610647b5178c3f8c010745d56a54d28a3ffce8f525adbe0097c21882278a458c499caccb1d7727108e0095a3ea7aba9cf3be242f6a979fe3896f47c394b4e24645e13cbbb9f19a7e3472ab98ac6bd7a332341df6139647a9eaf2b076b0e9cb6a2f71689fcbe00ec4b0a706eec776b016b9e2fc6050b51a00dc77306707c90d89d98711199ccf07d5dde27ae3e15f4483bb3dc3088379ec38f1d9b62e15247f714214e8ca41185f46c3727c6c108749c8f1bf34f72c8f93eb0cea4283cf9d5a7d3f11be6fd8cb8996b15e1786ee2360ee538a787e15c08faf2ea225fc42048da898e814977cb5a68df2bc2d81fb70c3937f392425c38be63e58954a4506385e70df4c48712ffd65598b1af6f1b32c69bf349432c9c9b6e1e417be3c7f0631628280846aa6aad35ba4e0cd67460ae1a12136b02f55f8fa3f7ed3e9b49381beadc2db5870ee6c40f5c8894514657d6ff249437536e841996a4cd79a45db2f70c388e409458294ec439ad84d573a7a96598f24e33a983e4beddc4c8ebd650352df3af45f4ec0ff0591f92201f806e0f84929f8f8ee650098b3fce90dffea6b592215449d46838d3f4efed8199eb1dff17e6ea2fbe8ac596a87191bfdc3c6fbde5b6f07b13134194834ca89caebdb2a94a71c51180c201e3aad922357f2515f741030f3042185a71f032925265f0fd10b1a56ff71354b786ef12b8dc2305e453321ad17313cdf1db5f8a794402d0650f14d208dd328c7a5af7ce80549a9285ebf05e4f4a3dd6268e17ebab09ecdd76e5f8a34e778192e2a15eb2075d083d63220f4b95aed8139c0c9dc8569d3c7e777c0fa9c9854d8f31c80b713ee35bc01c1662113560303f3c8095779cdd730a2096fab7885eddc07db58abb8d8ea0b43004754c27921f27d418bb4cd30f18577fa41bff080d9a40126c016c0a018e95801a53912d14e8977b49258cb16da2168f016bea33047475e2e37899dcf09cf413adbc703df8ba2f3d38d721960f813ebdbd5977b40967ae292ae05f3bff0096e688e752b3fa0372e911611e279b001ec3618a4ce45227304291a4fe5da2ec8c4132d9f16410487ff873cbb2b1b242a4808bb547bfdf451080969bce36eb7049e0bd465127a2612ac7f64327a016bc1da2da58cc228f109e41bfc477c0122474ec5e40ee2798478562c38a82ea05520517a2f504774484f1b109e280ccf981967ee1238783c260eae4b38b7028cec710c658b86402b2e49a0535e0f5f6a0b1c5d91fbda06ed9ec05c23053729173c6838739a79b01e1bb9fdd16f93b7db46c28d0d377f94d1118a20f210c7af8af209199765795949efcfc782b6541193179b0ea2303a127b0eefdf638017aaaa94d73b133400eb1b4eb03db9762e57e5b3541871f5f871a7d5454424f7482921cd1878e47e7e9bf583c9cde3fba00704e2a3a11fcfb08038e49044129cdbacbec1d4efb779f707178243fe581f0e68391ac51f0f155d5ba1d9144095d39e6a2ceb71f5345c950d67c2eef508bc7dd1836a42bf2f21d17a7245f956e56ffe88a3d538249a4cc5facb596fb47d82b67d53a2b8c2d00a1640b882ca2246abd0489dc19226bddeb1b0b78e11a2887f9c6b8d1cfb6666e6e44d74346475f18c79495aa1ea02db4e6f17ae7a7da8db471866b691eba51fcf4eb6a1f5b163d0d64289e38c44e5f445088022dddc2334937dd06a26e76625f82050bd510d160b744ea91284a2ef4281ffd406842950049da9c56a43169390341ad26972cdaf69def88411550009a362f42177769f209d33892d5d649e4d840a6df21ecd86c2fffa00c62473b72e8929564ff78ec999bc7f33c3a34369d8443e6665fd86134880d30cc8f5ae073e24766d11420421655c7998d180f682bd5ff27dfae54cd2be586d07308770570b2eab2129abc261d04b298269c9e042d2dfcd3bf971459bb0f9b434cdecc1850023125b674dca1bcac6b348fac6cbc0844d264962335df39c0ad892b4e192d5dbe2c81049902b1a764c19c09e40902b21d3ebd80352558457dc137a166eb6c411faeb82de156db491fa38422249ec1c1ea82f1f61d01a7671bcbc350b744b5eb3b343747ca91c2ca1856567b7d9851a3c35159e65099dd10996bbf339f4cd97528648ec8cde2f4a2a23031bbad275a9b2e28d3d90494497460e23ce7ec3179c9369b74afd77967f8cca9a1f232a6184a35be64d44f35ea5475c3c264820ada42dbb223b0904d8e3b3b9366008d4f3efa2a0b3e68033ffca729e8550b1442c30fed9036335232b794d0f15a025f1e6edf65a4d692ad154b044a0193497cc96fec70bd7d6ff14daf542aec6b1280a5010eee2b30b29af7949b2eccec1d1550e91052aa1fb8c077ec1322bc7ce1e746165a5f0843d393bfa7ed32731abeb98af35cb53d91166f778d466742e7bd5aa088ab9c7e5d981e5697f7d8c90cbb5a43dc392d11f6c04f085cc05b0a74091b31428e6d0041c200b014538daff0fe5eaa59f01f6870d50f25fd4a59850a23cd053c6ca3254ffbeec02dbedea084d6cc73aa16baef4f5702f144b0c456225e6404b205c959bd404d60b4c05b899427e3dd656ffa5a42618cd508d6bb05078e119850b8ad460f080a4fea5d5f04475dfa241fc65dd0fef86e835b19f67510c9c359e726fb6c70704fcc50aa7f3006c44e45e17c843708493983940da5c5a5a4a3f5d88c06c9b05e392d677563d6f44101a19db028334205b83a6c2ec481aa28192d65f644682af7512f705c3ca264f91bd61e419025661c1a812ebea836b0a0602d81dd0a44e2962daafa9b377b0198f0a5bd7659e463f57bc32436511daa0368ec4bcc91f43b10eb47545924c647f20530a529d6e2aa652bb2fc514beb23bac1e332a939a8c78a3b9577bd04e76c2c2313673414daa7a6dba5b3e4780c421e654c71ca1e00c592e23b7388ef054f925cc0fca08d66a79cc97fe95f5ddbb20827116b5a9a8146e87eead01e7905da2bb00e60c9c16f8413096402b1c213cca7f81be1e6870a8dbb2667c5e58c6e116b9e9e2a3a1f18d4858f9f75b93071ec0e5e5774af736d5ce22dd6d4f062e414746226d7ebee03bbf42d5687f22422f1238b876b8c00bc618b8025b7b1767a1b697192e6ae48242671c70c7754180514dee474c7016d4cfb888a622dabb324554546c66d8109859832f487f3d75b5512a34da7c655034545b8efea95d1184d97d57f1fcda1336b6d5a09f88e9d521991ee16d4f5f0c7b5cc3f53170626dd5e432fd92233042d096181164e4bf998ea81afcfd769f0acbdab9c0b4352aff62e3b0234a06a127f4e40006617b8b2801e5b344b5dabff8037e9c8ed4410259fcda9700573ac3c33374fc11f0769b1f6229ac8b78b7bfa270d9c1421f4fce4d999e46b9339094629d8fc817b66d4303f3250b8f8ce90ad88a8b5a1b1709c80d23839eae95dcc273d1c78bddeec07ce81cfa85a576a109740b1bcf4f41c6b1d9665b4780e7dcdcbbc503f0c24708caaa1b2a968cf409e3826c5b26820270c45fb3596dcb5cd8bd5697e3ae9e89239e580703931b50635a31e0ff5ca0003b0526b522906622a7ab13c02d3998700263919726ad5c0aa62c3ebbc46ed2ddde822612dda9d135a7fcccceb068fd910932b0ef74bc3246dc00e12ff2c8ca372d8d2b13deee62a68398201aa6aa5374f191e3c1137a8d78f59293020e10e0aff06b51dd32b77ba3abcffa666632bfe6c0dc1d30941ce193fcfd1a00b25d3601c6ed3f5affea6989f61f9fe068127455bdca7fb842f389eb5ec3f0025db1efa37b66d7d100ace725e718e8228f39439f477baa90d5ff4056d1154dad1ca2195385c2d4257a4e82d02381759d9d46d1c522535a42d6bc76f443471afeb26773f224d13c8ae4bd889cbcb09070105416b8d84a8e5ab195bd277955128f58f525b1dce7c3c922567d9fc9d7a7a15e01c37999f1b2d564c70b92156817f57ecc1b26c1fe853ba742a33ec39d18676f38b85829855e1e0063f8d83bed8900579db2cafcf9da2f0a9ffe0424e8decf4b2f113669b4975f9c819f8f267c5428e9c04dec7fc7126ca2c66a5959cbacfbbccd1429576ad38e2cf321ca0e8971528fab1eb62de9a2538dd56dbdf5fb32500a5a04608ec89a298594b2a8818a56a0276eea9e2706bcd0699f73088bd460bce564b66ab134479d45c2ba90926d1855acbad2e6837976d8498289f3e798c49b36178b411a76ca0bbb78217531c630ff7ddd0f7ad0acb35577806b7fc906d7b313267334365c18d3de57f3f9feffda66268ec591a85a5e84cbab29e969e668e5779642b594cea6e6ac5e8be847b2a7c4d4c0608a86f28bde1f50a7d9f048466671f715c39f7d29cf2daa577f525df30039a78ad9908ed670ce218a1702399d4b94c1229d9354c8c4cbe68c3f3f3112631877604d01a795f24cf80951b2235662fcaf9730decf9231e8a0b212f30e0973b90f17ee0b84ebf60471c140175453a37a58d84cb0b5b60a7af210da7ca5eeb6f2f233c4d03d42006f0c5068183d4126c64d4a57891eb63a7a1104db054711e7ac323ba76b953a9695fe653c3dc46163d439b42c6c10def4cc361f5d01bf628dd8f5d70b8441362683636349cbc98c9acfab4236c4af24dc73c4ca5d5fd0bab04f684ba87d0f91a54ed0b34584b2c50e0acf5fe0c4e2f7ed2826245b04834e75c816aca4359b4096df181b3c98e1a8e151ac5b81f1571842c11427914ad9083ab33a256237eea5d10a69cdad96140295964fd7acfe0fe85e29e8f632d4856d7695591dac74d9c42f0b86d6ed062050b8d77f3571f9cd2aedb58fbe9a44beb28e5e3099454d1f262a6f4b69c5a3674281b83985b9eb296c2b51070959d1dcad035779b60f23617b753985bebb7caa1b28ec7721791aea729c54bb17d5fea2b091fed1f00fc8c3e4b8f9df097f03b97c28053901bf6554a1fbea5108799e07e161e7a1871d47db0ede80a66f212689d2164e01bf8672a115e1886c028393577930708521cab90c23d7292a6f3e2d2707586098d39abca2dc52aeee2e4c86b6cbaa37c74680ae00a8c1179c5eac21b4f90fe32f5cfd8f0b0059870709328f6780e846631137d6909d12de520e26204170b99692da01c7a5af353cd3dd953fa27c03df8a85bcd448bc57743840a01da6a67cfe8dffd4bff03032e4abfb19ec939c9eada458d66da0c306b7999c3d4512a2064dc0d714ee1dbcd1019c38c35a6c74c4be6c3f548d55345e654cb3b152a30379556fda9e9d0e908354bb364bb4c108539032bfb48c570362c2a7de67541987986ebf0cf8c353774b101ce45cde3d24c573763e1f2ae0b526170f39cc35284d076124f15de28a7803ffaadb8a094788219423ea5c72d1d29107611ac219f6cc42549c67855942742e160abfb825c9d7fa5511f16370eee0fd5b9d317f10ea1e77e817f1165423ecc607d480814cfe58c3df99e228e7b18cf8bb1f3e411d5f29947f106ad1ecd13ba5eaf95a4a11e12a4808db9983e27e3e98c318270464bcfbf092210b487b180bd2906117ea0525a9606383d0921302535aa4e5098939a6260c80955aa8038cb0bbec9e97422e457135f1c208e4f93cbec7abc0c0c6f3276ba175a6dbc0e3c9adfa991d7433776b939a0a2a850279064f793315a2ef6a508c68c4ac1e4284f47c9989bba02042840f5f8d5b4409472f59be86ff6589915108ac47beafcae6b03448133e42d6759bb3a72c84433c141983678fc4d02ab5a1f56aedfe20b614423e74c070e821897ab4542f98e3eef1a9b6fb1b93c227ac92e492f2093adea45efe695e5faf6e95a003d1b284007deaf06098c53b28bf5df59055f56aacac3b2234e81c6c487f55fdfd818854d0384192ffd248ae6a19735c82c72d33d690a35a28235dc41ebf266d5b9eac1d4dd04f7db49b888c104e4f6b95b794059316f737096abaa32513a28d623422b80c2bcefc6a42960a3b251e2674a879c9304c818b90ae6fcc1751afef3d0eaf381f02d670deeb1774a811473bf8cfaf1f631a3eda7d45996a8c9ea5ec02dc258f5eefbfc6a1753834181c090620c1002818060586848221d03002f39650b18a724038157530f08c098d14c9e34b96fa688db1c767de860c64ded0dadb33db335001b95729ee4210484a909c86f04109dd1adc81172b392df5042671e6e9c324c583cdfc5e43568a89171c72760fbd4dc3da8525298bb4c1c1516567701ba9793c77314c9257358103690404014320351e2295fc329e7b6b401b80953a2834c1808fdcfc9839ab0761a12c266a8e41ddaadcaff2e2499c2161f97cb20ef936aaac8f5735890f24458a4b050b51cec44f6baf12b6af8a27db0b411e5348ff8a8a32f4a5eaf1798ca601a7324f72f8ff31c38cf6df98d5df908c23f995c2c269cc2d24f4a35dc1a55bd03563c0c2890219e704f82d1f4b11ec5e217f04f79328faff38081d21819a44e0ab864bdd496e414d2caa577f09587d80015f1ff0a869939743c1e25a3b84c6105ee8970018ca9122c22fbc64c06b25b07d9200a12301f2514a902f01bce77bdcbff1f7d88e5d6237b17f1e5d1cf63ce626701ea1be8cf577f0c5ea0fed7fa8fe10ba5af09de434a1121dc828ab646bd740dcaa4e3cfd838475e94e3175d5e9a400e005ffe349d9cff1494e706816896f993f61948ba939a9cc4e95a6b4635d6ed3d0f4f1cff6dfcb8cec0cad524de3b1a255ef5ec82afa27e71cb47f972289534f60470bcc5a155aaa3cb87934cdb77d15dae5db8b295dc66bb6d0cd1d901fbd3bcfdad6a3d4040bd4e69f13fa50a819d870550f9531b44355c99502fb425e1f6afc7c8206b3f14ac9b44a3ba2974f90b5a6dd850b5b96e5d0a4745f928abac394947788f1907061143d2ce894e9f1e728b15f6bc90f55360990a4cfd0b5c107465978be0df80b33d24519ed44c0678d2534f7f0b9c28d41454f5566e632b48805c956deb462c4e69eef1596f2e7c9fd07fe496c5e1d123c88d3c827f3151c1331527b8bfd61c2024196e09eca01e9045806504d6ff8762429a20eed141d50a781ba2b54100e524a7fdf91d0a2a3cd774ebe70d9bfdc35a6e7abe1decff8e44c911646e35e3f9fedd949dc082a9c524700a0b222c63044525957fdd998b9d62947225edb8ba741b680caf9a55fe1632f0dd296f183ed5b22f7127f9186f02c121e986b67d70fd3305d3f9024095102eb5a297d7204f8c28e84a349246016282c2b325127cef1fc6fa5c541c248bb1de42b6fcc3ce7cc5964f1bd0de23d6279603449fc34da6adf59365049bde69bf3b4194f531ce1613b3931c3e7cd0c3284c7dff24d3864f0fda215a08ac743ba121ed94b2079b86572829c473bd45db7582f97de80678130f0f2093d072f2406022d0ba6749eb41db2500f4dc3635d6350c06540199406ed7c81380bea6cb34794a60a98a2202647a28f76f6dd23d1c8a0a30ffeb2f5b625d7a29b745542b02c224278917f5aa57f680b2e73fa9f9bd72ed7c8439ca8852296d06a6ae03b77ac686704e9d1ad4dc0e0407a8f29ea65de3cd06096ecd0cbf8d47744f04002703f08d6e9aabf5b63a28f892ba2a05627dc055f34430469053b754e8c1c0dbf003bcc39004fa44346d3a9c049d3e87489fff7ac3afe2356a9b01f66b4b50697b0ecc284134f8039a00391803ad9484bf8eeb0a1b87dd71baae07038a4ec85c7cf30cf497165e9c6ffaa5459138c804d416077c4c14142da450380b86033498c817fc2201c8dee0dd7a8731bb80981f7b8341867420e46ea80f11e0f4d27ea309afd863df165e90a4a1552deb0cbe2bfb3274f1376cdab004bb2aa25ae96576a0862ce5bf2c9ce6dce21d3772f514bd4e483466b870a1fae75861ced195258057a68ccfc008276b7243c211e55b05ad666e9e2b405ac3301834f122dd091825ef63dccd38a778448344adb89b5be6ba776388eaa17d24a344c57498df1cefefe47080ce3e6e99c23bfc15a937144a4dd26161c088846e47bc7dc759a33b1d842254720013296f8398fdf735f2eb3c324a60726802e07448b85490a109ce34a736f97ef61313fb86683b62d5d1f8719141ec2a2383b9f547136b62793db4b89272cb0e4a76dc710bb5cb2ce79d89e7035288ccb8431230eae174a50b88e768f1a96160257871cd6ec4ae782c59894f31cab49721bf467cfab1e336c201e43ff855cd19adc63fd1c7409c9775a3d4d66a2bb026ffbdc1400ca2984dec317c2a9a1086f7553852b796289bb66b7cc9206022885c6ffe2289b5704b6bbbfb0511594823b3e6f13f545c0b024d3739f7028371b9a9274f956a54b73fd341239893813e9de8c28afc13209e21ab779b6909e244c407d95c0eb0a2ae5c0cdebebdaf249d6f3cb08a1050c3807cf869a58c8886983a4a9922cef63de2a265a894c0e5b5749da661d3129d01162c15092dfbb69347558a8db232916b4e9fc5bf347ef0d6d6dbc75ead139f0813c5142d0d9ae3e09a4d787920d04028fa69aa9513ff0aa655bde6f2bc567f17a9839819c63d3bed74ba6e414044b7b9c35e386ce531ac43055b59b78a69c39e9aee01972c420628d39f65e1a352f2a22f2b0fac14b9c76187d79859a83a823a96abeec23a596b8ebd78cec1ca1ef841c1ab87cbf96d8afcd49b239ffae5202556316b2187b097c67561286cb535651f3337f1c0a4083d2f2ff5d6730b3479b800c6581c59a4f9f9fd546d65a7581ad2ed5b16a6bcd0e2ae8191533cd2808c4c4994175e101dc0a0d758bdad22e8afb8c8ca1e1b21b04fb0fb0416fd9195540f7dafbd867528e30ab3acd17020283a2a668ce35e8ec4f269640281b68de98c5bfaac795c40dc79819831d6786410fa82d9a83009a0a2a141a5633c3796b6ec05d9f002a009f22d42aadadb22fca2420774ced22207965f408b9b305345af0505f05bcdf18f3a217d22069680271e1045e15c03a3473160260959b49257380f8005d110afe41beedd46d8c8e6003eec1092a80b6f88058e0c0ecba930444de1ca579e2395c19de35b2108cdaca8833c5240b70d72265b0c81bdcab7325a0291bd66d8b53a8aa44247549d3d85d35ac29c5d1932cb44ed585de9a279b38469c766b480d1de0c7b3a034921ff4df887002708fef6171da79412063eda48d2408ffc9c2d52bbea0d83cbd4e15d865f454f989392514c35a141a7d95f3373193703bf8e8f0c16eb40ccd4a8d43baf941ed6327a9bbf17095b3834a43cd919e39ef07ea1552612470f81803e12ed15619c65d5211b7d4370722971bb7304f5962a27dce7a110c2d356da3d98bcbd6754e69b59bda262bd71a776b2328390cae2499f6f338d4d9fee3b43fd14aca8b5401363d7878138cbe4f556cbc78cc255d5610ced57fe4062428458ce46a375916fbd70abd70c1b1b535a6a0f3f0c4061659cd602466c5dc1a36b10510665b81d19916ff673e2c8195f2da059fd2d18339c44aaca84b1db4a19e2b006e836eafe12b53bfc57810668805a78ca8a0c9f0dec60546ee201c46c359e2a43eacb7d815b2447260cb565a68d11ddfd44c041c0a8c92326f99d72e02c51ddd00916d5b710f49a1210a3056bc059e331169133b031e4f5b15ef482bf34ceefa177aa5e9553018e3f80187785fc1d075f036df902516948d810cb2b5528371c03227e8d97368c5f70a056181ed0775777d383d2b1508032a28eb62173e0a28f57ae5f299a1a6516787d0d35c5a11ff29636ceaf76135f3820678c9c223306e21ada3ad8e15bd0ca4e4435430a48ccf85da6578c8a8e5fd3e4323abe36ad3e689bf129b1ddea8095a4603ca397d790f93e57d9f823ad2812b56d155dcdc595fa2c244e7671ceee34bfc0e1c2c1f39b3e0b50a84e1c378be82c5a07abb18a2f4864e9071132829c9a214ca0269487a0a0b88c84274fb51e5c496656961c748bdd84cb84f797a7be679d52e813ab1cdbd1f61751500fe62944821427459fb619e5af91d7bbd07705640746a1903b14bd80bf12ceccb980a00059c613d3207c6bd89dbe3ab9ed37e59deb1c4626db634a50f765d3574889eea47801a7f79e903383521b26f7f19bb766f906abd1500dd636ee8f04c76a22d73f2da394fae3133e8d2cf6e6d9780218d219cad0fb0abe9c5840062c231055dbfa733bf995301ee5a8d75bd1a5cc30d8e6227a1460cf81e013cab381d21e82c22d1be07054a54d66df2005f68b12ef2273afb3eab44fd3c46c47458005f36748a9602e8dd91b439493ee29cac7c2c1d83813c74fc2887084f53d371023e0c55ce38c0de8fc5af6a22a67b0a5bad7208d79e281477d171863eedf72c9a57b1779e57f8371b8ffbbfb6056a3f3d3c4af8010b56ef6efeeca73e83a5c319dceddf9b82bd5bd302749a57b0998a4797dab905f32bcff560fb30577f935708f3f39b55bc8baa221a7b019f93237a364f733cae42b452951253c6839e1940ce544b58869d44749cf2c94c3011197f9583c979b5fedc0aa51d8efbac012e8d69f07baaba17937efdce1b90ab77b7c45bab6201b1a55ba70f08523892317129911d0a3721f2bd921baae0a15f37338606e55f29bceea17dd20f279b546af17e36bd4e34b1380663bdf38533fe9101fb898cced76b96e9750604d670fceac10fa83b1369d680deb121422c0a186c51a8a3df5206577e5f1763a8e325fb13909383b65558955de8180334da871f1624ae7ce2625e46efef1c7b13922fdcbc0c46671e95a1025572c799f83316f715c9a9cba0b42e0cf79acf208560ea0fa9094f6bc5aa9984f27e492c06d8880b251ebafaa616a8847bf9f5b7e0ad88a842df0e92ba25c513b290c0823b431f09e862d52e72f15a135889d2b7542719fd4f68109cfb93f50fbb6b83889ae6a310527e953fcbcd810caef30a85ec6530a237ed0003a6f6400b0abc9eaf0d9e16518c14636851234500886a3000ab5fcb338788224e7c2fce5bef1991efd6b730e172d03080c06bfc34783a96cf20d7701981c1c54d9c8e5c399c360e0931caa6049dcac46fd7c4cfbe4acfcc75301768a087a7c4f0149226828ac98633d654bd91960572aada26b64607a8dbda7854fe6e5e7acd3dc37c29e8f104428e4726d2910e1299fadfb2f3f31b160b180314962b462e53c2d5b3e923a1cfdbef03996446307a1de847473bd974f8fcacbe9dd0e879a6fa8a66bf971fd570810b6348970495811e2c0a38d5de4c0fa43ef1015ef3a3e01608bb5caaf5ee34ce4fc519518844421092a19eee21cfefed5ff8603c74f1c765f634038153bdf6ff43b92e340cc83c6ab43193cc1b4c7c018098e82de81347c3630917131b451d319c627b01d2917111ee12c95fc95427c54c15209857bdb60384298ddc8a83554753720572c32a113996e5fc6f0ba79e21c15ee00a09206a4ae93a68016ac12e0667321717178ca7e7bea59602fa127858aaf0ba432e0d91469652b36fce690374516f506eba0275d3fbac2254c27427ba99941c72f51bec57490e99e50cfa5ee04a4d9d4d73220f361eef2643c60fba319852b52141cd0b781398438c2697f4c8c1f09af322ad89a82d34c29cec2b2cf11feaa021e2649169a972224096a8b262420675277ad55fe8c7c95628901f269b6c87aee31adeb1b7cbb3ed1364c17f5e1366e95ab8ab3a1db921770f1a501311271452c95b7602825ebb6140d1d728fa8eef4a3ff81357116696d016a0301514f990a71db3f32f345b3fa83e521e4e8448a298b26035d7ca27f174b0032dcd69d4df5bfec74ed8c2f06c37a210ae445039897df1560e6aa99507f7e0ed3478897e8cd67a65d66b750d090610ba9a1ccd0a4c7a4cd6d9a37862a2743509abac49e77c95b1bccc873c9cf626844dc01fc56a508e0281640df2ade7619b538261d1ac733a22d83f0f647a6723d906ba303d6abf13c0d8bd61a5e4fc24c040dba90ce6ee908d4b9f44656f51ab82d12aa5975c9d543057db8577f05f0835aafa0b5293a2d85c98edb31ceef01df745642e13466dcd87c95ce33a2c18503577ee10f3844045ae2c690f51a99ce71121a081c6ec2978fb58ec20f07613119317a9a97bb855647c0bb183ac5eed2e8ddbad80dda219f05eb6ebf2ec443fd5b16e6303a0881944a560d72c85d4d9abe1503f3880676a6fbf565b2957e586d16e03bc57c0c9ae48c05cba1d5c7406cc365ed9656f7fcf25c4033c98145522957d9d5d7ecdc8ba7ea15b45e50050bf94cf31b1d12560232e1c5cc0e05120a1c568bd2d049f1a46874d82ca861564e4348782cf2a8d5df0e1c121b66d92ae96ae42a9463edf196b18713d6cd9d1fe83e526b8aef4edf4e09bb1f60347e2d11de60c555b116a2cd720c15af7cc4390747e432caaaf6729163687cc981f839ba0b574fd386aff9bd32c30e8d9f355c7a94491f3e58dc2c0ec042377edd89eaf4b31c5a19de6ab1fdfb4874308aa53d2757edab1f9dcba7e44e7b3765d54c83903cc9658f16e7aab996bf3beca354b6140100fe8692b3db01e22a5bb321aa3470b6fab63b0af4de889c0ab6317792e8a93875e73b5746c489e1fbf58d20627239c828f582d5d4555b3b562b1b245ae9e60ff44ec693ae064bd45d07387072642ecd1438fa349c676244c5a5e01c115f78ad43109e5ee80440237ac9594c4353f11b727cf50440419bc852682fa8e45868517c3001b9e0dc62c91cafc6d858527c8604d9744d6e86a0ac397fdf0c960031902b43043b72547ab4a2531dbb17663dc30d0d74ac4df44fd4108404565e28f92afd774757e34be09242687db682bdba425e2ca707dec4d970ca5ccd2d806246d94e59f0ebdb68e7f57d4e71dd6b8118299cec5b69838ec20351f16b04a186a79e5d442be6c2eaba2c24169f48affd6f61cc1bdcce9c6c64afbfa00924e16c23c66dd6b489da874a9ebcc14ce00d1d55dd2c903c59ab65cbdb65c7f457039d789c5965985a8eae4c84b0174ae7c29c767069cac33ecd28379463ec832654f615b690cde1fdcb6e46a5c54afb0aa502791c4f91c4d405a399ee16ba5f5a2021ccc37d2df48e48c644884f007ed47c225e0d21c4480eb6aea3d9a91ef36e8139a5fb50f2c14c5465c0b2e7a2a0c13d3e5bbdb57db0376e808a8e7a3cffccf6964c231fef0be2143cdb176f72b8651f06dbf2f93dcaff2e5c25be9e93e8e36cb206e34fb1dd859426d8034da2e609c568a37c1235fa0d04fc616fa7ede94af68cccac905625adb584b5aac560034c1a400bb957f69ecce78033f3e95651596ee5f2690c4ef5f4225283bc5420a88e50af01a30a0fb120ea4b65a2c35e765ecf7af801dfce3db65067ea288219d2ae0cc8dd5b47a8220aa0b3318b2bb492622cadbd337993a17b97690293b90c962f6059b41d78ffdabad42aca1416ed67f30282c2cdac6472484d249637d59e10881cfa08e21d015b3f8038113a7faf7de1f2567463d38fa6ae66df0d76317351f0085c7e743b25808fa2b1f6a5ab04751b61ad9d91e847975b67f7167352dd69001e38f1018025a92dde99ceff2af2c9b020778d4414a80e74783cd40eac3055c7ebc8fcd40f8ba77e10e821b64e539f42bcb4293fb5b971c17abceb9a8368bad5b76671afadc393636032138b2eaccc7dd173aedb144f3bf31412dc5559c12d9300d23b3418a273345dce5985219288f607620c1eba26989650e4c7b8355e0e5ab517dce11979954911ebe8c7d71f4caca50c5cf1978222df695d47abd4b434403de3e49ec9681bee75c6aa21e9df7fa8dc50476cbda050b74bf1c1d642112f0f1d907b8c0ad8a776781116101a9602b00dc83be6b5109c02f04111ad39ebc201d344025c6c895205c110b823829f474aa1c8108debff8fce36af885f23da6a23ee394bc5bf4be79941b4326d85c099867822310ddaaf691a52ed9c9bb5d7a6bbc413a284b056028a5e386e6f7b896190c31a947e06cbe06194c97596003a3699c2bdf38ca4ad5dd185e5433825c55fe3a852ca9ef1dc2b7ad86efdf99ad6886787c78b6fb131fc24edce2fa08a358aa98794d36c2d24a4fd58d1995ade51319efbed0ce489379419ea3dbe2959e59dbe435d87acf4c1c150d40165a842e608d2403184cd1dc7c1145fd0e2460968ce7fc477d7d6ee1a5a0bd6416e19729f7114a22bc0c8a8db81afba96cd9b38649e6e57ec679acb867a5c22cae20c9170663d4842570358232b0a329a1524aa1a5ca6abce1c5d63cd5a9c6eaa5c0e4af180cafdf61c3b84c4ec63e7f114db8d760b9459d502bdb9a9cd328642fb6312a3e14d01e884fbff2ddd45935d94b0e8901787d2fbd5bd0fd5ba3f0f4524136ab5a9102c2026e572fd97e32c1406ebf688cd3a701cc39f5e64654d73d9200b1b91ca5740206ad592f251b843ea8f635daec4d84572f967b58d5ae3f972efefcfc8e3ce5d6143da9893ca16ba7ba608b81b3f1212f8aeba52a94b3314dd8ac7abc18fe6a47c8f2225ec864b014a568d5870bc3b09b28add1196cd21d8ca6886b6ddc5744fdbc20eda86cbb87b6d9e0950265267ded2cca5aa93a3753bf3d5c6dbfb945c9ecddb5b334bbe75fc987a815ceebba1bafd8de9311653cbb454aa067b5c5f1676082b2ab421e9d3408bbb218420b8812da2b50957d6aa86af24b03420caa52881063505fdaf5be39f06f678998ac3a4736f5c26909fc30867f92b56a806717be2b8402496c131286b39688da00b040496ad583ebb4e2507ee90c244629d8932631f9e8263779a1027f263cf10a03bfb13f5f8bc880f5376c7fe87300543f19580722a8e815638c90f23539ce7adb2f9c5dfed0c7189c19449e990b4b244d952f05d710501696af2e4ada13a36e5e86681ff9d2978f647c96c61cdcfdc3703a68502250f18d737b16172c51d88d6365a9e0e083861fc18b9314164b08493a0d36e98e3ab8623c7b0fa179e8c81d2398a382e8792cbfe36de50856a0ab8f25f7f3936996618581929ec2a9c0b897efd399d691af0008f199bc9229a9016d980d8453280aa91c752842f1f183b74e99e620d883d73a5861cbd20d1b1b64656e8b2426d62904890384c035988c7a0d80d112f7ef5dc06432c28b87c7d62586ba3a2f44686cf6254d85e6a72a53acc42ce3f04288ee568a7c9e7f35a18c4117989e2fae9168b13327022aee65fe89308e78a420d12fc478e8840782363be94adfa82917b9021df0d043355157e175ec74153ae3d4d69db5eaee73efc9d45f1e12256aa1fd9b689702e5870f4d3089a7d8c702ebdf875828e761fd9b6a2330b660a0fe55ea5fc2430626f9c914ef91151e833bac7ff90705b4e4fe45c3c033f357882212f9fd189f7ab51b8797ad8e8ab95e977d285678e74e3a1424273fd789246ee110b6d0c16757b750ae03b11006e5f6858b8011b74fcb8dc62f8140c0600178ab73009c8e6f72e63a53cafd00e3d480dab896ac14824370a018d61d5c49b812bcfc61da051a9403baa229686b753e6cddba875d744ee5bc27e356994e34b6e7c3c3c75afbbcdd60da40afc6bc3cf43399189b6049c062b4be03c644e259e20752117554917f12dbb37077a472a7f675ae67673fd237ca19ba3646e6ad90e1d715a14249e8a6402803502225d72f65a2a39afbff2181f026328688e0c92cc2bbcbbe95740dc84a117699b3498c15aedc1b9bc7553e9af2f01c1170b86ddbe621aa520f6cc764ba36483c015e8c25856b8062230a878201f05c2d7a4bf50782a5d0327d28559ad0b9aaec8f89632e00ce1bd0963d98d1043e9d4878601e4193f5d16229b86bd71f0ce610ec951875bf0f58936a18ea656864c06df17c8ef3407180e12f57513a772bc6d7eddd405d09d10b1634dd99b3e4552ddd4586b0f24c043a4e13a526cee573b830f0f9ee642cdf822e69b631bff700c7e72c24b678e77398fed4a4463e1f6a403cbd126449f97c1ef5651b9978c6eb0d4a84037ba7cc8a98fa12e0522cba10211d3503946bb78f7b2b99a0a276ab97ff25d0ee9051824c53a03401150c14ccfe5c026c1362b3454ec7da3c3010be9884f5cdf800ba8fec84287f3d23aaae385eefa9e46352776692079a532c2606c0145169c94d4cda4c3c4541b1a3b893daf5333871644b588bec16c2e29763253dd7e5e83fe9f1e233e99b4861d91ca0584df049aa82efa8f8f31647dbeb1ddd0cdc29ea23b5fd435d4234cd068e046ce706e5898c998df1dcf1ca0343e7f2943b63780a76b373804ede7f54703da8655999a679ef6ba80c7360592c282cd890bef80f90fcd3c2324f129609ddbe83f278dfad00bce0c7e024aa9058101ac2a8fcbf47fe41cbdac51e607577a629b4523c01e2c06bfb20df3bc461986310939babc6c4d2064cf8b1ef3738c0e5a1fc2b20b5c3b4f12c11d94b05a11503f2edac8b4c54a54df567a65dda77bec4adf5491c094ca45684bfea89569f48c6c305be24a33cb2b3248a8a4bfb7ee9150783dfb4ed615628c15be9be87eef83b88811b6965c55139fa173639135d1c72dc0dcb84fa39892af38461b12630f341eff19ce98a9bdba4cc47f44717f079c66453af6e2ebd48eb3f2ded6d38cccb05f2bda05446f25cc4c9a89255992e09521a79fb4fa3a49a096006742b57fee3d4e3ee28a06184c96db2526cbfad217b227a99c3396745f124c2dfdc1342a7424482a7c96d9d09c7447de99297721fe0dec98afddf31b8c86d88101366130609f07f07f64c33704b109bd5231061f31f49135066571144b1fc32c8f6bc0f90ae363aa600070c95730a7c312b0c4ff421026cfe324ecda396d3ccefcb34fdac12497b044174d8055055afd46590a75b7a8d800bc3abd5a614841e46aa2347000de899db09697a8412e25ae748173d1e1cdc9fc5762d7aa12cedf61e0dc47a4ba28238252b557478c63127d8b1425ec971210fa46d18fc3288fabda2683b1580a2a288acaf98a040ab49b50dd86ade33f462c7827d9dd500be4995c79575561c82cb35e14fcc126f07229c8577f724309b2487854806cbca114baf61f15550078edf35d6ebc814b30fd0c98b449402194e124801d569fbfc071fb29ef6351845fc0e1af7d50b7f93c3f658fc9b267e0041de621503721a5ef6fc82d63298c5f9ce5ea5158767d47e97809a36d003035f744a62f60e29cc4226c61e349569fff2ce3c8b295e6cbedbd6ddb041303443e944aada4a2da59cab71e56e60e78c73a81a8a2bfba0c7479cff98b19e39226c223068b8485a3b32ad4890ee963eda1d57e6693c547b6693183151f569211a53999084095412cb90788643961348072022d0799c8cbf246cac79ea5b005d032e0b273e5e8d6fbff1eea43ebd3fd125b0cc9d9e974533d7cbe7163f3c0030d5bfb732aea3a900d040d0405b79626db572ad45b0795aed5e4dbb713cd8b1ad1ec11f46b1a144cbcf81634eccc5d595ca212158983af620425ec7be8684910225032be6331ed6561a813aa756c78f17c35844ffd809394049005a18e21a023f321615a83d8fe9549bb3329ef167f9156366d42f8dfe55bdace05e7e19e13d8890991b2bc9daf6b5bc52ecafdf03ca37fc85fdb868e81557bc48ef5b3e1e2c7b192bc64ca3f3a6f61e4b14411e15c761e1dc3271cc7ad16828c70685323a00067b7441704ae2d63f55eb93834afa09b05122d3f43746a8a71c69dca2cd39c2b61cc5e48b29104c1060971352650e10b1c3c2e4e0f181c786025ac40bdcd5b592403e476df05d378a3c74a0c5e0b7f56c7607e39a562b98e42ec53ce6fd9ee88bc5f880c84655199383bc5c2b19c31608cd9b3c7465b28af72c9b529895789a94a61494320de2d056279e503645fa9b12cb69d9383c0308f792880551b8d3823fcbd817512bea07e4051b0ad4dece376033b4f465bb4ff078e74352e6710aba8ea4ea5fc63688966ab401a6e39aa494fbe637c890fd9811b950a45a7d095d4c1a9fcbd0cc084e5af300fd8f08f6e306c629125dc86f8460bca0d967d5f3daa0e040ca8351696094d17cded48bde8fd06cee8fe4b794252e16fc6e459865c9df64d6e7975aa1b10f51a6c5544f5693f2aeb5bf07d1e3343c3a6fb35fda00f5f84c474c58306573bf948a00e2cce361ee8ccaaa987cff6b059c7a19b381286c78e2d982309d1d09fa7c46a57a1f551efc73a2c0c23db5d19db2b24030cbb4bd761cf6a49a8aeef9eb82d90aa9654fc9402c2fb86397a76855686566b475b4421933c0e30ac4b8e823e0c7eb411c2815b3b1d884dc4624ea01c3bc3777070b00e6c883a1d29cc2a1931e5a4421919eca18cbddb3ed7dc9c330ff1b01f114bffa5940c5c18805a4cc40967f4d4ce02fe9bf3c0ec113be4a1fc18925e865b8ed56d11d0a6f5bfe1060dd8904e86604fe0edb36ae1ff02b13d793c210bd9cc1ced8c65c67cd8d730cf8e7338b748a8d6bf30ef9dc2a98bb6bcb82317c4104004cf685cb679aa8822c9a3ed45d74bf282821e56165fd8944c56703a963a03e4146d6366790d85f64d6cfa6ed31cfb50780cfc17540a612481332e1035952e58625525232cec5184024162960be9ea6a9cdd37f024ac26ef331d2fcc9ec9a8d8717ba453768e24485908fbd0a915683c97b45531f25d13f6c74887e426d94562c7fb2e43fa3a13aca7d29e46def204aada4836ce009c4117f4f52673b301e87acb42e20e7e0684860694160e1c81322bcf77b8f1860350e92d2205a8ccd125d39839356234f23b6a67f251b8e3d2f61909e74288924585f690adf34f93f872602984098040173be1f0b621b388f94e45562119a1e10ec4062e7b83714e3a3bdde3a2a97337c625ac84ad135009a359d1a16b0d6703e27b1563723a4a4d67bd9636120942a719e63eace6343684e3e0319489e220ef3faa9797448e48b5401313da4e5b2eb7b01a8f404ef6df277311694380dd01048798db24c3815aad8e7af5b16741c44b7216a26c94dc3ee629a7eeb36b9e2a473e2bc01650c90738503eca8b5b5717d0a1c745f9cac77549338a96b7e034271c6b471c8e79bb773f8993bf103852ff64a4de7077f7639e1f501b7d69af184788400ce61303a77895aab03a0d38f9e0ba1edaddd7f55dbee22f170309b48de7504c0d5463c4e1ea5d0b0454b9040be01993f20488ea2e0be0af37830bde4087a28877b80204b39f7bdd4114d47f7eef6e4ffc221b4b42cf9a2c4bdc42d75b5483ecbb583ab6c3f74137104f277a717e3a60e32d6b7b3700776e99520881f6164b4d7b54d6721c444af60101844c2da0ca0ac0121695b6a0ca3899fd0205badc639c88c7c831a9de76525ccc4419a3b942428790e33e2ccca9a578febbab74ef86b47b16421c0144e2080fa0f3571a48ef07a3d4ce3a2b99dee07840a78929f0860bf49088177875e48859fb3e0e43f727a5e9119d8b285c99d24574e63db858e5aa002e83782180852583453fbe4f96c8c52773dfcf113acac2286c21c5100fabc7f10851ed4735fe6193e44e4103333f244bc8b18a882899ed117404b575f9db74d98f9d64d5a757167e0d5751284a6c0e7b2a4ed5b01d497fc17a2fee5d4340fd747421553494fa92b03ff29af0c37672aad1f65c43f9ba7165d8c80d60ca205d86f9298c40f1c86687a3df98032b4ba7adf4fd6541d508dee5090eac50e62a4e69c542bf98d81742ecc0c5222d6a63bae9721738963278b472f5008d36f4d434436e3a23156268ba8b4d961f0ae1908368f7542892f288317c045729e67df718ad812508b210eecb95a6daa48223bfcbe87c82e9c94c460c45fcb38556ceaf27801a978b2a116bb6b79830402e106fb08a89023e8d860589903d260984a361edaab935468e8f5a52bc2b5715596eca83bb2b32be783dc208f84e097f3574ece3ce39e3ec7d4a1220330c4c0a706f56ab48e926d64944200ea0dfc0150d26a29204e0755b271d1b7cdade6d28907467c23a0168375474e2970cce1b6659210fcfafded110e82a4e41496c6a9c6a48a02e28e9648519b2e460e27625c368f67ff6ee8b13d239606839fce69e242889c38b3c820cd3d734ed3a44bddd933a9bb5d786ef39c140188fa0a8425d347ce73248ce7dad94812151ca7edc12cf7261bba6aa95bd1df5124403647748252c1a27e2438d4e2ab8738ade55ee83f937bae67935c2d9a2e2dc8464e0fc2c0fc79d06d98778fe492337adb3995b7feb2a3eb09a239d0e9753f1532627474831b03a3b0b9a1f5001f3e8a2ca9b74438fe885950c8c62ecad94cfef3529f8454fb5a25dd8c9cd541e8ac7a01889cff7deca545cbe568204113e4920c4e1e48937c9303a2f88c58189c750938246b704c3e124871026f4dda7723d7a83e1bfdbbc98390eb574265a7def22745d77a7737e5629ef055580f5a074c1f845a01230a4df89c0494d994525ba9b42fa3aed8465947e56bcc4e6f6a432c6e6f4990b78ab7c3aadc4670a21ce25e39e54e6a1c25a0322da0feb046c01b88aad36d8fe7f0a510e4a967e228165a56f0edd20ffae349a35843cd0d42612b12ad128c4d876862c56b5c56fedea59b76233c6f7922e818ea3e7e8a7d19014a3ef981ae97e09661c9060d025e5585f6aaa4ad629d125d0acda60f57db36af6b0902c5c6aed209e255d3f9f2620bca942d636c04e9b80aa1dad843d3442a95ae24be129104d95237ef0837955fb800e196ae6b8aa9bc0df6ad0f9006ea1d8ec66f06df74c582ddda68ce99c2f6d6779f4157016458a442670fd76314176d5f201a5ac472634221d170a6e6d5de8311df3a81e3305e8a350864fc860855a4287912863bd6bd83c0fd7571c8e5a58e31841f369aeff0d08ae188fff846c57fd424fe7637869bc9dc8a7273ccf21af199cb9cf2a6e31564afdb4554e62f975680d138fae14e607e6bcd1e11eddd345e7213b2e0d06af3abc4415c697e4f6a3c157de7bf374590e330eef63a6fc68e2e3281abe0f07c5650e3b3dc98d595b3c54d369dc889ec54786544bd50bcbaa6488530c3ab621e78fe958fdc09ad8b0300bd7fb5473a6d5fe77ae940fa08fd41703a968dfba198befaef91f4babf64630a6f733295527beda7d4ec78d60016b1ad25cd642093251471b29ff8c5763dd7d639e7345cfdf5250aa6e23655a250f0c3f3270783842334ca0946831a07b6310e9d23b096de8d059060d7309b11b994a6ae9f2d16c9b9ebec361a57ff0e7e0f18cf785f3bbaa3f2249c012730beb831dd1673c6fda38d97365ead8a267d9ca1ea5ad93ae397e6800bb77d983076ea808090fd02574c7a0e071fba75a546180f8fc578c6edc3221db253a29bad2ac261c4414f83e2acff1108581c7c05834427baf76b0ec6d38a0dc60b1979dcabd8d4e5ab6c4d09732f2fa07074a80dbd278f57f9242198a7510a329870cc713c2760b5bec5ce6683f18ef1bf2fc889de3c996ce79118c07d57cab1ac496d31fdd49eba8bbf318f830faa1d70656bc951be241a2b10386b22e3ab6b6a1355a0ff052c87888876cae5281a54691868529afeb2aed14906d48070ecf5ee69d116b9eade0b396f0f57333a85692419fda189b2ecc9810efbef01a4c9710f754391db430ebb930ae685072e539cca3da4c764809229ad61eb8f922607ca400edeae4a8ae699eea122c12fe5913578d29f5eb8b5ec5f4106420f49356036ef53715427c80cffa38da688556f858ebd7c30983936305be7238cbe6c86ab00199415ae32862c3ea7d3b40ce699ee4f4af755a642761244eeb631a371ce992e37b9dfa599226898285da247f847729f6aca1690f79a21f04462b03bc5a75ab09bfd187e8db3fbdbb6b475d795fc76e8b7278b6e043446a650a909e00e31c50c2d68c08ea5c18733122f2edf433604eafa66d7c73eb4fb9b37e2e3f65530a490078ce9680663a5e06b27b3cab8d240ca4abec0ee51fb9169487f15ac5a0f4d18eea1bbeb196b62ec79db9bc80a02c9ca8c422a0ba2967bd272d1a068923b6c5d6b1da11b450e0ecab4f8c84c0581257f3e6f0591d46eed2bfa15d03f3e38d4018a4e04f58b20e27c6c07583ea65c23f73c0b8d294f0de67a060584cfd2efead04a5c2a39d47a4cbbe7482b3d981adcaa0a14d1719c8e81b63c664ab5f3110162a267ec875e4e1a9864ac7bd1dac1c1f0ceee9377031a17337a3175d7559421563177dd65191a31829f468ddf000f0537c742173cb17dc293608d9b8587e73b05deab934d5c34ee1a22c807df60ab0532c241eb4714a3ed7253d8fbd7c13546ec805a46dd9ef5a77ddbae9fe3feeb494d5c1d3a522741e73ed7d5dfaf4ada60aa8f4e0a7ae2bb0ca812135d7360f9e5bb3ea9c8720baf354fd458576db281bab1c9cfdb372f5007ce3b974261a0932fef42e691f2f1c315b86a065a00c2394b7d2d01b08200ada91202428c24deab4af4c50abcf4a5502c69966b603c73b84c10af85589458dff445e26d5f8a04615bb76cfc83c084e525c2d25240449fd758b5942dc6730f5c0a30752e9faa7737e04f65a61850cdb55791960183524b42e795415c43e00fa27388a59b6be414acd7b84cd55cf0dce2c6908b698257c88e21a24da3e32290f750603ee926403484d1bf1ad2906d0d2cc17aae6aa874d31c6df9c1dbf8a33a623820e340c267fcaea1c365d21574173e0fd1c4aa43df9c9526b9bbd1abe466d53b93a2aaa61bf66271145578b40ef5ece553c156013638aa3a2e3b39df56ee00d21568f5d8ef999afadba3f91384a9a89af3f09b83a0dfcde2487c4610573008be5010616a55f91aaaa1d91b550d8e01b4a3a0a70718e90f81b7388ac1a6e5fff33dbbc8631be27568682857b7a5624ddd0903b27993f0d0fb1e80baaff9e49e9460fc0462f1d44dc2985ddf40965644c22c0d47b81135754771d00db7b3a41b64ac6e5c74779d70bc8b279b33b054bea38021a2bfa5875fbf1497e5ed0d1e1594ede6c13f4897690a2ecf60ee82babb529d1961e3b9f38654f8bdb84bba6962b031c789eb23b3266cf46615cba0f68d9f3cc23d65b0e4a5cb2a4574f43a5448cdb560485730b7e10bf6c97973529544d0dbdebf150cf8c783b045e6b5f52a6991f8d0b46402b6e774042bb505a8caaa8b90302635a32734feeadab5fd11eff6a462d5771d3285607b3b40d5b9edb05fb3ba4d466d3c968d6e225a6466aba75dab2f2041d5446904b2f5a30a50304d66df2d99cba8c60febf06e20fd6cc3bf8334ba22a68cb0ddf6025e3c4eab87e91dbaf70c78e1caba76c4b26c24c37bb4f73a7a765ca722b486cf20ceadf3512174628fdd0e7576958b0b5d5709ca6e2f67582b57a661736f7acc1c0a7021004bccdfd9449a8c8d2cb610bc7adbf0da6eacc0f220ae29321a36c9f1f48dab9d627d05c6c7766b70f3d6cff22feda362001a81515a2cca7f1aaaa7ba6baf79cb630220eb6df669190d5086cdbb6357106f46499576b49375c877f1064b71a3142ac2ec33b24df799e200afabe38b74a6ff54600053076dd21e4e203376a3e5c6ea27d16bb6bb2b36e27efc565c6cbe7a7878bea98efdcc200b420dcf5f53f2cbc91bae480969498ee8c24a88a5d8f5b3375cba09ee476de8565796847f3b6290c27b7741aaf6a5b3af02a1a93fc1b5958c09c3ab9b88d90e71c235469f3a8b3d93224e789321306d8be21026da3414f25b47b1308edcf65cb1b2acabfb1b6a50dcb48cfa2f5fe1d4586d5a34d3b4e906409e4c3625f1d801bacdc6801c96bdee97da7fe99d2f8d3f5c266c4ea1e29d1b43e06d2ccfe5ba5f5b3cd2cddc9ef9ab375e5f56afa3fbb216be51aa45807ff74d0a0a1c32aa1cee522a890cc059030e1cf128549a2e2f38ca72d064251b8bc860262c7ddf1a534a90baa96ba8ed0d6c7a747ffbc1f265939f92f1e96496c772588bb4a3153994fe0d2d26124673342175fb8243e1ca473b41cf3c2ec45db783aad523a25ede668dd047ac842507cd8231eec11c28ff85fcf9690fdb58f7f5d4030b83df749c0c59b71960d8098be930f7ac8555d02b9d9e7e8051790cfec97987ebc5d967cb2bd01ff2b34af04c304c17e847785ea1ce1cfade00a994bf5130b2490af497a7de1bba6d09b29e038c9642da883b50a37c045e286a600bc60091954a5ddc462eb9852b527b0da09372c83f259b8b8d398492197f25c59735be51666ff7be0d3a6f4ecff06b3670e7f36fad194920fd24e7c0fadde53840b973447c49b8408fc0de74e311e070abe859e2fa864dc3ac2d348a9fa0794aee507440f3d9059bb782f1f53d5bdadef8356087cbb31d4a988a424761cfb684b6650bc31ffa763f601059c9e252c34e78064278aa83a81826c2c20cf06d6a1a7ee58f9c40491e5bbaa381c3946e4d1442ba06a8d101892a12f85faa80a513080921e17faf19d580a3fe2dee45bf73fe077992d29d38334140186d6bf6a6e7fe079891d20202b98f688e7b55134a02c02e9fb5f5a85afa050f683983b961b5144640e5a73c02230abba23ae417537125baa2d240b862c72a7d46d64565dd0a76d3bd253f991305f33a472651942c798f6b7a09b1cd838aa112233130501eff73701f4a96299cbe1dc22680ab08e6445b2487973c8957f174822704979e788197389ccb674e2e62de46b13ddfc0603ac9f288c09ec4517d08fdd8c207fdbc153a71bc3d51044b28d421262e9fa3c360f1a678870fecec321183c23110f2f1758ebcfe23c3c33504bfb11aece8747500242c08c08f02a40407101e131e25ae10d9fe9f029c754919d87bfbb4d1be246e7ed928de443e1ddf74591c631474c13e4e96328758668d2618eeebd741376a13d52ae8ad720a1eca82303aed904a0a45f161929fe6109ced48b50e19ee8edb172065e8e69c0758a5376fd7e3e45a95d54e923740c58ec691a5d2fb374859c93bc42ac9955978f907f3b6a697e4e786bf4834daaec3e8e9dab608530d9132e8699a52258a2d11717cffcaed2c6509ec638f9be97008bb4ac7c399b045c81e37765d46d649a66bbeb1707468fb52eae6c58d3fbfaa41931cfeb816ee4e631202facc8441b513a1c41517815f414a6ebf43df03efbc9f0557837407380da09ad74da3752c035d9bc0118837c3b79de515e54175fe2d206e4b139a90465e720d0b51db5198731d91a08af6fe8a1e2c2c818413db3b15f9b2b931f47484e3212a0534746f46f669b102c3b676f908a8940a545a4c1e1b472764bc0e5f87d215a24853a71f7f4b0f49811fae02ec34b843831c0f98ba30d7e63b709fbb4b0e9445f3228cecf1675e4e8d4980c8783dd93594607c40b5f44d9febbcde7c6ba56ee4d9afc9b2cbfd2163eadeee69d49b1682af9e19af0521485187956bb0e4f39310203abb5cdc56dcbfb5a1b99218fc12a6bd93ae873e37123c6c93b55e5b6d42805fae83aaaf2dfaeab78bc0c659bacfbda33d10d577918eed207493ae38d4c9088c5fd090b06948e1a90ed34f91d0dc59b94440590b613902669efd4e4b8c301f1c7e4f874e3079528123ca4e32b3e55eb5b398ad752a62a01de56ac375b55470dfcc233b033a23b676892b9db942ac4845678f5e951f7c7d3cc77b7d8d42a79b6c0da944befccdc8c6fb896810df9244337cd9c75804edef2e928800dc241ef7bfbaec45c96349f065e218080264293283fd1f0033e7be6b0fd0c78927446b45fc1f07ff3b5a109781cfedb06bf71ad64e13e11576ff40976559d43634a4df9c7008949faee2618b825da2a1ff03c53ba17b01d8f87567620fef8e3bd25470737ab31f363d70d9acf70c89cd56a54b226066bd811e26bd36e81da63757768fa033a8370015a87e1891896187c0a3bf32da1160f9cc8d9738bc572a0d44c7de1ac2dd1a702556515f6108704a3faeb00c1d837a499d203d4b62e9a9d106ebfde54eaf0c3976267a4b644d4f67619bc8a057d053a39741af003d67e27ae98d33f380cbdf8e4581c3a231f9180d72737515d760255ea180a2fefeebb1d52663b5a7ed8aeeeaecb65fda17a6c21f6ff18eacde583356604a8971a8ac1154219859bd95e72830ced500c134e88236d0e2a67f56ec403828158bd2205ea54c3b941ca71a0c9294aea35ea44c5f8ad7fb174f700f682191df8a4f4839d204008b2d5dba4bba788a1f8b4b631e44edd4282fc4bdce20a641ad423aa5a0812a74a6d72183610110ef62dcc5f3eaa7a4434952beed321cea95dd2f4fe96f446f53ef4396a51e07ae3bc8cdf91bd541af2a61a9fe5833d815d6f82c3eda02792c7f7922a248ca058bb988767cee660f1388bd5d3f7e01b18535c982fdc09f15187c0a9c8576ba1cbb207e91ae0a2d637ae10ad01bfd74a717935bea95fe9d5e3c7e012cd2048e7304720e571040ea6ad20148a4795bb7a32010b8c7b052f1bf93a3d17b5ee7ade000e931177f9bc4439ae83c9c0e5ce5ba84601942c83c23603c781df883eb3fffc30a778365e31b3d627bf998fc81543a4fd62c516b441a215bca1d940eb00daa0e3d6ad8445fab44ea7ac124518aa689e254ec1d15ab4dc5b3d3bd3344a448370fd56ca748ec81eb9a8c09bff556c8c5889157d21c33735dc62feac3b16ce315a3c4315d9b3df65c8ec4611c3ffb9d39a3118eba9628d5b459a6693349db5615bb903f2c098c536ae69ac6ba619cfd157b38c3304b22304e518891212e0b3b1f3639e198c09e3bcdc0a356eb358621cdec47536ae674a4ba26adceab8b97179288f5f9570ab88826ba61c51bbc847811f182e225023bff0af3f24255868a0c15151a00815de2f5245f46d8c981d70578007300c171c4895162d4878b3a9a37f903d20e694431d61aefb931da50f13834c77368f81d94e632ea3a0f0a3b8bd67cde6033669e4b4e1cc54039272756629a20388e39393f2de8c379f3e672c1fa16d2c0c145fc8581e6f9cb14c51cb14fe62d0cd4ba327de64b06767eacbab55ee38fda4cfbcc9381c664031c7374cc217b67eed5c5cb8b1714f225022919e8be52605f54c8571806d20008ec3c993276eea02f225e4248dacb08e9c381d705ec7c7961a079318e255eafa71c78b0f33854bc8114dd9034d0837ac13127e7f5a6e2a618153464af1835a45367d3646ada52d7661cc54e4e4afc859558e9ca165925abe0b0f3e06c6cbd62628e9d9086c705ab39d29aaf3935a5b408918849400ec187db895de129e414d3020b033bdf34985c48fe70573edcd5bc5d5d2961b213636a190fa6becd469e9d585227113d37a8c4d9d8862c43f442d462f6ae92446cfb0dcb67d868810b6c93d1568c869d9763c8908da16692449c4409ce339e074feddab8c68d3b5ff24a8a7dc94b495b9e3361ea2658870e7b9b89e97342fecc2f4c37c1451f18099405d4984f0aa70f87859de2ab18f5e16657aeae640becfc6c047762364e62b1310cc51608ba7648109ff0d52f5f9120f2d5cb69be96ecbc2fa6571076822e1107b2887fc538ecc459d9295ed929b62156915174858166687f45316633367664a4145cc44a4fd20ad98504bb2d6c8eaa34029a7a4126ec7c7561ec7c6744b781ee0b175de9729071c80e0739e168d5db360376bebccc6ae7430ea619e67efd726e4619045d3b33b1158b8d3c3feacf09560a9b70571a8703aab2b9b5e8bcbd7862632b1477401714d173630c4be02b28225f854daede11b5b8d2b4c9f32b4681b1da3b3c3b3b558c521aafacfa15a3c428397d78ce53774c338debdaed2bab704d4e73f6cbb9d99b274787a78a5e1c23063a6089088d90e10664d8c445f3d64578c0ce87514439ee3cca2b69e751a688f295a4994a123553edecc4787073e2ae746dd645cc766263952ae209555af24b0a620a220a61d36fd894821836852189b893a2ad578391a7765333e560e4df66ca22eacb750108c0954ff2d8410091af08c082d885195976ce7ec531fc798324622f3bcc5451cd704c4c37a519e5fe8c1ee08bea5aec3b773d8cd12feac3c57ebf2fcc517b3818efccf1c3a639246b9d5e22b5aa2c4a8ff7bc4a3dad35d0d7f7d41aaaac751fe78254437d8f2a6b55590a3deee3547adec15befa06e816a552a3deea36ef97b4824f053aa87e646fafa1a7e7a518cfaeb25520df4bf5885fef5522452ad557e4a255ac99f1b8c3b55366d36a36348b3b49dfd0bd3b59994ed84357476878a61e4cf3c0d4d437800f1c3cd2f6af6a30e119000b1995a101b1786b1cc4e8dc3b594d3c8336b41f4dc185b0122e72491183934c5cc5c2ec7b9308644295eb66b2f3bff97d2cb66a7d88628035b86f4c24e510b3befe160bc8d9bb99d7a7366ad9d16d325b853ef687956bb5b5689513377464e0d51aadfe82a492443366cef78cd1b72beaa0f273e217fe6797cb89903cb84695a4735ae69b8db150b00d142c866e2a2c9d4b7dec0bd174b8e73544c5454636cc6b3d30091675f140e8ef17eb82feac3bd2032657e75e164653cff25d29439997dfcec5212c921e450e7a68ca7caa2d0f778955adfa3d60045e5af75d6504fab9c3eb34ba4191598a95089963aa2d6d7c64d330d10c3a62f9268f6f9b00839f481913e518449e49698d50f377b77560c8106ac15b236d6402e9a4e0c34cb98b2b3ca4e8f5fb3ab2f924a8cc2dd84523718771ebb8e5792b69d991a8c5cf9e6346f5ddb994362941317cd1c5351b51835a57849118338a33dc6f052d2a10ce26c1c41183ecbc3577cc5579ce3dc391793a26d6c876704b5880ea09af6b203c42caf247cd56ac821318aab1944be92442e8b44d3e63856be3adfb3c178f98a9d6e6f8c93a96953b47ae9204acda10f377de61cfae7c5dc97a312a568da1463553c33dec9641bc7b33397186852c0cecf9e0267859d5054e8ebb9d6bae5a775beca62f7e1c48494129244bad3cc9cc2793161cb754ee15431ca8da858edccc89f1a8cb3ca4b5e1ba312b3d1b47986af9af68569da1cc7346dde58ec632c369b1dbc6ada99d9fb97af667ca6952346c9d6fb618bf2196683af988daef119bea106e62b3ec3b5ce59fda29a36e987eb99e3abd8735d1bef5989451305ec6725992a4060af1835e2e650332d71d1448281e65f381a4439f29c8657d2ceec4c050191a9787876669f62a4cffcccc91f279ae9659999de4cb189849d1fe5cf8ecd07e68b82cf7c625ae9cba2976c625417316afae0782a14316ae6c4a899db898d135022ad449231518aaecd442ec432638af88a452089a668a666c6b3d384246a55297fc07a99065604d209599bd578b868a7f255bd6112388993e3ec9cc32b89e7bcb4d3b8d98c67e71fee3fea0f37873e731fee75e6c4a8ab31b633e3d981d7e02b0ae0d818af183571b2269b4212f1d891f3d9afa8868846934886187545313a7e5df68a51585c918c5416b0571417279028f8e2573423565938aeb802cb39069a4c45022b96404e2be424236b392ee2dcac82a75eaec2ce59bd6112763e87023bff61f191f9a42491f8f92f0b49147efe2301d75c2690445b4822f0f39f185963aaa6e1fa0bf33df1814012e57cfe834212e17cfe8b8ae29b4212d97cfe1b8124aaf9fc478524caf1f92f278968fe5dd138cfeb58545d1b6f6607de6187575277dea171e18c8e4d3c36756df6f9f14bd774ae02cbf32b62c1f58a5225b8e2094414885d5c118cda8713abb0571463e7c30f27896e3eff8191351d9f3dc7a61ebf346d8a2a10a3e4cffc0e15a3903ff3322a868069f33ca83802f933bf838a54c89fc9f303ce5aaef0301aa3238d3d07ada1790e95f2c7a6e61fae6b926939442cc2d8f92982518c4212ed7c5e0c018b2390443c3e2f522189767c5e8c1a9bbac6cfb94dbd62ceced7d42b8ac951af58859da7a9572463e76135cace8ff58a5990e0af7ac52dc47ac529918bbbea154fd0aa57440158af4865274fbd2218b37ac52ec677bd6209ac68859ddca55f497867369bcd66079b369b7d76f9e2690a93e09c943fdcd7a1534625d36edb3e0f96edefb0fd1c1c2ae5cf0db57d9b98edd7e4a0b17d9a1cb66f8dedc7706c1f46a5fc7951db3fa1ccf65db4d5d4f63f96d7499c9aab8fcb6c3613375d188fb5c392a4f5585aa7d3ac0fe785695ad79a2818c1f7c7de0ede122e4cd267a669f34b67fbf3a2ba766567f12c780fd7342f6a8dd1f36830b2ed5e226c6a8e39312539f6f7c5b2bd37525d6b925f744d8ac9011b375f3837c2a63e25393d1abbd5e480e25135cd05b07a52d5eb220c45f1a30c8bc148d5b526a74e147ba86bd2c2a86e0c77bd322960752c16ebf3aec65619b2be772e48b2aeb228ddbd43f5b7c4de552add3d2e486328ac0a46060c0dd855d362d28a6c5f9e54ee8b030dcb55ae4b2fa49838c8b0f3b02e1a4646d73c33f267be456f78b861ba2933d545d7c0b3580c5a8945d36daa69336cd6fb5eae69608551c1ba1002892e9a463b9a2eea5175cd332389caf450f709f6fb5e17b6ab5e4e360d04d9936ada64fbd99a366f7f97eadc77a9ae7dadeffb3c292fe78dc9f5bd319e54833929b07e4b4d9b9f52f7b1e0a1d3cb49ebe11727ac4feca84224ec0d2ee795842cea1e24101292a8cf543015f6baaca4681e9a07f9e33935356dcc7111583baa0e73b4cd4dc783b573b324897ea3c3cd0f9d19374d2eab31c08eaaabb2b3ca0c3b1f7a33e8605573a87badbb6a9a5577053bd3ad216973e963f5f8600fbc0e04ebcd12d577c387c30d05ac37462af7e5ac54d7247fe0751ece6b0ac31f2ba0621e6ec038e161e05e0c80bcee570f0a12048eb9d1e166878e0676feabea9a7c297159090509a56451b1358dc3b0c59ae778d822ec06277f5a20cb15dee0585a18d587c6552bf66ab1b4dd6a7b83bb017383c3c1bc77af617cec35180963e606274267459763f00677f4d93e1eecbc37e653b29f92fc99476e3c2454ac12af03695c04d61f3fc2253d2e69f3ec7d41c2ceffe0226f0809344f44083c844ed6e0123ccf846e8dee0a4ae771835d141775eda4e02ae58f141e0309529987a64d90ba2c5883e4cf3ca11b532548901551ce2146bae1a1bbf162e75d373014c0a66e9662f6def48481e2cd52d77aa925a487bae64203b6038729eb636515383cd91004d148bc09d343b02e9a061bc1c992940e866e055d0c3264b9b97180bc71e20601a20ca227c6c8da99899e1823ccde9b2590f5a903cb9c88e7b3b4b0a91b9c27c6e8d97bb3f4c1c071bc92e4ab593434cd6ab9421dc4d0d562b50cb49a3edd959446eabc178cae2b2b9715683d31c6570ff166e946879b251f3e5e491fe8cde0536aa479d81949f45db2ad6be0e769b4964108c82c21dd1b9ce5f162d26fda6f4eeb778cd9624a2c68d52b5f206770590370c7d81d06d8e00deec2a69cf040f4e095e442c375e5b27af7a0a2914192c8e5b29fd2b73487683e3b0869629024727d71f29a5a67353935b17a90459739e1bbeeaa960fcaae0325e7c626c72b3c48cf45630f12685ea7ded1073b2fab3c18ca9c393875dee8a8739e26a766586fd054ab7a511eeef5ebe1c6f13d6e8b9de63b5e5eeef53539c9a28c8fbdcaf858ad018a4af7d86bf03e56263b5f25769a5a43f758fd96a6cf573da6a5a6794b1e93b7e431794c4b1e0fde92b7d4b5e681a901afa45ec0d2646a8930d86161e8143a3535b95c6118baacc41ca2cbe5e4726a6a72a1e1620016d755d35c56d765d50a4398cb95a32664001651745d14b1b45a0c7825b5b0b4d82ee053fa6cdf12941c948a159755d33e979555d75e9f6d014d4e5558e191f14ac0459ecdfb2014955aaedc0dce46451456ca98749f57d2d56ad334d92c1ce459759434c746d69cb1bbce689323b9b312bc8d7cc96742d9f341317e5e9791d6b47f67c97f97afa7560d9a3e0d529647a4c7796e90f57bb0bac03a78bd4a24481ea44fadf7f450ebfdb7a890f6e99f16d4b4d661943507546294bfe39c60c6f9295f4ae45914ac57b42ccb3aea8a45b4b3825f46ef0662b358acceeb7e573b9644dcac83200bec6e77ee2a16d136c1628120e829f1e0358bad686585175dc1ca932b5c24becfe222aff57e4b12856208d22b4de3b33a3023f82ba956002550df756710294b0235b7151f8661f55810e85aac56586f045cadca56bac63a7f852b204b6489d66b279b9293d8609771e6e8b07a70426a24f9710e4912e4c460524292cf9943728aede77d1feb6379a2f4e9b7a80dd591e0c562bb9b05d7c50726dbd75e0518d7b0be2813c516b0342191658a6d574bccc45fc48f05a56b37884a6843a5697c16abc36e014bd3f89e08a354da475af96e8d65d1c8a202b0de4922d759f562b18162658cf1fb955354aa950270d1012410bf8c1660692fa42d3c691a97173a49c4fad7f485162e303616276d59b5933fdfbfd777d62be9f5bd582d607921cc32c319a6f79238ebaadd12a62de9da92a631ebcc8242a56bdfbb62b1691bcbe2254f88182142c4f228e4dd65ca5edac8641b71af76b53c16f85006f19932e2d015b17ef5f2cb89cbb6aad04b89ebe265d7bc56cb6bd1f54a6ad5ae695e1d9b2643d939ae43f3f113c5d64571268a5f93bd7f6b66c2cef79678d84ee5a99799bfef9fd7e2b2c50619d44d271760b7c1b2f8e9bd55a7d78930212eea3e675c5b20287a572358b3b4755517c4c37e3f2f3d61b755b3b4156321c8e299ded7effb1c3acab1e339adb72a33f3fc4e2fb6835517f8b0bfbaefb8a961af753bcb536fe7dd8556e579e8b55a8fb55af566f1d8e3f32475a1f87dfcc1825e4abcbb3e29efd0d767b463d1c5b2b74ec5394de521ab47d3a7cf6347bd3939f5e6e0541df58e6fd50ab298a6bae01d4623c445f38a10cb57b0df2c1ed75677b15e16625bbf125e8e975dfb2e9e5f24c0aa1003b50e529a2a03df0d5d993efd31376bebd313626f164f88ed3effc1ea592f13442bfeca6c2356adcf16e222b173d1ceb320cb82f701d6bbd75521069ad2f3c658afebda85c8a10b7574b481737c3235c24fca6b83655d2e96c5ed791eab597a7c96ece63765be17368badd7b5942c9ba565e9d1e9a5a594ddecf893ca988bc79e077a7a6c6ce63442a4bbbbbb6b504fd7ed792c569639c1a6c9f38f264f10c81301e5d114c1a0dafce6f942ba06ded575f547d3827ac0f952e21169daf45815ec8818f92d0a79d79385d634f6bc771d8bd5751deb9e0bac7b5ffd31763fa6f7c677f64056f7651656e5183a0b46cad93f844c5d2347f387ed8f534e350d61e514a2ebba96dc89773d6cb13bf43c2046175cf71e521a0d029b2632f953ec477d5fb0e15d74d22df350a64f43e95e30caaa48a45696ce8a550c635422b568674316bbf173d1782cf492272f6ce9b38d8a95d0e511e9dacd6955234debbb5cf7bc30f42e685b77d12c9d91f6e94f570873d523223f8cde2f11234fdaa74f73fdaebba57b31e9aceb47d3e3628918e95a78f94a6ab1cc893743675db5c7eb6c7f413f9ad65dc7aa63d3da02a3095e15b9738d20943d97e541f182200b043f6666666666fe58dc499af4a1c176306cb15dd7fcd93d11821d18d9661425f8b045599d053f0f04ab6c9a91b1cb40285fae7bf41ab11e10eb53f3bbc332f3575fbbb3faf3e6e48c34d661f445453a529ba6b1c079efeec062c4ce2e9c9ff4ea5377eea6ccbdba1c423965ec701dce765dd77508a0b217bc9a324a32407cb117bc648ea8b2f3e054c0ec39e79c73ce39e79c73ce393b26e69c13ec66066c2198f1c410d66ab55aa7699910dad68bd52d98b434b09025ce29b2bde1c7d61217d11c06a3f9f77af7ba8bc689cbbe2a53e0a504665daf24d8d8b4799ba6cde7788fbd0e7be87a25c1be16052d335de6e1a83be6ae3bf320856551d92d8dcc43c78f31eb87500649f98376c3b27318e5bdb3a763e3494fda4c5993c30369c64f4e3006c25a2f57288231f063d17435b41b291ccff33acfeb68facc18eb60de8be5f1cc117f842e518261277f48d63ca3d1c5c6a6e93256be69c61c9ee7795ee7b5d76759c51483f57d9df7c19457eda161258bb19ed7f9d83b673767074271774d93a7792cf003dd922cfa81fe3e963ef21eb304ff8532478262270158eb254e188cfcee5fb764e53d8fbdef8717ba5e2d4f4a0b695a8d5460ec63492f87ec660e469eb36a6c1de264c3fb70d32a47be6f44f003235f8e3c604e4b3cc872796127caee2430f219ecc0c8973b5cedbc999e37bb708a39af30267a9ee779defcbe392708ce0fd6975eccd311b644f0f5314b26ac98d7d148cd1c5492bb86a5a3057e2c974b145fa0f782c13836bbe31cfc123b1e3a521f76ebc124cb516c1a1f1a0835f2afc8e01223ff87a5fc995ee7791d0cd625bc81450c725ea6bc5cd1c01fcbeb9ac59ffc40cf04ac6f727fbae055b0765dd7759e3732970965cf65263b5af91e3b5fb2d74b6466666666e697788444e6481d79692347294a5076923669b3756ce7d88c625321af59736e0ec84c5e1539297be49cdff755597789e49a55d6b115295b4b78d268074e1f3e48ad7cad255042a4aecaa27c075f65ce83b3cabce9815f1011575010f8814a4a73880f2ecd2199c756786c7dc9ecc6eea818af94b232977498318a1c02a58f7cff8c31c0b01cc4557237d304ad0865d7a4643d640549708c81f4d367b41d58a70fffa3de901cfaeed5eeba779d3edc3d9c5dd73d99554ad9c989a469ec79b5ab47d586e6e2b537841496752941094ab0ebbaee2df04d6fb5dcb5648b5bfc05c3dfd1bbad96d76a893b722c7b52ec3e285b1294dd27df759dd7c931960526944123eb565eb11d08b2baa5c7593c3bc1c44228de597d500eb9def57a6f51cf8b5917bc832eca6f5519f2d4d9f3aba094af25b21b3b8cdb183db786db4be33a8c14f5af324affbf56a87e85e2db50346585442bd4ec8eeccdfa1388c9d413887993b449a7ec64ca63588a85eece7363f47867f6be75edce252b4663b2d32f53f541b11be4b1addfd1b65ab0ef885138d7781e9e310ca2d1fe9e57f2a76f2ef467bf7d268d040f65cbb9aec919bdd242d3caf0981e9a53938acb34941c774ff1f0f0b43c284d6b79312bb118e287564bb113232196e925d80ccffa3c3c9cc34a2c88706a272f3ce339bf99ba76932845d366c7e8ed2f6294a846676fd874c533fad63549b58424627ba6aeb597ae3512af8d9bd5ee8eeacfcef33b7be39ad651fcd9678feada6c67369bcdeaddf9ece10eeda8a6e19a16a6713ceb5bd62b69d6b8eed0a9693c346c6a1c8f9f544a629f5d28d9b9b49c337375d585218b402d24901949d4461861efcc7db139b00c5846feb4704556c158a0924460c82166a931ecdcc2ce1cd303f346c5b45e4c910ca9314c50d8d6b4dc1c6235de90b2b395ec165f7fdfd73af80b478521ceec1cc54573a999bc5b1519cc4ccdb4f3581b212fe0858b9a6836c44a5da1302f31613bfc42695884040a4123e4cf0e0e653c26b7c36366ac1962a7a6f1d0dab301271fa107b40fe867b3ca5720f0acbd845f42246c38444804d3c083638cea9ae4d90f0e4a2130f355cfce5741e8675026530b998d6136e0b0ac06af312d405db68aaaa9aa5c3cb5a1b0089b6132988a88aa887e66858b6675056986ca080aa07869da12338c9d5f818ba612d3039205763e1441bae08a91eda83bb10b333ad9d8509911abbae0d8c864ebe745f03ce06c68449a2ff24a9a5d358d5bb3566b4679369bb5ce57676cd1502b84d1d0fc7e389a9af37abd2ee75a67517cbd5eaf0f07cb0163a9198fdbba4baa693969e56b26b6ee7a48f44a72d566ae59fda23e5cf8a211c51c9dcf5e9fcd82b4662dd86c769e8543b30799cdc270e8951406a16c61946dcd4599aa8aaf988de6331f8e867e61bea8a6f5f97e5df9f6b128308e8ffdf21553b1991ae758ca0bf91a9efb6ba0eff11a6a8fd357f96b073e7c9cefa383baa5dec7b7d0ba654b0e0cdab05921d179f9d6b4534a2512a53f3d1ab3012726f943152699496245ae9bb534de99bb6cd180b1d95477416586fe3518773e7b3f3cb2f311767a27749a43b2ee0ec3b49a3b0cd34482767e83c430ad56d8d4ba446ad5f00909509088c238b0128ff9703b6fe698e5d9acde8e0c0b9691445de3315d8b752d46ff5909b13789c5ccf09cefc1312251355735adc794ea793d959ed7f3ab8ff7a85be87d7ccb43008851f42215ede5fdc5ce73335961eed9ac995410e543f0c3ddd8e985d4e28baa92f31b451bb199665f8fe8f3c10f53311b700c61a4234a9698f04189c239005889a11380c814b4ac8624e201ec104f19a9470ed1cf7a5643318ac72caa69b9a6512a4ad13ef3a763ac1885049a17451062c0cecb9e1aef879389dd09c6d78bdf718032960e3b3c3b17290f1d7f7ae6e1a152370cc3c3b3d3626e16fa607aa79966faa1992ae5972cca5fdfe37f951e7fdd22e7dc9213c71355d800e9f568fa5c993b95483c76d0537f1fafd2f30e6a0df53df751df5367aec7ffe5e437e6c3fd84309b5289f4959144ed756c74edce9ba55f1932ba367b67d5a1218171e74ad3a62b4956ed4822dea1b3188db534fef8114390af246e8cdf4b0993fc9967ca6159398c376cfaeb6b0f5ae5ccd19def481876623d3b0f0e0e0ff85397683d7cd8aae112401f10d02ba95527d02b69bed21e749a91440d43ab4e29d255631f830819d263953f43af2436c324895c458abc9262efc2e8b062145599190f6b02e30d9bbadc48ff5f1ddbf771391e3c38d610577df4784ff5764ecab9877a5b2aca99877a7b0aca79877a9bca843305eaedaa12ce3ad4db56249c97eaedab27e71ceaed334ece13a8772a353977a9772e3139dbea9d4c4bce38d43b9b949c2550ef744a72bea1de794b3a2bd53b7148cea5de1975e436d43b7348afa1de2965efb422b2df52ef9cb2775ad9fe2490be2783f4590ee108d0a779083c80062ae58f162ae5cf0c54ca1f0750297fb2c810c394edc34065fb2f3480010bc0e282029a6cbf850420e0002c18a00053b64f002adbbf32002bdb174000f88cedafa0420a4cb68f4293ed5b01c0cdf6abe06cff8428dba73245caf6a54cd97e142adb875265fb2658d97e097d65fb24f419db7fa264fb4e9a30d93e9326db5fe264fb4a6eb69f0467fb4951b68f844af973a48f44a5fcb154ca9fa31168df084787083c33231ef82802faf1b17da2a1214546108108992bc4d8fed0165a6461fbb52fbce0c2f68788110618b62fc48c32c6b0fd2069c8e00cdb1772a30d356c1f888c43e240be61fb413974b9c1f6817ce84107db0f4188207eb0fd1f238a18c2f67f3c257184ed83c0049412b6ff01144f80b17d1f2aa688c2f66964ae1063fb1e6ca14516b6dfc1175ef810230c306cbfc78c32c6b0fd1e69c8e00cdbaf6eb4a186ed538e8371c06fd8fe73e87283edf3f8d0830eb6bf2344103fd8fecc882286b07d9da7248eb07d1913504ad83e0f289e0063fb3ba898220adbcf21738518dbc7d9428b2c6cffe60b2fb8b07d1d62840186eddb9851c618b65f93860cceb0fd1c6eb4d171340efa0ddb1f73e87283edc77ce84188207eb0fd9711450c61fbe2531247d87ec8049412b6ef82e20930b6dfa2628a286c1f24738518dbffb6d0220bdb677de10517b6091cc9368111498c20778631e44e309640a459e5ec37e1f2001b8c70e18e71c0c0153b2c5181a80a4cbde06279dd6cb6e1b3de0446d0de4ed2d06834d9d56e1a914f4b0e7d40cb2102ad104dfecc2b5d07a59b20b841b2f468bcff680e052d11e24bd73cef41446e9015d2b4a0a3202144ba99e3f55408ecbd7770765e37df81720a2abcecb9b56a6c1adbf41ce1c278d82fd8b18e61c162c7039d81f89514abb18f2ec40e7bcc86b7bb637404edd8b43147068d616cf72e85af86b045694c13617ecac349a7d0f730ce9964567e459177dd7a191879943f35072ff4906e098f468945076c565a69853e44e817b4411ea40a51d9b42142433697560844a269af24a10a3a1dcd1609a3d0833c9c21e8d4356985285bcf8851e8425efb14723e8844083a09551089303849c4b2b3368770ae43c8e52b49d2982247825ce845aee449e771855ea42e11e42604b90b42b50611aafdd264382119ae6b4245ce457ee461117a840a1d91b6e69574a4f228749ad71269851eb2c8429742f5824934966b1a5f098d794a8c388fe570aaecc825128f5fca8ff0a0e0f461295fa45ed0ae7029f9ca027685cb51e8b29bd059a876234e95722154acc118e4425ee4618e575291ca63908faf25d206b97c25a9241cb9d08fba0865ebbd9c083d489539117a9007a92e1ca9420faf986e5158dca2780723755362e010234f80ebc0180eafba7663b9908dae4915583ec77293a70a392be2759c5f55bceba83554d307c7d64cc9a8b4aee33aea969aa9e9c36f9d0b528dd4f4610f8c35b42ed6489d49322d0e4e8df1ca6e43ac743485d0a1b764555c35847f25093d94dcc92047a26b4275e8422e5f49b2259ac632a1b315ba0d9509551c1c124e98f6e17b3a8c325cd3f842aaecd634f036d6aa6c9ad0e7afecd6c91fa12a9b46a4deced608516987d42bda1a2c9460c3eeb0724c1a392bbfe56b5de9e635b42e7ff3a36ebd699477bfa2c8b7eea2f2f205830c34505cf7aac62bbbc96e4f23ce0d678927b11a17d49051a3829a15d4705173821aa99a2c2411917184c1808046e84212d54a202688944445888441940708e5f1d234a12a9735752de87cd91714e6d50842bf9d1de13828904541cef3e8cc7148c0454270b04a4de3dbe388914538515c54eb7640bae45ab7d4343ed209bf42f6c6406024500818c80a0954820950ce9f572494600214122e54431c1c4e99aedd1a261c1cce95adb17c9c291caa3964eb9470b07c9c2a1c329cb0d06103968f83460fe54ce1485165f938b91aa6ae5dd9ada6a96bb70353e3a5e64b8d9497582e960322bc0aaf8efab3c0d8167492f20b3a5119aacd2b2baa08411445c0dc80689e213272be7c456124d9ed87b16dd784e5a750d5343e9223bf9d45729c12482222e7e394914445ce316062d5343e93e35421896ae7e358218986cec789421209391f27049268c8f938384924743e0e184914e4bc46931b481aff4eebe44cd3f84efe81ae0950e98bc167f5ad216b2010dfd577e6bbc1915a55844a4b84b28de52ccfabae814a0de4b7e3cf335d03977ade40d6c01da452d740a60681904b5d039b9ab683ac8144481abfe6d64ee06a445013d535b91a2b248d891c482d52e4458000010204c8e5ab4811204141414140800039eb9504a4e656e3440dae4604355127526f36a812d530597e6dc88a2535b925582841868d72117690b51a20248d6b989ac6e006248dc335248dc32b2a44a8ac04f2875f84cacac81f23239915b22a64219045217ff84254869381913ffc1a2036b08691f36b9888ce079d8ace0faf8cfc631a6ba470f603f6c96f2c17bb5d115a4386fce113a1352e903ffc215ab302f9c3afd11a15c81ffe105a7302f9c317426bb8d861048208a0aed5a4a4c1ce079b80ce0f85688d94fce107a13559c81f3ebf92fcf0a58b46e8322141707042426a92b642842ebb75cdb3d28a3367ec8d946c6a0ed9665505acb443b61793156f2c61873c2589c55293e5cba2e65023f1850411c2c1494575edd63c593e1f274cd770a4e89a04c3728d54cd544d17384c42946dcd53d788f0910411a63cca8fba3585469142ab5015e8059dd018ba09bd21137a6d90d03b4b81de6a845e5711bd3544f4ea18d1eb830abd1f40a131b409f48625d06b4302bdb313e8ad48f4ba2cbd3547f4ea8c40af0f14e8fd60098d8181680c7d439b3b7b426fb5b746caf257a077b45776dbc248accf5715f92fece7a05d2fdb1cb117baf75f9f8fd1d7737c76ab39bf65b72eba769fbce874b163e6a54c99ae350fb32f20fc08124cced729d3b56b86f611ced721a36b77de9e3fe3a16b77cc97aef978d1f93324ba76e72fc2f9321ed9ce7b69c6a4d304c29138219daf23d5b5fb24fb54d7eed38e5375ed3ed17e74be4e95d1128fcf3acb3de5bceb4caaa96bf7c9c78d9c63f5e927ba155982086e284c2daa6b978a145dbb5364b9ae5d29b2315dbb2ac8a8ba767bfcc9f932335dbbf54eaaba769b7c464546d76e94cfccc8ac869c2f4343c8f9b2ab20e7cbd8103a5f76a66bd78a0c8eae5d002875ed56b175ed9e7003b244100e280cec7c9da8ae5d284f3a5f478aae5d13bec2f93ab9aedd129ec2f93a63ba7649380ae7eb5875edf6f93a6874edea5c75edc6ced761a36b773cd3b5bbe4497586d381a36b57c957a8b3304a5dbb499e429d45d9ba76938e429d49319b9a435b3aa49ef32da53628a210a80deac90fb54135f9416d50483ea03628241f6a833af280daa08c3aa045c7a136282a537e436d5029ec541bd445e14ef9931b2a4f52b8b9918242bd299c4ad5324ea997cacd942752a2542d9f0a54051e273b4d769aa8b0b3c2a5ecd476c69d26287c2aa470146ea87c4ad502dea030f4dacd0af5d6eaad5d859bdae5e636a814ea7dda390a3c53786a979fdba086ea7dbaf950ede6b54bc19112e54f709cbc09ce932238442e05a776c179e2f913273c6f12c26d5045ea7dc27911223827721dd406650500b7a136a82a5274aa0dea46b94e8ec4e609122936364da2d42be54faa96d149bd4f6c9c2069c2c4e6043a65764427ca141d2a3a425174461da428364253a43c8acd933ba95a409b28412e642344a55ea17a853ec5a676b1b90d4a4abd4f3a8f327ba27327b3dae583dba082d4fb64f3204236177a131d4d981c898e2347d28164880e216fa2a376d1f1343b9223b323fdb80d6a48bd4f3a3e44888e0bb9486d50504c78486d502534d9516d5097c93df2a310c95193304462526f9323a95ac623f522098f1c21d9aae523813a918db0c3688791931d4f8eb403b663dc61c4e473d2e44c42243f52b5802113a0c3c227f5c2ea85dd4958bb84b74135a9f769c799c88ec86a170f6e8302aaf7293c102c3cec482292fd9138c28daa16f00888187424b176119f643fa223c86e446b179fdba080d4fb241e4890f8a0bba80d6a0955f216b5412541caa936a86b2f42d502de118e8c20b58c44b80dcad68bf4a3aa651ca1dea3d6084644a85abe247a8447b5415d115e94738b4e944374240749ce6873c61c22fb8d47906e5b471fa16a016d507684d8c716927ac77ac71f69d52eaddba090ea7dcab9e57194f31178d42ef436a858bd4fadc7c67ac71b552d9f7d1ac14804d03eb98a4e54b58036282344b7418de032aa5a445bbbb86e8312a1de271e3752b58cf6a983221e27aa5ac60e6a970e6e83ea7a9f5cef59efd3d2915c45880cd586080922042408081602edf90ffd7f5010ea1646eaf907f4f7a1b4baa5917aee01fd3ba03eea9689d4536d503dea6caa695cebac8ba6f1297d9d51f1f80ecdf92ce732caa3ce72d387bf83e6d499d4f4e1e350d76f68eb3aa8eb36b47591baeaac5567512e3b5216183790800d1ba35f099654d0849d740e7183d40c6c53d60e62aecab0357576a3d15018601f9b5eee8e7aa44adac240dbb2afce7c8d14061a5e8f51183edbbda7b3b26dd7cd6e5d9be1e6907817cfa4a6ec8cca8db195acb45776c3c14d1f7e28655b3851961fe2e0e6904c09e9c307131545ceb24c8ce55f1c298b839b4312292a872325bbc91f3e4ecee90613e0e070708d839349c96e2c2ac35159d4f4e17b448c5776cbc1c078c74ecc18c5b29bec26bbd5aa904bdb00e3f24d2e5d2b0058f09412f440e94939bb4e326d3d3cab32734bc93d4d63d1ba26a594f2f756bae4595256f12c9a8d95204bbe465665b1583d4dbbde6ff9c77b188b8dfc28658e951294fd2111de1a3b4f238b440672f508f2ac97c3cbbe23ecb35e2c16164e2a4bf27aebadf97aeb4a5ed5cb71578ee7685559121a9acf2ba1f96c61b1e162d9d2d04b918b2818ab6d5b944602c97b350f5db4fba8f750960476ef9e08bb7725b0bbeecd87dfc1cf9ceefb6a12d6e7654c589f57c2aaa3fc91e712b3d96c07efececec50190f1e07e9ed966cd4c8e3d745656507a9ce439e57924ee591c58367769e994c475679ecc8c181bdc4d0253b7559b983864d9776c3baba414135f4baae6834f4c2e8bdbd2eaa0bdacbba7ab1ae5c645c171b76de4563e8ba0f94b69fbcb75741246983c7a53d1b980b8e0dcca55d1d0831257a4d744add9224e2346c0cdce9f0b25cbf33200fe30dbf33b6ad42abcbbeb2b7b3575462d913367f458e35f39518229c8098f262e311396cd76c75e0c7627d1ed8b5a6ab4316e58be58230149790545cc28d99b30d4ea6d9349de66de2a272b7dbed76bbdd5e08baa259bd2a878ac83899a69aaa6e57443eaa2aabab3353692edd6eb7dbed767b81081122448834d55453d5ed8a48b3daa96fb8a89cd454535353535353d3ed76bbdd6eb717aedae9363dabab334abdd44cddd4d4d4d4d4d4d4c455b7dbed76bbddac7a46e5a4a6a8b80a541a977298de44736a6a6a6a6a6a6ae22aaee22aae62dc996ee2aaa5a6a6a6a6a6a6a633e038e6e4fc345a90ccf514eb6abce0d26406018ef06b62bc6018e35752e772afa40e87633939c5be26c6ef954465f9d2b6533b5959318e7167cec89ce5af891166c39894d2ca57922925c5a599a545d8fdf663d3ba59347088054eafa73b4f4a759ad67595f631470681008b0e94f112d5e3654c0b3b5c28d9ee5d98b1a301d7baa8a67dbf5d0d6cf7ee043cd4c2f4e96e77c653ea60d0b5c076973c743b15d8ee9d54c745d78298d6bd7b0b73a893ea6e17959353eb08de455b956d8e674764fa8094913cdab6456f903aa9390482f3b78b9242eaa2e61094e9d3bdeba26c37e915a94eaa8c2d48aab3eaae3a3858dc5d27ab84c8175a607b650ecd778732c58cb2efeba4ce78b61e9224a8eabae89ac4420933b6935664d8eeb2ebeceda66e0787edfeb1bca0ae75ef82b0744dae8084d94935ad0c08cedaa3ad93ea21dd540fe9660cc6db497552dd54d7a455ea3ae4004fc93c7b7ece2e86cec6d0d9feacf30c4b8df17e57b6ff5d7d6cf430f59eef93a0f4581eed0f0a0a0a62aa8202e138d28e4bd27c0eeb93e68c6b8c36077fafb058df591d97a4f9d1a66bacb7c7aa32afcee0d9ae7653054eb67f67d5d108bf130d960cc34a31bcdf398695655869c61c82c01f7069565e22564a79e59595f2729395f2f2cdcacb382be5e59c9597a7acbc4c65e5e52a2b2f5b59292f9fb1f2b6929552cadb4e56debe5929a594f236959552cadb67ac94772e5979279395773631b9f366e59d5156de99b3f24e292bef9c9abfadf9fb9abf31a3df1d56ceace411c187951e18f9b112a8e817889543ac1c22fa2d62a508568e50e4578ab1b288946488482dac945b0c0dc92f6ab226c51822874833844821328d2032887443480ac93880fcf20d5602919c43d02feb606590641f8082b05288107e79082b439046fcfcf21156fec8a71fbfac84953f241320fc32182b9fb0128a0f7e390a2ba7b0920a9f2bac2443fbe52caca4c92d3cf8652eacf4407ed1c12f83616507520c1fbf3c86953ea4193dbf7c86953d328d1e3da41b55561907fded1baca4b273f865fbc0c32385d8f9ed21acdc9146cc7efb082b67f2494747322193492878fc761456f29054ec903b24991c9923b7c0f96d2eacc4915fdcfc361856de483174e89066d8fcf61956dac8346a7e5b0d2b6ba41b39640e19078da4913387f177ea60e528a70f3119849542c0244c1af1922ff9244a513211fe4e305686120ad7ef8cc24a97a4a2f53bc558d99264c0df998595a0dcc2e8fb9d5c58f9c94f1eb4f6f6e8e8e8e860d38e2e5f162a029f0088d4d9a31f9d5f490cc53f6a6ba5f70d07a98d73708ee32d6a6338ce38b88bdad806e71b3ca4363e737ee322b5710dce6efc456dccc6b98dc3a88d69705ee3316ae3abb31a1fa98d67704ee334d4c6689c65f01cd4c63038c7e035d4c656e7336e436dfc82b319d7416d4cc6b98cdf501bb7e0ec82e3501b579dc7780eb5310bce627c07b5b1997318e7416dac82f30a2ea336a63a83711d6ae3149cbff88cdab88bb317dfa1363ec11905e7a1369e3a73f1531b9be0bcc529b57199b316afd4c6243897e03da88da5ce59bc87da188b3399fba0361e73bee21d501b5771b6e21e501be7ce624ea3361ec1998afb501b4b719ee21f501b87e02c8283406d1c758ee23fa80d84fff80fb5f9fc8387406d1e9c76206af3f10e1e446d3dde7320d4465f2f446d3cff8350dbec3b17426db2eb7c08b5ed388fd7a80de7391fa2361dbf39116aabb9cd8b501bcd739c88da621f5f446dafc36e84dac28b1781da5a77dd88dabe834f1c0220f803c29c0627aea589cf00e60ec03d0b1397e1038f01ea302cf1173cf00674e00c50e20bb81dcbd35de0c06f125700126f61034f80068e80237e00a7b360c40d908117a08813e0cbaf10f10160e00218e20168fa0a425c850b3c85208e82975b01e200b0c0abfcf013984ec5874fa9c0a5f4f0283c1cca0e3781022f418793b0f42739dcc904dea4cb99d8be04872b91c093dcf024252e3f42a5fcb1e17dc391b7d29123e738909c738084719074862329e97c8324671b2449727e43c9f98c12256737969c6bb064c9b90d266736983039afd1e44c83264dce6a38395f3971724ee3c979064f9e9c6540c2190d123806259c61504209e7334c385b9960c2d90c28e7174081722e23ca998c2851ce2e90726e811429e731a69caba64c398b41e5cc022a54ce619c703673c209e7155439aba04a953318003853010000e72fac9c5360c5cad90b14ce5da080c21905299c4f90420a672e54384fa9a0c2798b15ce26586185b316013897094000ce2510c099040210c0398b019ca506308033992b672cae5c395f4180f3180210e06c4501ce5514a00067310638e70c608033152c9c47c0020be7290e7096e20007388b804a390401e710200001e728a8944312708e4a4002fea38583d0420bff4001f75180024ebbf7e0de77e0c27db8e0c27bb0bc07162caf0b385dc0027e069c87010cf84e033e6b4003aef3c2652fbc701e307c070c303c2786e3c410c36f64b80e1964b84d96d764c9f21c0e388d031cf07186c76698e1302d7f69d17291868734d070d703de7ac0030e52298740e01f6559087416020fb9d01a6e03ddc245123df22414c995d0a42fa149ce842a7913bae44e28933fa14d4e0275f212e8939b404938145ac2a350132e8542f9141ae554a8949f40a7bc0aa57200d0136e8556390a14004f815ab90a1485af40537800a80a17005de103a001f8152a8013800ee005a0576e004a80b3400bf00350031c01948527801ee02d50045c013401bfb485bb4015702cf47e01d4853380627903e802fe0265c061a00d780cf485cb406178161ac31d4065f80c34cbb550079c063ac31f40b51c029486b312b5e17c03e572960065a5330e946f38db284be0dc85320ee70950b69d73a0dce5bc447902671d28e770a600e5a5f30e947538f3409902e71e28ef70ae00651ece3e50eee1cc44b902e71f28fb70b60065a63310947f387ba16c8173109481385f80b297b3109483383751bec07908ca429c3140b9e94c04e521ce5f2863e05c046522ce19a0fce56c04e522ce4e9433703e82b211670d50763a6f80f2116724286be09c04e50d9c39401989f313e524ce37ca1c382b41f9e9dc01cab7b307282b715e827207ce50943d70fe00e525ce4c50863ae3287fe00c863213e72628e3ce4e5006730e43b9893308283b71a6f30a8aa7efd38d36867c759e993e0d0595964140f98923d10f277ffa967e51f2a799b28d00959605c51343fadef74d31a40f017aa71a97a687f1da58ee9a065a297f583c8cd2f213dfd4bc6a5adb1fb5249ae227a89595d5f5b1775a5d2059e82d2203bdf2ca2b5fa05736805ec9007ae502e89558e8952ed0cb975ebedc02bd9c007a1901f4f201e86516e86503d0cb972f5fa1972f0b805ebebc02bdac02bd7dfbb6157afbf6eddb54e8eddb62ec9d56b7b3b0775adde6c2de69751b0c7ba7d5ed31ec9db7cfb8adc6ed379cd03b6fb0775adda983bdd3eace1fec9d56770e61efb4baf3087ba7d59d4ad83badee0463efb4ba330a7ba7d59d6218cab49a3290222c3d8d33a451278922f0febc92441068c3e877baa186343212e1578708bf38f30d69248291df99915f9e1ba49191a25f1f45bf1ee8208d8a887e7f887e817e904644457e8714f91d1a421a1521f22b0291df118e904644ae18fa9564949046435ad47ee51646352f86fcca2fa2904643c210f22bc510238d849411e4579a9185340a2203a15f990617d248a80d20bfd20d30a411101c04fdca38c69046415d807e398733a411500f21fcb20f6a48a31082f8f96521ba37a4d14f113f7ed9881ba4d18f2440f8e5271da41108501ffc32133f48a30f9ef0f965288690463e53d07e998a23a411ed0a0f7e998c12d2c8032d3af8e52dc048a30ebcf0f1cb5f44218d7c84d1f3cb628891463d65f4f86533b290463d64507f390d2ea4516d83feb21b6048238a83ff721c6348a377e1f9ed1cce90463c3decfcb60f6a48a39d2066bf2d84f786349a15a1f3db46dc208d749290fdf6930ed24806c5e3b799f8411af17862c76f43318434da3145ce6f53718434cab902e7b7c928218d70b4b8f9ed2dc048a31b2f74fcf6175148231d61d8fcb61862a4914d1935bf6d4616d2a84606397e3b0d2ea4518e36687edb0d30a4110d0ec6df8e630c69347689fdce1cce9046b11e60bfd30735a4112c88d7ef1482f586347a1521fe4e236e90466212e1ef7cd2411a8550aedfc9c40fd2c8f544eb77423184346a4d01fe4e2a8e9046e015dfef24a38434fab460fdce2dc04823d64558ba1746968290bcdff9c5178534f2fe8073987a471ace4ed49ba3e5dc44bd9fe10ca65e9a03ceb87a83b29c99a897880ce70fd42b73319ca1ea9552309c97a8574ebd70f640bd92aa01e70ed42bab187056a25e69b580f3ad5e7985e5fc54af3ce3c29903f5b2d23d27512f2f29e08c44bdccd4c27903f5725302ce1aa8979d10703ea25ebe1de0ec542fe358381b512f4719e09c817a3957807311f5b21401ce5feae5a92b6722ea65aa019c31502f5709e03c44bd6c15807353bd7cb5c259887af98c0ae70bd4db4a299c83a8b79750387ba9b799ac9c81a8b79b0070b640bded54e5fc43bd7d3be1cc546fe3a89c7da8b7a3a69c2b10aa35a854eb564b9349e9181a01100000001400a315002028140c87c482c190228871930f148011799e547a4e1b08d334c8510829848c210004040000000064360004e2261ad1736104e8452344449b7b0e742d4be0e7ff2d8725505b45d1b60cc44c81856547376ddd71d8c29f78a62755f5c4c7b70a88cd583b097c2afe06da0a6f9e00ac1fd8d0c80aa38e54697199fa0b09fe52b66e7cbf7ae7f4d5bc1c25b03cf6aaff44841042fc21044e1488cd37a38cec35822cd29c56f0d59a9c26ca3a8bb333f52368e370ea1fa3185ea943051fd83eb5fd8336ee9a335d9ba9df93d427951f4e438bbf69283e3ee83570b270fcdae62fcb5f257ec79d75ed9b1002dee2c563dd40a9e3ff7f8096c9d1c14f4e202d1076b292d936a4bd4e480963f51529d4cd000de93406fb596b9526d983db8ba7c16a5b4f818aec09d1868cf0fb5a413ec9f3b97f6de72e5b2220d8f8bb4f17c91b12f6f385cf94ca532acda9243f7a5dbeb611c83043953c55b354cf529949752695a953b57cd87f256274e556b66c1291b5a8f78153fd0f7eb4cbfe009992eef4fc68dbc1fa53ecebb5d2f7adcb0caa2d8048fff9d12eb3404cfae83ff087f334512dca4fab977fa70ffaa00ffaa06e3efc99fc688b977290d44703699ae83b8c4bd08675ca48bd63b1af213733ca212590124809a4045230599c0e4010a113d1cd2887144c16a7031044e84474336a8e179c803c980f9ff9f259fd1740940da8866ae3305ad5536d7c4365c522b860402d6d2011f524e4ae98880935c8548c80616203055dafebe3c0b254b7f12d25100f8cf007501462a688076bd9eb9f43629700954f9e970540f7870f70e690aeefb9a0de180fa7d63efbecb30732a26314221211898844442222111119968e4300a4e094706bc8454486a5e31000293825dc1a92db032ea01ee68b6f3e7c6612bd0a390582d05398053d4530d05378007516de2f0b5b0f63d3e9acc6031e6c544a20eb65d79823c49b10a0a3ad54f8a863435eb8b3236133bed167d1ae94f419e287f9811301fb1f77d47091e5068e0c8eefbbef7dff3ea7e4fc329f99cc4c662633974c8d170887fbeaa3cfbef8cb091fcf066087bee1752d75801ab7924121a6d6fbf0b96f9ffaf6b988a3e2a998f2a8e8d86778c3235fed1a7994f20e702c296f046791f206c068ba7553e774f4eea465adb4a56ae589b8623f8e7af8fab21c9d20adb85fe4339219c98c261dc20b94837cf1c5071f4a44facaa9405578c595132b08244231db6d2db064e218b3ddb02a93ba5991cd88ca69c00a03b571008953c49b93ae1a2d8a8f4f62e2a737cec089139c3811ee9acd18e1a1e3fd6b30d2d0041a8506081e5d1e8c34442622efb1cf9efbec9743e481cae4837b374d6d522e8170a31c280817951c24e538e2370d118456455bc441f03caed38f125fc4b3299113f1b73c07b58e267f4cc8d31136f9453f4b40b3700e8b80fecfa1c67767e4ce05bde99ec84be6b771d3045c506c44855db328e37a59963b96246f87a41e1dfdd08e9c2f45d68025f0366ec51777ed053ca24e0d89c766f6e86670076c7f867c242a6280485d6b4b1676f4d4db99aa923fb8752270ef90aa7f4a0b78b8d2924756cf8723bc856ee9be93bc7dc027005333b07618eca23c989b8c455ef5ab904cf45c568bdc3fc4b64c2bd15cdcb888f5a32f3abfcdc9d6265584e03bcbee6152972a13640402e9dce0b1554de3226ff7cdc6609e0c65fdd6b9486f8d64ead0dfa2106907c8732abd227f34520fca35ee9444e4f6e6d38537be3c31f7b9b32f7a4f4d681e14e88a605f80abeac8db079046089a84bf9d0d52fb313846c06614bacdc3524236861eb1c8bc6f4046d9d536e14bc4544028fdc6c21e2af10553042a222d52a5ba528933b0b2df1724d3cb4197649f165043b864475cd8fac437eed01469989a566b44b8674fb747589bc6b211358cbf9aa1feafad005b4b21ed12531b85432506adcd6d90163a21b3f0ad7568c91f9a120bfb4b3bf30888513dc2befd08dffb002df9dc07ce3cf8f5a9460143b5d85b424d58227242deabb017610f48b04f58e9d5ae5212218edaae564ec7b333376647048bac137f1d779f4ce94a55a9c9996dc7e9aaacb4062053759f0c8a0f8f2a337db5045910dbc128153866a593de9fbfd3c3dc753980bb2cbd734916b45163260d94aebdc1805f5417494f5f4facddb25f22e7a164880e1460984973f1b01aae6a7cbb93bdc0d683dec4f04cfe153bee5a8d5b4cb416c243dd5542e04722087890a494381ba7bf268e733c5de03adad8d9984803cdd94d75ce27865c4e5085a9848e0e1d80f46795ce0f5542f86aaf904653354424bc1c5bc122d312ee5642549976a492570985c5d746b19586f898e4f5f635fd343958eaba145b744434a507c2000e840ef05f990a9652f97e2e4d63db4e47126e96f6819aba97f7200d427b4bad0b6c08e0ac0b0c425a2a8d8c15f82df4f0ba58087920657c25324dbb25d90917af3a1e62375db774a8d66cbbe35775419985cb38484b072a588c33f362fe02713668861ce142a05f990b62bf7ececc9ad711b3506f282b0d6b19644b9c50180e884b9e39f0cd1df30ad3d9686724670e5aedffb18ae4e5f50903a450dc26a42043f3a22439a6783020233b5e3922d03130408ac17156242be19beaad7a2ea18ba4cf45aa0f65f967062b7416108b921a5f3014b6410065dc577b018b0bfb99aa00a43001908d3e61463e871405715557f91fd3f4b0ca4941e1d77a4bdae889f00412bf12f6ae25953b58afb9b9e3ecd523050561ea359d7a0a12250fd985852915141e23277b79e6dfc1a75a9361134760a9443169c67f85d6ec1bb3b83526a400e3d2d74179b8234443f2602411a0adc4e1aa9f5482320004dfeaf69a6f9cb3cba96b772af5ab7899b67678c861280083a1bf348ad3865a615eff9d30ac52179a9434ffda0c9b2b65a47cb1db36affce730bae444d9901693b2f469d28ce82868bd69bca3527a2a9957478e21348c385ac820ace652ad3462faec766f3b133bb88d0e00f21687deec67db99d718f6b46b55b27d847b9c22a45e3316770481d5693423a808a9d27a80976fe3ab3296a3c7383d8ed17e4b4e65e425b797ffd851144a136af35c695668ba4b8a663a8e669254167c1e8d19268d158e1901b9faed088c2681adfdba8a044b0c9ab9a299aedf02f74823876946437a90a79907f5c52535f5e7e9caaac9a8d1e3c89ad34e59a2b946a6583096c0a6fcd8585b21abcea613ae36cda23535cf6d2ee0434b7bdc48d4cd5ca11a238837478a6fbcffe61973153b1a1c8786f392194d8a28ced437cee08a9c09a49c0930677eb862dc37e71a7d8e63d1f9d5de45311d326440c1d4c150c1fb65ada35f61478776941d3011dece9db596aadd39cb6c03f61d0ac0b21ae1415c7def4d8b472b79943ad344328f9468a759d0731395a674a7e7e07a5c85e2f1b0f6782fef7983e1f353afa61da003441f2ff679a619604abecfd8989fb9b79ff9ce9f252bf7fd261d708ad06f25f4eed12987721d2354f30a15f08cc14289fe0b9dbba16ca5d38e3b74db10a5ec4e7739a2bb4e940aa40a069f82b6154da634f326b52a56d41cb8e833052495548b9fa17a96d1db94de0030b75bd434dc68dc6a5cf2975c83d42c7934c66a3cf24b96556ab6411a9f9a45c1aa746aaadf467abb5251977612f8d4e296f4d15211395215632865efa9982f55615da589531a85b5ade7acd4342d7d04294236ab62fc52b695ea337015b8649a68564a7daf9a394d9ff20adea8e91f6e7adb577af39be23da7b155c3149dada3e8d4243c7d02294216ade2ec5396958ab3ac158a829a60565eedb6daf3a13ef34a2d025751302afb4c954de50a8d484daef4160af6175457e42c351635fa1925f17d575b9b7a57a6a47af46a2b507d8e02180556e5cf579b29d5fb4a33376057197fc55955638bea5534b0f5bcea639662841056085a6585eadecb91d36a58eee62a85aaaf518e44b7c432e8ab942dd5e15d2c2c873551a5dd6e86f2702c5bc84a15d5089bd1bf87accd9bf501af7c89c9ca83b4b267aada5a59505c6bf24ae7d8fda22ccca2c7ad7119f553a8d9e286eba34a51329d15a3b9b2adfa81d215ec3f9be5bac658cd10d2a59d89d63df07a27566645d29ae67a7da680f57b96557b75adaf37571a9d701fe2a92dc9bf3ea00004c21ddc58cb25c152ae7a94c1f5fcae4d73c2c6d5d47f416c8be3b08f3245cbce560c13cb3653fd06db02076313654aad8b5b3374ec97692ee8d26effb2ea2d8c110cfa7cc004bb75aabf1d6884f7847a571d614d3341d0edc6423fe77d9ea1e3af1699dc27745944239019d826b82da210491bdc25bb2da012480dec92dd16d1114b0d6d925c165188a40676895d97d08924063789dc5224b21d8fdafb6b81319bf6945147f9e9ee3e508e4b68243a8a68aea79cb683688b5724399b0209b506987ccb81c8d28c3230aeb191ed20ae49de92ac09a63f66b1e4ed0426dc0660726c0590d50e4062360292682f2099b603486b1720399b0209b506987ccb81c8b7039cb00d81e4b40548969d00c4da004cc2de0032db0624cd6e0042ae146ba9c6cae0ab86ed71d12e051076174041360391bf07a008db02c8b90ba8042b81885f00509cf541042f0328899d00846e002cc19e0022b70194c36e1012570016672100155f632cad06b9c39cbc7bafb36e11de836baab506707d57fba89617d817dd70f9519a49fc881f5370c8c9cb60635a2d058343bcec746c58f4d695c8c06f2f1c0e9ede1ad71dcc911421535fb19512d5f509eea406ff33d16b3f71329fd999b0f90e87e006873f1ac32abfc1346498d078c314ddc06ea8c023e16d20c2b5e1e785f134010875052b48c3a43b1028314583d12d036650191401df9101b9696c0c4c2cc43cc320490ac310693360d8497f8173ea0bf0e40ce38f17ae72176e4b173e652ea0162e04fd16fc58b3054885b5b006eb2fab59182c596095b14058b0d02b5fa1b25ce12b5be13256f8820fcf1422ace0900bd1789539196d81e05dde57004f8f70aff854e4c455681e30b3caa9791207e536631dc2788ed1ca6dc436c6485b6941e94b8b9a6a0ff6c6392d69ab953ae0eb0765378f16ead55d4aef5f95cae3568aabcf5addbe978baeeda954f5435c3e289f7bbea9a9ae5174fcba40f1d94aadda89f1e0737160c44241f539f3fb9b72cd450dd5aa2ed0eb47e5e37737f5d5b5aa765f4b45636b0ad5f72d5edf94eb2eef5454d5002d3e966f3dbda9ab2eabbb7f5daa1d5551ac3e646bf65d61e0d041b54297e9fbbbb279bb91f2ca59a8d5c7f2a1b73bb5ea7e15b72f4a75c32b05d5678c2edfcb5d97ee545595e1ae1f97cfbedaa85717a9dd7f29f58f5828a83e677e7f53aeb9a8a15ad505f5fb63017ae38072e500c4e583f2b9e79b9aea1a459bafa5aea12b45d5c776efefcbb55795a74dd1722aedfab8f2e5cf13ce7a95595a74aff409b32a7ae4f64f2e2e25f15bc56e697ebe382ba95f14eba5fc53c4b164fdaed82cfd4f26ae25f1eb6279a97ca2782db9df14fba5ec53c5b1a47fb95829c5cf2abe25f3fb6259e9d3af1c14dfbcc433b63422875ec4cb24f831ebe3225d7f61e3eaf5c09c6511d3674da02b49115aa42a69237982b51a088a9c587dd9f2d383617f454659e5887e782f5d85fc4b5f214023df0c3324453ea235914a1664ad689e8cd5e7185bc306ab134877ce1790c0997e8baa19e26b92ac1cf6228e5bcc1cf5f14868bc47e88eb95d4de510dbecc37b0b1af42eff45ec45a37be03596ea7bc6cfacaa04ea16c068a7aca83c5aaa2a3b9e680364d10077d8d7a9f5a64edfb1a8da64b53f196b1ee6aaebec3b015d4d5be318d415da07f598abef895a801394618ca62afc9f0527508957e00aa013d836bc4fb00f8d17b837b80a7975857a3df98050343c29cdcf432c631b4b8f673732119d454d1a718fcc0cc73a581054063f4bc2da81a6b58e148e92a5d8fe3ec75049aec26d7bd2ccbb6626f9d6e2a2a27219b69e6f622e9bd7ba8f3a8a31f5ac7d52a71bb3e5845691cad1926c369f9fd8ded8dbe93bf5ddde267db8324b910d80a4d8f2fe8979edb8d63fd4a94caeb76c939a5cce96325a098e44834dd48f91da2c97cbd5a5b2c58c01d5c913780cb991960a6b45d5eaeefc66edff9fcdff038c357838a97fcce570331b053744f3df739bc6b3b41201f0811ee8873ee8871ec2bfee5b7515d0c5e8a3c9055012e451b5e531ed144e7877de27eb0b8db386d6899d7fdc631a18ee1ba4e5815754bedcc98921a267f1ef603ac6d66e45e7b867bda04be1cfa2efb00ee0a32e40866073074bb3ffa8cfd9add5110d600eeb488d9b2da24002fcb56015b7db3d3c692c56cd11a595044e5463afd4000a077550b2a9d29b74b1ed2a6afb9caa45a11bcb702ef285d19b6b007fbad2fd528e57789daeef80c1559b83313219f3175abdc1c6b79643aa5710daecb81d655d3da59258f66a417914de852276907b61454ade3f45e141f1fb93470c3cb7dc343494a0f833a83bc81b7ebd40f4c0ac53b48597ec99004e54590789ac46e851831b39db113d7839b61e3a6cd30530bd7ff22924dd90b80f0dc30ea87cd8d3d17159c31ac290f96c5e190770a5bf9f2bdd6c803196d42419df854936a2d21d08e738e4c595733f1a4149fdb0f0ac5dc3fb4f47238f324d9a70ffadbcf90bb66ff8a13ce11a7d21ff610c75b118886dcabb5e663a1e9746810eeb210ce58cab18501d66084fc9677356824890a6c2c4fb3c2a95e0946d74db1fef59a26a0df2af9990c336771c7460cad2c95b8f588c26e69dc2dee45ae824419661916b1096b2871eb56962223e64c2b27968fee9411eda8268dfa3dd8a0028956c6a8087e8264977cb49959fde0567eea793e247ecdb2fad78e92f5095e64f88e4183cad21f6602ca1535c6790621e55f9936f933179e3afbe946e1ead87f10de822d2d6029845dcb317c007bc7d03f77bd19ccfe7246fc8b00685c2eb7ed492ad6d969165d7888f543d7ded2f5e13eb9ebe14886bca375c4f11b39d506e89c7f2532556a2b2a02a6253b2532a401f6878bd1d7eaa12e52e1ce6649c594d5a7b4681074955d2b4d434d085a64ef2642004d9278817e24fac31e9eb086df036ba79058ec122dc2c7e964ef0a4ac73f937a53e45b21197f5bff61759be84a46f24f98ffdcce77627c36a68f0f03990c091847154af1c59f2087115c8dae9959b0e4450704d2f46f074efd6b47dabcd0a07db2e3144b679c14f2ca3d6e4cf46a7f08ea81ab500b3a4d337c1574255907042b20a4615b1bf5e291afcf9c2944ca24a42fa974161b5d0a317ad630891836a21e407799ae86525419e5501529100a0347e3db5d4c6e671c2ce344aa756ca4851cbfc08517f327bd3812c5b4ba0fe1ba14f7e8cfd000b5340d5175e96e750145b6ab0795056f3a231cec3c75c7930c1ad8377b43a72397fbef46f24bec49a6ee823c6e9fcb6d720d4728269518cbd516b8ceb05d038f32bf6d4bfe99366717f6e9875d15e2827b273774173731832b5569acfa70348df8adcb28829ce67e298f5d29b465c6545d40964802246b6808e5ddf4cd4fb897edb531e5f0093c99fbd77f794feb53df57203dbf3a718ac60755bb01cd205e28def674e5711380f49c3e1c1db8b67efdec1505dcbb9e3a958e5bf24e3d580a03da4d1b4dd26a3cd9e8d85549f5226c38a6b2186972edaff0254195d068991f69f35ad952ab1f6de1344d07fd8fcc386b72845d61cfca0bb63584923d40bf1f613e3a4b8a86023058d4910a892262a98c345871083f413c5f7f4b1001d78fe41c71005c52e21b789e2731627bc93a4ae49e24be6a943523cc9645047d0ef53f483d7a64d841b315f7b8e103988cccf0eb4768ad98cd10554c06e405cce4c359f10e2d4ec487bfa4ac7ee121f07b39f4dbaa6b3854cbe539b49bc7cc6401ab796bb7606c5b0f135ef2ed84d8c00155663b7d20104df9c57c504caccc78ffb17431ded63ed803f7624f62a97df0f4e7a796b7dfc8591128517389ac5d454863c620a5bc166dc655848aeb4d015b712efcc19948bf8323139e5bce6a0c6e592f93a5cbe87fcbee130bb2dedde1b00aab2ad90b38c941efc04dbae0024dc2d5756223b554106c7504406e8af6729171c948def878ce3d22bbbf72a435d3b8a59382663981e1799191e77f08fec84fc465f612296cce565902bcc6f084728dc172631c0073329814ac60665a39e8d56ab65d7a0dd8fac0ebf6d7219f7152ef50cf199d87b21bc4acb1fdcf08ac7d136000b6c930b7592db9a0d6f01867e7f52d38e977cb68c0d5918781763b23ade9abf44909a83a23321003584678ea880b859157be5488fd71604dec58a050d6e1637241aee55f955b3260a2cd5e7441e9444a8e89470ff26638c3e19396eaf9e9e31161f4e34400c8c81b033b430eaf72ffa8903330cef49b931abcea4a3b7c5d84b11caa220108ce5a8b9f57920c7583742dc6b42cd256a572f04fdb06af21622b9f618492294b850103a08350dfb19aa545d77d0a8fba08e373da1d2f0791274967c25b3cd0092ba9a26a3e3f54151b4e930d41caf83e319928af5146dd56689e8d613e1d78aa5067bbdffea71b69e3f7b5b92f81f015ee02f8eee09be966e72ad6a304e51276c05f283739b2785d429538aea85e49c1bb8c8d12846cdcc26eda9c119cf41e658600c06401bdc63a18b21e14ecc8a4fbdaaa2a786ffd8bd4d6554c187a596d612fc325b02ffeeb946d3b95e1cb5c795509e17da6368263e803eede17804c415ff01dec9ca4d3e52077ed0bddd5cb93ca618f5ee8841fcdbdd5f4e81dd7043e29328b5cad28f538d93fdb2b63051d58471a5187bf494de4e7a22df08423cff4c43e3aea9da65f68b9e81d4fdac0f534caee6a5cceefab4534a35529b9bb3f059a70b2d681405f56f8ae152bcb45dbb1e66500c0832273cdf2ebe0a596db7ab9225d665e4860eb69a1f385ae00248658a497dcf54f995ff66666c5a2ab22a23a06e3b831cf6c4c13266194c7df38f85f14fd4eb82740f6ec43033d96eaa1b97b710b1c10a5397aeba35d2ad0bd8933c3557aaa41a8db15bd761ec853a952e48c57e980d641b5bebe46ba2d67e3bfb3a35de829e287fffa01896e2a5edfaeb6223c541d033e1a0ede25ec8d2761c9a2c62b5451f0e3ec5994154140ab9f252d088c29ba4e75c72def7e805c79f2c2f98351380bc6ec5021894ebeea4434863bd6d18d0fcb6690e2d99f85e02eb0c988aedc647bd97d9e9f2803306a6236969aef71bab1a6368ddc3b117da544a908afb613790ad6cad928f8b5afbedcaebd4780b7aa2fcfd8362588a97b6ebaf8b8d140741cf8483b68b7b214bdb7168b2887557dc30c156e54797165c10aa9862aade19557ef1df8c194b830a566509e8dbce80c39e7170c66c05536efecf30fe88f7ba00dda31b71cc0cd54d8dedf21622365831546caa9b239d2b484fd2d25caf92d0e858f2d194bd97064a0ac819f89808e439b40e1ef8b3c13467204bf8dd03b2b5280045efb74631443ba9071bc097318120eec1c7328af6cc17490463fde54cac9e4f0fe04a146c093f0bf46db85451be3799147d7215917f9cf33a3d41a0edaaf105323bbdbd230366ec1b60c2cd1f1b260c1ab45fe94ec60d0f260f90ec950ef288ccba36f747fce4968147f09704c19258428fa089d7f0ef3fdd7ac4cf7ee45991880f582080983cf6f65275c17cef6a359dfe4c1f80a415280c22ab8a328922fad6fd10bd63a43ef3846ff6afddc3268d9d7966eb0844110f864a12d159b0dcbe741ccee90d0505aeca1c37e68e12a6610e040f1d43f0b48f91ecc08ba4e86abd95bfbac33456039597e9faf2684e42f2c1a7f45c117e1c4ff127cf6c401774912bee4376d580d8c8b16b8065efb033ca47606f2f1798734efb9cd390f5cfdb914136d268840321268bc739ea22fd66c8c776dc4ba20a21d88b7a2ab40b47ba910a50215b3e91f3eaa3444244268a9bc99c4c1e830c34f8d51c3c1e1942032ccae5071f4a177fce20f85ee6066b7ddfbab0f2e070be17c7f441bd195e5f80474926df4bc2344d11c8311e038dad7adfb597e9def7fa27245b5287469b6f385d9bf469b41813341cd5d81d44a8d7a3ad0206a05071788496276d68822c0d4035228698046f5f5573e7aa24405b68c32cd67799068ea6e63ba1d3fb2140cf20201a88340c53ef5e3d9bb8d28dcbb72a4554c75668667229285ea9dcf41196be8c8ebf5862abc14b75190116c8502b0e66f0f8cd0d9650e1774224d5192057ade788d4f986851819f4f1b1c6139226be2e4d208aeae61c4bcc66ccef608c90ca48718aceb3b564599228d6159d6971442f87b6fc166b6ab65bee228bd53c475a85c662fbc8c58d36bc3a0cb041e0a2e9417430f36f6a603d5b0d633b68a2b3a4ab4fcbb2ac2eb825ed543ffb880d5908098de9c95c3dd00723bd133a4f672e57a46e5936e44894cd6618f8406805a4fe97ffebbf9a0d883328085c0043e8d0f4f2ead7c88d3920fa92fa8a86b01c12976c5f81473cc89fb078c9c86662dcbb92e1b4102462ae6bfff007b8dcaeba7c913b12ccb87ef4ce1b1b319634aa07d684c197afdfb0d74f4f7014c932bcf37ed2b2759c8e64f30fac917999cd9115028ccb554ab42597ed623912989835737af39c822a502911610b5845e41667e2c0bcdbde99b28a5f35080d3776169111396d0e5d04db79db46a361bf6a63e494dc16cdf4f09658d0302abf8e3a4f4c0ae41126b4cee7aa5e69fbada491935c93299bac9d16e6394ed64b5b8b5da6f124d75d2805e06a16b210b433a671928961feee99de92392d39c11d528068af5d4f61127e6691c989f42548135fb4183d4081d4e4396d344e5d7a34f883078ce2acb4d1fedad8fb5ea3e214334411b7d21e73788f0e6a34cdaf726a746c933cee0bcf62fa834805a6ea05584189a2afabe5571ed84ff0a358143028fa60fe3e0dae46046ec819360729d605f0dae42a6ae0aa4c12c73f6bf46c3ddd80cd2d8bf3abab0f819c3e2948f96c1b36a2d27a67e8aa7d95cf1b592a96f3843bd25a9d1e9367959e0b8a5baa64a0e72931b32c01c0c1ee7c5a1e414b0d5b39448268a332fc7d39cb0500b4b83a993efa34fabbb7f721bef588cbd1ba5dc17825bcf1f9088a955f40c6f1a2329996caf2b59754524574394ba273377b6148a42afca2da633b65bebed91b1a9e7302849c13f1a8dd4c684353ec9d19011b368956ef222e15985add2bd4f7bb97d6f6cf083791966896a379b36a0057c50055667a28b6f77d4ca9180f53ac917df68bdf3b613b9c7b2ef258c0993714dcbf615e241bdf8f37dc736173e84d9914851afec12ca75f910cf89e76c0b26d2f2f57acd8586f6f2a1543f6ce609195967920067286587c52201fe1bb706503b0b127eefd005e8dd23de7678cfd47e86d3cc0f4b6a9a8ff4b9f3d673b415b174b6fe8511eb320e42daa857435d66e37c91e0b5ff3a978a7f84ce892cf22f38c1c630d953bf5bcb617bf0c252ce920a177b2cf6a97162208b12474b40098b4498cf5434d3f5cb3e8b9be7b219e3a5b58c95aed44dd95eea6a2c51cae84de318746724bf45bc1b4200fac756b91ff578d07232f36febaa9f5003196b029040606cc36dcc277c3f4c38677c917d03815aee04a07981546b53dffc91652cd2ce6e20987fe6c6c07540bfd71c83d9501cf157720dc7305b398bfba24a3e928b8d50fb4075a5bf7e6e30bf666b1135cfbc610c80d769e33017dc6e72b44a221583dd370d0d6ae50f61189e1f61fbf7e708387a8e7dbd1d1b053f9dbfa98c6a9990f312f67a74583b2345e37c9db8188130d9f95a92f865ba4ec0372e2c17e0f6818bc7202b6a31fcdea54338be6e967003b481eb7e3f49013304d491df560e50446b6aaff952e489e0fc8385f1c9036d08318110a95de813b244aec1c2612bb4e92a159251671a2ca734077ba932dc4a93cf78df3b85e05258860d11bafb88697c2c1252d9d1f3500697ca8bf43da93e4ab3d93d4c28a8e485b79756869c486248aaefc30777a61b200a971d3c0d7549fa5f1bce15188dbcbd432b7ed9a04776f35ecdff6aaf6a8f6be654d6a25a11544dd8f17015267d011e5a2fd0ac2a8499b08d7af623ee486b208413acdb7ee0795780914a14940592198161b0f9d9e69c6604a404f80adad0c302af205944b4b0b266b7ad41d2d251a3663c3c3daeef6f2fb5b4ddd898f9c27cf90a673a55080f28bfe3947e3b3793de241b99ba679a082a381e6b207f8adb4441512246509d1f63184e74753d39369943ec7482cc78cd56c12fbfd94fcd0920182a9b0a180f0529e9299f4c42fe34db3560673566db6c5a1beff3f4c58edabfa34696f68258ee9eeba59b6ec371259d53f505c82497d7093e018132fc328d897b6d0b059863008a1a86e27b4e7b205074678e3c743c95d335caaa68bb88bb5c5eff454d1075c4d9cf61c08d3df13761a8658f625adf878d4d74911e9595db73f4c5dcea775434b1cc34eae7cdbca3c1133c385819985c67b360437718c0f1bbf060fa00b4babd2919353623e9205cd6c8081b70e6744e96327dc05aecd620f65f450ab64212765f0327fef13563e5dde02884efb1ea33d7b3af3f5a9cdfa67b17fa0d9d9392421d867d9775aa304a19b098ea7359ba081b4aca239415eec9c776210579c392d212f7ba970f412273307a628440f217c7654ce65bac904fc7615b184b0551eb7f94a7d9c5d101d365c7f9d2611523fb19bc1aaf413bbd10034d10f10c26da295a2795216ac34864faeb7aeac6d4eea89bf6b7160ec3c97418eb474f542fb67d05dfee5747dad27b6229a3da4b7511649778c56975f960c343d616dc43a471d41b477a360563a2813a06956900e256df6457da73d406bc0a490e4c1ab7f0c662d2d483e9bc459126ab42975c7c275c6aca3b209bb81501035d2dcd23434aa1471529d24e516f3d84d83ef3f9555fe342594fc2d552a4676713fbb026b4c7c1bdd0c512c4c95156f926c943093e77f1eb15f1b14c63c804e9589c148ec5adf64bcb6c896c68853494bbac2f0690cc8d58ac8490f63f330c49c3133f9650b2ac3f57e9521323fb8c4330bb370426ca57e4cc8ae3e73ae56d3116c40ed958e82ee86a48bac6c6db1d4846f42e949dddd4d2d249c9af2f62b13973723e0fc05aad211fb3918fa62a1920c2ecd217e7ac2e83d9158766d71203b533911839dca9f4c1fbd267e6232264a9a76fb5cea90c64d1877c5bc122d93ba24febb558ae53e4c8042d313a09c407124e7710222dbc8de464269d1ddc8590cefaa536e17a2cc89ba46fc4547154c5cdc5adb2a8fa909e4d21b6179f731bd996ed2355aa215731237031f89d5fde9fdb75107671c4e2bebdb697a2b5fc5b4e8eb7766ea931b3bb1b9534e2f4a3441eeb810fd4ad0e8713416824002a721e0e91870c3f66a0f609a88cddd5eca36eb6e0f49c9e782299b2ff105a792457d825e756a567572d95bee120df01bf3998fa4732565474497d37da7ff20faba0414c71c68619d2b55a267ac1c31ac3332c7c9543fac332e03c56f6056e6340967eccd2710cd5d8a2df718fa5cae6f22b31a3b28bbf95081773c6760eacaeda7819071144e6d144350437dd2fb8ccdaf7e87ac52a0928dd12ec1f4f9a6d31ce860e2bb40cd4367316131a89cd3066558de38a9767b2d5de26a3b00e5995fa477029d2ece03555afa310f155ecd96d37297ec45c0a04924329d899da0ef77b9a8bcd4f6279e2c8b8fc2fe0edf6b8984417d68c63753c9eb2cc688c53b5e31669be9b59800a5a85e10ceba371c32eb60148b365a2d0bf0457d9b3dbd48104e0d7b4e16aa184014a72089d0e97fd52373b113419cddd9550fe79f201ccf694887e421e01308c2194312af00057a2fa97104e10c70aa3a6971f9c64858409fc384eae67786827024b294350bc6fcfc7d01b947efe67c90fb027490933d2348a2f43753d087360da11c60113d5e8c1d022a5a9a97e205d0fc01b3297a4db099f0e2fd9bff3441d513ae09d5969c6b95155afc66cb29888c791abd61d619129e0b310b98e426fc03f620a01f23d12a1794ef971cdf3b846fd7cf331603e3c63d8bce70168150beb050f8d3be787dbb4d199f8678e5955fcdf3601eadf3a665ac8d0c074b44789ba6594814152224a40e61273a6b11ff637530d1eeac14cf0e7433c5e498c3c3d3303982a1904629295fc1507ecd98588ffe3906f70f91b7a5cad82d626c25bb5b1dd19abebd233054d60c61b7fc06b68e0f557a400a0b527825a6810730d1826803cf0db60f8a9aa6da81650ad450f81756cdf5d91a72b516581bfbbc405e560aba234042940086dad86ae4eb761eec92648160507483670fe4c2e0d83c19e808278a256c40ff36b213873ad624b90ea50cdbbd0e685d45f73b46bc5e0fea09460cd968fa9af54fb8a50d7485d997f066d0ca9b2cc279ae82ea43fdbfb663d87e2ef9c1558cc7f4cb2381a12daed2188f7420bda999189ff8152a35d2f3510f8d1014c4545b580f3b9cae1c972887924bc4422b52e6c51aeb07b7418ab0b661e283a06f2ff5b8a4b2b940de1923da828ecc208dd11c19852e891192190c450b11f6d91b26f04bb17d790c21450dd897422f023499557afda39405efc105872ebd4165603501feef9566974ede2745955f26c521260275d3c1f422391a920ba8da4130ed7da28299ca7ebade7276580f823bf22340888a6bfc04d8979af14a0c51f3dd96f4f8fc1cd23708ecbf71daade172bcd9daec2b0aa31aa68ca2e0d7a917785eafd8001d29b2986263d6d516a53cd8aee0ae66ae9085791ce5ecfb1980dbacd39f3779c0640c1d145d4034cbcf254a21ed0748fc6b6d8695edc133a896284b012cce322893824e7e1a2010c5a4af07520705b815e960051fca47e826a8914763203e742e955ac61ed5137b6095879ae70286a13296131ff1c81fbee8edb00b087ad8a743252bf68f89fe8bd5c870967910ce156e234360340ab154bff3ad7cdb6f080963376dce23ce15586e697adc05958b9ad30b1cc5cf99505a413b5455425946aeb008093d6984ff84561fa9d2d63291116f56f8bb83e22d8caee12b7251d0c52eb2196f8e91c57824d26c89a9e3ae21d9b9b4f1919432d7d4ba0be5cf462540951be0a1bc2af3a8b972ed248a9085b080011c414c119133a0a3b5a86c09a95d24be7c71cfc886b2b63400eb31377c09b050212885fa87af77d022546dca82682b0d5ec2d96182e0e4e2c9bf36a03f412d2fb1e5a4d68f6097239b259c603b51e58b4daaddf28684878b9fbaa5002d4eeb1e1a9fb1c9b4078abc6534481d96fef615c1a0329aeb2c303ffc7b45fbf445e9fff84b709ee2febdd2571965f81003d581332f9c6042a87b08d8bb31b597ddc05fa5eac591e468635af5c4ff372114dc015facce69a82f650b8a8efcd7c70520637f36b933245cf67e5c334ce6a95a3980ece9ea50431e59c360baf9a8ff72f7350cdea03f65b4b70cc0bd011908953c2dce753f2de99a0f898ee0327f4e653c89a0223c635093cb55131af5bc74bc6c8cbf59670b8eefa1d5751ab886d4133aa2e26b361a81eb1e4480b3048ec23c3206c38aa63d8f65eec65736ba67aa1d8919be7ec96784aee324efdc77ef02df180263000432873aaf4975a0f7dd6e40008f4da0e9625f51ac7d2d5892b99540b3113b0d4bddd2a8090c705acdd71db45e813525018b5cb1ba4ea084ea1c4ae9c2a6e6c5c6255ce73a45804f48ce0080597c6bf8eeb22ee8fd3dc5c91353067bcc208f9bc65d6de1229370cb4fa4017fdd3e55973190965d376ec76074774f9fc74833d63ecd299b582018279e6d8f7861248d21fd5ff80f1ca09b710926dc6099cfbfa5de48acacddee32cb7812a024d40e76415f139ac6aab9257974a0f2e2e6860ee2742f3535440768e448efc4f30a98e5c45c453b47b3c46b5629bfc8873e75f17536601394b26f50004d052bb5423719fa77a230c02c21208f5a9a0540160f7f4da3816b3762d6925ddb086eaafd92b6cba96630674854eed50ce16d860d8a64ce7c121b721ba05e2ba4a7e71fc54cfb4b690aa61502499b3262a817ffb4ad3390d7dfa21d09c86eb7192a2a8e8f0022b4aeb478b3a70140746439b2b0c88b26d83894e636d095b52a8d8339f1728c24dad8e09330472f58b3f7f24216edafe175a49ef1f06dd6025adc2e5abc51f5d1f3208172aa59d4fb19204e73ec1f0f8497967bbaaee5aef40179899ef9e975fb7d9458fa9e99eba4cb15e4b4f242af42d269e5ea45efbed8980396b3266724f5f4c0cb94aec739c3c712fdfc1967352713fdf521e1437f3b917e5451f0da9e151015a70b7b6b761c35d06aac28d082786f7887027141466da70dd0c752c68f9f4b0a774f53964001e9fc6600cf94aa27aca3c4a6be3899005154b1a58488d63ce4221ce0f2eb09446e62a6ff3413c0d527922cc6044d81f1dc9b3b81e9fbba3931f743cd7f21f75a63b8bea660a200041e664268848feb77251b1f207fd5051a59c29fc2efbf920d1a01658b9c3c760a2d6e7f21a3efb6be6661b859e40bc5a403facf803c15a764a510dc541af442fdd9a0fb6497ba6b4212f3df53e12e45397ed9c2c153c52c26819b329d3c056b916857100a5cf2fdb20be32e7d802fc128a7c32db6a78cf176ad7713c9cb94fa845ebd834b5ac9849e309a0dc33df6b9f67849d230c2db4e8566c39285350a93aeeb4367159c93fe0c17edca16de4d821e2444207f0b920e1ba2a20d91cae143cfada7dca85384acc9a9dab797a31947aed023af8f286f8a5cf791259b52bd6d428203eb77083d417f2449c546c84017128a56da0b7a98997df61a65d0b75f5af3f3169cf602108b80af9c9e647acde14e5155cce83df13b7ab7b3653920de060f47414afcf91d5e7522f9fc7d7e59e3e821f8d0978c88281503c3c974ab9d812b7b328d1469c86a5631a6ead6fd5ec0dc10df366ad8206cd2eec5f615f345e1c17a82dcf3c047d06ed4449e5f9f5bead32ca621050954b5560acca63a5226663191a228d3d2806e11dc37d86aaac713ea3fd3caee64b8530b0df94babcd8171a3ad4f3c4acb8773782bb691734ce3fec0d029d46d1993e3f6b27d3e66820741126201ef9e1a07f1972b56b7566a8d9080a747e9d676d21a3174cf6790575c571a0f939a0891be41c6a213d18df1756c4abcad20ad936ece13ba798a1a08c581156fa2624249d81c99ad438739797c951a62211e7ecd16e28dbe7ab87de6deaafe91bb821b11b0224b436ba09011623a7e6f8b5e027b5f0506d5a4d98512cb3189ad2432082beec90eddf2a56df3025edce48ebed20fa5d701977a30d84e1eeb1e594306179f505428ba7f7d07a3cdd9bef5b617941026c6f5091ca93852bfafbc1049b9dcd1335cf1d4770b5e28ade83a43206322659fd1c4594a5bc3d29e9e1efcca0c5b2551edabe85601df012568b1d77b27393b20320b60e556ab8e1b3a97621a6e0b96950ccbb40f45c9a1ea1e12e727980dad9c49eb7fd8ced16789ba208519afe94d5d1b4d9f7405a648af9bbdd1d2c2e786508d2332d63779abe74375a9371be917fb436074bad94143441fb6ca5b21480d71dae9b67bdbb44f0be28c433f445f526be184e340fc05b5a805542db307cdec112a04f889a468780509426da97bc233526c782f08eade28b6e5f236bd663f9298e03b7de2c1502a238f0dcdc8f449c4ce8f90b495a72942d5be3789b44e47f8374639793f173e64a5146c30a65a3d7a26d5994b03fd41d93cd6ef28a28acdc8230063d73d402531a00c8e79fe29ac829697a88c7899d8b28b8f06fa48e7c1b704496c989b80909d50016b26337f5221e6689caf57c71758e8a686173f76210bd2c3ad4801547ccb55069a5a79c0a47de11579cefceafd4b21f6e206689f1f66228fb4765cdf982e6123d5e7fceac74d61d7b718b9c7877cc63af6987850ce2ace74cfc4d294380b29f62f6a12481a67e375f8e6662066fc3f9640f43287eec5f048edc2f5f76f3e8f30cb324bd37d8899dc17d9a904658e569caafb93e9b10d7bca942412198f3d49631ddcaf6a0809c0e764e76749173c09729449958b141205eb7879cdcf21f6994777276b655f3939eb2aeb88586192dda8908e4ce85239c0612b036b111fc80cf041a781a60f288ee852758fff417813098afd5c30534f4be78f798ea3064c00082b6e9482bb81a139fa5998f0a56aa8d143fe8658c8fa048065f55f32866585407450c953c8a17d8dc904a81b3a04cc59e1bda0ad545d0de57238c42da360a88388d58f2a5b918cad77627d2759215d867f34db132234785154a78f598f276c48e847ad495cc3dd119bb288179beb4978a504c21f7d473f22bafc9c74d14d3f2df4144742cfea3292159e243be89f4657f1599cbe5c5acb0cb3a47dbce7b6bd727f564d4b1bfd0001c21f67b0986d9b1db97bf986ce5a9eaa4796998edf01da05d97acab5f8abd3a43bbb6d3719800972ec0e33d8140bbc506678de3ce9b7e635f361a8475a6cd6ffe485687433120ea303132ff1eca3df1b0717b11c1ec25db257a257e3292854b05995056806542e0b4204c770f16d2427748b1c09a10d6ba50d1db940d7db2ed74df782277993a65c5e5b3b25586592350f4d88303e5b5c031620b1cc4bf68c3376f60cd77c2c1c8242191fd009aacc886b5b46ecb66913f048ca52c24f9fbbce02509e0a7fb56f694d9f9e3edda31fede9136dbffe8e7afc52152906d480b88d2936775539eb7c10b9ee5ee6423b6e5de8d10d26fbe823dc3e43127b3248aa5331fd96404e5b95bc407147e1babd7e816c98a6a12abfd617d4b10b650897295d22d227839d574e3cc226c74263943e88e054c12c9b4eeb58ebfddf42c2b689df3c39902963b49d3983c6fa0325455714b09713a6bd6a54dd7f8804f3c95b45e297ae393ab9788209b73375fbbd25b8e680f240f628d75ceff0673c243d35f01360129c429a0215897699f41e6634247ec55a4a34df0e55627af157b46a7dfc8ff268e8a80940397b6cb4ded7a2399071d4391171df30d73cd4fbac7b4a697217c5ad8b5ed469b10083afdefc6e165ba18b4228502c94f42ddd0ce14354ef73ed51ab4a05059c1a887f69e4b93740574cd496be0c84b56d7c98df86010a02d1a9efcd5f6eb24393ee44398f872d39457c23c45719d80d9e57884eac358895e87cc13ab5ceb43aaec5a95291630cf7708bc24e911d35f38728e8ea9ed744cf22a891afb17bb4f9312fefabebe157cc4003017a0203930e3742dc8bf741a19849ab32ca568c995ca9b5d7234e4cf41c9db59d059c8d04196d261854d597547a7d9614259f3bc03a5eb837f4ad73bbddd76f07232a0d2a3c41f720af5e92ba739f134a1c473b2dc1f99bcb46eb6515247fdf88085c01a902329830968c5c0f74e46ba8968fb00c17430f4f2ed25dde5283c8934c77037451874e97b7870800c1a748ce7e0f5eb04c24df3466ed9f57013476480abf44ec2014efc92c044a28aa03e85cd246e36a9cc013710835c64803cf4a3859056b31856865b453a4805a2c5ce0441d151e72c71b6458be5918fcfee47219f6305e401f6ea4ab5ad0b7465d7a6a5c1c12190428cddf8313d5926f35e670250a31c31b8f552ec2167d0366912bff6ba2b3d990ecbba633b1b94b37bbd90b68eb942a606ceefd55a851dfb7bb9712a87d4d9490895a03efc9f44e6a60f51bab9968723e3889cc84a21cef4fe991eafd6507674ffb7d0693b91589b2f4317ccd7149b6f3ffa2f125d97c901fca44f9d292106811f7a5d7041294facacd4aa27ac69052d12a5fcbc63d87f4f136e931217ba95d6b1f4fe24d5545b4bd73d40bdb0494758453a636e72b5bfaab277356445e0e76d344a2e2ebd2362602ea2f4f9c05a761bdb8f5eef7681bb3962550df57154158fde5e3431aa684d90b84681f05e9a5f14e04dfe251d4669f0fcc7ecda48d6402d2210413a3439d8c50b021bd8750011b4704ad2779f52813ace7db244854d5277bb973391f9df0b3804dfb3555834b88adff4120d603e321a084a22b20d114b4330e0f78c488f1113e34c11a26bfcf6e672a27a4f1d6eae6c1b44fef4f911a1c3088787fc30ceffe2cd3a858325777e6a865e73bb04872463fd4acfa7d32138567a599e82fcf2236d0f347a71e1fd38fa0e63213fcb8057d60626fe53ea5560ce8bcd536755a85929f74c62908493f9083f73c6cddc0544f88338bf905268004f49598fd7c93448d7815e6c6317e84932179ca2f9d670502de1962182716584166f201610c3dad3022bd5e0fcd01652ce417f2282180e3b911514046ed88ff14a8ed9828eb2e44e74813200942b5021c32884558018a5093cf0e619d331497e99ceb8879193848c237efb476f17399770b29ea0a1feea277d24731565fe577847f2ee17d3d90a85cfb0aea08f891387d7fcbb7b87439d883fe6d5f1f8008c0331754920fed2f20162adfb62b5685441188d9fae3ee4bbd311db79e877ffdcb1f930bb2a83b52312526494600293d0ce5e9c5b0969be054ea26bde2bfc6a5e67cdec8692ebb1ac3c31571b2caa43a2820c9eae23686c67b967d55f217210e4157d7528823ecb844c2bd7948b542e26fc9d18d1264fa84560df94422222e73f90955129858fb7cb0e9becb532485f10c3704c8ee8e6ea70dad64a16a1e26daadce2b650cacc1354783be6c0d8c4026b7ff599827dda156fc598df285eff04541ffc8f8bef8992346473f51843162e3256c544fe1f4d090a5cc59ac8e97c9bbff557fd982a6c065356f2c47b59441b6cb614fcce48531be107f71b3caa1b8509efa954e7ee01572c968ab05fccd854d08e697713665277e3a8d9e19b7c78398692730059ca166d730432bdf0d4494896c2974756ee8c5d11071a28ccf0ee8cb56553e02359f9f54aa5d9cb8bf2989bc41753a4ab64856bbfd4b3ef4c5f4818a416fe718da6ef9f865fbcd1299fe51f60121d8947d4bac8f1bfe466d98751166a2fe83c82583ba6d34aa40a20a2a60bd85768d0a77216a70fdfb15b843ade9d08bb9a7a3ad7585191199a87e01e47683d2b40bad0d783d6448818dee07471f9396458291d419c95a674bedc78ca2e3e90bbb517ded6e12f97d8db424fb186771254f2e0fa4c2df31811741268422562e4890ae743d92c18add60d12790a54dd5abeb33f15e99a0fe400d14ca666a209f4e03437e4ae18d9c5933e1e13c169ed29be5efbf3f36f09021b37fc49c899f65069f9330db010e0c52b5073d553bb729b43e5b90b5b1a31b833a2f6cb266a0bcd8d580bcc7b7e21ef3c5d3d2894832b1a72f133478cf14373c4fd920b052f679056ac8006216f1ecde0d5965442c0a388d03a5a9c03ab8e3591456e209bba899bd76209b78619ab568d384e8c158b6ebb1d759111353aad86873529de484d54b491d4c3642bede4a08c35d25be1eff1bc66a9c045c6bed5ba3beeae753618f8d06ce16a4f1fdf3e7cf33c9bb255bb433ee2b87eb95788ad8ef0297cfc2f058825a2f9b6e559469d891d21d2834bf49e1de9950b04b5f681c40c619097a62ffb39077c42a71159072bfb282a106401dc78f5d74133922d832218b3b8f6458017fa0806037d524837ea402f25e8edccf7b86d89bbd4a4c320f6158b0bb62aa5956895116546dcf147f65d399cd6d6bc4d77f672329de42dc78934a10ad46b2963620a863fa07c689d9aa6ed3ef51da6f12ed9c9e5aee732b7b2910b30972bb99e89be4debfbdbdee0dd5dc86636758a7967c3eb469aaebd0dc27efdd1f7b092b6f319d48f50a823c47113b54f6af7ae583e34b71116174d094ff4765e3530c76806edd01d51afb194f9c87a76fdbc953f00b260f8a7270bacc4f839df29fe40621a77bcb66a2c2a862e70ecf81716f5b445f16c8f1b491b9c5f39b2430bb79145353abab882aedc44db4a407a76e847272c5f2b5c59bb8c3f321f037fb8f37cb948c66a0b3648fbf419b68393c5de9047308fe3b247101d0a1b24e4573f68ae0b8245a8eb7a039fab2d0b5aaa7d837a817a5dd5fdc52c2aa7e8f80adece182a91c6dcf39ff961e8208c1b4f8e3ace387bb5cd1c951f8c0c502f16f59c3305afe616b3f8eeb6d2f98b1ba793e6682213bec5362b743e9d5ee3ccedc94b29f808345a3c289098fae14b1d96de5c63c53c7fe89b9de6b4a644ce47c46acccf528569bcb6152cb7714113c4fc75c54b1e69a166fa6977d17f8a52ea2493c6ebfcec227badfd18539baaa08428ac8c325fca44ec1438cf21d5818b08645677c23f4c0464de953579e3e3d8ea33f6f81608c3c254568d16d00c7d8d011438d998b8985c80dc620aad292db831481c785dd4b7d848f87e300d7ddfa7fb48da53ab8d58e6ba963af21ae234fada3aaa0d8a5a38a4aa248675ec7ff2a8b7a34d04f1fa0e5d8ca0c98d21ba181770946e0cfd2362a01d54c86383cc1b8ebd859e5a98cf5246758a506ab0d3015d8126c214f11b1518318b012ec8bbb612f294febc9608ce3142e8effd1bd0c56701bab8e645e8a9c25493880c0c58ca446363793d22da6f182921f30b5e36a3afce46d993588888bfbc2dfad02e35569b8ef9bde5512aa56be4c675453eb7d7fcdd48296a644f3f61924a6a57d3f244ecbc897cfb69990d789ef33b5fd2bc37c3e845e4ab71cac50cc31fe4b3220b3839a97224229f32b895debf8960f9fc477a7c950efb3b1437749aaa97164298aaa799af122c6b752f28ec9b3a0ba6906004964440e1c0b0cfb7d66c14fb89f31efa6c7f55104258c350e9629b8482ae1deb504954981b40eb9eab434b0e0ae5a1a44f01156416dd4beb1a389698d71d0a731f300ec3082dccc54f0f8791883c6e04d8e9a477ebc0b8d1c51f53a4ad3ec938e5fae63e6c0584607230595558a33570136ef90adc34f228c496881606707277f12db311c91b92a1720b36245d1460409b2df05db1b4602a093c6ba053c2ea9ccb5a33845a401aba992f80c393ff32e2270883a0d2dd64cba1ee8d286c9cec5aa05682c442458b06fb913995e890db29b62a9d7f0b170b7acdda45e3faa230dd7e4fd24c4c479a17e485727b2ffff229a3357abcdea6afa7ccd5e5d66f5d53677614deebbee916a7e38516af2b159bd835aaeeb5c08992fbf7abafc880731483d990d943e170e07fbff961534f7745c16bd6b0f08d65d65740b161418a4dd3c79cc0606fd262fd3f4dcc33de0d3953654a122a0bee905f6cc4e23b1558feb9c99acfeda70f946b246d373f5e1d08bdf2dbad6c353512517d10c10dbb5d410282a1e928e6e822dd56a5d2e9e7f02cd43d278b70f3e675dff410127cb32be9017f7ffb7c6e21430c6426566cb199622a487f2e24c394e7fa58d0b0c7ef5f73a7ece2dd491fb854d2f1351a9f6f4677c85b2903dd4dc8993b271f15e1ca982e20b38d551009138908be8fa00522ee6e9202e9d3a7601cd4961267fea6f749f62787e34307cde1ee744fac2b890aaffcdac0953e80880d13be1279ca6e1d0c28793408963ac963545bed33f84f727b8bd4829d2ecbaeeb970fd7970068d4269e5291d94687ab83812ec41f760d4c4c19d9c81dfc812f41aa682d129cb040e18e8a8cda79efb88c0901b59149068a16e77eb01bcf2c069c7196be1fa515648518b01e3c4490b8b45363dd240a404beb8508dcc73c0c4838925029eaa89cba9b258a49ff5418f7bab02c0089ebf358f7f6abad7ec46ddd2269a4ef6b6247a99ce315032a7114801ba4cb8b3d6bf0487592d11e3892bedbf5942e9c24af945cf72a5483f64eeabe7b0c26ec105e8dd2aea8af0b641da21453382b259d6ac62650d8359b2040df593a603e20e149c1941f0214710e42a49ea81e1664f035444b7a735e8a30de7221bda473c369cfc96ef04542317d86e59ddb24563200e6d44e9f0d13e82a22b4d664c499304c4ffebb37b5eb0069f26f57fa21acb11302d22cd8d1da43d95415f3653e394f4eb0f0e1df7194b9a06aa358c6f50f1f6c50867d80d2db9f59f36249981eb9db2d0b0ec02947eb29132b2def698e04db60c6c925e4c29d25068d304a549cb799026a1c29a18aec4f6e5a0ad1463df28998e21e1073f157c7485577b3fdfb38687fe5dfb04d0487021787682fca00c9ff8a83096595fa0f52b589f3947b0655ba1c3eed3e09bca93a5cd64f9f0da9ce675469c315208e99136e711b41c13a8a27482da02e31a7695f3f823ed37dac0ac2ceff782ab0fdd4174482b1c28ee05049340eb57815176a7bad3a31d1e86d7ea6b541cbec904dfaac9aa5aea667681969a5b6aaecffaeeaa9cb77e5eb750fd9ea00ea84057dd6202ea739c70f443f1848f49d24fa2fa94ca2a491e2de924af0c5f2adf191b453a44be72a7c78f7039f9e92b569512d8a573ae2adea3d74bd118c890a2b5c8bb9b8868eb66e7abeb10ff105adfb95e35ddffbdab2d0c88b99fe4152602ad4259ed66debea818a0e3e3188c9554a067832144384ece17a0a14e038650f0a7885e319ab0e060d41ccee0e62f4223b2a2ff54455b29485a8dd9482213673be998e2ee82c58881033e861b9a9500e9441f175570bfb85d9d07ee866f9c450dd9ec46cf8668affa71e1f8e19e96d9131576549e38b44c1fd7b10ae0d04f0fd0bf5588839e4c34329ec7cbcc7ca07ccd8d894c072309028f664d0dfb68d150d21bfdfacbb8205a5abb541f1d3da3fb7f7d5e7fe9220ea62bbcd9b0a28b5fa09298c409607a8fc1081f850e0d174ddb0bd87340f5ebd3efc6202141b7c5809ae608eab76b5703b4739c7593d0a69f4134f261c9cce90c2e3232c30a28c785098544ddb28b0a8228f2afa51ceb345081300c78f17ccdbeb6980656502dac60c3630ab992438b7f17a33a93fa542e3e4570f1350ccc4e811ba5351e2264452010a08730095d65cc1be5017f8b4b93ca69fcb39394e538cb53eb522169aa9f6399365725c17085139d838e42dca564a9fd062991c870be1f11526d70d022c42aef12703844663025237d8ad777a7fdb7d00bd732e57bbf24bcbe9eb2694d76b9ec0a3f7d8215709bffad4f740b392049e9ffe8e7ea06f9be8ae2d4927c97013d326f18751520b9fee91366c4f3890f072c3e58834cec1936a9f2b3745d0ccfb9f28380ff3ebb84611c31ea389d69241c4302d985a93cd57f74bd8d668d39661f49cbb04377a6d4a464ecfb0450a4815c04e460905fdecdaf09aa9d1f5b0c56ec4f2f850d9735e4387bc8666665c89ee3fec5795cd549ca97abb7efd1f0a7fb9b490907fe23de8dc0b7764625bd552251c684a6572101abb1f6d29b1a986e148e12ef4b2f0931a7080b75280dbc5ad25809aa40a022d0e4c869cbeee819b05043c197caaa798d88db0b8f72469ac1c112807976ec4f20aaceaf496d34ced01ec0594bae1680c0f252855ee863e472331f43a9eb8d3b9a35ac66c105ebb638f73bcc54a5968aaa54d3c45b06eaa8bd9193bc09d544364cf1dc5e9c21a845f0dd51cd12bb7ac04f435a42e1426846178f7c9922c4b59014c9caea3f771f11bc60742f6741610e0ee5693ea598a31a2a5ade05e5ed871f21783f8c4968030df392a71c79376891bdd838e22894fb5ff27f166aafb160095570fc908354f6542c7e1ee19b7ce98c55290123ed37376bdcd71d1424c0df99f8486e39688a366a2dc668ea92deb2b51596cc8a4916dbf533e4baf9accdc5e246dfbbac71eab539dcad1f26ab4f813053163657ab30430deeae9c4708f274bd3495496c23f1be994a72f7a9ed2d1b53c067c4b56c83d660a14e000926a7484d374610717b90c4ae4ea9c89e831a60934fae78825b04b4e914942a65fdc9eea2b684675a381d17ad4e048be6c403cfc4faa89bc370e7aa2f8e502e4ae8b9d242463804f8285f2d4ab91f7d2986f6f1e2e9195c6e411541aca0d465d9c13b41d9333ffed3d0b7a777cd95472f2b485f302594fc652b3bee1d2919e60b73f0f5d72f3071686dd7be83e32a6c4b9644599becf849cb66af39380aad2051c241e1502a0ef6c0ffb5b6a9ce9f9fd17642e10020a09ac2b98b43ec1484a57af9382b17e6f79542c0de50f1098b7bde9b22787c9f2d2d50718ac2243c2288941339177943b7390b0b55ad4ed1ecdd2a3a08eede1ebcdf067eaf087df875c26f4998e4f31d074de23fea333b9335e4a3d85960060235136a9a0dbf4974e5dc3d38861268b681ac24240d26678bc6165218953de8959e01c81b2977e006a1adaffa48c30e5b18daf7b4dcafbd5251e0cd97074c8a0f5f48fbf52d87bd2462ecbcc8e40904369f390cdf9e974c3e8f5fe1b2dfab79e0564fde624e1fd4a63d2a08b644e34b430d02d42c236445f8de5b03fad21202b6f16c2ae173b992a62d5e0677d796ef47f0143cbe4607d58392d14bd626be016d2f3dd4c4448ff195666592e50e0b58e5a0cab4dee136c4bceb762d115fe49bdb2b64993f68c88b6178e981aee33c772a02e2bd3ac95504f5c5f271aad1dfe92db29347d1dbdae6e47a101e13603b5f1133c5f3037863f0220abce9d622eb3b08fc4c28865183525244e1e9a18dfa9bd383a31555b1b63cb7f46539e69318f80cfb1ea06355c168302a909d57d46c17574c139a6af6200ee417674454140209136c485309e3d934c03d364ff6428c03ac85371438c70a680fa36c2d5559204600f56623e5a81e30a4fcd3b942608d500b280e752fea8892914ef8005ce0fa0b21381430b4983e0fff51f75b0c652cd7b0131264aef24c6ce4851ced9cf3e0e965be4d20709d38805aa4ef030a4f2c0b8c96d19c21c89c103b0d147c0f94166fe76dfb1e4631fd89e724e774f8810c128caff43ed25e8c424d441544f293f084ae169531010a6fc1568485017538a5038ad12d5c3b4754cec5a23bbf4979b345dcd8362d2fdaa635dadf29b8d2b96e74413d12fc512402b2c1be40542932a31d4588e15e41249dd208613bc53228adff37874b38034f75dab2e0d6b5020d93ae81c21fea460712cb2c105318818790998a18ec6cc493b58d7ec0a7748eedda8d3a1520912cadd265debcca808062c08ecfaa83025e03ca45f55e05318bdcdb0cbd9f1eb706eb908429458b52613af64d04e2a5f1188e0995fffb429b852fb13510927de586159112b8292aab0ea90526561a6e6609a983b1f7c50b39edba2303173e47c81eea3da9465b44cef7b9bacd802ce0830e48713b446091d1464d39c903fb6dbe11d3fae878f4fe663188b1573af76924deb1f73e719778965c2edd2647e644996a1d022045fe9c50d2f3ead3a765abe33bda171e2cf3c1d35056e7cc80d9e55fad7ef06042dbefefbd884c9cff71f97676e84394b258bf69da3c5ceddb8949c2bbff6b7e86c45eefd08d032165ad99ac4a25e915dd5aa39b207504af486dffd4b48150f22e54b5c186d5514b961d3accbfc61e086debb86772debc9688950501cb23f2112e0e03381cf135ee0446ec8891d19783be859134945e68adf2cd5207b3997f3df84c9c9d4f8a8ef51da5cd38e824292e038249668fb29189e7808689de3945e42bd5c7c5dca22cb07ae809e252561805027717a3ac9123b317b4ba45ac26a94fd596827ebf75f4ce6258fbdee31821b6d25e26af0faa519acc3beb2a5edecda0a681b0b02a8766158e5068a01bd5faeba7f072dde092fce4e81601ee9308037c156bf277ac321be4e73be94e4fc4c74238080c9c42d3aeefae1f86ae54fe67149b22036f99055af3dae8859768d2dcde877649a2c047adbbb61c58bfb7b2f87431731761238bd4ead436eac5610e2c8324ff8965273a9f802216750b2306832e2960f61952a6b849f1e06dc2c3a658f3a7dcb95ab53de091edfc1e6feb4243e316ff155367814e1424faf98cd98be3761b0e021de9ce1f2f8251fc51f2b40072e99c62040ff676497d033eb1c7d71267ccec06b25726cb6e92c03d11323047fda607c026bd96f9adf63a1479c733387c2c22c1fbb8f88b3e426c40172f59a885410215df81a4b5b68075cd8b017b47eb13ec48df6c1cdbdd824f902bce2b3914dec510ec330dcc2c0bc0089ed38b4eb3c11c8a9eae48b4f8f52702445846316811f0b562f4c11e73b6996aeb15a8247b57a1b864a68657208a899a91ae032731d49090b51c0efb0cb3f99b55d29324f5ae8bbb5d84c1f498b0288e193dc6f668667d2cbf920ab3f95e20a238a5a842291254d2622d212be727e918e803c4f5f4a6cc49254bbf1553e62f92af3e60efdbc493dff3d0cda6caba02d240c8a89536981a0e989bdc9265d193d570d8bfbc87bb5b401c884de74c31f5b2a4b266cdae870ed594b53ca0dc0106e826cb6469d5e5ac0fe933384b5b595d676dd6eb54cb1f38f4662c0d33c50478d005e3d91f4f0131a412678549e380c68bf6a9592949b1562495f0223671e18193ec6cbff5a8979adc4262be7720cfe475febf126825f39367cbee7f65974728bae62e2f9acbae77afcb86b2c875e6b21f094bc0f2da7e47992298bf144273b56108e02d8f28977019863096c80882c7a980c8b076544dd09fd4043b62884eb11b0e19efcaa7c7483668b22d02b6a8b182506b291b1c2aafed15c3940e853e5b909b108917d6b8475d28fecbd151464bcbe785ecfec77d9e12ae1890e872f8491bf51932d72c5be17f982d9a2a8cbaa2c3c8841d9b4b41215566b600ac990508214552e36becc4a6895bb6c4421cbd302e111b90caed1c92297d91f2d095daa58ade43ca2a66fd3d52547db04ddc803d0e40d559f5d015194013195c77e92f66f22f85486880c6e4585c91e9cc91544ac13affc98818d6d20ca028f9bc4d5adcdb32f3381538a1af761f9bd63c2fbba2356463d94fa8f5f1ccc9d869171730e1687b73de431a7505d6322e2fed8ae0ef85784bcbea758af4fbe03cef7f1a8b5ea533621769c1a9212b26ca98d9aeb03d53ec2dd0c441f520c970a82aacaf9831e5e574dc69306a4e4d648d901431ee10094559e78532b525b2daa933bca722c3137a72253ee65fd6fd6319f496ebb9bcf5dc28b20dac0541499b6a696843774c97ad645b70cb9c8d79fc48b307037ee1a7a828abdc015866fcbf9a15085604274d19c37ef520e71690f37216a43938e5627ba411f045dd03fcb84acf32ca13da7d9b2193d97a708a740cbbb1bc4de057b9692e12ba1d15d8d0be939886c1ccf883438bace25405016c110e0623928c3c5b3dcaf5a26285ae4002c46f3690623beb907bd141628c727de0d5ad41fa4fe8aee14f6d8b5cd853fcef70c56aa63082b203c7e9fa9080f9f3edcd93f20b8c07a187e309c92c9c37c36312d2349d9a583e0eeaf5e0ed9874f0ccccd28358679864eb3678d8a4d61b5048a8acadcc2d35d93035811c65d5fdea074880b0488c0080a086c01100c8da5fcb4adbd95dcb418586b65200c05e961482e8c4c0f93f9f391961b5461d1b8ea01686703ce7416a2bf69bf02c23930fb2019de6230961990d0841605f407f26942d162f97121a50fccf011ce6fb93efafa36621194c2403d2352145e4216eb7cf5f3f98c89886eebafdcf8602618dca449de0a8c5ad497b9674bcd4c4e34f3462e6fe9f5247c6d44324cf017be0a8ea92be5552a7a2b01c344ee7776c499f0caa51f68e7221d17a9908bd97f3e4a2bb4d850ee9150c62aae16cf4707241a3aec68adb22a8d832214f97224f9ceca049c205563580a365a37091c2be1cb4fa4768092c93d0287ba3c90e5baf9720d9401090f8c2c1443020004e458d1791afaec7af363f95404eb6ae0010d05db9df1f9271003fe8445fa24bba620d1b1f4c3422543c11caf3cb10af0f1f023d5b34dc72683ad071082531cc9231679d02707f95cd774da93b7545c2c1ee87ed305566de83b68d385a03adceee9541e5281f7bf6b4f5d3fd50226d84fcc0f056aa4a1a2878d70b0dfa2a16c5347fd189c1001ffe6410b8e826399aad4e9bd25fbcf9c9d7d1e9b38f012b2a1190dd4509ad6db31b99ea331931a783a1ee197ad49bbc012433d345e60e0ecc76f4b443911a4e799e2cd0e2bd89a987e50f00592dff16c46502971a468182f1631e54807c276ec16ab5d58d22fc82d79be4826ff6a2ace4603155dcb8077a7110d43002942a119f0ff8d08f8a078a213c1f2701600c05fb801d29184ca1f23deb384e41008b80668c52922a589fc7c262326d7142917e9db3b09c6dcb0d029a50829c0a45bf804c06a96a618273105108bb9170b55250c1ce48274f45cd0628d4032198313053386349f944b694350a08cc432288e3760334923e2ceffb0369d669d192be72f12d102039a1f97dd3f686f9db47f91d966e271ea2ab7e2ba8586770c33c42df01d14d4eb54ba8d235b24f5b6fa90c475bb9e57a3562c7dd5f0efbb81db9d1089ffb371f20264148ee9a65a01b0891646f5148eed7b9f7decf3c681832f73fa97553b4f305bd8d61586117c81e419ffd6db948d54186de94da5841553d22c95af4edfe331ae74c17620c8cb4a5cc4a2103b37eeb59891e450b3ea7347bdfb9fb40b5f204a21bdc9ea05f14f07a4f92f075829c21ec358e9e0259014411ff1da174d08fe71d6c2a0c80b69380c1c609130cbb80dee7b006a272da8eb32be9283baf2c7f872e16ad6d4a6e13ad9f7028840036ef73f88c7b0e744f1d517b389327e8142a1a94049272ea9d4393a258cb1a80c81a9ca53b092f01ecf2abb76874e740be10e53b51a99467b8853d338281f2d84001e42b525891d6bc9e1576084a8625dec1427c5a03a39f5fe9979f8d2b848b3afc10512d6180ee3021f621a2c02d1d21fa97206b0f822f6b154b4f5870074f337b26d2018475c97b48ee3ff03bd74b55df842597ca46659cd30b66a28bdd97ea85f429f1208e11264bc042de943ae942e7d5d679d96cf820e18bc07f46b98f196ce95d47d4c3eaf95597e03977832bcf40496f91d6ca9380418c481b38446619317d2dea33cd5cc619d1d618d609b4af1d327b71f5700b39a56aca30289132926c9aa75d577643a328de00f4048e99b12baa105388c7f5314396739de4262d0caf83cba539ce478bae3aaa9031eda0253a45530be833c9a831e81769a525e6d8c1c4c9c5f0500b34beba06a3e9ead827a1b43a6ac4a191890be10939db9805323176999c718f981f483a99b0589e0c68ecfa47bd4b1c4286a97750d3499057c6ae12a178ecc3f210e3159879560f406c8b446071aaefa8a335f38a6566422641d1d517f9f447c0d9153b989955ad637c04f278d7df021517ba8ecb4f319091f8c071b6e008776cf7eb3a24153582aa87f9327fb5b732f94f703d038173489e63ecd58a6100eb38267d04e956e07eb0b442265c9c4bd06da1a921fb3bd965608a3bc8afad7cc4669c35ccd58088ba4cbbd67fdf42a0146a87cf33163e9f7a4face319c8f4419e00ce32217d6f48cf70241c1cd6f29b4a00adfc6fbfcc4c2ed397c069c7e672dce4b16af3d0eec5d568b40bce580798d3e42468d609fabbbca8e49206c767414a769b6ca4e9abc1691226657bb16e61ed459692690be33604d9c056bf719160de987516ea2f59918f9f7123612fa5553c142ebd8cd1e70d4a611f1c5d0b8733b48964dd7c165f0e5d0e53bdc923f0bffc2cd504c82944462b3cc773c538e15442224323f85867079f06a189d3384a95b8aab40a282e836ab9ab45f49836b5202c206b827df84bc693cc4361a595ff1aa915750c0803e2a194de95a05b49b07764d0100dde2a18de4984984a43adcb8008c125a938f0ff023288ad4ce78cb6959d30803440c3c4dee0b366c07d8c5c3934593619183432004e13c5356523a023dc435948fc7be01abbf8e7ee22ddbe93c98193a3328f0b5e3c64e098538eb7c4d5144ec6dc80e30209889be22d9c9f4b1c051a369031e9ec4e94ff15871e98a939d022685a5e845a82b3aa7d5f40584f2dadc3cd3a0a0bef5a6050523b4c9b3e3fccdce7f621b706395758d9b8c36e2e45b262d8be6019d926f468b31b69a7e49c1bd163c3c300430c700389451506d928e7a487c2e2e344490edace265732cc588040258eb6203ce8730af62ed4b62e59aba3db90b9e806dec039a9a0ddb01bf0a7c64eaad3c56e887b31b0ee251f65c65fd549f8134c926f473c88d6e2c6b6c7d5d7659f61d620b622792fb654bbeb2148a323cab841f83bfa5f9e09ace3f963e25dd8c41712f2af8bbe0051c5b99ef3538da4a8795dd986484cf9baecc6f24a32f323cd52b8ffb619232d54eab57381a64e70430fa3c75e591c03927e3cc90bc8b0bc85a868103542524d21f22956811f3648abc90ef0df8cca200b61b63bc992a3982c3eb311935f894ac44445839c61381abb330e716aa16bd1ef04503bbf4d811c7c10d48d6310c5d3c0be0013045ecf1eed2a8de4b87bcb8232964b2088e9eb66abc0e56534b56699ab3119b7a26693cbd665da51f347e15224e24e95fce2a8d7d5fe05489d80ba391ead7ccb2719f02e75c7656674ecd415175809d5a10f5005734185d4792bc94bd4036fb52d110e891852210e27c8f01f4e06f7e76361c69a3f319563a73fc61f4290c357265be61bdbd98b3906f34251cbf2e05a952c51e3ccfdd7cb8850b1de4db8e53abb064e26a7d797c31a584cc9537d74c6bc49e25e49a458cb2996b655eb3fa0bef3608f87033911e22ce42bfca943c4267d3480589a8ad0217e62de8b5b1bf64b19a33402ae2d12aa468c794ccc52d4194d8626f7047ce570b005c61c5c1f2c4e37680c42f333a54cb19d0b3481cd0163a9bfa4c430700f4b3058e84863ff9c8b75957aa5a1606bd5b1cadbe0f2f0c3668de29ef6f2aa70cc92b76e866e194ae406da39429cbac3ab40db0c4963928224a4cb8c6c9fcc93b9cb3ee0e59084bb584b7bc308465067004d1dd8149dfe014b2693a150818f6981773965f892077b0e0e7c58f503988f61cb6121937bad281bf66f8f58550540e859018cbab618fea582296c95804e16ad50f74bfaae1e4ad8fca8938c8d5859d27ca91f822cd53503b016cb90b02ce1fd70072581e962df1f1bad4f80cfa764474a9c5748605d31e86f202993b6746ea65104a5007f67c7e372da5855444d294e9601c4c517f42ea4cb291e8a61747d6e4a9e2aa967e2367e028a5e65577da16a1f02f3906d83dbfd54d5ea671ef533ef4a8cb41edc23b9bcf1655b9a41478676963d57d00a67611d1ac0ac5529182472cdf05a7b5ad4112c4b6119eb460706518bd435749de548d102a1fb8741fb53fb24502a89e3da68c59ddc500f713c096469fbae8f6b3ec6c788f4f739d91b650551b97d0bf54284c239f1005c47ec1e4ae4fe05e789cf2bddd19d14e0209246e511e7f6f014c2046510a24463111fe5573d43ac442e6d8ed982a64374b0b3b1e80aa30dc490a2dd1ba92ba060c3c53a2dfbf7c51d5ce703708ba5d123802efdc0ce23e6ebe8b19c64d3ce1c803ace6b0e2cb64a0fefdbe1340e17544be5722037b8b2ae5fc1014d936c503da9bbc09849b37c8c5e37eb78842fcd501c5288d2013fd0e8bf01e83702cf17e4262c1c17777b43db652a65690bc2a985f852fdc158d36223cfe9f794b6cceb0642e01c029e023ef5e8ebc6c5ba1ae151c16e1d0a04dd2bb6690ddde98bb01ad63019fba98e9a82f913d0c97187e3752fed03bf520c35ef446fd9f76cc7111385d0710997ab51c252e151251c67581abe90644a27d2a9384b2f417bc38a42d793803896b01044055cfecf1328863cb4fcae8dc7eb3e1126de147eebb88922b4d87797332c91c1772f801b8900e849c4c35a8bed174723b771e0529d346aabe4224233e15cff5389ef36e5232025e0405be73e416342e1df0c07552c39a460bf0da8c3c655f4b6bd0cdef091059b3b12cd4534d9e7c6bdc2b153eec49473126d50377f3c159e5e57a048b59fa8a16a53fa19100f600ae451e2542ef830500628d20abba5d04ad0a8ed54028c8c0954daf76a4eb5cf877991caf0267459ff1dae6f4487ec670a9e2f06fa740820b223dc30c4249a32e5d7258ab26f5b64dcaed8112476b6672c71b2e526e05cfb93acc445120d8ffdf82f673dd182549f323f55383d2b34ef22eabad1e5e44450ebb4b79ca7345656b2c638e66171eb6035e529370ca8331138a7df21c40e17451d2638914d31af87a33c3d173bbb319eb589ca5a161833d51b61501d28eabc7508ec1180389180ae70d0cc471d21a3e3003b765428676a9428181d602187cc45d06aa58134bcd1e6674bd216c178246217849d0b5b1c1fcb881f7caf656481c9c60769d1833d8807ebc00efe779f0ede98e0c7e22022dc60586e83122c9bd8e266f0449f85162b2bda5de322061723e3da857966a5025a7a2c17dc707dc5862a8f6b1d1f99e22e484c993b288c9c38552e3c740aa502677115fb4c59c1af56b4d531bd33687f88192f5610626b23342a285cc868e77a4e09497a741ff060c88b0332446cc81d0547fd682cec464144b732f4d173b3a0203b5402e7d850d00e15ded989de9b389fdc2868d796d80d9f186e88a922a6b56830112086c3027b4b8215f72101ea1a7b8b169a3382b882d5d0343f58908c10ce3ecb1c5925895ff04cfe2a68f2ebc9e3887c6e7ff918092ee7f882a63599bab73e8dff3b309f40c64f2f2ed5ce4e9cba9f9e06a6ebdc0d7acdc214b708d1b6e64b60da4c619735cc0b052e6604e50d521078669c0e2858b89a86fed4d868e3d4d63ee9f98dd1cb506651360adcfa836bd8703996cf1ce22688d7c3de341ee9e867f317ea846760b00287b6b1320f98d80af7569c52e07f0b697befbda59452ca2465ba0dab0e990d5acc0ae82292023aec9eecfa45e8d0ebd9f52720014d1dc40fd045a80374881b509f081d6206b476fd21748817a0c339d3d12156800eb3103a2c01edfa41e8d093edfa4174580adaf513a0c34984005d04880ea313b2d8f50fa0c30e68d70742870690f1d9f5737411fa832ef24317913e7411c7d1618a0bbb7e0174f89b003aa42c1da6acb0eb6f1dfe8d0ea314a15d7f003acc3d6ec4767d01e8b0c58795cfaedf830e6b78767d1b1dd200e8b0e3a1431d41bbfe4a17a12a1d4629b15d9f071dce5061d7dfa18bd01de270edfa3a7438673be890eaa08bd01a1de29dd261b701a0c34944d303b6ebe79889edfa333a8c5914edfa38743867281de20dea10e7a08bc87d43879a8c0ea315367418d780830e65159f0ee517b40ebd06af43e7a2860ee7143474a8c5e8305a01a3c3b8862abee03530e9d0b990a1c339450c1d62175d84b6a464bb3e8b0e3ba25d7f4587dd6cd7fc85780f75b3b98a49dceb992bccaadfc53ad75c4516153ea42fec645dd06b87b5756123ed05956a0c2ce88b224df785d7daf53d1d59f2754514443d60ad94ec8ad8153caf9c2a3d1f2f9b088d2dbf1c97834142400a238c30de80753885b6fc463065044e5ef66d51c6a158d89f4dc85256e93e2232b7e4008dcd048d2d5f6e2edef86675ed41be366ece8631b05ddf139aa82ab7f582d490f144017939584ff6e356821aa84427bc94a08627405e392e39137395cf8d238d7c4e469f33311224e9f922ce95f480a0d65acebaa7433f4f882f74e207cbbe446aec0b82a1d009d81e7263db0eed4b04b75a23d84cc8973b7a4098b6fc62a4b936c7e560fd35f8ecbac3daf284bc9827f382bc28114a11d1ae5f796acbcba265875e9047655720247df9d11ba27bfa1da1df7d71be8c1d5d663156d099155fb43c8f35e95a567c0185cec4a21497cbec095a50299aa8fab48341e185bdb4a8c7c7f5d2e2478b2da2a08489957a26e632b33ac71503eb017be1c458ad946c0c39422962b2e78e50d4e0c48b85de948bb3846ae17deedebfad7d5f7a3fe4beeefd90dba79cb11b8520d831d2dc2f949ba62951a4a96f751c42fe1471b2a31b11143d557a40e6e6a6a67fb5cef49956f64c54fd29856cabf5eae36a63600ed6a7308f0a276360d53f06e605b9aaeefa5e145745285fb8767d8fc803c3575a7d2f0b57c52b9e10da2d2f68d71d7a42b35dbf28c20ebda15d83be58c20ebd2f76fdd08bedfad7cada7af9fcfcb82a94aeca53bff654296a925d6176585bbbceaf2f5d7345a3147c90d09d0c20f19d5b1d0a4b98c28d39e0befd8ce489e5d59155756449d055f41d48acb2e977c4acb2e989d2bafd7324d9fe4408f11585ed70e7dc613d34d8618ccda090b2c34885ca19c2ec27008171957ca2698349690fae40597e88afa6784bcf7e8cfed4c7a77cc2c59adcc2451b218c8beb7a40bf7ef7de1ee490ba5c55d232647ce9c1b9a21e475f73d5f29a28c72d41a621386f21d70fb153cd5234512d2d9fb9e5b59df4b59cea9f7e8735439fead3df2191f42988194f5f67c6d3cf4893fa46e8cff8fae9bcfce93372fa976f694d94b3b84fa9a54bb22a2cc76e920ceb96174d9aa1e96bae3c9bf0b7f090c06891e2cb3c1e4e109e28a268e99928947b3f5a9e8820683d215a486b8828cfb5c3b646e993da514beb2322c3d04b5e7e7a9d122abc1f998912079d5414697a9063fcfce8917e64d2d7794248d6c90b72fae815cdd5e9fd7ed5dd93882ca968ae5ede575abeb9827f6a7d13aef5f1f7539f847f8242da73fae2ac5fe95974d8d2437b5a5adb7f763ff91592d6d0f24438897c7cc8f8a812d0bef7593755fab3fd5f66967e53f6ae0a69cfb6a6d2e7fcdccb0debafe0d47a44e975be5f6bfdee179674b833e466661df7dc9949c8f2bb24e4b02568fb3551e175cfe9ee39acab900888767d96d9ae3f5a597919f547f559b00744eefa58cbeda3af5ffac2187fdf7a4058be964ceff2a52f6cf9fb997e3e93cb412ffdfdd273ded7fcb5f44386b1f3e74386b157be527d2e1fc0f45ea90281ff7e27efebaf3cf7579fbccf7f9f74f23e1f2b4ffa7c7fe56692b415d3fdfb25c0f42bdf11a6f7be2364fc4a4bd010da734d1f95f1f6a907c4cc91f1c518dffd952f74f968cbc7c4dca3bfef1e90d1b37ca1dca3910e91ecbab252aa9b074498bfc4d5fc2b5f1a7de111aeeb705d297de6bef03e13b314eedcb8cb55f5f35abf90896972997ef087261315dd7cee39e97dd5dd93484f5fb8925ef1517f4597fe45ae442f67ae68d2cb8f952f1c427b4a1f90eeb94a8ade77f5b9af2bddcaaf7838c46a9f3def3ba23ef7ee01319fe37c944aa5d2d75a6bd5a32f7121f71e1757bed65fd11d1172fd507a3e4a9f4b3aee8ef4db671d22d95c189b0839ec00d10eed93be21b467733ffa7067739dd6f36fb881a1100445dbbee9679a5c2d41515a84bc7e4dc8edb2e7db4a6bad1fe98471b5d4c801176d841bd1a6df6cca2a2ccfa70e4ed95c7985651945f69ff3f2e4f0baec5f170e4263d5efba268ade10647ffa1b91742bb80880ecb1189ba822ff299b923587badfbcf79f559c34b7106d9ac83b0bb18791471b6dc6f09c79ba7b4ddb6dbbb74f2255521dda1776813c3dbd98bb1bda4490b436e99b557c93f4ac1269e48f6616624a7adce3adfb9670f6b5fde66c68ce266acab09ef3dad99cbda28d0f66b1786dbd5c745de68442ce8aedcf11613b57c5760ef6dafec23fd8b53dc9f68f219e62e315b07c8853205482ed18053db47c8847e0f22126418845b0fd6388a1187d78df2063c3f6bf43d1e60bd186beff05835c91deef107ee2c3ab86f0ae61fb4d83196e2bd2788c77195bc6f6185f8af1f9a3f1e14f2e228d7f8b9e5488297f163dbb88297fc5c0bcbbc068df941269fcaf9e58c494bfd5538b48e35ff584424cf993f42c8244f9533d891069bc85a5c6cf18cb8fbe1adf7daa19c11e396148d8fee1cc8e8f8a3ddc2732e51fc31b3bfe275557e845aa6e2ca4b1e3e790aab9e3e7106de8cf1a3ada8c3e8631760c4752009115da1d5f46b4c11f7f46b489f1f157a4eaca48d166fbf8a54daaee2cbe943d222b3ed7e9d875ddfd71504fa048331a7d9c50a78bf8b85ecc279dae3df07e44076750d7dd2f7cdde80e451affd10b711cd775dd90ec216e7f4e684ea068337aff498468f373a97015f70e743f9c52acbb4f2e66f89cbdfc6d29717056614f2ce40f27155abe7046614e61fb8482932f9c4c984fd83ee584b2fd2712a4ff2c82ec417abf3edb6fcfeb0bef13db791041fff0f2dca198abc45557c841bf3107dd7f0b2e4a5a98c81e6e1499f287f9c29985edcf9d643c29c68398c57cb99429ebd92f39b6fc19396cf926f95f1305b579cc6c79a36c7f193a4a1e728d2be437b6d4725f21575d2531575d260efa75729f38e8ef22d422e3baaeebbac70e761fbdfc37de7df7527ba491efc5903f7ad9f2af92131357c9f7272edf45490b131627db9face8920cf9a428758476cb77c983fc1b7b91adec59b86df934623164db475bbe37fabc399b55b44813f32a8c0e24e7fe310e8aac75c3b85714a2d8524a29ef1d420e39d95c71429cd016be0c5fba63d2bdee11fe75b0af631272b297953d84525b6ffb8e8ad1d728727ef9b55b820e94ec1d765cc28b68735b47b3856dff1ab402ebc9ffc2d277ddd7c1bad748774c4a4ffab07bdd0ee6aafcb3f4db87a42ffd11a41f71f90b495ffab820d2efb849de12ef3b26bef27e7ef772957c2a8e9a51e4b8e5d69efbeed5c138edeb5c0e869c1072b8b3e5e30fbb9f3d1f7b40a84cf9cbcfca94e7c45ce5df74fcfe0de9b6f637e69c10ad226b1f72425984dbdfb87d61c7fdcde48486745bfbb81827b469921c764194d6a7d4c3a95d50f7a4d65a6b17c547400e724f1c9c40bae7821c9cb1d3bfcdadbd7b38da4b3defbd5f3d1ff839fcdcbdbf5df781abe2c5e688bed841e080b8ebc27a527170723fd13b20e761be089ed505390f53caaff390936d99aba8b8aa3efd298b3433e6e074f799c24564ee0df89691663e373ba9eb4ee2af3d9f93525e26fb2a719093d37d745d5e8c34f3ab923cbf705d92755daef29fd7b5a7cf7d9de4f9e18ccd9ff3fe449a39631365a90b16e69c13fbd39f37e69a89796357408172a104054181c1a0b85c502e94a1a1a2a20b452e818b00c873c617eeec197f85e60a00ae1d69cf8e4f5bf3638e8f341f6f7cfc393457397cfc493457331f7f16cd158e178f30c7cc064f93138d8f5f335736eae3f0321f5fdebe8c36e05bfb85f7459f3627bb17fd52f58c69daf805e3178c5fb48ccdd5ee45c7b0dd8b7681f9362a8ebadd8b6ed91cee5e340b0c2848a889109175a3547addd0d467a2e4d368a017bdb24d1cb7c9b6d936b4e50c00e9793807399cb3175dda3e3d2fd8088888f493a4694f1c351f464f20078b82729037d791f60dbd056d425b6ca2645c9f89b2459e572a95700e7298f78b1e01406f401315e327007a5aaed7083602ca44b3ae9b41317a0265da12328dba17edb9b6cbcfa7d1f72787be3e23d88cb638b49dafd16b038a3676126d2b1fe780d4bde8ee869eb38992311a4fd48be67e764b8c0dcdb566441cb795ba17adad742f1a6f1896ee45df7dd2305d8bdd55f334417d4490b436eaebc9e4e1c0ccf07e881b071acea5ee1b7af4a3472e9e102c81c3df60199239b86d37b42d721ee6576d8980904d9668ff107ec12f2f2f2f5c8c8e863ebdf6ca7c1b5a466f430ecec7416f55dbd9fcf92357b4b15aa4918ff1d3a081699cf0e954f17ed17473323a19fdfd8b9efba497c4bc0d1a7a49d53cf51f07cdd344d7783b9b2b4b64ed6cb25e3b4beb25f56be8259668ae36d944cd8992bfc9ec4f986d3fdc66fb657fdf6b5de3ab96acd3a9c69ff43f57e3f4a7d3b7a4d61a5f234e3aca0e4a560c67721dae3a6d1f77125f1fe78b221c305cc5e32ad9e3430a1f495c75d2763e2492d0433404bea5bd284a684f280b072b102007eb2be03989659c2320b03b333303a507a603d2091ee4b8c378450f98177707793efd7b83acf3614a36b5902fdcd942ae0e5e0750128fc4ced7d7e1c4554afc91afaf03166d646bc8873a80b0ebeba822f630e4e76a06003b3a89972d6df79124debe124a7c3227f136092592f85abafe105d8489bcb9df8826ca7e0d67649b56424707a96e69baa79e435107fb3bdc9c3968bfb993d07316698e28f145078fe8b891d071cb96f6ad0495cdfd102b6c8e8bcdb5b4dc4774dc3b13094d04496b27f12da116893fa291f8a62cd2702f5bdc7d659de7be90090dc70ef91be7386e880e91c8e8711c677f7ba9ed6f3a078f4cc9ebe1d82f47cb412b7fd39a08644abef6713bb1b9973a47cf96a387e3368d13f2793c0e5e1d2141f4449a7a97d0d0a464f24b51c94196df81e1a0d772b0f2cc4cf15564551c64f91d9183d4c3915f9183d5f70fed0b3df01c1007be89a7dffd104d70e09bb389d2bed39ea698a460a957a4a933b18963666666a6b5c399588e9e6de3b8af7595ccc4b61c229029232f441ff9e8e11cf91b4fc1769e09bc9128f1f5534c5c55a4f54ce02d9ff8faa957b441e2c3140f76fd940e620f48c41c29a05d77b4125d1ab2122f5fb694782e7b38b2f5c9acc45bef87b8956829a16935c6228d6e25f4f4228248741378ef7c732882da4fcd3389a20eda8700498b35f78e9e43f209dd04deb2f5cd2a11d4b46fd9d21e094d7bb977f412fa48f4921ecca2af849e4313a5fdd4da9c459a7d6f90b51f22e4877c1249fcf47092784ec8d484fccd1c2264c890bf9949e80ffc100d82770f0704da1fd19e11dd81e1607d10e8ee8b0fe8ce0340983861f138cbc709edd233510be880f68426ca0639acadd1ac888fb308297a7c7a66a552a9444490188ad4754373351bf0d1570d782efe682f89478597c4c12e46bb15fb2b1e8efc150fc77ed6e6bc645a7335838563441129599c713656d9f63b4272dc07e4e5a0e4e2131cf09cce5d175472d9d6a545cada62e964261659a6e5aabb2716357891aefcca714d9fab6fb55a2160c508e29e4ccd52321a482f36512e9dcc55db7352fe35810e180e1c38b60ff1c6f1717b1c614ab66ddb364345fbed794c79e34cf9c1053c3832fb29b9041338b2fa7706b2999829461507abb5560f99457b2845450c1947e62038c130877ac0a20d8ecca3bbbc0ecfc90ec86bae666272e6ca20e7bc64741fe5b80e301469800871e22aedeb6f2fb5f69c16f29c0c0f4788906e7e373f24b487d592da6e2154d895cfea355727fbf4774e3a4670b8bece752376b2df2988eee7eb743fdffefc8c34b19fceec8cccefbe1d96fdc20e261f098d33e5c2c087df18f074df44c7813f32bf6be23b429f03cfb5ec1b0c48c9927824bec6f8e831fec220dbcc6a6abc5310f3bb77c074007d0e7c71a23821385a427e880e77f690770f67c8cb70d3f70561dedc6b425ea2de2053429ed32108b485fccd1ca293f87062483c27bb2490f870a638f8d2019babc8a23a826eee4f9e385c1325392b394e721a76851880382b71b8b4e8623e0786f8e8abee87780e68199fb9eabee8a8003c0b8e6543ded971a8164107fd2db467cb64c870829302929192e10549cd4c999111f1d19b899562135527157288c3d582bcb2eb7333bacb821ccaf8ecd310f3bbefbe232720b0070234512cfa75311c2e1cae9cd573328b12f8ecaaa3b3c56c66364547a7fecc94992a57c866260f47fe984956d003d603a6029b598c0f6d6601901fcefc10f68005e0c31e59ec9c0f6762ac968355b68b1152d1db385b44b07e38b78f8f7185f331aa747cbc6cda661680afafb3c58fafaf13fb6133e3be00bcfd02f0f20bbd2d7d7218af8032a54c2cac7dab7f4ae15ebaa27cf39c749feee170cf7994d25527eb333147d517f221ce0130a9c29958003efa4ac6e6a3dbbcd53c7c70b0f2d8756e2257715fb84ae36962bf7e4d6bc88778f7d0c30379cd15fd666213e5aa215f7450c8a7e955126e097daba95ea5640210c0cb6fe572b05ab9bf0265fbdb735a7bee5b2571b0be0cef87b8656c8f57543858b94f72f676138bac6a4256ddebfdf09ca02925afa893166fdb9f913f13933328366ee06033d431a1e56f40dbe75e45e4ebcbf4b8aac8d79791c2559189b77a03cf69bc392b5cd0ca71612166050b9ed4225a3e116d735647a11180b1a596b139d9ad604b5d637353469f7494e242a8e7075bea199bbb8123437553ca4d018ecc77c5a1c26ae5d0dd14e4b0078cc3d14d2979a6bb29c8407880f40069459a1c25392fd4472fc7b583ed01e42abbc30ecf3914acd65c4d89824c7b3ce9e1c4559e9785cd8ca3e9e6147218e3c1e6eaa4339fcecfdb61d58fdea41286242d560cd044558ed30e6839015be2442c8a71e2206b033b5b7e314f1cf418a5152201d18e58b4a147c78e4224d8c18ef156ebfc449a25f4bc76dd5b70f193f2c255ae75578a9c92c91efc89b992ac964ffde0e04e6a21425e7e26c8550b39ee3025a39fc2998223c389711fcb67a22a941f562bd294205bab573e3260323e2b1f199f950f37f5944d94fd58aded3ff5c5b68d662e10da389c188ecc553854b81edc018ae2fcad43878e8f7305e4d5cd0fc8ab7e8e2f33311b2f5c25e40be5cca68acd90abe48d2937641ec77d11cdc413d11b28a2e326a2e396db8e5e02ecfe15e4df3e28472b64a06407e199edfa3a248934394a1cac39af7a85bc0da5887609b2fd30259b0228c66c8a27f84ce1858b4fbc711df553b2e87573e6a4a5bef87cf8d652b2149524ae7229aa69cd15cf8ce960d7afe9a991c2573c5e8b054bd8f56b92f8aa73a5aab82a2e81053cdb59f5b52de795a3248789ab2216e8dede6af9405e9bece1386bed77437623e6e08dd48e4fe12875534a5e7dc9fb21778e6b033168ae3416b67624c3d81c4b37a5641f9ec5fb21f7ca47935868a5b352728f77f17ec87d6346855c89e68a16cd55d7723917baeba7b2106db4901a9aabf9367407394cc9666211ca1d410e53b2942c0851b4e1b82c7218a1b4ae08720f580f18f7a5645494e41eb09929ae9a6fc803c0f66bb491292abeda58f575d8f6bcc145b4b10318c0003e0ee0593c1c227273cf390fbc6dd549cecf8785220d90971272a0449a95cf5c619c330fecd51ee4b0b654aa0f53b29c1c253956441aea24eb00a2c2bef129596a166d7cf340c487dcf6cbf131f7129a232365fe7e191ff98519870b025f71366d08fc6cb141d9a0dee639979a6e4a49c96662abe884d76a3513cb71a56443680f8eec013166e8ae311db818a34b943ebf99dc39ae78452c0f61f5b82adc9e7bfb439e7b560fab1584bcbd7348dcd8b6429ed572168f77b16b4a166f2cda6c91f531b23ef5d2c9b408f035c4310810e309f0dca9dbb6e7382134568e8b278729598c4fc5b83704d3c341e267627346364325f5136de24c42be50e4702636bf3a13fb5c9ef6a4644f3cf7f5806ddf10dab39178f77090f87a003938447b316f8a83f585684fe660017ac01ef0b587a9ab1e1074fff0a3f3136d248e1dcf1980bb51da15678a83d6e5571f3d1fa46d3f20af1b410e56d50dd2b63eae22c9dc88dd90bd040de0391ddc0e9d4c6b4f2c728c4fd197cdc500e488851798ec88851698e0d8118b2e28d9292e62b459e263183d45354f10ad61a80cb32fec1aaf90edfada128f139bab207c26aa3ec6399b4c3e9e124108c9902143860c19321efb449b24be9a5aa696c9643299fecaa20d125fffbaa2cd90af6f87a28d90af4033806600cd009a01340368861040335e5e5e5e5e5e3ec69510441355ffe52d2cda685fbf16459bedebebf43abd4eafd3ebf43a29e075828181818181f918570a80f91a146db89f989f989f989f989f989f989f89aa1f9302c17f9329d3a0f131ae7468d496b6cfe90bfca631f09acec00bd146fc10ad814742879f843ee2a7a64a68b983109a2b1cae88aa8f71ce26d3ff0465645a322d99964c4ba6b5f20102020202ba618371ce26d37f0f560a04ff4da69c31ced964fad789cd154e6ca2eaa740f0df64ca19e39c4da67f299fbb80b6505acebae28a2baeb8e28a25b47d2574dc41f8e490834f0e3e39f8e4e093834f0e3ebb7e10423570363d58430ba15d3f09bdc350ebbff5ad6f7deb5bdfdaf591d03bc080b406d2401a480369200db4eb0f118208e39c4da6ff0982310a44bbbe106d53c04b01331b29f04d19872d5e29f04dd9c616b35d9f933a3f3a537ea64c993265ca143f02870bb364fe655ee6655ee665fec3d40ef50eb048537f863297b5f2d17ae5a3573e7ae5a3573e7ae5a33f4c6d0d681d8a224d7daa016d573e967523f63dc6399b4cff1304bf0f5346681d82aa1119d03af4dc885596cd0c87af8f83cd0c079b190e36331c6c6638d8cc70b099ed0c68fb18d035311ddacc28ab07cc462a0582ff363e34d9e801b3f121de1b08fe9b4c39631c53a90982ff2653ce18a76691a63e06b47da92fa06b7e224d7daa278bd592b9f129f04d59e6a1b4622a0582ff2653ce373ec41c1e71df92f9f18a9864811fa3b6a6aead89aab06c3f20af4813460ea31497135e1078d4e7b8e68ae21d2e99bf847ef38bc087333b76ecf070ec8e192cb7fc0e4fbe4ccb5524999637daf565787c95a232e3ac23f95452b2eac2c51883e880c9b410f021de0c40c03340c71307750439587500459afad20ba2033651a9998335c6479c98836fc8e14c8ce36126b6ad1b3290cfc2c1dac52153b653b31b4f51012387d1092f20af0314b5214f202f575926aee260ae9240aeb24f8004011172d5497e049285ab84c4a6b88a8aab84cc805401e285ab4ef64b79b153440ed6d4506a96aa92a2e2a5646cc8f2e50ea31457989245e0c328c595800f6762517674322d57bdfca85b7e299910723813c389e14cc1304e08da75d7ccd55c0179f90e10f8033c107f800ff106e2a31fe0c3bc8178aa3da1928b87aeb6e64a63d59769a9569d4c8b0b4027d39a2bcbaa2fd3833d213456cb539d92e9d46ca2eaeb70451b9b9261a148533fb626aa42e043191fcf8a4853bfd39ed00d1b39e000a270cc7c3974ece04155e99d2e65a2b671dd4a096614db2fdbabc0c7c0a2cd85c20e5d663e60b6fde2042ca0c309bce772d5cb56b29c47c5725c1a887637f386be90119486d8aeefc526776d0ccc554e5c15af00e4aa952741ae227dfd982831423159b82a065d749cde9ac0bb7e9ced269d22aee41a22eafed58a484c1cbc3f7afcbaf75d68aeb6bfb2c8816e4bd6b3ef57bd6dae76d4f3e13ebe7da2cd56cd90e3de1cd07d91e5809a89baef7da7cafd10dd733f04f7dd779f034dd4fdc8da6ed1fd7b6592c8c1fbf893430ede7b9fab9f2c8a34f76b1745fbced58975eb770a62fbee87e0defb8ecce7bee3be23f4b72fb2eebdb7de7aebc559449a7befcffbf44e91edc77da7464477e6e4a470d146a811ed68a36dd6a9936c45b4ef40aeea4c5cb816765b93dde14f441afba6b9722824cabe75156cbbedd05bf6b9303c116d4a6fdfa1903dacbc7de7f155cb8ae54397427a3f7ccf2f228df596f3687a6e1f2dfa445cf90bb4d6c6980a9783f6f1e73f0eda3a861cfa8febfd67db7fe32e3457dedbf7a0b9e2debe6721aa1ce6a07db7160811b4cf75fa8439cdf21999dfbd7c4f53568b8e13c5a2e34495f48a6e226ffc69fa9d9e5e168a6d20eb93bb92f68d714e41d0f77e08fade37c4fc2226ca0a4159dee70e3451f6b3f61b3a90076dfb246ddf815065dbb79e850876218f3eef71d07ead5cc8fed2fa4f1779deccd509bff73b2c8bbf5310dc77aff3dd67a409fe74baf7be9b89b26f843ef7edb0b0b5ef40f60b25900483478d83d6e20e6f4eeb3697716e7594824cdf37d67757fb1da11179b55d0eb8489271474a290325408182a11428d961e493567bb1b6719d371a916e30cb51ce290e4a998c85218732b6e5cb9732192485ae90a3fc662ac8b112ec884519d8e002d28854317e2d0abe31c6dc799cb779f7b5e7347c31ceb163cffaae7df8a35670c9888080ec914984cc39270f1f62949c354d23edf06cf80a868818e5663e1151769e9046179b4cb24d6fb66fc6282e3c86d80b78ae6b97662ae5d31dfef1f876cc2e7258b3fd79b84a7e8d8377878337aab4e7a4d63574cbedafc99473fcc2fbda57e3e0056fcdbecfc35579ab20dedfe1ab17d61d020c22ea659fe2aefa44a1dcbf7f9f42c14ff3bc34d3fb1d11832a12b69f8fe34afb99b91b827bde38bbc8f1278ca925c7586bac92457dee00042d0f6bfd79f86004130500e394a0288bb3e8857555887380391c8c3466fc5cad1e10a46dc3c1e92d4102e6e8eddf92d197036bd08683b366cac41e7888a9f91266cbfcbe2a712fbf94759ca8ad7b0fac71d005d97e08e67070be8ea07c1e5366cb9f0fd8fed3e331f1aed503c26eeefb4823f59613c0d9fe5df50ece6dfa053d470d06b104b77f36e63f952dce710d7e663106a50a2843509282994f0b47e4487316dddddd954c7ff9f425de717ea1fce66c4a8905e5245e82046435c1ef1e0e7e1b3bc696ab65624abefb047d6c5d1beedfb809e39cdd747795da5b3d04f4718b5050bb1d8c690a3963530c0283933773d5b9fc02384824ff2517833c3f1e5f8d83f22d0c72fcb046b6ae98ed494468a9b5f1fd5fea87f183384844fcf8337e18c7a883e838e8f375de9f881b8310f1f1f89a3c6b7e080a12636c8b1cc4553a44c4e2dfc41863f489c10fae28029536cc1c33ee989f5b4c30bef2b898b1c5f83231f1b57342c051f3f15c193151f32726e295c3183302f3d8f47fd8f271fc708c3a46607aef173a81378d3aaeb25f6864cbf77282e8605d00faddf0f0c155e00bb23402e7a14b6f0c463e5bf370aeff887bf45c9c1d4b932d73ef1e0e776ffceec7b93222a33842184337a888d564db80dc31de3d27958220efa425cede207f2865f3bb1f8e6b9cac4ec8bea517e37d06551dd42aea6b42616b31ee8ffaa24444f40bd2cf59fae8adfc8d73b78bb9f4d7c3e16650d9739571d6271d1c272aacadad3dce8f442bc3ed3a0e7f968b2cb8cfd686dc055ba342f6bc25584a5cd5d7e9c3abc57ef9f0cab6a6dd285bbb42249f370a8f160dd1cae6e9e50b499bbbd5a74e515d5ed8f5055b7bfc3708259a286ddb58d3a289d2ac4c7b6b831c52224a146de4d69e9661e5a36bd8da135bfb18579504338806654dab5a645b831c5a996ccecfad6c7a43e0b7b289d26650d6d17908abe783b4bdc795c338c45929b7eddfa863c12c8fc49a6188859b6c4f9d5c19c48b83addd265bbb41d8dadb2b44eb86b802274a73d5b6b5b754a24ddc9a45c3d6ac18b666b9606241d66e145b7b4b831c5a9925b24373d5f21a7e2dbf367368bfd8da5f5d8d907fb7683c51da5b309c7ea1294996626b537b3b831ce2adbdf7ccd50f9f1057ea24aeafb9c29f93608a9e3a84adf9e73d9146fb1bb7320867909095cda019c555a5d77e562b8b34da5327e4fcf8e57b2b469ae8e4c79f1153d119aaf861e52f4f94f65a35014f102bb24230c30883d584f6b88a948030c64724c73f22338c30de41ede9bf681b0e6a6fa9c8f2e937dbdacff8a4cc41edc3b73fe5477d197390166d4df37150fb25f92b14722c5a626573657a2dc6934a3fc457f9b537c255dc6b9fd55cbebc4bdc8a8e9b6359d95cc988baafcd4a43578b51e5752a2e87ac545a99a45ced40d0ed6c6bf4f34f762c1a0929c6ea7956fe15fd23974aa552e9f3ccd3e4e6ef92b48c34f7a937fa62a4e1defb10dcda4fcf7b1cd4ded32e85831ae749b6f6b509597b8b71ce715ad9d6bebeb4fadadafb16b5ef8891cfbc17cce20a23c07c5c3e3294e793567bb1b6719de78d6e08a88d346feadba9fffd6c78fd6c38482b359972beef207d6ac341faa08314744adf06e8aabcef8d4562f8d76c81a321edc1b926a53ce286f6273f7df9dcbd3b7a1a02e4d63ebba377809dbd3526eaa6392fa98efa6a28a5411432fc487ff92da6f8d914850caf6da3f64073f0624ace48e34f3de574d329a97449a59c1f962fa7115cdb7fc6e769a23d963ddc0f3dc6e80121f7f685f2d33fe28eaca9a5bd6f71de72497dac676cae62a6dab7dcb73e9691465f57a529c863e0e2fb749af7fce274026956c9ef2ff7c3d73bced90cbae987a31deb8776c7951d4b9b7eb8ed8877d4545182f543b7217dcc79341a8de41c8d46a3d1472fcb39f34aa619af3ddcf6ca0e495a303829a57477ef72ee2a2c09b5d69aadb578165d987f534bc618e38eb66c80e0c35418a5159665b7e50acb94d62b32fd7ed45558ee92d07549c825da2541beff8c716b45222e602730cdffd9843ca524f1907ab6937ca837da241e47f94717a975e35f29321676c8b9482dd983e472b05d935a9ad4c3f9703eaea2efcfd1c77365dfc3a1a129683b671f3ffe8c4896fd4edb0eeb2fce13e5a4968f7f3c3288e70bfb7e21e987d472fbd52fc49b92781c74520fa9a52487736868925a2b426e6a9956667e5750e3a0df14c0410feb8752caa70e46fa31a49452d7b40f67ed0be96bcf510d6b549338deef071e35fa46675684ab5cb68ce896a0411cf48f0807fdbbed4bb8ca095731e1aa592c22c6dcdfe0de591770d146b8436bbbbc314ecf3e27259e82ddb453eb0579628c37a73ad13db76d7193773573655f8e74b4a3d7d451730accae3c4da86519c28a0516fbaa6c16236cf9dc95924f3e5b7e8c95e6597f727fe373db7eea90c220cfbf995bd76ddf119c96b2e330fe6d633cd330e7fc9bf9b7ab8f751d52bdb698eccb68135465a4c1d76ef1e99d9a5abc61aca99e5df7427afb79ae466f7f239d36372a3969a5c37ac9e8b7d1f7557194fc66160d99b6585cf489b8c2016351b225932d710c61cbc701041c46d8f2b7193d4657adc831c401c3b48503465b91e68b1c7e33e97fea39f9781fa3cd6d9d216f1f9e5a279ebff1efc4a235fee9fdc03fbff0c676ccb6dd87df6c4b1cd60cf9692bda581f787638605b96743db54e3c9205b6e56b5a6eacc3fa9946d06681b10c21aea61aa61a46b0e54bda8a28b9a28e922135414bb5974467f446f38b9146eed06a5112638cf16f3cc6215cb4114629f848e9118bcc6157cdd8d155a61de9081602d94bb5510a3d3d3f2e2df86c11052d28a5d6caa65099e260cd62bb08c576751172d00bf282a0c8459b6e29ae1820a22c442868a812c3982731b09992b514c5972f7469edc8e22e14b0295eecfa315cc4d54c2c1221ce74311493855d63b4d835468a053e8cb142c8cf6c11e34caccaaeff45d186c3b248e3522506c67d0ccc55a7b843b92985922bf0b90cb9ccee0c52320b7c42be106b5f98b369c7c0629cc4003908cea11cc6c04a3e2db218a05b84c6c05c8a935d7fc9fc1bcf7161890625bbee3006e652c565c85561c967d79ebd9aac1ac5c50b9cfb1589b2ab0bd0ae2e43cca7df11179fdb834cdf93df7d143bac269eea28765834ff769939e132d481d7a1df8197df8126de89cf48f74d38f14638f0b403bfc3aa414d3c1703b3d409dd011d272a0938a809ee0b6384626095de1898e400acfb5edb06d9b5833e4f4002efcfd1af8bedb022ab9b75b3899ac2f57cbaa109684f02dafb71b0be478547858312d0f627a0afe773b5d72385833e0e564981087c8837053efaca7b80d41e90831e6c7a2e49e54566d815216072adf45cb30948e0a3872381bf71eedefb37534a246ecc02cf5d6d010bdcc73af4601e90abf0d7f75c7325d3f25c32ad29e4d00b8a323e3237821cbc1185087704a230361312081391906d13f2178a9c1c568b524a69b5b7b25a42b64d13a2695a0f98cfc4aee02c67bf25dd123a841bc22d991f374e151c2a5d104259c4827073969ad55a6bb5175b9c98b66d56c86b1c67df85d8c9f22eda666731c658b390c39998cd6c4646238564f1b07a582d07edd7a347500fa11e307923166346ec466ce5732366a5ec019bf1a2ce10cd14e568e5e0c92185af4a3e33548676fd99d95cb9cdac87c592c255110b3d601863ac6d9c8673c58c6c29f1d1c351e26f5cc8732f5b1fe2c8706242deb7b671dfac96bd3cc871c896c423a1fdced7bf4c86ccaab86ac8d7c719c2210ad2fb21fe8d83a74d77f47264abb5f17bce8dc7eccfc307cbc364caf98789b23f7f7a73ce399d90473bfe24c2fe604dd1461b35fd7e8834f6a91332fd8c34d1d17e7b234d74e86b6f44fb8ce0974d9aa83bac7183fc0083ec1f46a1a969817bea01a1b9b83d64a2ee26e4a622c030610b8f1de2afb1d6628bf3be0f5384097fa63b9bf0218f9afd71855bad562b88154da69c670cda314b39a5cc338a1d9ae25c01bdd76a9a86a78635a9e1ebb6cef94390493f166412117637140bd37dcee9eeeef4b4e57702827e8e7cfa855262318390e5939c4e3ae7a4cfd5493d1f933ef570e847ebac3fba3dbf39bf29651bb818638c7106217b446418bbfadca1915ddf07fdfae948433f22328c49917c271fdd9e2f7f7471ee50e9602882b3a75310dbcfd7e15efbcb3ad5b72cc98ade10ddcf4e7a31d2d8975d909cfe89b2f70891c656d664691afe23f4b56f08fc47e663f924d2d86b838264ccfd0deeeede848b36426f6dea2a4961ae69fbe6bca335dad86ecedf3e23a39f6f647baaf144dddb4596f276b2c3b6ceeb126b78b4244ed4953ada15e4faf43be1df9efec43f04fded8798cf3df7de09bf0efded75a63d79af7df75807417f0b62d3be537ded4ff84b1f59a4277dfe21b42f7d47b8d73e73af7d35da93be918e2cce2322778c349b170465dd4cd4ed824754335197479c28ce93628834f7b1aedb8b48731fdf22a21a6fed8803dd715a8140e9fd9a1d3b68921fecf3b8ce59f529a7be7cf9ed5060ca29a79c71cf39e7d470ed226b9b8848c3a2b1fc24d2f8cb1ebc67db4d49c0c5afcfe1a8e9961e4e7ce9d92fc8fcaa65a44f3c7b0a625ef79f9f9126d2a5a63b4f14fd1bef02176490a6ff14c47ded75ee6bf3efa773df88fffdaafde49348e3540a511b544e3a9f70a41a4dd332a2a8bb835fda34544287b88aa41ae93ea24f3d1c7b298d56ec24417a39bfedbfde13d8f36b117bbe9c1fa53de01240028209b9e503381c148b6072c88583f451e801195be91c851fb8c16d1aa6a3100439943269e4d551680434c988e1d2c26247e111d4d7a01103737ab9a310090e1498c30d191b387c78c4cdc8df91929680070f1ed1667e941d608eb76182c92d8eaaab1f72d88069d961cbc62dbbfe0f73e584d0ae55ec8a733615091581f50310575207f393453982d288d7f94ebc9cf01869fd30e949b2ebd359bf7315fdfaf6c75575c748e7ce944534bf57d334986dfbbb69dbf6699ff3000deed2b383d994a38ef80d39be4b0f985c3533bdd7521ba40d032406edfb51a7140a9fe19cf1e5c7c9516ed2fa1c9d94ab92d334cfd334cdc3de63ec7d0f63f23c2ffcfa187bf83dcfc31c7e6e72989b35ac6f9fab36da58df5a6a79d41fe6d4b27d93abeacb87f9aad1b076aef254d3d3dc7b1ef5a4b49cbed974017e905813a1531f3ffe88f862ac7e2c5b026b3bfaa0143ae91dc11503178c4fea2377d982a148e41324d10ba690d25f4a29a594d10757bd0c322ba5945219140333ecc06165f0e2e3346507f39e1804520691069bbe59a5fbfc5c66a722e28740942ca6f80043e7dd418d98141d624db4a10fbe6c49d813290528a9903dd2f572b227be565611513356438ac98a3d251130ced964fa07e9276116053994322aae2262c241eadf12460c71957f45ac21fbcf8ec0596b2dbe9406f131c6f8d65afb494a2dad8934d17e747a8d0f95fae0c30c6b2a1968adb53ec62ea7cbea55ced9d1aeeb362ab76da335019ab669bf6d9b369fce3a25d619a457bf8334ee98b5d62df24d017e0852fdf3fd982dccedb2b491caaf5efdda5a69aeb1ce3a264441c16b86022974489fb4da8bb58db337e8baae33c22345122a64106d38fc8517dd87b1ca942ca2c49c2342a0f301c6a50c228d942f88200ba29c42065e0803197cdec6f79c760a39bc20822204182c21dfe7a2865111853faa215b70e3227483aef236c6351fd8cabec13888f16f9fc941d3c6184f9d95b8e4f115fd649468631fbfbc22dac40f25930fa5930fe593ee93526cfcc588d2f017238a13e23c6e1e7fcd5cd5e7bed00446fe62fb42ec85890afee8db07461afcd409b93eb8e5d86ac037647c67d545e97d4b7dd0afd5877c2203c0828b4f9faba9895aeece41fa947efc24503619e12a4bad88abf812888b4db5d8544ad994e3348edba298a10088dbb4e836fec9da4b291d0111a594524ae9db1b5dfae8524af5935cbfb9c355e1ce9edf0e19851c7f09267a438cd97a88836a7880356fc2f5ffc663b5c664c29548113f6a369125a6048ae2ab4c94444a217d767dc927f2472a913226fdaac069953ee787e516610dccfc9f3353771370d1465863b56632c5e7a1e9c97216377f9bdad4dcbf1c69e64f3b4f73621e05f055266a89c98298c876cd20076312861dfa609ad43d1cca8a1e10a46a77a4d328b89977b491c6f8d5e218e58c8f371869e2cfc78fe3caff7eb65a4ba7ef5424eef4c5450064210e7afc293f23be221c7423a4fc22a4366266c4bf114568210ebafd22841841652dc288aeebb6adebba4d7b6dfb9ed3300e6a9f69db364ddbb4dfb64d8b44b536a95f76704a6bade651b3c3ee5279e3a0cfe83b952264960f63adb513e37b27b5d6461965a49b9ab8b0c3df7872728485d0446489ec9d0fb8f85a1e21d2f0f8e8d349299d5f8d83723e89340f664a73a5d7be7f61ad7252253b32c9928a2979a414328991af82bdd8f18b1d1f025f0d9f5170165376f421a2e2d76f4a8ac477a863216e7e31ba6b5468358e178c34fed83efe10fff645ec187fd88606833fbc1f2f0ff37e784e8bf5dfc771453fece0d431d7a9857dfaf787b03fff7e479ae8d89f7fe43e91b310e91a762dc3ae5fd0b487fad4fc7fd0b73de8f571f810e7107e581364ae64cfaca999f9c21a10c717828ffac237e51cbe30e3f0e9efabd9ff85798735359bbb6f9288c94785ebfbe68f7efcc3e2402da5159813a945df67d1daafe8ed4bddc368ee497af4567bdf89e4401ee4401ea4bf099b2f9a811cc88362f044e5ff1b2f8201bd60aed78fcb67d7f771dce4bffbdbf3689f1f7fa7ef0b12436387157ecc77c29fceb5dad3f88ce4d7dec8f6f7775821a87dc532c8f485b854eb87510883354e04f45ab22650b556c409e42aafb50ebd9e4ca6fee6cbc1fa38fc7f6de5705699af53a8c6dfd0302fa34f6f43c77c0dbdf231f4cbbbe819dfa24d6f6ffc868e2c19fbd3335791555d387cd3e7bfd9d3e34f1cacb57ecd41bebb08ad1bfded3b727fdeefc49a7fe424bf201bfdc88a3281fe4996413f7fe6eae4afbdfded87b8af7d4768fcfdedbbdfc98fb0bcb51f59ae4d57bf354da03a81be977a3e019a44984091a66a1af81fffe34f88c8aaf1c17cccf39c7ee5ff3be92f08cb77c26f69c0bc7d1d98b79f9126f88dc47c317fa4f4341ee6f1a77332b2f21d217d8cf7d8df5ec7fe1b297d27fc349ebefdff74b6cf9f11d2479fc60f313fe6637efea6573e46971e46e73f69d2bfe896182f43bb7cf482d4f87878623c4fcbf3ac7c7e1e97e761799ed293fec6615e74644d2a48b9b4c2d2e21223868e2c973c5df3477e387fbc203ca3f7bae72ccf25e9c88aa26790d0aebfe938eb5ba22db2b4f924e32ab7b94391c890b7461354b4f1ed6e9bef4dbb77aeea5f6d7b1b60b4197de75ee79f8c34a43791908c748c3424136934613aafe376d8dbb7a4e759f8976053b8c4f69fee2ae91f45451ba71789ac5bbc388ebbdc9d94c5c90edcf1f564396bd32bda4bde61129b6ac9e2aacb48e9a81469e4fb286dfadcbd5fa6797aa5319833a43452e91e67b494be66a9db49b5faf1006f0dfd99dd9db6e8cb48238d94ca2d72f8aa59530057d9af7e41660caa7195fc4c23b539c839e74adf86a4224a2661944e767cf9441e81c78e1a57756f4a92a508258fe98bec45ac12a391180481f8c5f721ae6224913e79844823891065102228bfd3b28a08ca2360d18410091436ad9f746d2f1ffc2365cf96b04d5dbbfaecfac9d626b2c46cfb88415fc43f89362e2b12bb33e71d4290ab648dab68733ffe1273453fd9832351fd39fbb169b267ae7644e1c7527c368eb9406fbb955ff3a296ab8ab69d5ffb1845c2b896966ff6b0fc9d53b2e8d97210dfef26d2608e002d8f7fc71e5a1eff4db4b98fbf00be8ae162759c52f8cc1e077fa2f0bb7b38a720b627bdcef6e127bd8e8c4d14fed2cdd6c130ed2a30eea44c2b261136c6184fd978ce36ee22d38b7fb87110ffcadb18f483abe2c67f3357927557defe8dcf9fb9ea1efff499abedf1cf2aa2cab9c7231b963f4374325f1b3fd772ba1fe377589b3eddef14c4f6dceb6ccffd7dee33d2e47e3adcc7f88cd4a75da7292b864b8b6e02effb4dce3bfa2c23ede197b0ee9b3f1385ffc67b260aff484fd744e167c1bff9199c3891ab661511c48fbf7621af7cb3653f2f9a3dddc62ff1e7b92a7da78b4f9752fc47ea6f5fbc9fd5be6fa2cdb6318d4c36fed9834dee45a4c1f9932f07f16b9f7439881f3fe9b1f7611e7d68fa3d5752087245fa6e260aff8700d8a1847d7863871236323dc1cb4be8b04402f737a25c6d00705511cdb636a75121282bc84461291cc45dc8d2c741fcf7933d0e62fc560539c41bbfc42fb7f74caa31de577b6b73b4bb1ab73657a78cb4d60f3ffdf6d5b4b5a3377b1cc41f3711b9ef3fa6ef8fb7a0e996250cd7e7bdf7de7be7bdb70813dbfdcda788a9fb58fb0a22cd7dae56098683b7258b1cbcb2a8258b38d9c5beb7dacbbdf4628a17ec7b5d01ab6da8948c9496559032a566460200003314003030140e89c4c2c1684c2429bada0314800b95a25678581d8851cc29648c31841011181000000160200904cbd408f066225093c1ec21fa58b91a4364328247c4c666c66e5623ef696ed03eb88bd3d64b6a5fb6c620e2d6b2d46b2b8d18295d33dd637509cdf887260406f73e238943e1294c718bfa7c93b0a4e0033edfa9823899898514a2a58c5c1d3e7ae40e1906abe2848369e87146bd0bd519cc4c0d73a1ca291be582cdec5e30129a286feed394924ee6ac32eb351dbfd1ca2bc46194a9fee16e8fbfde3a8fc5fdf088e84dcaa3327e629f84fe6da5dbde299c1de0a210ab242d9d936792d362f22f4f382347aa6c030c5dbf74ccc1a6018b74da41786293eef2c5c5d3999fd119c1052e81810cc96f870409b428aa7d4ace1bd0492937aed69ae2885c7a8401a9a142ff58dd265ab291a85c53174643562768c189a0da4a55d10cca270d26a4e0a1f9e2bdf97d071438512bad4f2ca1b0b41e03846f1facaef8eb574575595b2d265851d286e68ea6dcb5680bce046efa400b0907de7d3a482c399e1003a3faac2de017905bc4fe3531d5d237410a18b445f5ba1391e1ff9506bb0e78942eafb15be78ff29f29860851d474b844f2e978bff601c936e294b84dc70529c8a520397b3f8453ab5842712947baa49a7273dcd8faeb440079fe8d745e3f0dcfe12711e36c9da101ba03e8b95036af57ef62c5891c0e5b25768314c793cce04421f2f94253639b56e5cb5d16269c8640f74e0d87d2db8d36c5910c555f5ca5c2799150ff902c44920922d709030d337bbfd0531cd77b85a4f4f68f2e69a5ee174aa84b5da2201a723951a250f95f2845de6fe4dfa154da063f7091baf41ef051cd8c2837463b2c0d92431b5a517e57565531ea26d394484ee52ef1327a37ce9ee47980d36d00db64f4c55e67b5b30bd3cedb4728088197f5161ae59cd0b39b6eb3b09f8233998bdedfcad05f4dca0b2d5f2c25068cb47976869eea54b3c9fa05a4ec1ec87c388676d8890b6fabacdb6212abb28e38f7a641825341caafcdc51faa008c7ece08a157b61641fdfef0d68c219ff54fd546298d039b70c41d936693b72459789b9b7390bd13f077c9d4936ce25a3923a764669a25cb2bdedf297294923962d3250faec740578c1ce91402946070711e8904dbd0e6cee1ab79a09248422a1b1d79e222211bf23cd1e1d1f2291cbc59b4b67da8af5b8d2441c9514967e678bbcd577b3a575235a05079c8301162a3e4b47acaef9fdcecc0792d600d038c9338502f80e33d43eb899bcc955f2ae8d5fb66ee35f6f2a508172261b910f6783f7d26b38ffb7ea181e1f83ddb532a966c4f68d2ebb4c288dd7e8ffe863ac740094c915a8f74689660ca4bf18745b6926d0e0f41c717706b4dcb13e5786a87884e3644df49b0c779b7df81a24d33ba7d5897d72a5c9e40b47ac386d3708a9afc177e3b492cd148b54c383e7222531110c5ff4fa31a45f1ceeb5011f54a5be44e8dec3dee5c018f44716356b3c11bf5ce4c81f087dcce612ceea7804088781bcf96e4a63371861b8a1baf00147299c95022baa8fa4b51ee87bf854d29291194f594d0668eef79c43b0da631c811975cbb73873ae2452ce93be87e2c05ec33858a126e715e352d36bc9ac9d4be592167d27010f9d5b4ae835b78b6a983fa499f781aa6a684c442407a91ee78f921b19048741f80fa7a1ab85b9a617f85ce5b59d840541a1199f690aaf3578813578942533d5b3a05a900402c0405647d08b99d115250ee75c351dfd87119f87cea52c16e0a2205106144ff557500ddfee3d0e474f33882461510fa795cd3e1904978a2b66d84203fa8d7efebe7a09bf5d2bac9123ee27afccada5e01d56373e3e51e0f69c91602a8807452bc50e0448fab5edde7d256edc36256ad63dbbbd1f5475df96069e1147536752d090c8b18050d9d78ec9131e25361ed3f3eabd8900e60f97acd297ba41d3204afda225b80b50593348c2f4940e89b1f40d50c41d5d1df618116b44c50a1a090ae10791b21bb914858f4bac3c0c49d2ed1ec4b5e85616862d66fdf22f4bcddf60845305a93b1cd295d2edd2e1fb842c93cc547f9ac46b4f4b06638672788f17bad33de7a682d44f146b505b8a7b849600abaa07c48d937b02aa2518d6004e6e5d53bf532ae8b04be8c8dc67ad9e79903e0b64a024bdddd0290bd4cd30c44c459491a88644e53ef98f5358f7d108222a3e0fa7d5544c14bd92ddd652e10a7a7a4103b83164181469556547ad976a974ccbb3f4c93cdcfaf89496e7ee4f382b33a4407b196645521c9b0363b4caf73a3f053f4992c4b85a4e6de5db41ab531e20215f8732eca7bd691f68318ae54c5587b477f62a734ecf8addd6ac455da31a4eb536deb806b9914615ab84b1a3846e1c192a72bb6cf10d98a22f62977958ad3bd8657c108263406c1bd20a0b698d8137db5b73c612558240d57affbccf81915084007732ac8ac37d0aa00f6fb2d0b00883a081961968915c5676942fdf4a103b1673e9abe02731a94500dabdd6ed3a96641e185fdc4ca4af0ca3302b566fabac6a89ca1dca01e58c8fc6ec85230ce798308b5cfd5b678120bc24888a605dde4e0220ad63e37b7e16c8e35b840e6368bf644ea98f5837a748a0baecb05d651d2b1d5b1e0869c9070ae8c802fa5ca66cdf2036a9818f556e0072f296d83ccaf12e502160c2113447d8cbbc28d2e5a468fa66fd1ac2a303abca44c164dc60c9348527153eda2678d7554fa74561d8f4af6dcc3d4ba64d8372a3df6991a640382c95e9043bf77f3053cb55083900f54356b7cec264a64f107c820f024a08abafc1362c4c0e2112b28b6f93c45cd540dc14436f4bced1eda03a03d28c7ba5dfc64ee16b8d64c30f228f0f1ec9db0e9cdee857ef66ca2a693103c2ef7c308d3979a90346f3919bd9e669e8c2822fe580a00e1216a3b142798a919e0b1b94cf0ff632450f09e6503bac1c42352878e26ecb1b268b2d9bf819b35a75b0ec01e2a3a81c006564d274e3c577f9393d7b2ab097bb14f09b9b95a68fdfa268818de07a044bd4d6d9c53ca23b65b03ee0213254bbd81528869ebf03f970f7d7c7b3d572995261a4e3c851b39362be2d3b39d4ace91a548e76ca6e59064d5071fc653b54f1dccbd0389a1c9fdc58850c3694b784936c205a964dd3ded5c521e518ac648ab182616af6c9f43826508346e08f4c896dd082f7ec1a9d2a230deda2254f2b428865d27dbe52cfa8eb49d90a720e174f09f64218f8062e90bbc67e513235f6104ac6d16a2d42dce0001a82b2f0c4478291c6e3f0e2104ca3389242fcee606fdb5c325143113e8d9df69635c064b6822167445cdf9ac9451800e9a159aed4cc886f4738747a8bf0004ce4b2f919566b283a082093ef21966a1f6becd8d210272044cd5261ef3651fe04e6524b8d530c085067a1f024295e14095a839c27cc17c8647a32f311f7aeb5b368234e4b857d66341008c989e0a2c79c1e25e5a2cfb4cb2cac1ab8244969287e2957c159035fe55d659af2c88d98aef4bab91294bcb2a1be304003f90d630938f540f4130d68a0ec74ff244f0fcf51268c53894eccfe28a22c700f9e8b915850a9b06a69867b6ddb8566c914597244896e06de28e0e558b871327ab21b62206c2c91056e2dab1da47072b9b63f548a816bc137259254ec7c20c22aa21f7d8b955d9ad419be5dfa5622a159d7922d7a13930b7adecd4e8e1d71f14151d91f17ebd13b41528c445a9510f30ce99fd0d06b087dea466b46826f784c68cae03efd24f45ecb0804aa22b348ae879a76813ab82e87fe7d8d625e61c3e14b970c4c6c9a00b4968ba6a1a14c7426c4ea46ec0d98d030d590e249671fc06ff07d657d738b77f6c85ac5576b38a15f2d322243d1325eb4375860a7da6d38bba316bbaaba8507da44db7e5e1a291bf25e623e750b9843b722d0f1b7a64e8b6065f74da830ffd5de47e6f03be0b65c6d9d0a9357670e9e54d2e609c5389d690003dc5aac99ff4c70bd4b2054fc61de8c648f5c3b82bd322843bb03f23bd2a5af93261226829b4636caa802ffce30ae6b471ac5088ac25666429fee055f48c9a3832729adebfc1f78eb485f85a12f40e07f12773568aba6c8e82cd5e1385a16b7e4a4fb6443dcf89afdd8cacc5d80e1bed7def52f3c26ce5af00f0e13ad710f7a9d5b632f87cd48490c1de96df578797bca25982a8a5f2bfc4753fe43cb6a634774a3995a7087eef61f8f80ea7fbaf250a5da39226322f3719215ff41a30c414e35ee60ed290197bb16c1875f89fe18a1d895573003a86e0f365a87a452e62585b500b981fe8e90f83f78e48f80fdda982ea44382969d4fea6324ed901af7c29819006cd277c27be463f4cc0291dcc714c810586ba84313b0672d519d0715b2c33aa4f62431ac7a9dc2a9c84a1b47d64d709960742e26c27d826b3940f9578678e041040ba290da5d11b7e1a7fc2fc8eb6a7809dd43bf21da2dcec14f2d1ce9555909d10e03ac4c028aeb8f7bb6b0f435a4599d7086c2cd4ff417f3fd19f8477a83d2ab0a57eab6dc474e769dd1120a4166debb66ccb1ef4133351d9dda7faf353aecca320c61ae529f7cd3bd8ceb77ace7bf39f89e09d189945e912c9587757ddb5d0667aca818b62a2bde89d4a1f78069bb798908600eaea2821bb4eb6e0bff2d10f9ca86ddaa7cf2b9ce6abbe1b13e99be5669fcb07f99f8f77684bf3f9783c7e342eb3e98c77b98c402a348003ccc4f97a6dde85232300fd4e7ee4934a0bf46ae2a38b8607c9ff2895b57365147e8bb9d26c5cb115e8ef6f0d88ba4620a7331ddd023dc5c318cb79c25fa268c2d99a4aa05ffaa1e2fb2f4759abd5448b271e3ed58cace006f577565fd8fc27c96bd0fc7e6c7820a19eb86d277a3cd9846c72688aa254fe70886898afc2dc263289d3c77c16187d5a3f54e9530443924f8be8b5d62760dc067ac709c0b5dbe2100ec6bc329df651b81dfbe866020c52054dcaf451badbdc978e5a53db68df176901ceba27cd3c513814759cc8fa99b7641551c2ca811b9479cc0d060aae34bfff112bb112a3d88abd58c4548c8aa582d3075c0677537c08077b44de2a7f65c1eada6e647a8549fec64d9476992cf29530e2cc17694f3be609da77368c433074e9db4b68baa539f3229dfa98aa3548b0a97fba5b718f0b1e3e8aabf9005047c5385f78b5d9ec4b4cd058f28a8812a2e655d6efc685f4bd417d7db1d47be32379d5b50f6f3812f816512198a598618372b65967ad7c8536b4b2b5ee78426a16a716f6a9d83017725cf47e63c2916719121cd75e9657f1e80380fb9859f014bd4df57ffca49e1cc380400a15a9649e3eae4872a8217b743012aa4eb23aa26ada7b351d783f0ccc8b55e56171a1281ae16bd72f195b7cf524e0cef2810d6cf3b022e6b966ad09f7404dbce9e4593b2fb09bae2cb3e05ff5107e3c5f6ec12b73da7857c61bdc45bc7aa2ba80b2be7ce4e6925d53bb96e452777a30a98909c943a47a20d1948e3b8eff755097b5339106706ed4dc6c1282fb7277c6dc056352211a03e02592deffcdfe99a1300faa78df810ab293cff30202c2de48e63d9fba327e6ce27b4f5f0179cd48266c742928763da2ca384e89fe5a5042bae0bce41f4ce85d3269d374b4b2aee2bb5d3c88f63af4df043061b21ea01edc680693f7c5de1cadf38c2b63edbbaa98629dc4751ac4c057341bea2cb3976977f0e96cd43e0e03e3d251709f416221197985acbfd9a38b476e266ce9ef032e6df55fb909138176213f0903f5f5ac89d51afd4724a888137b038530e640039df34abdf0926429f6157bed671558fa9f8cfcd2701361842e5f138a2cd710f65b548431e627856772022f24b0b568221f165cc26b752dee1d1d6cef9588f660b5c940419f571c658f2fd45209e1071e1e8c528bb04518beecfbbe3dbc5903eb8103aef61f3a26b5c23b6703aa4afb15a5b3dd262dc097f21f1deb21646461fe604559d9cb95c3ca0ac17290eb17efe3f0d0abeb68341ed419f8762de63de003eff89d20aaaa00d9038c1baf7cf589fdf274d730059bdc0c573622156647fff85a8d02298c1d9e70c3286ce7de24ce0e537fed3f73e41dd977966d3ea61010a7662f2013300b30641fe0e777f7dad69d2c71dc55a32f74d3e83dddcb71248c75cac3b08637d3f88afecf189e8b2be4d1225be59092eb89879f4c69d6d9e3d822bebaec332ac6efeb7392d00aef43ec1cd0deb0ea759fcb0d3ec9b585c81a4f53f359ab72f1aa4dc20774d18e335edb988c6d90869f60de6f583cf675a4ccc9c38a4f14646e7811f97e9d238925b212eb8818c2d0d93dbd259220849a908a388e5c4dfe38857435cd51624159cb6d9d8edc99e8a50df78a021dd1e044b9ee935fd1ebc36e864592be9f83980ec30c9c9d7467655896160ea3b4c88dcb48c3ed5ed324af3729c5c98c6c3ab927d4c335cf5d8f9381bceb14f27332e4b4e8893c793f847d98099d148bda39dfddb7066e9506ed913c9942d1c6c8b038c3d9e01ffad1f8de074959b5f7a938963a8927afbb3e3308a8ee126b5da5bb7f3158e021f66fa2405033baf69088645a337ee5070de8502ea6266b9aa10e3cc8b42b717365d4f5b69cbf3cb1375016cec387e3f43ffa0ea0f0dcdf9bbb37a4ef34e41d102ba4e37098ce035275a545f890de2aa835387065b0037bddd354935ede92349372c430a53fc747e9d746a0742cb807a21dd642010676c6d90e4a91f96155b86b67200507aee19cfbd163f31d26984b916f5ca12fa3348a5e9c202248e54e7b098cbe4cd8b3f498acd5650494216c37a227b980966f848622a4cc6dac2ff09c6766a83c6b01bbee0f5adde471bd01f321d6354fe02b3bfcddf51ee48368f22121db51e15d4c6439550c7d1f0741dc8206898d845040dd26a3acac0ca25344fc5d7b88926ea0720262140704428433d50f41f4e78bacfdf623d92a8a297aa8b930a7cc5921091b953b761b29ea240e37e12aac3c7f37ae4b4a7b1676ee292a3de30d23723e029b7010456a2cb362ebb28c08518eed46ba6ed6884e18804a68f038327dc80473ea775a1402e99d786846f30f6faad1487f3ae03e354ec84ef3c9017834b7d4e87be2e80530dc25089b7843a941022ad83f35f98b0a60b90a284df89851af4a32d396f6219ebfcfa2d263f8fc3f9fc73f789c733154d73bf36180c98baaf7121f9cceb98299d9f5e460c90bdd8a6a43b7b21f81eafcd0b5c485ca1f6f24e445c2bd730154df98be9db0cd992aea5d1109ad5120c205dbc2025081c1af394306b327e0a1f0b10d67ad059bb423b40d2f386202cea6f8714f1e08cdd293f67e3604bc043f424341443333ad0e33a75cb4bbf4121069860fd80ec510630f873c0677920702cb721eba12a78530921e4ad9488c1ca8bd433b84bb6263ce2fdb28806d1402b510f1a007068880f2b4d2a81d4b582218070dc9f82cfabb469b809c099722880cf450e7f1a125ef8c6013ba1a8362155dd52c3dbbcb50b53ff7b48aa9684c9d3298d476cfc9bc5758ef70cde3c7c779f442126301c0a99bf7b2aea0f0bef00ac2c572ccd28b28774753b0afa5b923030ac88fde7d24dc912922f7415873bb13ca59965adf73970145a15fcbe7b3499aa3191377e5c031c2acff09f1dd1b20e35580c87764d73c600c7785438445eb666cf48058a663b24b20f32ad9039b70bf1d899777bd699240754beb185302902176c46c316573b4e58ca85e2dae7d541f448d69df207e31e9ebf6565120187b7e874a1424c52b2bcde7cd54ea3a91b2a4fab1fa602fc646c51b6aa7d70427f8adf652eb7aad51bb235903b10d3d69903613d077acb4efe6ab444a27adceeade4b219da2aacd45bff87a33a335eb1683c03a6a8a9ed874631f98b56405bcec3872d8bdfc7eeffb0808100d92a0408e19c971d0d23b80d2ead241e51a5e0c7f12e21d94411f00eb9edcb081b6abb889481166d91b00e1932258b84aa9d0b3116d29cf146c241708873894ec94612531a8d72244f5882f1720311e803dff6b52b51fd10e408201c285baa3c3fa9fc590764cf31126227f20f77e1fa7c7f593a57cc768900b760473b4dbaa9304bb7c1aa70122008187e54dfde5eb4a6dc3d2bc3e360f26bf127d3749e0aa917495d0d6d6654bd1144624f0d14f78e91c90ccfe3e105647be93c25ae7854009f57b8f500f51e558715f0837ab5590de6230de99552bf82c2053c62acce2ca4a254b56dd42d2401031602049532b9200f5201061c240c7af98d968113f47cbe838b33c135bf36106f916723881c83e6392df746ea6e4b86fe67ea3f9af60a11e211140304a0bb0410dbd9650cc3e9c81aa7f3c8c1fefe147a69fa7537a93cb8a8a26e649b8b4e576d54bb6dc01da0e25aac3fa0c1046e400cd03dfb90a42d4f58eb2ff9be972004adcc57b5d6220285e04bd9d71545a82edf5fb1b051ef3565d4bc42802ad4a1356d4c6705b0728903b715b602613c3095f299e564dd3c954cef3d5f069e49faf82e298d874a9b2a321502638902c1b553267e1a2900d0789d850eb6fbd685a2220997890d6b9084c9311359855f648138b8de0a34896c8d9a8d1e3b80b4f4bbab46ebecf1cb1ce9b1beecdedb831bb356aad4baf292f46e7fb6b333f842539f6329612b6308a5bb520bbe334e502213fcaf791388cff9521187b9c77bb8ef476a1e6dea0273d96192ebd511c13f139a0164c086421a29391b7a11d597ca125bc7a192c9c8b5ae4839236a72a781c86f04b2284b27b03328d5dbab8e59c643a0509f633a25e41878dd7665bc1a2a3febff3a53064faf09628d907e29202f2d3620d921f3f447ac3748c8737368e73349c1a576329028c9fac8a093b80b9af530941d5908760cd6597984656b3d9b94e05f2d0d0d6d012bafe8e666042bd4b6cc9f6a115c3af947ee7b4256ad015e6a20fb01573762901b9f489c0c411e2a3f5fadfb88ef59693febb9373e35a5a3c84e326e495c07422d810f25e4aa8cafa33dc1471bc5b6bdce6ada938108b2a2e4e5b506f964d5905aaecb3b82a91f81d9836e93207862f3eba354dcb5e3052e20c04d62a64b169592aff9d63137e5a49782effaca066f5176e24d55dcfa93b6a091a1139fd453b22d11450c91c242831af05107859f35602bcf56c61d41f229043472e2569a0c3001021c2daca5f7adacf07875daf1dd2c81718dcfb5e0436de7f7c216017a4dceaf1acbb45193851d13d4b23fdc183573c3f2e5856e2253ec381107793bb7f9277af3393f68ee846a3416e284b505cbfa43dda176b64fe8ae1cfe4d36131eab7a67c31b6c6b2e627b349a67b55654942d3612bb51519f685f23de2e69d9e0ad59c744b6e87aa431a4818d059713a39624a6b0c599806a9ec9c532111c1597b14acf60247cc5f0d886f724ba11a2d577199304f81c4b81c4816d6e6871286cc3300d285f422650bdc82f7885cb528282c538f520690caaf1307744f751a7e549419fc0d39c171491fc7502a4eab56b5f8570c9cdb96d0d9040901d8fa143cc142e5fe52d4523177e94742c626476b943f91d1add2304fcd25b9a831aa6d185d0d12e9622fef77792361607f7c2b8eb95b1ae07f7a61f6ec779b8300777779879120851d66a8ef7f0502d5f915d5827379abf58683780253f0919e215b773254a4f3fff767d0c24f9e2b18f1eb8acf35edbf63948f73a9a6495cf62aef346535ce66e94c1a5114bf426a416f74fc1fabea9291f19c40efc3f1a84f8634929683fe5124ddc6bc0a9b665bcbe0a3f55aabe06cc5ed641ab0bb9e2352939a4044efae45d9abf3a6047c08e57ab51022d665b5eb68867ee11eb1999bf417054d80ef28f43d8db11b3b49b8715c3c79a6a1644c913902f688dce6bb2c917c66510e5e276f086a8da01af4037b6df8f859b0a4bf62dbe20b011859c142dd22ea39ba5d2188a3c4802cc79ae172a5e05e1aa2db5dc7311f8257492792233e90aeb21e6d638dd51b95e7281a8a7d0dc67c2072c1a845570a50f83b698e194b1307d0b3388005a8eabf581c3b15e93fa5929be0447cb8fa486e2d3c4c806106e3682249696caa9a2d6c6be373f1376b8785851b4fd784498000281bf2b8063c9af348e379d8c8c00933d078b2d5ea526f03790c6571b199b067b3aa8cd04d76c6006dfc6ca7890793c90a4641c28f6f3d3a12b2b1586a90f4e44eb5881f6071cea505e6bff100237466f290dd299ddad1e93d745fe7b4cc94ddfef2eed90a45842a18b7bc31dbc69b89e3ac7a24f7f9a47d8cbe89be443585f05991163c13196b082af120cbb871c581af652e5359c93dfaa2c89b664194098ba557a2175d69557e33c91a0667d959f670bdd42deefa09bd4ac685490f93744ac9944e7da2bc085d9483250810960c6ae8891a7004dac4186950bb6424ec01174de1319ba579e65163febe4bd69c2ad6187e965ef6e454e025c02e5a81f2625c91930071a36d1483ab288c49d5714381ec6fe5d89329547fe63720a5a92d25ad2021191332c1784a9f3ed3b25691a9f8f2f01d512baedb6e6849d27908ce60725d0fc16dca9b7907ed483f1c1aa3784d29b54d79a7e82685626d20ac876355ea9c930f07de8e87c682545120a7830d7e3b8e6665b38e6535e8fc3bd8b83ca221680efe27e191e793dd7b405770c791eeea43b2528e2d01166e2618c05d78aa33a5472029eb440ec2941eb855507c3b66f1c6bc61768c9df7a9c009995c27375cf805cbd5769f42bef7ca02b52d3ad9f91c1d620a3593c2b7a7a59e410fe4cd2fa07b6282bdf33bf8e4b0dd5bdffe186f9c6c88ed058bf8ba39f4744ee1dc199cb392061850e5fe3436b08315267cd16a48f96b9308ccaa5672e217c7ae99c77ac586d125769b338c53fb6fbdff92bb3712bef97e78beb4189bf8fd9ee6e180aaf613b8cb2039719394886cae3416f355275a2fd46dfd390a04dd4d955fa908b764b08d5ec0a0e4c61fb52792de0f39839af716978ccd35655c3661e4ec9990267f69f43f9066a469b4345fd4a7f4d1b53b064d1023a6067eaaf4ba58c27f3ac139be5e4c66d57869c8073c2c61e6af24832e653aadccb386ec69f76fad4d12f03fe096c7ae903ed7ca982a6e2e58eb1d435efb694121813aecdc1936c3b0c235a518fdad72e743b0694a2f91a6bfe21d5fa9b12b7057e2c4122995ff61f7d238d09b070617519a6b029e719c8e3c09d81c4a271f7dd849f355177720bfeb5f7f360bcee9226cae2ac9939033013e5c25c9fa6be45a64fa0d8084932fdfd4166f03e4a7c58dcd4212db5e544265b77332c04a9cb35aa7e15c1f8223b6ada0e6747d58254d8d8441473f5726c24bdaad67867e664877a863e88c9f818a103aada8c9cca265b96ace1f770342fab87a65f3efc16b223240133a7531e743ee983bd0ce1defbe1b02ac66e3d7d70e3e77331aaaa143451d428d426bf97a9a87655300d63c1baf565dd0308791591e8297a1918b700e6336cec91492f21aa53e1dfeed7b98156e00e9dd25a824e884d2764bbe6e7a5c5a81c5dc50279e09823def443112469cacc5e262ce2a493b79e9d25da873b746125cd2728d45455d303f6b242cd079875e2819df5fab40114c786ab8657688e48574bb9ebf2c72ede30a3f3ea799bfad169dc0e521fb08bcdc35368d98e51d4ed62058c602c9bf5feaef7c258ad4c29439e2f91f50be07bfad603a7d647cefddbc2933548a9e0eca17f65dc9b000b583646d3c06ab8568264a45805aceffa7df0bfe3fed69a60289a35ddd0c0e3fafcb49b820fa19dab59a0c7776d97bb0f8a1794a2049e688d96d8f7e4a14a39e62a720efac2ae7b57b12e753ca1a7adbe6f78002cc6acd061a276642a8140892df3b476436a41a346309d06212ae1abd134bc09483b6d056c69539a92b0b85d0bab083f65d503252c56a6d0e4a6ae2d86f677e581b17db17a9bb055b72022c64259d66a671e1ab438447a38db3cb373142074ad922dcf406bc51d110740f5d23638a54a2265635bbc3b35b57ea375ea6d4c79ebf2702afa6acfee6183b23c1037d399853439014d1d0f9cebb505e130bf79893c78ea90e29a6ce0604ec63b33bfc684a2a6c13813794707918a10c6b75232bc8f7a9c381d117828c175173dcd8b4cf8e4088c9ffeb9267a1d98c9736d2bdeb80250094524415912ad262abb9b205d9a585c0f06213a462f393b68a5826a6cd3aa0dfb99744da8f90b0a13756227e3556347e74bbdf8f53c453f21711f7e601c750f6808962f64c2df901df5f7e61255341b68f47b244a31c10e987342d1f7376349b98ce3dee9238205151f1d4ba1834a4b50df0f41d25b77aca10da9038403c2c1981bb3eaf77562663cffb9e482f1fdfec68d1ce2b41a2df646ee113f4b1d621f1eb962c56eb48d30ba0a83464b8be4200b3d395e8a4fba7f1ad9039de30c1e603ef72ab7f13ab988b418c622426b1154bb18b891822d670cf0f2c847b55d8c0dd89b195f6b916307fe7226c994cd354db40dcd4cf1a12919b4de6af2c3e1f751e2988f3e9614352c7dc755d2e32bbe08b12b27aa0a2b9d5a479615a2cfce4dc8a9222010957be8b64e5048a45e283a3f73926803546cf38b049c91d30f0cfadbd4b7c32dd3e743202547e706bc563c593c6a422a1f79ae3d50bafe5d955dcceb591b13812b7f51a0642ba5b1a565943d4c99f5c10430d5ed8fa7718db4b313bb152fa52d666e99224f65299819d2b674fb09879f1d8fb2cb5fd06f45dcd30d08b8efa010e55f0e74235f0f73815a715c99a901a6081eea864892971718efc187d7b8811bfa66cd2fb31e1c7c78f2e12b98ac1f7f12d5dcb0a4558f78943dce6f8df7c1d2970b45a49ce95025a128cc992675f98970fc55dc53e3bd195c7154777d7772c0cb08c4773adb5019f798ba83a7ea51bd525bed76d1c56a957aa5dfa8fb2086d3594d2b5e233d973dde1f91e6c3178902b54e44d593b7f27018230d713a48b165647b9c9b9bf82b84575ddca86d4a58848503de36afeb86664dfb3d4b51e72fd7afe80886ca728770ef03e76d5d41cf956dcf09964a9378862804fbd64893bd93a8b8f52f4b59b87ed3d718f6e1508db2f0ca3074c94f36903110a69346c499935d7bcd90f4f0667ef232fc0fa63780934238c78d47712e6d7c36036fe6eb5b5cfafc96d4d6fba6b45bc54cc1061aac8b09adf61829706fb840afd1f3f0eee96d2fcb7d2eccbd775b660b76c86c53d87e58e3896b51ebb5f80ecd2b7ac5e6fe3b9c560745d6e19fcbb74f6fad156a919d38f3a1db4387ecdb57d3bea18e60315ab53afd2ccbbef52a55b8fb558b383816662adb019f76ac4ad203d202f647821d5e87fcc380d0b5e47409c668429efad14e52a1041cefcc3138cfb2683eaa3a3e4029a02882201b185cbb41ac6ac3e77dc6cb711fa9cbb456d4e632e847431db4f3378b0836caba0d6212a0e5d5556adc75d77f21b90d12252dae2c7281ba3061243218f50ce9b00dbe11d0735462c4c3dab7acddba2a6afd9f5d3f9c9bc842199ca688074dc8c23d731b6a1e85ecdd3d5ca1cdbcdb16a7cc7f502ac321a51cd39541788e21c3710aa66e847f674a85102bf0f9abce4428085b001033b72f907dc4d7b68cb4e5b3ee13bdacfc4a3e26ee061068373c5390fa2f8b99dc02410ce13de7133cd5524ac1d4a6b9e8e8b6714514af275b0568839e420a850bdabd1770701123e5b35067e855f74d58c0b25ae3461fc0f1f33648f5a6c338254539a56f221cb5f039fa718c74a895915960a52489f9e4b768b60827a2653ed69d353055030b9eba31295f383b27b5fd999a43344fdef28717f7fbfeaed70e70ea0451fd63ce180805a751832fdfa4b3413a6a5dabcc36c19ff3c41b4edd0d108a50f8e00d9508185ee66516f4969efdc72fbef1313040cfaf10d4e7b222298bf39621a102884a1d42adbc1049d3156068364fa692783a2f7cde7b847154498e1898aca50283187cee21edd30c7c21313a3b4d00f2ccf76deecc9050a7f3cea7553a919346499f943f49cd38a6e73ba8a784c15a2cfe3a0b8990f4091c2cd40449370b6327f609eb36688b8fbb697a45a50fa0e42451f6a88136a4842ade99b9630f45ac7d09eead2ecb6b1100046986c643552c679b647dc1ea6ba385b8a2478a7f502aea49f771a7350c15ca9ea3c5e76cbdd7bf4ef0f9418225bb39ca016218a35a78ef4a55ed862637e4d58bf99cd134ecc1fbc3cf432ff2a1af769e589cabaa415347058f365c7366779d4e942c98a4078f4c7a6de9762d6621bcbffc1303cfa2fe2d15c1278a9ee6bc6c5ee9c3a79f4501dfe92e85768ff8aa1f6230690b0d67b557705ae35def556b23b82bb39f5f3a6efb56548039d510d7ba64f7b410d183e18c7d0d7c77acecc9ad41620aab7c9a7b67717b0375489590708190d9ede304bb475c0598f5880d1de5b6bc59d4893130aebfa59982d130ca675c4a0cca30893253d15ba2d7153447d87d2baa29b61e5abb677656e641402755ee64ba6af864bcd6e88b0cc42c7a7cb0b747aa4462240cab66c470b23a243347ab8a04f96ad98f56a047bfd52af46226c3af2de1958c9c160376f0f816b7f83a6ef08e2025d4aa6bd5751acf19378a1c19a092c366ad0eb72043a3d20b4a301f240221dc43093a9d2e5dce8089bda2f3adda733916528bc177e7d617807af048b2315e23496b0aac087da0af6e8a929482fff68fdf660300e6ea8207be51771cab007794ddf3a86d32ba9cf40c782a1f31c665c7c02fb5dbbbfd108b5793728955b1d1904f014b534208fdcaee17b9a2dec2c357c24b647ecc7d85fc2ee20926bbd8c4bb1d4c0e45a640bee0ca37b8d4731b61aa6996fc26333318380561d7193c30b25401e19a4d511d7050a08c1f4ceb2ac57143f2142166c4b4270c826a004db2621009fcc4d935005ccb62ce825ae943f32a7b10b62a110fdaf30f244f1d2e345a4e7ceb235000b09aabba60df2d694abed5b0c0445a8cd52af36c8ce9f3244d3c518e87b90201796de0e494572fba43dcdac6ede88c0ed9cd640cba123211f3407eb356f3d983e53eaf7f12198aee5e55c348780a6385203a17254249c7ba8906f40232ec61f7bc57e14ca9b28a34069b178f0e69862416abbd6c3a380425b8cdde9f1256b573f19dd4cdb1cbee8ef0d29653f2229a4f3615c80bb18b743b1670521ce8570145cae8e57929f928944b8b201b1ad6677996bf2b8f36324857c75abcf2df2c6cca041ec1a080a3515b70d835cdd42f97e52dfb8585566031eb48e781f06d18b264289f7e4449c91a648d80a89fe185fbaf3439a7abba315d7064bf54c90c09d35a77c4892baf67479d90211d6218c0f438647bde6bd76d9830d744924b819aacc4d90b5f6cb7a41750426d7496507b0de36604686ea9c0a1e3706b5977abde6b3e2cb3fb2adb17faec1b891bf99b9009a6d92adef8d1dff65917514bfefd4481c61836c0d2ac2403ab7fc816e3916413aa9ba6533cd923513c5ec438f29f609c737d274b148bd43405feafa9d28b44d3e30b185bc7a040623c2b51928a454df56b87994600292fadc72855c66a8079abaaad1bd5c6e282e1f687cff070413038da1e106901793dd950f0c3686ea8599db07f5ddda720bf9a0e61183e5f874947260bc51f7859c0502ca653bdd94b94bd5e94678f6da1006e614849b7910e11147d7750e290d051592467eac8606840e282482f59280c151a4c7bcab751119b087b899095c755b3b720740207b632f2de6068238082b5cd1a465e248177e7cba67dcd059acb6f2e88ca139d19105fefea323e211410af8b6d5a1a013148309e8cb8f900f1baab629ca62c984f8931b863ae71f0e695c43c3bbe8a0b515b4b346be04c317c3df52d86d48b61ed14211c6de9fc41be3e30557d066e378c2dac01065f60855de0841d49e0eb16a4c8a009c20d9f6a725782e7ae17de05130d7586e082d1baefad69032952c11bf78bceb0de9edb05b68a887f176e8f4999164716ddecc4252f9c2d449a60d132d0fe1fdd688a8954e461d14af4da27421bdfce2bda699ae9ffc1bba91e15f1b7f876dd0adabae9fda2d761b04c4627a5d1f446b0aab34c5984d4ebecae99a7d0ff3a89206b747d5d516c1de7a3f47a1e001c65e1eb85d2886441ff84a2e9ca390885e5f3d0e53d1df75ca4ddc46f5c762f466c45bac7cc68924ad2b0e9aa9e32c205640aa9ef3cbab065501b272087a32d06677155eb63d0cee546ba77a56318fda409b2ca9d18480db3dc110e65b2f6cffd272f2ff46ca7773ec45c3a5e187f91c0afb3102698a6382eaa598a59250f05d411c694f1536a2595967e1e0efef1ac2b924ec898eebc7541098710fb4ff1964c1399e25f40862c722857682a4c077e9e624cdf1a51c26029a5f51ce7da25760ba2e3d0295b7f5d591964462b5a5027a70f982ccb45725e50d7335fd644048a6dff6ab15c63722c584c5d007df1f85aac37ca5be1a9a30f4913b0d01180a51fd8a6e0e4ffc029e3d3cf37afe82338c0d89f46edc1c85f29473b02c85933b0f82557bd4d23f81fb0072a4a9ecc6abdb7867178da03801077e1ddf7cb64fe68a61521fbcc456f4338d0d40de81c6e46343ebd959482ab02c3a2c7bdb75ccc43efd232f6a92ee456e68bd0a3da3cba0da69a71361fa3daa4d8b4ec9f04307952e0aea2a04c28758a4303c87f67e9203139e431b42cc2336213e768766b486b5b23ed4a51fdce70d127abe4b8db9d53fc4562cc52e2662284631160331c56ab1e869ec4f384f639f7d5fc1af951e3116023973cdc671d2ff2e89c4e51839e4199a95f29f90e83153b09fb5531d6899585ed35f8461097dab37169e89767cfbc01d5c67ee899bf12faa9f43dc374450c4e1cb599882fee0e68c18e39ba83743302393a046f0d6996319aafa364c71969b4353789717d5d06cc32632f18bf0d96d1dd2156784a5250d90d703722e47f184015f069c1070f980b1c1eb325a9d7619c7fbfa3bd5a194e0474888210a58184dfcdb115df651d6a478838025f0ae9de57f599a09f07ec49e6dc7bbf7aa5f953a77e0aeba8c83761fe9d3308eb95a7d4879c575db646ed4b4adf65f0b171a0937d36aa53435d26d54c309dc187bc3996c3399e4c9c3c274f2bd3b95920a4d20605bd313de1fbb1b4c7469c0553a9e2fba27b293f15aa6a2fd1f05201a19ef18b1c8f5d8a0d4cad590f0df9b560b1dd5003bf1ffe04cd5a3c40b47815ddfc1fe822829a1197b1a16a620c1b2b047ae7da19e32090bcd9c8e2025c11d6fa577d3cc72ec3eb55e00faae8eadf586827997378a5ea0c5502872a89e374049eaba717809a6cb093007d8586efe2eb91b00db4e9c2dae8f9c6499da63f41935dea3f01d1b5692e9a1a033aeec7f73cb4c4c8b06867f4d7722b0c6d693ef140d907ec460c8b57d93b4b4d140e46b449017d6ffb8a3329d42818d01312d0598981fb8a67fa24fbbe9d8924bbcc4cff94de64983ed99c07c25b72f71c062714481e598db80a78cb7f89d6a2605b8055b042dfb9e4361b2f63192347f5ecc2cde30c3c130acb61b97da330ff27e766f54ac2b8c8a825f63b1b70082f4941a51846e6cdf2098535a06fd2c3d19b10ddf0e9c17239badf3a3151ae2130087d8cf9652024a00129786c3bcf905269240be6f789a848d944b0f090e3293dd0b065d6b6ba51669636f8bd14e2019d210b66b0d05b502fd59562ad36093a44c813939708a018207592e8fc35412b735f7ca0739be379e68caaefecdc474ee42f1152ffe33f22bd740595d9edd6d99744dbdfb592ece7301b1b31bc0a28b5b4347a0132ca72f1dbeb90b7ea7f482fa0a0c9bec57060ebd1a9209d8ff2fe13b0bf9a413f3f24e613e197b7e27636bf251c24dfb985e3cdfef70da70dbe0aca60baba18d2c6881b9acb9e9ab60beeb4e12da35134eabcb21e8f523b60b2a58d9b8e9b2ce857c8565cb2a47cc84ec148d1ce055b09055b696334c46590e2624dc2a8cf82a0893f987ad5400396923fcde655ec175d5ab81fa5b47414598734eadd811747454b49d9c4ab981f9728e9aa21427425ad134a27c0023440605c4ee1f08f2041bc6628ef2e96a97867a56c9bc9419195bc36f802eac5a6da5408d0d6fa248cb655ff80d7a5f3792b46df573f01bfcfb3c8f82a7e284973af2f445a8d11437ada8d60bd953ab24bf60cd4b540de00f298a2f5518f267f2d34a0a0a51ccbc165c3d8eb5b04538da0dea99acdc3ae943c5b59aea2a0b2c38d413ce7595efa6147615fd63e66e5fcb1f60d54d5852ab82830d3b051c450507e5b0bd4d9fe0a07c00553be74dbfb5778e001b311b59328443e9e4b303e538d0ec13710dc281d687fe7081e8f9786de24697264bf9ae951012c6c3db285efd9c3bb83eccf3af377c9e5113e67d6933887ba2f25139dd5852c51a11903ea4e5bd09462029c7c9954bc37aed7bb74d1f032fecdd1a9ea26ea4ee17469b66a3f39d6f0b5faaa5ef037aeacf70c44eedcf80b0bf5dacfdc55cfc07bb12e353f728f17e06f2074528602ce38bb05cbff42af4276297e50632330c95f7c4ac2be24e762a85cad25c21c43f62fb878005a3c84a5202adf020e74c391d295f9c85b56c43e36d2a710cc7afdc6ef15ac6b1d1f06a84987b17312dc7c3df95c503d74ff9328242b8ffdaf0f1bcc7ed6d8536eea9bd6f79cd9a747d0674d8dae8a46632d6bee30822beae5679fe16d84bd576965f04404aae3ce81989075069397e17735af3f3d4857614ad6c43fabfe452305c69cc0a2accea28abd53138e584285900657457dac55d128a1d3999cb84874fcd0818e5e29a4e473d1809a1882e91d81579d9082e400d55e820bee615961f2b27be3c63b3fa4e0d47d0b07f2a2ee79702acac58bc5072dbced429600256a0d72394806fc2e3763356b07d84d55ca7c130540ded74c9210f2c7bb1620c21fc06c8097715a057b84c3d11c8a3f3ecadf8e021d3b5a1d10ae4517ff18bed3d94a960b6bb466ff750d523c4bebbaecab6219fd4037af24869d785eb1d6106b34ddb26c26de55a226f868a7f157db0ea5db33ec4b45ed2786ec9c39d2fa3d4b1776d11c5649ed1286bd1add5c087a26e439bd6032cd16cba7684b0974156155d8eac23246184305c65462f1300532210a568eca1b8a692ba7c3cbea0a8950d5518e4b9b623f2ee2308dff8f8faef257ff87c131c99f2ae3e3fbbc31ad243470a8355b9699aab44aed3b910f42b1c0082d72b2ed82b3639e470b5b9e6319b5f9f49945dabf7fdf3311a5bdafffe8ea9b069485f8a6fa201263125b487086a296170a6c6b2845939e4937e44398319a9785e54922ec40ab33a1ba7eb8bee9a1cfce9e2b691211a39e7dd0ac4699f9ac91358da2bf810d932b1b99c509bf346687bd6073091b20a28f6e0d1f17b0ee2a84921388a5f871e1418d6ae984284f8fd98ab220ffd24b8dc522e9c882b6e1e204d876a34407a537e93e467b9f2eaf77a9f34a672810722ab4248ac4021f66c5509000504447da116e83553de6bae361b126b46687506967ff0be66c88bd8d9adb840770efbce9cece49495ec7f2a47dec3e9789f30284fb35bb4dfa1b66b7f6d1ed1bdde1df39136c6a0ac9864d92c153a4d47027597eea0e6836ebaf10ee380f00d15037b44820a152393928c5cc659c79a81cdf07468672b5bbeec0435001748523bee6bf4267c7f128eac152f089724929e4df8b7d48f999802482b25ad3c844abd7b8054a9e8183106ad752fedd5ca464aa32115ac9afb1657f37f58ce9fea7686e6de8499a49cd6d6c1f1835da0b216782e11621df9a05701d12bb51a2e233d30e8c18df7793977bf7d03738f06f333703994f650acd3ed0eea465b3e1824c3d4beccdfee2df532283ce14642cee36171bbfd9b1fe98a39a58ed145d096334a549ab2d4aa767136ea797adb7c1abfeccd86c3c602b0a80b1982cccea04a418f6541cfd90e4df1dce2e2004c28c7f5b3191d001a99757b8c48aa26e837672e11074b60661fdbc80b139c0b5957e71a3d564f8574afe9d6c36154edf722e6c524fc758965245a8a43d8d9b7085c7cc8de83ad05dd60f192f5499eb53b36133874baf7be63869633be421b21a7a581511fa0783d478ff451c7a54625058203ba3f348971de14b07b9cd63f019fa28f4e27c87d5ce3f9c958d753b00ef8b06177cad0701caffc8ed50f083850e6d147797593f2c89fa50db4558363b577c5b50e914379df114c65ebe50f105bffc6d3c925e7af388c3d48472d00214d1d3d8a49a3e63ededdb1d8943f34823f49f0618fcfd9be2e6d797f3397623bbbf2da371d2e84ba65baf2accc7367ca66d513b394d0ead70a03949df645c1c7bbbc48508f11b34392fc055b9d9d882ab5d61aef86d7a51a058ad45409a0d1e6efc1b427860367c3635550ef81c2f3782ae3733612d9f075764866488e707c1a633f03b52c8c9338359840470bd340359184b3871a46e71e9857a9031dc6f3daeaeb5417b60e8e7463b8abb4b1fc8ac6bc063a83fce47469755d8e11b9a99c21b26307e53b63e8d3715d6b29049204237e4cf708e82525a7539d3723bdb01422522646ef9e4c4519c29978f6c4a694926688f83dc598692e82ee7f75b9c3df431da055d5b131b4456aa73ae1b11c42af92230482e7d76811ccdb25a217062c4d039017b52c5516623b0b56f0a0f81643590c8f5df57184b99661a7fa7208588b8655465249287df1b38b2c070c961b1b7f0f0c32dbdc32088df88391191af5a034a882485c1ae6acc1137d09db3dc0f1032151da53997d0e487a681ab7c52db5741b32c41d13ec35987d2bd07dbf2b250c4513a68da8e44c0456c8e7e7c5a0b6c84d53f84cb81373e499fe271a2696c8c5a74d745c9806b4bce326a731547ecde01d61c38723cae7c57de5faf8605ab63caf3e733cc99e28b77be96d4072f80b7f0e42139b991bfbc6581e32ffa1c788ebbdb63addb62fe674a3da30fbeee4b006685b7275b3550536cf613500ce75f852721df9d7c01a9ce48bb09038418d482b81ff2f6ee1c853d91c894381006cff461da1c73992e3c14e17142c0c9f197cc5f6db0cf50ed9ac10ecff33df667228b58c13574f4a37612f38cd002dd3d64247a14dded909a66b33904d7645e9ab2d8abb444e8b5489d88652f57cb702ca62676016a40fb766953c34a16e70291a42d14523c94a109a203b078dc4ca5a172a96351898cc67d9ca85a10e31c7b78409511ec64920da738137838d7d8f522e03f20ea3356f6aae0935d3e18cfeeae72a0129cb5b7e2eb0153090bcc0219f63d164f14e9a4b48248e125e78170869f1ce162cec0fddd2871e714c66c5878cfe3d88d7fae518aff98796b609a5e89219b2e151bb50f3a024daea572294102307dc97c9e4c60debaed2c7d748f7f07ce2b8e01eda0c4578631ec3552c3107606bfe5a8980aca44b5b5a23a2a57d7206fc36bbe47f28a9eb662fa7538956eac37a299638e3c56b0ec71eaaa17119e5a02fdff1ccf849bd4db976213d9bc4a77fda0d175443ee61d48a56a2cc2e1c202eb22070092cac9746e01d4e05fc5a9c7354c53722e0d3cf55a68273d67bd0baae7a2854c9e0c6661bf7be340b12fa00d00b8d1b753adb8bd2083ce3d59d24a585fe72799e80d2ed18d27444cf538cd441d3cb979295e6d083c08226bdd2048aa3a7e34d51362af7242fe32b2bbe04a8182877902d0d26febd863c061a9e2eb1e4f4db06c5a8f3e252c548e8cb65cbc93506e19a8a1194770469e9c04eeb02064d19de96879884542e74c73c4191e996696d72aec4b25c54dbac486bd45e2f5c6abdafc83c4edaeb2b6ee436ed7702268134ed34da1fbff749814506d96bc01ae5b0e161c49e1837dc6b1dddb377670d0cc517f6e928c5c3d7eab12511047b5e91a53838d4202239b120cfd748c67a9671b247d4dc7334b14054bf5d520653275e64a05f0d6388ac5b88a33337952d8f1c8e517b8f807a45a375db2efb3a3ee76a84106dc7df30e17342c37360a09ab6d10f4a5f47805a683cae46a890121415d13cda5d286a38528e6926ea81eb4927a6c71f8c5fb398f974dc6f5d09b1e425ad13f85a7089e7adc4a9a85d0b9d73b67d8939419d48fc5d734caa5ab3e507f1c49af4a40eaee7f24e0efa1ce96f68ddc9ce51db4e49e832ae5eaaa909930e321981f510a8c003c85a6ef02f8a070ef83ba0f1458a3ca4679c8983f321f31683cbe77ff08e407be344466a5adcff82566500597fd93ff679df54892d519260f2ba046ae78f6b7a57d2530b1cef9e4a45e664cb324e5528832b50a13a0fc8a8b47fd5a9764c71fa2a3823dbd89251bb5aa594e213a94fe5f9428503c7267e3c7af3865846cf8517222927f0566afaceaa5b518bc69639442744c14adaed3bdcf4a18a4a518a2361c7e4bb3d73a7fbc794288d19e1c27ca227f70b5739d6d74adc7d55d5cd165ddec435572704cfa2e739a69bcd95a366cb24f022f288f05df439624a9bbecca25c739d94c29fc739574f59739d34692f76bad76bd2447ea8d775d2aeaac7efeacf0f4042e2421a61bff0bceef99641c15b4b165dd117b2d0aba17bf8fcb4798c5f8b0403269e5b6b2b11c2a91c08238adfd4bc6e59df66b6e531c095eb25a51b54e83e7143009827693a079ccecff637f2b408a52f4575af7b30d66d1c432efa79a0078e44eb449b787d5dc0393d9ffe5c1bb570e018ae67b2349ce659b5ebe6fe2ad5881b1e401f400fa07deb32b3147a74bcba93fc8b40840ee9785da69e1ca85a30729b9b27b2417d2bf097cd16c7c650f3cc3a459cb17deafd58ac34058e6616384e7e590420ed5ea363d690c7d1106676f8899ccf0cc9ada24320cd5f0e57573fd2120bbd7aa1e1e21fe174605a71f52963243ca8318045a27b38294710ad328791dd6a99c4a1f1e8ba621d81441996deb6b881751525a8cea3cedfb157eece85ce0b7a7036ed4687d43dd292c4e639a8d4d815c419da6e58b2a6d23216e692495d28f73475b25b5e0b77c730703eaf92823271bc96bb7155a0e522b074c8778bbc16eb5905e633283556695ca1846e9a9acf332c0aca89d2ba9e841d2870a8d61019e60f1fc0281a40e905acc0b10430ead7774645309dc375bd91ec87af4069b987b9599318127f27f28657f898e639241e9d6c0089d66d5c448a4ac81a0d3b7487d2bd66dfcd5c8b3dfec5be7b02bb32b022c8e12f50c0b7dc27b974003c60133bfdd2b414a9b65df10453bface8e2024db4f4d4e35d63beb437e80bb89519af508ad24e49f26e022fd76f1b41864a4ee01c0ad085dbbfacd1d57541c79bc839ee986afd2286ec7bc658cd506e1f8e51ea500e01e8f9fc657f73402143f27899407a66799a5d8f29da5d68bc781f853346a7a68320dbafdec48023ab9c51a38c88b22f224cb111ed8cddcbf02b937194fec4b1a02162fac125ee2b6dfe995efde2877e5b3e8a3d25a0072411ba15820800de1b39e3ee0131c3a5047bfbe9bf8323a49548bdb3c660cc65c1aa7b2e2a21f0a804638241599b0b842901beaf6e91e7800563997abe68f7a89d626540e917a0f1bef103c86b10e552b525a60b07e9aacdb4ada7dbddd66c473fb6368d5cd95d9cb8e9744ee2b995deba890d3e6271766622a5a53bf1973c97f14a0394d7b29f342ebe397ae1bcce36222c8be4968981bd7b87b64ba3bdcda39aed67ad2435e10f4ce15897be6af0b4406dfde2bdb06c3be0b6b9f2e6826b5aa4f8cc5e3fe0709531582d6c67f8f8961a265434cab5b5b28614cbdc2ebdae3b182df5d579f1540da79d884d14e654d8c91d3dec7a9a8aadc15d1d986f0ef61c9e7cd2954c2639aa8387fea1442b74ae2cacdbbcaba347eb5a7f12d5513b893f63cc8258bc2adc8a331b251a08ab15745684f52cc9f510c340a07d98d1caa792573a4a4352a744d7653376311e9a3484360cb6245f67e16ee98e0917ff1788935b9bf1003ce137e38bced6fb2bba609a20207a200d498310b3991a1871320012bdc014566e8154755fe82c80fb02f6b15a129440f5eacacfdab9c99cb789a4f620db2e837705536d855ac748426fe942c629aaa659eb3e28d080afe923d326817aee912df35168b439897c4657337f1eaf4c19b0414f0110ad672409c2dc4e550b4aa1fd87ece807ed0fc3f50114f6d5f8398b05e1e3ac066dd25ef2476b20f4795173b7416de8641c63ff3eb25adfdf5866ffeeb7b5c0f621e00d3859a4eb9096c52e28b58f11d4aa077defe01ab2fafea913f23f66c00da8a0d5b5eed27b80459b2070e14916a49da841c65009379c886d44bb66607b4ab058c099e407d79f8ef504420697dac553bc465b5f3a3533c61f0d5fa366560472ebbbcb250c7a7c444d1e34cdba6b941678c8f2f78213178101efb12ef951d0bc3bd93706b92bf963133376c64c32ff29652bc05e9399d4074704e84e63bac30329b038020de14c874d69d1b488890101582a2c7b51384e84b4cb0f8d62f6782e4273c9c29afe80ee2e99beb76ae614a57d5e9251688d44e6a6c1fc14757660c2f7b66659dd86a6fe1d945d40629ca48b7119af9200d61b4f5f3d59256956b9f7807c1ce3599f476da9be3733296d92b55e0c4c8a9efa7cd15d8b4b6ccf22d9e2a070252162e918263729b27e208dafbb64aedd5a38ead1fccb4cef19479d7fee24d8e5f58ed098cda88b283e2e579ebb2c8ca41732c510e1a85f6e6832beca86786206795f61d6e9e94119e51b4bf5ce4a3d835526b5c51340fd1fc26f3a0db8f56332208debf28241c004c17aec6964a0ce26b237c190f941c8007a0257686483c69f7532a04e611eff34fdfbc27ec8852287d58991e4d19904dfe12261498ae300a72ce3dabce2dc649c1c9f099da67b6b09221b555b450d043a2d08e25f8ad4c44c25bc3c5544438107cd4dde27452300c9aae26a27beb941545ea4365dd267545e5067839499aa8091754b12d7fd09cb5803d238ef710e847177aa7cb3c11b8d952fd1a174021c6be1025b30f7e38c00b9a4109f6a8bf9d35d7879fe6516e9f55cab66091941c42954f361c559be59e96ecc656f565a2982fa03bc3556e05795e05780cc82df73d3f1bbc29c1af1890efb24568265bab42348de3ba37bdb60cf8e3cb72b4b526a3f8be4061eab7989be68e262f6510c65b03bce510466178aefd197f07b9ef9407f71e8ea05233308a7259e302ffe4a004d1c6d30eb9dd8e8cc37d015e4569723f6b6fac487edc10db150aa67487b0350a1a1c8eac7178c1393d1b4e19d12c1396d54d8bda62f05c13cb9b0f2bcb1cbf3b6b327ea390d76f76eaaa310170cb61aa9095f782b373a6c532e7f5ba658ce111be9d11d2ef7e816253ebe2e2daba92fd9fd119712070917e6746c845e2808951ed983380e1380eb8b52b7c0a4f80c6075c7fa7af03ec279fb6cc5dfc0823d1fca8205be71f2d8e3c8c864e5613948561962fa7cabb77f3de69780baa9e34c4021e1b2ea1ac00318f6dd0b6cfcb21233603a6cad162d6a350e5ed5688ae9126952b04a2418b5353a402f1f531966b2f2cf2c43c6225ea75e1b02fb73530ee29cbc01d33b2da2197c7ed6883c00c371cab43e404abcba12efee3274f1b890515bb8cb183bcd08308449a7195430a9c0dc7f9c9ae39415f64f5f9384a984a2469ce9f7548ac4cfb64b1df398cfe01afc8621880a7c486265f2f5c633669a194c91dcd5b767659cbfecbbb1be00236267842f589e3e37fee07abf43d3cda46acca40213a7958e51873b12406aec037ba22bc165c54da1fc3846aa643a90ffeb770a07b8cb53f96def443253c971879a49f1eb1232a1d57891ddacd1b30b1676c0f06818940c8a29621d51b3a386eb10d3f38c03bb0f0196f0203e20216897afa4e44d2f4aa030226c558d8e5c664013b4a076e5256f74e48c7626d140751007b6cc0cf8a0238a931696e5723ba7c3188e50edaf2f60049aca18a21b197bd58e71556eb763fac7a3772ae2549e205b5028f8fe0c13e9b26fc5e11f710a0bfc13b31a5a0da6ce2ed88c5f58d155b5ec0a55124211a63dd005a93cf2784549b64619a901358566141060ef5f2fb884c13e66604ec8af20b0a96d9b6b5994bd5e4e4b9ed357ee7b6d8386b47145828486f1f70f632a22b875c0bb7f00dae49fd65e3e9428007d61b6421c117d98c6fb4bd67953bf50ce4dc425ef7cdd59fa3dbc250b8b359092686d9963c967cfd4064dbee25461ad9c26a3becaa95365859692db7f939c2f5501997a7f7f775d51b79fe889ad80025dc50a6a7284278ea852a4c6ae8d5c5d5d6c48811b6e029b23b015036fb7d134166610a6ea63622b1c288cf27364ab036c1566454484c19d72462adcc37e024c20c3a0f2d0653707f4817cc4f2bfe5c77eb3d2329d0997e731c31238277fc769e796fd253847c8022fd0e96fb196178c91b7bd9169210a0639a598917b11d1c5d5f4da766d1941f8444bc2eff6832eb484b1c757489feb0c8650bbc260099e2edb1c49305079391f76381f9a432397e370c72031a9a27feff6552f96ccd717a4b69cdab7d4ee66cf99303cbb8e9073d9f5ee250b36066f140a9fd8c90be2e4e66b06d628f68cf91a27032797ad61adb3264f8d187768035c12fc2534e2ceef8fc10f29c8aa37dc3d5265c7b1fe0bd6b59b050ed3badd1bed3a0f7e865f16c000fc3361c6e35d2ffb5cc1579d9bec1bdc266b2c2c6479b06f9e0c7b8323fed7bb7138bc2db8f568d313f79c35583df7ea39bb4adfcc5285107c43bd9a22aa8d6c51fce4b344e33f27f2af1832def045ba3f6034292df442e4ae138a89feef3baea356372425c7c7aceab101f0011e8b99d3cb80e729ad4acf7b4e959a1b161a481549b48a142eac39da428de12d61fc45e950dc0b2d3952ed119044507e8c517429ecc0477487300527b5e4942d6cf17cce0d9ea40c53b3f236534ebc0777bfc086724168ed2cc36c30d8c5a2116664187274ec1c7804618050ac748add82ac282e9a4e189b35777dac509385e03f999da36af4fc51baa7ecd0bf09bed36036ef9262277405e18a155ac875098978535ec58919d84c897575a650b632aed3cedb16121f996fb6cb4619d21d9ae2710a654ea47ccdcee9265d0c7adea701e6911c3b3621c413d3ba5e871d136029d87d59a6e76098ff26d661913145710d149c670c46e008a54ec5e8ae95c056885ad5ffef161f2a4bd08d46f0ca5b9313d2d1c4b5a5d5e86ed61955e6e96aa26f7895ddd58552a64f519ecc18e8ed89a2c39362808daddd45498b9ff0007fb700c3e849f50fd76030cf667c9f83dd82ad05564881cc991f0739578ab382bdaeb6b7a911cf7730808146ea6fbc0508fe30a54ef5edf1fba645955e370fb1dd2b6d15a0183167caecce36cc2649147ab4dd1ac424eb2999ebc8b4802233db4e43afa703c34fa7f9451f32fe1175263c56502920f9f1160a49c194ad6e93ea30181cca0e3b3d088fb5ecacb006a34db15b8a4b59557df0bae14a15670055463319405d4c4df8f059fca49a5970158cda3284c77f677a9059b332686775ee58cdb2f2e556fa446fff3f0124aea959ed705dae9de936bf60e03ab6326e64cb4009972cafd6a4cbe9c64db97d8b0e500800f5b9ed49025cff219cf237a59cd6601ab5028fa1bde98954e063215ee15285352097961a0d126777f6bcde421edad8364598d509c2fe2ab6cd38f718af3a69ae52e168b210d4455605ca4c3e6b68ef496cb8ed6482a5db62eb7cf489d70ec5ac73f298412c3882a5c921a615975738d0f5520805c11b07b18f40e4aa021def82109413920c16a2d121f49c64168db13bea7d856a39d52ed172820804e956786c0c7d712903d3abd41f97ddea003509c4cf4197d21ad9f2709d8077883a521402c39d6e454133cf1063ab3aee97cb7c7ef6630e719ae7de0c664e6719564da06ca49f3e9a9b850128531835ab9c0c55aaf570fa72fb429734a0fcccbda68060e164cdde2bf4f62c28bc19e81fb8422f4e3aeabc1a9d0afaf9693d47d5648729460ea6ed4b5e189a6adf65222535993bf2a110eba00d34150b90a1b7da463c50542da5b5dc88152692ce5a81525c6b99b956735e6952d54607e2b99d31c912041176b417d37558bf62c49e4a9c37e44fc263822a1a3ddaa24bfd48095839140d607c12533183e46ca0702e377df5268aeca66a6dff035988ac01f7c5b5002137964f5b9ed409712a62b522a78acdc80d7fe47262ef0084df6d76eecbf78a3ce3b9d22a4af76dc3cd9b2fbf2989b0e42d581523a734ea783532008d0370cd3d39c00efce9e9db1dac9a4e41443da89bfd5b74158eb5b836d9a813df89426917ea8541dce1665b4ca06f4a0923d46279f28f984ba833dc075e7e4f2d5f9f64ab7a1919a998b995a048bc3cb9b22e1fbb5340c3079f699f005e1b8506fe7910630f658dc827d80ce0cef2f441c5896c1104a51d57345168c23c267bd7599fe14a9f10301ba2006738ea7fc207a4d89f32d0471af91a61cdf6e7c88651526c16d41071c12ac0c77066e22b72057468ac1a6ab96037aa5faec6d4bd3a90396b042a7fa640307cda7990b29e65b39905db066c1461502f839319507e8a40021f60cd458386f5db3a838378066b8e61cdac1a2b94eb25f6dbc8d9850a66cb8676b375457eb0391482e161339ceb8845bc74db5e9219ad8e4e4e942fcd2828b96a7d94d4555d94e84a541186d9e51f492a33369bb9b45da05d3106b5cabacaa196f33d57ce8d8598f19d400a9505edd7f602f1b36f447a9f25835357cc5e68983c6e2afd202324977922dcae2cd1f6ad07db674b6410c90131bdfc3db7eadde9af81a4a25a0ac6be59cf2134fdb871c555d151aaef252d4f45f76a40c97599ed3ca133a9a3e4bbd20254e9b214154f5b453ef89d47a6604a395081a9ca3200076469f7db022b26c0be41859a6a7432525d91a7f5ee596a896fbbf3266b54103b02db964c86598ccdc93259b4c23e9ad446e4df58cf362acab49be78c852117a7aea8127b85bcf5adeea61ec00d7f909c8d658577d6a69bec9dc0621ad77bd1234e9a353f71b5f6dec2a554a453657373f8ff4433873c3a6e6fe515a0629aaa3baf62acd28e167537809d9e383caa118b2a9f39b6c2876f0dd720203a9df1d300a8b5cecb0a035aaeeaed0d45e361d0cfe223073ac0833d30cffa8890983f8c3e150f4ff2f2454b08c2c81b97e928b9baf1fba1a4e40a910212f9e46e53288933e172d796946830c3e335f30921a110cb47759f90d5d4c94279a4da301289fe2fd6e1588c62391ef05f1b943bcd1fbd2104253be546ba547cbb54e98c3292c53af544a62e689a62b1162998b7fcaed414ac14a944a3f2eab3b3332618a33558a478b51ed815204e9f58897d20077ad0833efa0949bca9d7a133ce1296a6d6e3cef7459b2a14315d348f27154fc3293e7bcb064381f72db458319c640ad3ad5e9a5089a53cd09b2685d4e293b00b818e3915ad4fd4e5877fa7e451bd51394eeaf880b126d67a29851b73782a01fcd251ad659781f85f824b35fc9182381c43af11fcf6e85a4b447365ab7cc82e6ca20f111de18e388d6aed44dc69c498ad53919399a67cb70139cfc52057d5389703773a8c46b11c8d652ca6c324aebd8a586b1dda39ad300e633010e36832f250710174a0b7c0a8d99a972a4101df03ca4816eb569318bac03f3ec49401a954b574f42a0f35c23e82790cb3910fc8705bb09563dce7ee686cb1ea4d50768bbbafd075d69d84ef210035bd3f9646105651245de336f9c7a048a3c470dc4bd894273f1a2aef146976e9da94153745a366e241651a0615a8b41fdebfb5d33f54fa2052edf3ea8a32cf5ce30a435fb691bbe30087324dd778502071076954a49f4922a6bac2db55faca7b0a82792d948fda28760dce91b2134c94b78dea48cffa464904dbeb8cd39e45db899691c25b7b9514883d8b26284e4e4d0ce58b6e8ce999e4d32b75df8f9842bfcb52fd1157c631e4c93baef04b976061e32121b7b29e3a30b56d8c2e74f31fe532b2d604f5f4c5aa3ab54e03d942b68719767125539f6aad4ec69c7f0c9967c018b9b29469018c673385101b6817483f4a00f14e8cbc51e01855595a789c6cdcb2e495172957da96c13de4b189c67f0112d848eb8bab18f1d169d2700a18cf85010ec76d84e26f04a916ada8b82f502921da3638b925854c3cebe6e3a088edba6509512432c1104da7f2391772c8e03158bcab2c0a7b5edf1dda88f73fb686afd40f12de983a58e40f7c4615fbd3c0391f43d4a751cb90001920933971eefde8a6b0161f10909f3994eeb253d7d1c8da12b452c32f99e0b6b2c8bd1c5cc0d11b7a11f2513bd5a5c4fecb95984751066b8dfaf9f4eb33d2d79af7df8b5b3c28561753b900c3606b93227819737dba1325b5fc6964b323664d85e38071be72cabb85252e0b59062d5a0bcba3939a8a2aeadb13c666aaba30c2c727bae2483bfae49d22cb3c939f953ec610136dde613869115d1237152f5b4b910548be3d20a264c64e36c9fd5d4367e5522fc00f1250d04aff85bc70fc3fb9d48dc904b5e75b812227e358e83f1801bed0ab14212a2721935869848f75afea86fa5b38f1b271c2a8a9f73886f0aae985edc737ecb0d2b77d5dacd88943cff688232a09041f75b9b63eb7baac0840a486ecec65226a16a243ffe7c87553c703c050bfb03c3e3a7574dc87bb6a4638ce3df50d7313d800b50d2ab31efc12b9f9d0b94103cfd2ba2f641e9bb9e83a3604723291a86bf77d4741322bf5754e9965b7ffb819828f9b5447af31ac0c965fe6a139c0aa38cee5b2b615d281bbbdd8fbb0d009de4ae5189645732d446864db1ca62c42a9a87ff1cfb084449a537346ad691be56b189ce7dd43658d9326a8ab7c5f5bb273b894fa8b0fbdf1c2854e510fc05ca156612b3f3a08e28a6261fa5d91cdbce4555b98999cf152bbac97ece818ce4bf25c48594bfa93cb6800c2b643ba87845ceb44f6ebf61572e68f6fa2f4f66508b1015c315a174fa870ff2c93ba3640ec9b402bdb72809bbe22792842cd706ea5baeacd8fc2780a2bba82f267272f503e5842a72f8eb84b91331a46a2ab5fe3f6ccdaaf810070b829a8d00582620f75b9df028607c89176ad31128bf94969a2497bd458322691edef8f2fb6ce8c99e99f26bc2ccd0d4da7ece46bad224efa631d2ab7474fade530510c5523a57e4c8571b45bd9ae921a7ffe488d8e120c9a6d2c9439a54dbc13c0f1ace8046822b6ff9e4a8e6cfd11b8a28917a8eb4888697ca799e31992cf330b8ddc12b08e0f6e6f4b5048098314fb8be94b460ce3f03585bbd65b1bff179f9526f1b45dafea141d8ddc433e1edc1df93693cc034642666598cc79b2a9c53ea8d7fb09c91961df8ab83ea25343f2735cb239f332f6b6fe8fe7ccb41a1a34b8e63a8d0815eb90fb214735279da745443590ac137b7556fa28978b62a0eecfef4f8395567a241ed3427edeb29c46786859857f8bc28dbe2ee74361ee11242ab3804e3d059c339a8e86fafe1a61c35a80d3090c856821da8561c3402ce98ef5d267d071b6ee8f8c07cd688763406c68f17850b7a90057cbd64c246cc3ad0adf8b00d42eb9a606170ce83058aa23e6bda88a5cd2cf7c73ce927033dd4beccea2c9b0393a6346b7f548d8b0b47e0d9fc54f6eb9241082230f05318cf57ae29f152e71139bdc4f7dde74407ca7980c33c5fdfd8bd3a7afcfb6b6a701773881a73828d93c80bc0ff99632f7e533efdaff26de34b5399412a2227f2d242b76fcb92fb29106cd2dcf5fb1981c14603e502226b09fdb9ef87db808c4e3f187a615315ff1b1801d74f4510fc41b7001f5111bce97d9552797892e7d882fafdcede8e086625d2304ad1a3c86a55030d0f0c54fccc6d2b02de1a9e20f0fe68d4bed1599f939026e126e193a96d7424bda1110e8ad10dd62f8e7a1b716d860d5b135c9c3c110f61131baf41dc9d97ab58a45cb8cd22ff87459a3482701ddb72fd8a8421de2cf1186324c452ee4c3627a0c86363974af59698f9644396d5574ec4f2cb18140011cd35775c054ad59e945601589ec02b8d6a9c3d02d259dc546bf5ba4a495d7572140d82c6259a3f2e0640a2dd6d54230980665c7ce83271140293bdf7191c7cb82b598d4253a22d6703d694d79e4f66be575e62c613ac838b5f1141af291b44b09d714d5e96a06bb46117f31c041d2af6ed3a3f22fe070ee843340bc950b807782b471d97e996da0102e62afacb821a409f33191d616568f90c900d1af5562ec938ea4de013a841e7a0080b26b9fb1f42b2e5d789db3b333713cdff882d02998766c514d9191b056b716f59a1b314b17ddcf6f5bf064bee70bc0224d51d19c7f553d100b3f6c165396e31de28ad691d402290f0b023457d3f8b9afa294ff291839dbf083086513d7e7cf9691857d4574462e0e290736151c4515c105c1ccbe928178366eddaa7d99ec0c290e6a87d41a8e8fdf8b4f64cb10c38fb6e06cc8683b657ed7270232920f44d5a83fc1ab95c27899717479b62440d136c015ef9f0644a8af2f75663040c56b2a3757c5783d612f02335ddd16e62ea40658971e538dc0019d3edc39dbc8fc045606ab63dbd2265340644471ee8b6befaa66015c1f1104d53026110ea85ca51eae11f717b2bb229301a362ebc2f92dc2ba0b38fcf07e86269e6bc5f45277b34f44f255cc954be8a8fad3ceb9dbbc8a106366d52fdeec43140b177c82106e1be52a886184a734baa3538dbd607bc73ad98c87bd1366839f3a6b10002278b0a7c772c17fee8a66d58281ffe03d660677ac0a720630a554bf9309540bfd6c6e8db7750b68a2d6dda5473c94f50d4d5105b51507166c03544ff92986f2b9c4eb3ad89dd4efd0034d6ef5bbe761f536097f7d6f6207a90c1b62efee155e30ec05ed17df60b7f874031e2b5d316058ff8bf464d731d3e6e6f72e8d147bebe5f1729f54a5c55968c85f7e65748162f634228e05bb4a178fc6d0e293bd1759e06e02b3dabdbb832f319e66b8db123efb7189198dc3ddaefd58002d54e29ae67638cc14953927a8026cb82823db32a2d08e2d7cb803561bb8f03e58eabcd68423f68be6d976b67cba79ef0897291e3ab693a82a5418d10a29b830186076ac2f9cd7610a8551fcb40ff315c19463cebffdcb0b03c10cf26881d9c1304873365d4922f2d4d4cd88c4c81be33831d7a553e258125d4669fec27c4863de0e1280246f405db8ccb56201ec3b6afcadc1470da7f0423c0ad747b9368688f921e543c8b06f75e36ba49e88165c28696f00fb6621fdbd51a168d36ee42d13b44840e8eb6805c7a6e7138cc317ddfd82184860be3d384a18f5d0b00abf339c00e5b1822c240410c6c7a6592e06f41d40472d09fa7f63f5294683697a50cb35d8466ce9c6ae556b2dcb2f931bb8593469c3f76bc62a56779073d23e516369e161de8827eb40c3a61cf442e85ee4a19ff145cd35f0734cb6d1d64554ec98863fddd456b11d8c20aba2ed5dad62c75ab1801882ecc80c289a3adeb920851168d944b92cda85a7633dd3b218aeede517fc25c94c2c5ebfe389d71b7895d17c10ac87d65746196dec8de8e739409321110e365a22795c367d891b68b2599c9622a05c53a4e537ba7967fcf3af2b488b74f0185e886015c4847f88a0c85e89b93bcb62092ff8e0203ab8b9c89e1b4ef11e045bbe00d175e8b18886ba03cddc0f75f57781483e42921275ed82c9914f9912d8d3bde6e857178caea2308b29dbf293928d893e9837516d1d83939ec9a8ddf243737a752a647fe43d2bbc61fb7ebbfc796a925f1e703515903c3c6e165d5b08ec78b111f2f458b8664026215d0e0ae47fc0cde95d5341d7ba8be1dc5d227d29e19b05bc9cd6a3a3aff8b72c8814cad2d01d3a18010eabb5fe7e9d5235663de1f04780e230c1a88fdd7ab554514314f0821758079c27fc10080e635dd498066c2a0a4507afebbfb4c1a5918c09aa5eaf31a8badaa813a79d2e6f63c553c99810d922ff4fe05278697266359cba14b787011625d4e3942854f728fa56e76625df64277dbfd641cad9884eecf8a28058d7b25a354eb64e7b6f2d365b85d2890610139d825e332a255584ab0ea80868dbdaef2f6a8bd2943299b2044a00667c5675001dc447f9db9474919564701a16302c64e15dec065919ac9d637831d401206fc5eb46254970e5f473f7400484c92f384d722316df9712f8b580467f150e1742d6eaceffb204f00631e917791b6257f21db6e23abe2f80b2e03d6f0ee34f87836f12a879f31749169a9d262fcaf5e15cc049ef48675526a2f236ec50350cdc416b5c73412c6f5b7207d425b019fc1304df8bc05757a0253793cc4e6eb2fe175824c92f1e30f2a24354761b8ea068dd848c2d17390f169fb75b4a5fb102b22043c251c98e8414aab7cbcfe5b087f47627d21c02d050ecfd5e53b3d679837ce5633c631001182a6f6f5ff911ee7932c68bb94a9ad92aa7ee275651aa0127154fb1d82f4263a32eac06e7ed5b0517f489e24cf31dd9def73dba1edacb01fe5c08de68854a32b66a00fa5210753fb9a68450a9202c2b84d427f76756bdf73e47d4a5b96a7e67d09988f0997c9a8ff834860b4f000f148346735b659c157fc99709d19a4a5f5e914b5b2b31f35ced5149fa94def53a1bf46bf4e5f58f04a7eea5f5442f039c9a6ea24aa6f5d236abe99d24c846cc8d1ca1309e924ba79e44897302dbab73d3562067fd7f8bef1a074e63fdb93a468882a2030f9c6405aa542ee3912960c92bcb28b8e6a4d10604e0b0f830150a49dfcbd968bcb689b33c8762f810ed1751e4b4cea353be9bac2ad81b29ecd47fe3837b6b755010aa525acd8c9a84f3eadfefe6d9cc609ca241cf718fd9353a66347811cdf7478616b5c10fd39d0696b11967ef9befd961f7fadde33ea1749599d4d558b65cd25411cac0e0109ace330afd31dad1d0a141ccfbc41fd28ef663158625c7f7933a2666b64104bbd8ec14c9ca06207d43b804591dd12dcde306a701fb3cfe1ef7a22a6f8fcd18076fa483250e40911a21d61e19bd86c5700082f6fd60991f5b3ea05d894385e7ccfa44155a3551346447d812c06d37be646475d5c012c0428931848dfaaf49840db943cd835fd9d831f44485acbc4d9de6dc1afa71b49d6767a5d411f16cd12452fc3037ef0031b76fb3dd52572991e3f3530a579f96252f6df173cbce7f3b4c135b99fc561b0d9db1fd082706746795b4d1424473699cd1b55570eec176300f456f2f837ddff9e2f8db2fd7c993ca08d77db3ce054c356260d68666e0ea7be21bd211f5318bf55477d4c2127b6d3b25c4d0fa4efc4410f5198b4daa9e4a0b723e0304703089af25186911d8e9399e5d65d27c1d310f485296bf2e743ec2332f3699dc277ebbaf54f88014a3cc883bc5cefeb7b0c01eecd723aafe8801f02770f26c74556ee6fc6ee923cd8f447e79e70abbac8e15531f109cb2fcb558280edae0f80b621b8540be43a6331523b9b47baaeaaf8d1648a69e74c2b90bf08ae583314d385bd6af51c97c339c6da8d01fdf6b24d2d7483581635f116b7b10228584273edc0aec027ac54f99adc39e7c2d2e348503aa7bf4927da1029fa229009dfab300df7c411010c49fcc959ae8c1f84aa81a889537717ea9ca7eeb337c95389a999bad10cfc79c4738a7057dbc088488b0c3b7b8b36661664a1cbb084fc28b05630b8e55f5da4734a5b84772a7654349adb34088711a92c59a32cc3a057ab56368ca96b230a1e431ddbfadf356f61a18f9147c00a84d64947a5d2494a79f4ab3aba07330031afce86559c26381063ac975aa030c4f0f4402c147a21204ea349f5c0f295782cd000466d3e010ac55771a46afe8d371d1cee482831b05b7a2f82df15e2a13c9bdcab68a25dc4ef91a219f86e29a7bfa36ca768fd1939fb549259c3732730684e8bf93c4bc3a7490c5446caddd91f8fed1fc655565a9513b4e2f066631c2720e003a5415005785805a9b1baf281dbe3e57786f3103327c0a97f10128eabd40b554efec3d91251258f4f19e0fdc6cc9962ad40717fe6d4a095728f81f88936fbc441706745eb52d31a93c9ccad0e227b7e7c3ba2e8fb6e75c309c24ec5554c3e79588dc211a98f9f7552367160d375534b3c0314911eb50bf1df368339b01777b7325a1d2d9530e4484dd06e3620c02cd970af8cf80b558a558ef1bee92c5d4261b61bb8f64cb90bbbb20047f720f8f80f841a590c36611228d7d5960b648e706db191c45db733e11b6861050d2549e596132d91850c793d444d816208c6cb2cdf6896ddcb1c1ecdc8816ae19366000df101067330969fe57a4a6f7a8cf94ecd3c4366cefbb6da30f62a32dde81c8e57dffebd1167d83065bccbfa8bb9b7b88b1820e78522af922c1f007b734990f696e5cfe059687bd10d31b64009497b01ebdd11e179c6091db71eee8e6123d1059e5c3c14f516d19d049eaf4ad4ec39c5db8757d250033df5591f84ac6759425b86c8cce666eb6c6fdf2f18773e843e97ca2852aa0d88a0721a52708bdf6432004052362ad147d49ef634ce9309b3669d05631967e5e4824c6f70b340e0d92f47e73ac6a002079775edb6099f84b36703c44828cb3508918f3b66c378e3d9720c92c2d3f2ec15d59aac2308aac49fd0a96e46613d244d6d40bafe0a7ca42c950024be3bb91a0fb2fe1a8213be765cab2fdb2ff993636826c116915ebc93ad753a1fe1229167275a65a0c090111ae41d0e9833b89295eb18674fb352155dc18d6345c21b68a04c1d3d5fce9e5c1eecde7dbad9ac6f27f70c1e520c9a34e7ce6f0b25573ceb5a6a2bb262bd3ded9a67c680127221b2ea39121792043b0c916b851f7000f00657753a6be9086e2778ba3b805e512e623d3b8d29915ceca90e0150cb858d243a7ca6c6999f8e7ba6ef8c6eba37bcc73fe41b2162fd97e59cead84f68e0b4bf09c511ba10332f26646226b6adfd68cb4da507cb2c3e86fda8cb44e910d5d2e72edcbc8e7fbf83ddaf408f4608191175c15e7507bffeb5be4ab02f629daf4ad2c1fb7cb26451a086074d769c4b9ba1cde8c5cf45117a4d92145fbb1e78b56fb46abf24e87cc79de7c22915c9123fb0e4fba3ffad788e598fb3b4e18c856be5c8e80541a72ad333360e8361481d295363b33c1f78e61ff9bd1b209ee3716b88dcc94da21c043d86aa446929453b2b3a9a4b1c286cb4d5bd49502380ae465f5f30c3eb36eba552e4b541f3e8898c9c178be5bf394aa6d345891822fb4294ebfa8c8e44249eec7106ba78796ae6381d44d82233a4fa880cc95a4ad84088f5717e7b261cf8341f2b1a98c58f33a2bc74b8f3b2e2620ed9957a5287ada7015ba8dd535797b62061b4c10d1112f40ae4bc0a22bb52b611a63d4be5080873a4637c4c52b4af699b7a9574b9c1d05113642bdf90c8a02712a851eb549d0e90749833e90cfc3b7df7f61991740e470949c993ed9834b6414eaa565c89406f1a787954f414f1e2134a95cd2e0bb0ea2a553ed0eb8731d63bd6c90b84daec37a79b3bbfb25d81cd63234efbd6761ef22ec8cd838dc775ed65c90e3d16214021de74172490a12b1eea9db4491c458bfe27e0a87bae67a09d38522d03c37411df2e515b9533f92fb6d84204c24a0f9b43c361b3dc44e3b2aaf4c336a3fab57ceba615a46d7e13e148c7ca4cb6fa6b7e095fecb894ee160fa1258b3c23d493e67f38850e4a96ddd5ff44344f27d3038355864581b9f07d9e475d0e9c4dc86211ac810a14f97f85a0a4c532cf10747355a3c5656e650781a0b77b3eee9b975bb1334c93b8b2fc0b06a051f6cc65616eef6128808164da3c09b490fb65bf1223940ae326e9472aebfb218e0e4ef2344bc270031e554f201fa348f0f907e12479ef477f89034e8bd1f8b4a8bd18ab9e8f0af2a5f831510726f4861a05b079db4ade20e02610820be0cf29905d92739f1dc9bdd6fd379c6d90deefd88b953df2acb4b7377da88568706c4ea4eb981e3ba43b33dcc49337982c57071f12e79accd9760745c9407d5fa05e4a2456608ab38d1cbb5381c127ca355491063b85a0285ab01730e1a02ac54680845b047e9810c944b3341835c850b59c643da9e9f00c32e5ac43f88c0b0640184f803ea2cf39f573060d1a803499cce46085d1c8f5465d0f19e584a4864390e07fe3c51c5c76369934d3983ecf78cc178fa5ede4fc7f7f29cd1f1e6f5f52286acfd9267f0d131de3a8d3fa4641a4f44cd08b791bdf7de7bef2da594324919ee09f009f309638e6ed7c71f7ae9566bb5c8084d816e57799dba00040abdf0006d66acb5345fcee79dd3353939f7a494977a2cf4b95a6b9522518b2ccbb20f9d739274d24d97e5a427585014d180bc22460803423fca2dec1617881419e4fb5ebebdb2c67c2576649b850591cc28e2e3f5c39bd8f244497e92b931a17b1a09c17df9833540bd4fd20e74992743dbb1d4bb51bfcc01c1b0f358288b7542186e76dd344534b19866b3f158ea07bb54d48d853661c8104ca89bfba2a62dd69a27feaffb6a1509adaecb3c49b5f8efb9cdc663117fb3e974bce76408fa91e728481412bd7fa805d2845a23213d6622ad3d31b7c54d892287c3f93a9d4ec76311bfd3d16c643c31f364e49eec572414e389de6f31cefb7b62c670448fded11e4ff7e3f311bb2f7320cec8170a819d48a4b1241ecb1248ae3784d5010b16f6b25ab40075df07fb86b8d4ed434240156c166cff310486dde2e2bae8d82243de7ef658e8672ed4dd13356d31a9f1bac5347d75b6f91b9269659197c8f63dfd3861fde27e65d1a29b299f2e2f3a206ddc20f3c43fff28ebb0a52c2261fb7f9431ef7764fbf3a38ce9bc403f4a2b4e94c4e247e9e2643f9ab6fc20a48d1b334f3c745d80d8de167240245f3d31d4844f41a68dfb426b9d7590edf674a2a69b8a99366e11176aba2b179a853e91e8989076f9f2c8de8836d7992a6305688b5e7dbd42cd731e8be639edb3bf4eabb22aabb23adcc711c2f16a8c87f43b1ecbfd8e677bdfdf554a2ca2495d3a6c7ff9554d678a8e5761bc3384dd52d495d3ff782cf73f1e11de555475a92ee307e3ec8f06c5c7ab2ad5767187fe7b7c12326d8484cc137f2142b6bf3d5d562826d4a2247f562866fb87c593cc508c85de0b8551d83744e41f12e2232464fb6b465890743c22d04666e35d5628e6b2c65017b6bf18fa42ad506bfb83b8fa03e4d596da8267367bc4a332329eeecb9a3d3d212b421e7dbd3421e116793426a61bf136706b3d444dcb6fc807d33489c7c20521f1a8cb25128944df1ef9ef3f79896c7b1d0fc80bc116ab034f34f2b100c2c2a3add697bd1654f8c8bf8547592c6f8a6ebbf0284ca652646ebf4757abb0fbf23684dd505055d636b79deeea09edd154aa93a1e6b5c7c2792d769efc12be975fba07e54f7ee9709df7fea66e9169e3b2e6c98a9a3632b1d4f6223bdb5da621a524f139bfc5341f1bc01fdb3dbae371b4466f645e70d489171e459594949470ba2f6399d7eb5552a4c4f3580c060c18303add976f8bc562c11002c3f39898183162c4f0745fb6aa542a15c3a788e1398cc3c890214346d578e67e92e14ef8c85f86e71f8e7e45945064e4cd584c935fbae764cd7c65312f336607a18b1a8e3484e44d184c865c4893a51c699e93ab1c69489ae7b2129af89cbfab9546f3d3dfc7fed8f0b9419ab8e61bb2c51c74d9fedc0e9afe6033c80ede74f100baefa18bb70288b7fdd560c81a9ae7fc18432c7d2cb246e74b9ecd1b0290c271ec425262c2279ab7bd91f1cc8e27c65306ac6da7d97e4dd6d2c43e27bf9027f6c50c438eec7f992447d6449e6a6cfbe3e60d416cfb1a9b844dff002ef6c5bade49054bcc13c86cb59cc789c576535be509fdebddf07da976efe6658a31c69d971d246643e02470a7ccbbf15e9e1b9fb28c82348f45d4bc21b2ad4142387fe3329527f6b56ce5c86a9264dfbad5bc1b9bf65dc6fdb881c41f4ba60d6f8719289a1f538460b5ece5382f9fe370381c0e87c3e17092d054eed38d1cf1db7eb0294020babf0680f925e97b0e97a73cf9de662a47dfdf8ce5e8fb2d7372f4bd964139fabecba2247d2f66911c7def6517d2e47b8f77e34b62777e7ef578377e773c1a8a473455a365f8940b792c2f3e42cf08ccb9470867985bc2954cb388fa837523d708212ee4dd107532b42f62d1f485093791c76249a627d71384d3c6fdf1da49a70dfcf58379a908e1fc6a3d16ab2f4c382b1327f6ed37c4475f6c3b11f0d55ed2b6ec2426e96a8b3d6917675d29db1b8c8b5fad38ad85b6bbccbd0da9a780991a42385fd330fece63c1f2fee6a2e3b2fd19dea12e57ab814da91cd9d7de8dba35cfbd90d6efdd1acd6919dee76e656254694bd6c07f599fc7725d2c4d08fea29a201cef0be797cc3ebd916dab5ff7418fe55a1852d81841b032803072da012f7941c317210c185d6d09477c2241387e302dfbb6d46ae9f483e9fb83707a09638c61749a185ac5bfa131df1ecb075b0d81c186f0e8cc1019cf1b82db9e981e7c98bebc745df73731990cfdc1a218dd5771921218b772dccddace7696e1bd59ef46b6efddd7568c3b9737eaa69bcbbabcddcdbbc149edc318468c9b65a0f037ecc34994e4ff3f3fd807a37a0c3fd8f6dd8f21c3e26c37ddddb6ed86029bfee6bbae64f91be2247febb15cfdc154e1fcf18351eb534a2f6d55462acb1e214ef2cf9ed7884f58c2b6cd9e9727060a4f8c4788162b29f1585e7848d84a14f34b3c96a93d424610daa77a2be2231e78697b7f8f10cf6bf3246cbb12b6f574227b1395bdfb79d449999166234349aec48e6c6f1af7a310a650be420e6883f352da8d0c35796258d30647dfd73cf10f453d863426636d7f0141df5d56c9323cfa238fe5fec823c2bf7cf796abcc642747f53d2ca7b68d461e7d12c9d657f16d7ec5a41d3a92477f078fe5fe0e1e11fee53a5b4ef3344f3b903a196e4ff258b4277944f897e9d6913dcd5709c86c576c7290275b112e73a8eddfc55cb63f096fba6afb81edcf030f1efd19335e5228c93fa50194e40f662466cce84c3c16fa261ecb7d138f08dff639dc7d2fdde3fc923d975fbcec374fcc7d4d1bf6344ffc378f2766bcdd53d20ec2f9346f45381ff6346d6c729027fe4d6cff4d8f21f763fb15d2c41febd3f637f186b0dbea2d264dfcaf0e7ab80f83b44307f25e424af2bfaa70eec043874fbb4ebab718081486fa01de8df7bdd541c6613b357d30f9b9419a3c319ed777c5f6a7d20b9bcf0ddbdf13f312cebf5f79e85cdc8425cdda0c13138fa58e342df556c447fe26b8879b039aef66c649fe27376f6436b0d2c8d99e184ada9ed20d6c238383d0feb891d93ee389a1a62de6cff9e083c7b2bdf4b618f681513c96aaf109d38dcc666603eb782cd79303544546e0b76f3505405beaeec4b328d507ba2db1a94b927d1ade8d6ce3ecdbe697ec71d65b1127f9ffe0b15cbdc57c10ce1fb7d8f63c3710de1154881a9af0c0bee306367d79a36efc5c10f79dc79426f67798d181e1077a1d076ea09681f85ab08214f409c4777bdc1cd2f0983de6d566154ae0a400422aa5947adc61f7448573cfe904478f10ca39fddd7dfe981e6e0f3d44992d74b5e9b4df6533f3fb639d5689baa56b08705bed27d92ac2005eaa7a82ae33ea2df46f0cc2f974f5c2c912edd2c7cffd96c448adb52a73be103ea2dacf1d76db14cf3a606699cc293ea233934284fe53d39c92b2a91025d752aba4ec1494149a12fa08e42349bdc449406ca7f63aa1d6ccdf9d0917df90a4fbf267e86d212831c804f25c04121912d9001a0903f8e8ca997d3f8797b2bf5f84019098019a35669f95a82e589cd8f667c1fab4c29028b23e2aa055703eadd66cedf1d302b9b67fc86a81b0cf0b14137960fb6f9fd676d61e3f2d91e5a23c680f945b230c61103dce3c3914ee5280010c60d8b40108307bcc60342bdcb5992f7ce10b5470f25f4a6aa23388ff572194ffd59772a2442be963ce56585f85d67cbdc54f5eb2eea3c54bce023cc5ae8f8b204bee8259d4e4c3d71fbe3e8691354c1c95aa2dbb7e3d49935d35810ad9f5291764c9b24ebea27cdde12b0f5f7bf85af295f475f4d5b6f28f23185fffa5297b5192ebaf3f658d192f9ec6cbf8185fb5b70809af0f6fa1916f067316c852e60639f2ef5c28c94b5dca474d90a5ee0672f476b5c74ed5dafed98b9a40162579f6e2389d4332f27cc5c44cd8e6bd4c19ff91e9e2bc97d96a8929d047d3648c3c968f4a67cf0bbdd2b9f37d7cb07c5a3e27243c314a722d3ee12317553e729dc592fc7169a1247711862e369b15943c59decb84d159ae6879f2020882a126cc3a9d379f9327160a89c418d125c2882b5125a644174aeab468d1210161600c0b1633454928107489a8ee3d1f8e68e4b90abd97a99a1a8d66236e74d668369b8dc8114398ccc848d6625192c7602f9920356f4451e474385da733d843fe9c621e98e7e591f97c1ec4922287c3b2ea882b4fe7db35bfd0f81f7208e6430ec998d0f8cc0d194c64c19c28c9bf87ece1217b6032312f170ea70393f23cd005c67810a0cb03ba40976ec285a3b3e7c3f3903f274fcc23e381f910861a1f6064b1b512559b4d16dbfe2827259d4be7e2f18850b0882b1f39144053d24f54711fae07931779fea8f3a3ea82e7a3ea48e00e2a19234f49f678bc970cc474e63e17fdac6038ee53a2b3b62fa8822290c44be76cbf1869e98cf70d855e843c9daf0c192ff2585ee8ea831822efe5df08ba67e419794a93fc2212d06579c8a11d624639f49226dd0dba9497b81f3b3088936028c9ff45065d3e720fc21f64b1c4948f56e17c153595bc7f08266b68efbb97255a4c89297d2be8faa85c3ad7179994433294e4e2134ef2ef549fd6674549ae692332f447754777c463a92c2d3a5a45a84425626e31e5239da98c2cc6c8a28a92fc4116c8ca2425a9c414357db24c4cd5cd85920c6ae1bd84a1ceee42e7f9faa5e46f89fe40f1427f541f95e8e3e98838a2487feeb1ffa74966791779fca0465ac5189280ae517c8d1e398c7409203125a6409798a24bd8a3981a7f8f1f154823a6460f1b465ac5f71153d9f8518d21316c7feda31aedf1a3dafea398dafe272ff9f0163bbd222476ed5a648a56ce83ea0b8413eeb4da8b336df3b8aefb3a0950521219a0241d2a9817ca1b134e2f01da8a01aae78006c468bc0d0154589b19a31110282842845e4a8ae871e6699ee607a6a9c662f3148b7d9e27d6d83cbdb8e05f85485395a1592b6b6da1c6284bd6b04f75d6ca5a55a663eb10bbc282603b689ee63ccd93879a700a428dd6582ce6232d84ef792f20d007e49c30048dccaee585e608e60904d294b55a26d835968550b6a8a9c628c93fd6620912f2be8ef35cc410a4b63f77ad108e32e6b4da8b336d9335b69a2f16c2b1ba94985b89b9a7ce60a4490f3015c2ceebb40520e17240036222b07949bc3eb09345d48a8140411122857a9ecabca60c6692a4fc991961ced2e6aa4b90ea739b6704dd76f358ae1442099b809c2d536cff1cd29401afaeea9a576855171532404dd52563d55505d7762b8462b785eac28234cd96b17a613b4c08335ba82983d93c1691ce6c0a274d6f8e28c99fc3e1749c0404ea743a9ec909438fc7bec763b1f2d359184a7285dd143e7216d519ccad420623b92eb5e50bcd16385932d2151b865867754a932a2f15c2f94ea77ff65616eaf215c060d3ab972448267cbd5ca09649e5c3a94f3e9a421258be547665b1681276524a29a5d3a50b9c2c89027fd745217d765ad354c06ad6d29f5d962b58b396feaca20478df7d033cdd00d9c5420bc858f65266f758e9b1e2db5b60563d4e1fda873ebab739b6e58a943e8c3db61da2c7a672258fa0b9af8f3cae67c40f9b9e58ba6f67bdfa58cb512ce197524b29adde975d2c6da514575b450747e5ec6a9dd2da4d497269af26d3648680acafe2f656ead37e529ad85a43c0496a8ae2fe026a10b52e20d35392340c502ecb51545bebb4d57f36a0250a0ba46c1c3be8c63fda3d56b2e72c30eb40f5e8237b1144618194bd83fa50bd7a44f4d89e65b962471f795423c46d8fa09b46b184634a69663fac97f06de9b697d694d4ae766990d003fe9842f2a364c9d6689cb175e8ae450b1d1b5f49f238efa89bc50ac251c22a204dfcb92b8570879be48a3f27bba9daf06b40c222a8699ef07779248f3af6c8c77bee661cdafbe6383984a6b7ef383d2631f23ef21ebf8b57f1eb79dec7fb2ecf3d927f47dd2e5cb890c20eba6d1f7e3ef4f92bfe27cf1dfacfeb51c697743ec65f3dc2f8121cda6faf3dbe3152a777c4f6da11dd73af89a6bed1694e4b15aa8dddff17a0f3deab3802b4e7740787507bfc59cb2323bfbd96471d475c2df2fe6e59e47da7893c7d43878e7d5feb5e739ddf7e4477700837bda3e6e7348ece7b1a47f8db8eaae91d7577741dffab67848bdfb40cbd83eefba2dff41843571f613dc2d03be80ebde8dd3b40e83f2fbd0384b810be9fedaff609e9b1035af7c9be3f07c0ba6a7a14fd0eba3fa21e7bec8f165ff42a5ec2f94f16bf248b5e84f192a8c729bf7e5ef4dc274f98b9fafc3857a25c22c5ab38c705e76a7f3367ebd8dd57d18f5d1137f423cf8532eecc8d4319dfdc3deefcfb682494e72e829a363e3232f2223d66de11239c7fad691c1cce9671dce79ed338f76e19e75107e8a7f61ea4e5264b276d388ff3f5779aa6715c17f75eae765ae67ee4fe023d70d67ecb5dbea17943dc2d8ff35fbc97471e1bebf17ffa68fc9f9bf32a94935d7c49aefb451e91d8ff3a8f3af6ffccffc119ebea1171df02b20e7a8979a3b35d7c9e271fb948a54e331585f03e71c33d57d4345db427b4d962802ac271baece9849746b986ed2eb3092fa12a206bc85d3dc9420a27f9638f85e43912fc5893c0e4b9ba37f358348dd33025296127d951371619b1fdfdab97a8bbea8e24d77dbd2cab2af0fcbcad107ccf7332145f72b01ebb8defddb6c7ddbe1a07fece8f736b824c26ee5fad42b7e8559cdb2c4037d78139f417fcabbda669bf817a7ba9e5ab69990ad5f27d306f39f45cf6e8716ecf833f5b42a19f3fbc047ee8f19c029cde0d6e6fdba66709e6c9f6386bcf7df2c579ec76f79788ee37d646f2cbe6bbcdabd0cf739b0cfa4bfa741b13d1011f67d12337f8b304d386dce07730a867387fec0b85104f297cc47dc83dce776f3f6198d818eb717bf13931cfd51342fc52dc22543cdcdceceae67eeeb9f292f8fe530a37852e7e75d3e6c5a71e8ba86788b237d9004ee2c2ab8be080a18ffc57236a028db6e32f9748e99e11746b5f04f5add363a84b1cb0ef4f5999c8f0d52f551bc0495e04c863f6b03c660f8fc7ece158c60cc8bfba297bacc71c1d576ffd4158bfd66e575a031d0f2ab312c50c7ff888d64e266cf1d1ee74e7224d7a70b3dc2d5e024317ce6301372a93898ca85466d74ea79343691266de01f0eeb24e8f1910eb8d6d6f886ecb74196a5f2af696a17c04eace25eb3a170dfd8e52caa1debd1dbd1f08829b266f728772f1511540b0a35208c770f332942bac282f498a426dfaa097006d25cb509913592acc509c4613bec663096b05bf7e53ececc70ac5a6bfd1e8ce859268d7848f501e0b48bb4df67dffd96eec36dae1acc4a42a8e02440aad28afa85d39a7cf8a2fa0313430d1426351a031abab4c6da1311a23428408112244881021428408112244881021428408112244886c33dbcc36b3cd6c33dbcc36b3cd10d966b6996d669bd966b6996d86c836b3cd6c33dbcc36b3cd10d966b6996d669bd966886c33dbcc36b3cd10d966b6996d86c836b3cd6c332892726aad3907675beadcecb13310dd9b8dfb1d67f2beea3107675bec6208ad2dc93e461e847b6f3d96ee5ec798765b892bb10468dfcf3c168ed2fada735ad57c4a4dd3a856770f9ae14a01ceae9a733b072e4f0ba4b62815beb9b939ad3feec7ef396d3bbba347cefc90d31dcef598b239518f99e8f950d4638eae633b0fe60e0e21e7c71c1dcad6de8e9f8ef67e7a44e0e87cdda0c6c1111fecbc7dab47943d417a87ef8edee19bf39e1eabdd53d438380f1a016a1ecdd1383a1d2e7b2ed3b71daec36ddc732adec9d5479b9e8f637212634e7a1d3d32b13bbfe5f91366089f396186d0e9cc0eedcc9f524c1bf4c70df41c08a437ca715c9e2fb939b99f4f593e7aecb13bafe273725bf67c2767f4a7141e0f7dcf538fc523e3c9b4d31942b7a16c6e046273299b9b43989da9e710e6c9f696935fc20fa969f31ebe779cf69accc9f0e3b84e87cb3baaf71d27bf6c5ecc2f9af7b2cc9ad6fecbe06f7208e6efb53c5b7e25d4eeb17ccf7ddd98d92f83df65ef67f6c7e38ebae710a60db9270c0fdae3a36015957b6b7dce5a6966e7e4822721d3b14326e8c5260e7e0ef7d8d98336ad6e4a29f73e784db336c374ea1dd9d5b93b42f3fae29d4d552728ca9bd8f567cbb431f7387fd09ff7a7ceb697ee5addb87be925ed99ced1ed8cfb4e6f4febce340e2edbaadd35fb8c6abb8fb0dbeaca05ce7379dcb1b90ef8fde6394e7aa11ebb1d7a449de73bcf7fef095fe48499f380b9fa68945df89d478f3bf6e67bf9e51cdde6bc0a1d73749c597b08c3f045da7fb4ff2ee779c9fbbc1602813ff2249e0f7fd3f9af3bc2f3e1122ef6057aeceedf4545c8dd6911e77168be7b8ee6bbd774dfe6556898c3efe4b17bf905005f136604847af37693bf0f33c7bd67c7119f1671fef36411e7bbf77ca7a3451c2d3e8ece735eec3ce73b1c2d7d247d147ef83bb6e7c33ceed0e4b1fb1b821e8f7e0b7ea87180afd138441fe6e8468fced16d50571f857e237af92479ac1bf4d733627ef8d6bb21d23b6808fa115d7d04d263f6d53bc0e735edb98fb6c9d3bb413f8ff67df4d881ad7de6b16caf699bef438f1e33edf334ed7d26bdcfbce4e9717e5fbdd4fda7c71d94d372a669bfcdcdd3bd276fffc9e38efdf9baf9ea25d06f36cf6df2c7d19efff246fc8ee63b9a0f5fc3d9df83ddfebacf73b2f7d24d9a171f94ab8f34cf798ed674347aa33b8d63db34f72af4f3dc01b4dd6dd9f3d2f3783679ecf6e6bf3ceed85fe7ebe8cd86b4e9b6e7e57f79ec3a8dc3333ddd73bef3e4b1c7f6741ecfabb8277b9fb9df3c597a05e8b1459ee7bce735b9f35f0ebfdbbc277f1ffef71dcd73328e504b1f7d7bec5e7c15bac923f8dcfb96e1e3f87ef3a1eeae084537bedffca7a58f365afa4823813dca07758eee93dedcdb363a60c7962f335bb7acb25b896289d919e99a304f92d501f9dbbe505d9de494094e7ac97676cad1b49347284d3e341d05fd6c1e1187b0beb43fbfee7bc3ca2d5142f7ae9e61cd8cb0ba524a1d0a4e968c2853d33423bfc7ecb5a9b3c9f99477a3482124f111cd73d75548020e631bdcccb6d4757360b63939dd3f3933de3367bb479d18e0a494236b2b139bf6a8b3029c6888b9a5ef39e75715ceca5195d461e6733206c4fd566d50faa2dcddc0ce2e4755ba7fdeabf8b6bbecbb7ae9f3266ed979da0db7ecf9776b0921943f6e2dda819bfde229ddd6fc92fd966d2d4a9aadedf2a48692447f6b5113c8b5277d89bd1b3fa5d3af3e7d7b7d5e7bafcc5ffdcfa55e7b77c0c99725a3bfea5cedd09cf2c7b97a71c06159168e9c1c731566570c59877fe4d4ce47ce630bf6a9675d3857db5e3b57bb3a0e3859527f859b9dcd9948aef8ca5549f715771e5774608a84a93854e71312651ae7cd2b42ff1799c7f8cb6560317aa2289aa22ababa56a552a9542a554a4a4a4a4a4a8ac42cc090e301c9c062a7165be94c494949494949e984482e2c8642a15028144aa552a9542a950e57f9ca619ce52d7755140a8542a1502a954aa552e99030988449988485441d0b17a8974aa552a9542aea288a52a9542a954ad522cf130a8542a150a899852108f43f9a3093355bd33563e6cb5128140a8542cdd77ccdd77ccdd77ccd57d61d0a6c24f32f508cbb1c95726a7141a554b465ba5c2ed7a3680b0a65511545512fba794558d2b94b4a097397eb3103fd5bad47943dd296ecd5424d1a0c97300481fe4723149414da224d3c849169f6590968824b0b3096ca8a102850a042000300408d00fc9052fa6a8100f192e92b06d2c38f334a80f8fa2427367cd834bc14c48e5da19d505478a9534141963a1ea08cdd0ac8f66f8581b44c7ad063789243347e38a1418305fa6c9b6fad56a9c50a72923d52b44e72478ad613aad40745452b649d64f187fc59cdf078668c8cf8484b0079ae0ce04400272d56aa05c4156ab1582779b33fa90f2a460c19624c848931a24b6c892c7145492e78e0c1c5480305297401633eda61871d56401026c2c81a25f0f387add25669349a4d8bc56a9d64cdd66c361b97e8e2b44416abe697edd20203c66b322f4a72140fb44a877bc80f3f6c44209c168b7592c100a05c4e2d3f68fd8253a4e4d562618c81b45aac560b88cbd5dacf6a9dec5fc92217952c6a11627f7645162379c504207f5094e42e2d9ed8499af080858a450bce1017628cc8fa7f10464931182c8330d8890f2d56ab75923d95af913fa90fead3f27191262a1ecf7f3a3e402aa248238b2d4a1a1919d14edb7f00f9031340fec8fc903f2e94488402e20ab558ac00e84fab25840f2d56abd5ea3a9d0740c9c32afd7092b9cd0f9146feb8625a1ce7b47ed09f56ebc487939c6d1f4e7ca091c195937cdda47991c722b268d8e8c1460f28b6461601208b52722856caa2933401614ee201a7e23ad010efc76f055ae1a418f0e5a38fc56a51138df717b9c81a27e1832f4516ebe405beb63fc949ae3e64919592452d3f68910a3fadb6bf298ff8984d6cedc76ff591f9b87ce4dbe65b8b86feb45aa516abd562b14e7e781a590c228bad17b0153a102c6afab45aac16abc56afd7092fd24cfd6090d1afa03c407fd69b54e7a4031f9f9273d98ccc8e30766a4558c1d298fa311081b39a7f10383ed0fe3d31a47acdbbe8aabf8f6def776fb4f8f3bb4cd71334808656890ee4b504a22b7e3efdcf9686ed505c7201cb1cc0e42eebbe74018c8ca2d4e06cb8c9c4c8cccb620cc4bf6c393975cdb0f5dbc247230b6ad0d5be67bee0e507fa4da7375935cb1224cc3c37bdcaaab80c21328cd531c47ab70f758f511e842b3396d643ffa26dab6b92513e80043456dc27dcb7038c3bde7687763e1585b7cd7d33bfedf6a4bfde125fcf5899daa4e6c87a1a46ca7a809cf3809c67191ed9fc243b67f4a009ac32f0ebfb8cac178690a37cdaf27fc725437e68064416807dc39186ae28038c91f6bae95f9c51577d54796597bb11442ece2194177f71c5622fb1dd9c64f3bb0ad4b13eeed3bf75ea79d731f31fbd5b2cd2b045a5738177e4dcdb5fccbde79d4933d551f5ec2fad20df291ebcc5201621a0e4193286e4bd1c06e64b0991bd8ddbc36323f5e4d803f9ce45f57767555f46b716922f5c4bd38c3d4b31a6cc9b22cc4d242ac6d4afae1cdcbdb5b118ee3384e4a39b9bcfd4b9d7893eb7bdb4c2a954a8580d44a27c6f8822e608bc7b209430ac2914badbc346ec2b0fdfd091740ca4baa4d183caa2bba6cffcd6b13134f62cbe6f5f2f08f3815a6b8948f5a77f332f0e9639ccd6ce2d77c769f5e0fdf3521f834839f6150bfd4dfb8a8c97bff4d0b5cb5b4a4542da93b3fc3d6faedc47855509a802e172ebbfe5f8f853ed54268ab9526fe3483406c00b6dc10da1fc11611201017a00b978d5d1b66b7bc34670663b68a833508c198ed0fb2bc04ae36b863bc68103859327a52dbc72cc32368725e5b405dd973128551de8771965a966573bbaf792c57ca1c15b57d13e241bc3c887103b309c9b20a83fad9cb47ee9226592ac64b5946f506a6e557f06f60bc34859bf0944298eb17b3fd5d1e7529405bc134c806c65aed71c65bcc660a0f2208982d6603738210c8e7fa8278698ba126fad9d77265264d6f42b6181f512174d70e39a0d646a1107676db37bf682fc3bada38b3645bccd7dac050176a0383dab84813dfc07cbe81d1f4d7a22457e85f35af9b39dbd9975dcb851dcee0ca7ca16ff38a6e21fc5a316a024f1fdd2af5e9495dcf1bf4899a4229256acb9a2af26283c3813c99d3e9b7c3bc89a124ffba52a59a708253414169b538dcf3ad14db3998ed1c0ce656db35d3fbb1b68030195c5150f5c34d206afb832927b67fe8fb11ab38958fb6cc3da7f1381f6ea2324ef24709d15a34a1b5406d7fad850b122d5a282924858fa44784fca95d20f398e37679aecc2cee3134c50ead4230db5bacb687565ea2afc9db879b6d889b688c93fc83041122c40a2b6666ba215b03c2594aab577fd2ec5a7b31f6eae35b29d56a765fcb6ead3fe6b829160c54ad6068cc85fecce00673b542c5a93895ad9552ced39e4e8dc33ea6946a1c7366d987a7debce0108656d8fef75262ee31b4c2d9be967959fb1184d9fea00b35d118e7e0aa9e64640d920fff96554576a6bb6c69d627e7417b6415e482d7763a29865113d6190cc7613a1d3261300f0e349332188661d204bf015669a5d7d2d70bc09124db93ab36948ebf9b3b38585b27074e59a3d6984f351a10c997e0ac840404a2a4cd62359ab9959a911928af39ca9e738f74dd38c3bb479d58079cd7e0fc89a0bbce93f9446c7baa60db366d9330bcddcd6e5bddb68d6e9b6fdbec325963e3b4ec9b33a8a88a929189c5b8aea39573c5c4bc64b60bb7a81442bc8d40a08a7136a2a0a048133300413ba95150b40d6f5c771a51eaa945498e5b5c677d80928282e27d5d176a3a8fdbb4eeb33fb714501885e512695251994e4dd9c8be59ced884a98681ccded294235b31c65996499c5d8b5dd6eb0ca62dda9aeeb4250422bc9410cee7ec1461374548b3a7cf4dee71e8ee8a50d34d6cfaf8c7a63fc4acc3f65301beb2b92b80ae504a155057b65a6b55805dc1d95a6bad02eeca76efbdf7669e02f0ca86531425f3baab188c05635b5c2ddd19211cab02b297ad6ad10dedf113a1e918e9e123b42132fa588ff7ebd33b7220b673d496b959e82ba3db0b6a4b6db1d65620505252aabdb4e47fc66874319d242050f5d2a45698abb9923534fa4eb38c4a930e4ad231067b3737bbaca39cc57607d5f0570d6b320e3a24c9ff02d294c4eb8a245e1777d9defcb517140e7759a66d1444f2d9d4344e0e0e07b4d7669da64ddf1ced34faf236563ffb9405cfd245d1362e535d77f8886e4e53bdab75f840d6fa5dbf5ad6695be6a12008307041105ed0022068121fb9d398f977ea18dc9a2b3853186db9842dbc29cc0c197d9153fa37278551988fca10cec7afeaf4072ef31524087dbda80c95a12f6a2b862943c51ac360180cc3b95038545aab89934736687f3cbbb3410b6049aa7fbd1bd9ce385bdc1cee6ede6c2eeb6ed66c4eeb6e0e37b77537839bebbecd75ddcddee6bceee66e735f7733b739b0bb79db9ca6c3dae6349dc889ddcd77731caed3793e1da81385429f7d893570a549ad1bd8d4651035fbd0ce68ad53564b7dd64a6dbd33c093c236854d6fbba63069e2030ac359a88e5fead08384b30e9c2c195bac36b542f888d618582be5f49992129a9ba464841cd1227c4461c860f155ba54bb8ed585445f9444bffed7af296aca2d5c7ca545b62886d52f483e8523c92a4242921f5384d02a3ea28f638c9025bcc132921eb391a61ffac189b2cbc81e184a5aa940bfb9fc86d5fa6474f6c45ee4cf09e34ccb44b96a9ab6719b28db0d237b605621ca65d3aab586a87092c752f50608cbc6b56921b1615112fd667c443f51c6aecfe7e329e22491fe9c68885583e459e8310785edcf3d43582f85514f111f51265c6a1314b63d311f799b446f60d2c4072aee89798a7c4e5e921e8bdd284c04136920505062c48811eac8a24ca4bf26c0573c2d2f74325b94ef7e915f4a5eba29c4a224fa1f8cec7151127d16d9d3f282f8f4718cf89c954a6c6991c513fd108b9a3a1d4d173e196a2a79fa9b95ac217a5aa2f3a8a394928040d48a2cf5ac0eb138215688158622cd777f432c5b3f30d47cb04d3f51a6bb45deb42889fe27b319e224ba810501619e58163cb10d8c9a5cc81a242eb427e689918060c8719d48c8c6ff227f3a7f237e6dfa398ba9cf22ca45de6c30fa0df111fd629b7eb04fc647b485dec0845045559a5412d1cfb755a4ebe693d943f8dec0bab08189acc88646ba417af4e86053d81e3f1919d14584f1543152207be47eb04631e5f9c1a6ff6525eaf6c436e542ac518489aaf11bb2e9df0d2c4508156b5bac6c0f11762184d1a62c9915e1082271d30c941ae36ad51dec4506f7144db7142d73a93015663403a57a2cb6da5a5bb29a04ae83433865360bce69535b5140f8887240a6a2a4f4f73ec54b9da65f5ba849e47c7dc9fa3a5fbfce12f8f5b3590abf7e374b57f3b5a276f756a3705d4e5143d8fd880244f72aee3df765c718574dd3c018900a859651328d42989231f76385224351522acca1cb18d6c8013e7773e892c3963484f7c7b08588f007fea4d1a8444c1776592c15cd8800004010002315000018100c8805c3e1609666aa2a7b14800e7da84a74609a49932087410831838c21860000000019009091d10800883550d3cb0af54ad4c84c3f1e411bb68f625a62e43c9f4c932edadc20b65a4034281db47360d66fee60373f63e1f881488388d276ae6330b1c4051e6c03859031215aa461740f9ba2f5e4716169798db218a18f7fda6f4f3f2424188b30ed59649ed026d0b4d66ede1f925ae7790c5e50e29d717760a7dc3b6aadd027384fec2dc315789d4ba5bdb290fc5a4c633cfd041ce64f05c1405a91863560f765b8ec3cfa5ad0769bd444913c31418dfdc2320cd89878955004e972702d9915282b0edebdd5dd733ba319a123ab65fdc0d1a73703b639465aca880e7c1e4977aa55a08d4cf695231fd7fe51946088fb2029c474d6ca23ddb08704592acfa052cfbe9257c67f783bd3a17ab8b65586294064ec3f3ba851372f59e6044552572c551a8d1251f64e0bd2d020912e9672ff53aa972f5351e19e7e05e7b3062b57b077d5b0ef0a037a19ad6e0660f8e6821ede3efe6fee7f96f274324175429e17337cebca47566c96e44ad855bdb18c9506e6c86a65aadb2fb341797953959e7b6090fa8948fb4f4a63d7e34abd244d9475af2274c93d2a63888948110023865ead8e103d9743994a1a69869154c21df21e2caa1dc5d11e37cbe8ec8303b11d0d6747ce4eef1aac260f2a957f6b69593600962ba2ae4658d4f6833b410c38d3d089ee1212afa4318d1820fc87104c4113d934c55083bd2a47d6e0be27fed4f6a7c21327ccc53734276929360ec0ecf662ea74517d3458fd5e0c3d9692645e4fce4482c3097d35bdffdc212cbf5832596482477e3dce53ff06c3e08aec0bdcf4e47f13c583dabefea668b9e8d4e2945fc47b310b87e6f6c9af71c7d2d8e829874223fc918c2be894b6125abaec8850ccde261232c6aba3596cb9f5a5d76cdd07a1d6121aae0bb9e90f915ffd6f6bbe406e9705b4879f3b6d93b38b960fce4a22431bbd225b9504631692eb72e3df9a5c2ec9c7ddcdea0fb857a64540e100bbff4396cf50024b1d4e9bed014b21cc70e1e828ca231cf39c382a1f2e5f8fed4e2614e8a9b3f1734e189d3ef8d6a44c28d45e835f9ef6b173a3e00a82aecc8693ab4493ebbb59de6682fc5512b618ca01e4241b84ad56217c665cd1f27547e8e3a0a1a8176ad587c70df656cb9073bfac98904d4fe79f01b8d56bb73c85ecf711997e8df9199f8ddbbcf016df2d578c2e1a82dab0d2c9daff0f22429cb2f87b237c100712f26f39889819e121a6ad5ccc16a5cc64e19c48b64bc1dae8b8c1412bd420b7744be397142b6c8802eb25973d59c097017bcf4b1789eb16f8aa7195df8c52617b3cd3abb9a692987422f113b543d64918d3a2cb6ede3b285a4d2253a29423f490403d58449ad10d2fa30b8d66ffb68f1db9c2b90f75b506c36af0092ef1f264100f56d307ad2af20f9990537ca34b60849fbe5af1e443f52d983e8b50147fa0c2e889f3b3101bf73982275662c0788153a16aee592be71313b51afe0422d01a98149d041e50d0468ef3d9a8259a4c4427267adbdd603d4f876abf91d53e741613a9998eb6e121748937f00d922c381c6859441777d8c0125171bb86ffa99215ec16583b8971dc9d856765f78616c53858cb121df7a3b821970fe8bc249d66a3fc694346bb8dcf207f72abe6a28da2bfe680908a2216363131ca0129f2a58fa1eb9e314997687014ef01439f40eaa07b88a842cdb0675c8b8e8ee5be8ec67bc24f3d0473e50b508daca3a8737bc25632699c5e42e868e745191fef3b753455e23d8f6dedf8a1c9a3e525b43084a77f1d8edabca41feac262bc7088c19aa6086ba6222acdc790ee38f29c48885cce85669b87d221131a97be332b118aa022857b90930abdf0ad00f37449a88d97058fc103b510aa49b9618fa47f7719f81d1ac6216f4180af6934131d2dab0f196cc0eed354cd871bade5e7a28cce96ab05690a77857bd7de212456ae65fe7afed05b8968ee26022c61ab8e0e343c7f2652d9ade16e326f03d557d7b9584c6d210b5b5a2db9f370d6f1662b4640a5d639ec143bc66e6769bb78324fbc44fe7cb7b705aa070c0bffb273bca14862bda466abe248b7c2c67bc7a161b8fd232c0954d269ed0f8272631d8abd0f0e92bca16607def1bc471b3ba4506957d31c16f1b829f45265c42e6893c5e24ece6d9f2ee685cb4957dd8b97dc3b9c08c17052b795a0ed34b31d5b5de4f62fe49f21b24227f71583fc05bbe30238b18739715d611522b79672aa85b951f64ee6dabe8a4e25613e86306bd48923ec6303b004b04b1698ad64e4a295cff3a5a3bae478f823ae6da3415e3dd944b8b272357a2b5541f8515c49128f1d1a4a6b0b4317caef465cd2041c3fe4068f1324630ea6c4fa2f1a724ab1c0f07735d3f24022728967014be3fbd5a107421e190e0f203b3ced1b80596d127c3a38ca44509b7ebd88b149c664e9b318d1dec187ccb260b86eb208af5e7a8e15c55e0395144677dc385d55fddd1b54046fe0e87b20f08480736b241e75806451fe9990aa0c77ddacd2ceebfe207efa18ff62b3309d6972892eac9a42784ed123c59ce3a31f04ec9c2b376eafbd5783083724132a3e51c97dd88da73d31f66081cddbd462b7c4d3c4e44f7f0254e847232fc6c3a78d0c3c26c7412d11f5df3f0bd197c7834421e6f16ba906420a6a8a580e08133f4ba933acdb95a8a377e91e26efe095f6b24177e35768a0619054d975fd4656b00a4b2df5b5630e61186eeb1f065cd13018885779542e1765e0b40400bd2e217fe1613dd43e6bb1ea2d27b8680fdd961f34182e50fe4d13323f9ac1e8ffa1b21e1ad05a4a9133bb49bca3b637bb63fe23e039926af9304954622472a7c7532459a629d6392531908eb5033a95d77420eaee944662df785fc983a65a636df5600f45f13f9d495f78d5aa4d364878e2085f49e924b983797f11ec83c1568000a2e50e5f51efe3ab4b04aced858123d5276d8a6e26bd6d8527830549d7d81e2f4df8d50be45e6ecf05c227996491e59136a0ee28755a698207d548dea337f08d528b15af91171393f15a309874743a7c1e3dd93fea644b16a97015cc46acb2348ff34e1c31603eff24821e0808d563ce5fcd4c836e02263c50439f660fa74a1de7ca7ea0e3e54c6c0d8182f1cdb47392a190f7391db6ff9aa3237d92910405697df707fade640e0cbe5941207dac5ffb613846f142a682d9c232010c86a13b098bdc4a84b780640279c34835f2d40d3934058a59726fb0bc730d2a0c0b66d768daf2930f757699cebbe02daa1921959a3629ed4c91145cd78cfe0cc685660f50348dd679483f0c85f235afede521913c9ba965c32b42724faf126e9d90ede6b9dcd74bb7bb427703a094c141b3c8c816c66cbc66278daa5b64b5cb4e2f0e8987a401282f9b0453163ee1e25ecf49f60babab39867f7970539c18b539c98b81aeaf270d525293c6c85f27157591170a8e841965a840875fabbd813fc074905f9e4bbdd699a8ec8f39878b4aacd65f3787e2661b101ee34767b9fdca0dd86aa271adc28a8e92441738abd87895ad53aaf0353b25c891e0ae1bdc689fa60b216c539699faa1785e89990c32c63c1095841b1ed770f81634bc2d826e5de8e22ea4e556d71f71f4ab1444340ec0133b3847e0b6111b413754d45b21ae27319765519e1b11bd098d578993eadcc42c41b721cf34f0b7449ccb93885f6ee273bcbbd2f69077189a47903814e2e6c7d7e9f8a96993039321300ea9dd8766714caf36499d64fc1d0a643cdb69f394724fda59cb49a10b6d13d43811cdfc38c7c1456b246fa44260544b7381e715c63fc0b57602e96987ad2b85e80cfac5922ae691d09cb43dd10c527537598fa13e7839ce5fe9c0313ec70c5a3a9e04d2afa274e7b08ab910b13bae6000ec58286ccda32d17d284c94d995b23adeefc18988e9fed5302b545ddb34701903309c95061affea1353c5d2e181dd59cfc9b86031df88b6aec070409a2fb605115db0e120dc0f65292a5b61e3efe3276e05141b5ce8dcb5ca92779a99d99b1da0484aa5f0af3e6c58d54b3a2cc29273a641f2832e6252057456a09f51c117d03f804b48e7462fb6f0d212b14df64d6bc658617015252bf6f2e108c4150ceb318bcdc6660a153e6901142a30ea4d1020845897157b1f72e00b915d1e5560e4f4117a35e312225511c2697c71c154d760c1ee9205b55f8f7d6c1e7e56b5dac92c3c89fbb10f580282cbd7cd4b0b172c76f464ca64ad4f44f1fb1f64ddd1354511ab5f8ab2732b84667f8b48e25628fb73b0c97503ca94fe5912b6c7e6b59bdba81351e3a4f1c5bc1c7aac0a6754e3a0830ce72d3587e04dc77cd57bc09dea07ace083ae135ae87b1f8cd141cf12a6a795deb9a5f82b8699fdd3e9422042bb254fd175ef4d01abea1e98d2406004ae252ae9290def8e6de5d556153538603b6aa26fa579bf4609f8f1ad07058fe99af29ff85ebf6d3bac5d638f52eac16e5954e37a755d9cecd3e9884353202122c9e8a8e607a0f03937e7ef81009d53443d9fe967729bb1c6998cdec2faf00e8e32f8c8c1a8f1bed144b458dd9410063120158d567d560d6970bbb23c945150460da350a5076c800680c1a85026237441c868544f255e5ee2caaec95f486ce8569cf79a1a2f3aa6cca627f04ef3c76da0d5ea969ae52dd4495350ecb0d800ebc6a44ecac896e8380d691098377656b8fc06dcc7875e4f8478375ecc6e231d8a3a4e0e0998be528987425474620ee705aa4a81527808c630b43ec02f3366ab07e92df339562b7e4ac165547ad2a12a929cec65b2f21e19477021bd824dafc28ecaa491dcc92913ea42e4597a09aab1e61b1ee8f941f311c4081a42929fd594f5b40c7145654a88fc12e5dfb8293d0a7eff69c50c7523644d31e8cf702adc2716fa068326a6b8180e91987fdbfbb7126fefb3295e1266bf590f0aca96f39ca54756b6d0058911d1d0b11a2d27e2b144fc8c6e563ab59b90e340cfc683492ae96b295bcdd68a03886ec336ccc31b6318292f8f046e83bf5f7fe3058814b6e825a5a90907c60188351935c84f1b01e6f0b189f0c608d43cc755c18097f9fbdfbc175a2e44fa10c3025634d76d90d31a9e2421a5af0192b287338cb2f60981102b43c89c7f2857a616361923e4ff3eaef08c4e2a1ca88ab18599ea725908193106eca6f5bed818bcc2041a0df24ae0a1c0da0bf4df860f9e2385ffeea5a7330ae28c1c6a2cdb90e4a3e739561eee65bfe7a93b8d80caf8aacb6b6051075d7fc265cf412a891f4c9cf631384fdbea9957820ff8ee6de922c1571e7113deec0af25ca1605cdc50c442ee65c8f30be26bbfcf7528205c9d6386273c15dc1304bd1014a8f1e8dcdfebb59c59ce16f8b827ba5298dc22b7f4e997ad52d656fa2b73ac9f269a05e5c2fbdaf344c124ea92ec8942f83124e0ab48fadc8bc8e9401e9fed5584c4aecd580cb7a64c8ba623830c9c3df83dfaa0bf7bacb548fc9283e1c1f14fa9015aebc49a9156c2aa6fcc3c50c22f551d9ef8deae0761ee32a1ea95649086cc8fd1e09529cdc69edd3c96b98f2ad5f52c7340bae008d63fbc8e42ce59bac21ba19ee9a93efc8086399ca1725af18eabc1be44d6c835166ba8e8dbd822aeec029fc042b3ffdcc48380449145103021d26f602f8996fbac959299d7e09ffce16d77d26f02d05e321786e91af47811efb19422d5a1fd0d88ef49412ec78abf7d94ae869951fb41e1ab0b43d0dba2126aa64a0b33501f0effbc76d45c1b83166cc1c2879f41a05b64d94c4a59e06f4866016c4efb92ead824f4af19dcbde13e6fd520366fa89d4964c70bd5365b8b9b33226416f9d22999a6c886d90f37390acd86e94d458a4761df0745099068e1c91af894b295488289ccfc3907608e1008a497e1c5fd4cc2699058e579679d05fb4d8a3eeef6d2e4b35b2b8066af976aec81afbb8f12da2bc3403b2236834855bfba6af243a94eed7b358c00388634eadcf0718c4b3137a73c91a0d3a605801ae589e850aa900cc991c87519a50076aab866310e67f193044b45799dae7ce8827b6e7502de80edc1c912dd49d223c7f7020cb8492f2f85cf97c0f08f80f5a90888f3019ff884aa41812b882df6f3aa7a3c0d96c0e1dc9d813587fd46147c206fae0c1fbd15a09a802591a3148c363494c90ba85011e0f0ce56344708f712b0b14e6912cc0337c8dd6cee961442e41193c1d821e4c1f7ef808a9df10413abe113df648c1a3983df736d339421cf7ce703f809127020d82b2e8855fbe58114ab67f370dc09525d7b8cd3dd81ba9f5f77f32878986ffb2904dc9eabcee0dd8d1e90ce1200a9d732a72c8e372282e90c7165b6e56fa4650787e68172bddb1a4d88812ca171c33caa96cedb1c3a84c4c7bbcdd98813a9317495343eee90f26f9084a99667c920a21eccf82855f0c5e4bfb50939228c7601b4e5fc080814d2a78d6824da366cabfb9fb91205f77618e614a50f484057cd607d16cfe865b6f8c8ae52b62a345bf30b7c0a116e60b05e12fefe5809597982c137f267eece7da7910b9a5277d393ee1ee7e4e2bf181fc7c6a8c222cbaced25149d0771352e87764953964ac19e32c3823e349ea72b66a3daab49e44dc988e130323468d81d38442b378143ab7d8c012f9c45a63583f3b2476360cc80410e2c4901e519ae0eca389675774f3978c68530a6c623ce2c3074a7496e8bb3aa31ba9848d5dd11eba9e62b1c236f1d6b8cefb14362123130a6e49beb25593748a09a0d40716e6a1f36a6aa555b183ebdd02ec30b001660681cdbc0cae28ac8aad52a260f84299d087f0d225062c31641b0e3bc00d5851b816742991efa1fab3f7e1c5a6ff31ae44c02113a9a45b9367a4d571b4bbd75106e200974e032fad520d375be2f2d26d2afccae2a49240ea299c1e45057b3d36f010a9f05af8cc496ba7fecebe0a1c8f00ac92aaa56d887c52ec8bf15799c9ba7e136e4010362b6438518ce30a2dcd9a6ac18880c0f7a5927b4d809ef414684dc442036b39d11a7afa10d72310947f4b52f093c9cfaa665e8699405507839868e6d6c3bf89935397625873e9379d38b7b6f23ad79fb32e4b7c4dbca8bd577598ec3a05b7ecef599e3ace809bf67a97c7f354de7fa1e2ffb7fa5310dfe6ec19f069a6048cbb8b3667717cc1d2188e41c8076ccc596c075a5ab316b1127ede5568d31fc6dbceb2ad2c7dd678dc210745959e6063937cba7a8782878670a03d5df46c65baedb99ac03f74cdb9b168173d5a588c49807a544d4798e9aa631add12d2beb55eb5116b7ac1a998e94891c2246a3a8a49e9e7a21cc03dc746ada5af5c654aef3679854f2bd2cb3cc5a997fafb9cd8bf510d733780a37962353f81c65c6a2e542642de687d6c1f8dd26cc7b1e442b5f32ea69ca94c4710a0321c6fea48145610e4f62074109c9fe98b74f003c421e3b8d8dcec7ac55dd4cba2711a54e72b8d33b505b8eed6cd998ba8b1bd84f8ee664a44c4bbc38b81e12d09f34fd5823394b6b999d49e1c983f592d477821216e8a62cdbc2d7d5cb4c8dc8cc237814135876136424b5a52c38067278c6174adafd97127ea521c7ae84f44155552a147d0dde347370457f25970c93cd47387dc07f89e5cc8ee2c73dd90de3f0758c202b664d24711aa304bcc86320185593c7f1d7450be31e3b97d6e170ed9fd233bf06ff75f1fe1cd203128e4ccb38411f3e0475a8365d816d3d91a77970a3c7214f9fd15f6f52f1a6be25a84d909723d2ab4a83212939bd1fcf2370ac837914647f65647206f38d0cb0e5171b51033accb73b7d1311bbd99dd8ea2aa2b53b6c430b776465b42b0c64fb3669f2ce337e2c19c9857ad4fc5312dec4b7d80015947c97df85f6a9f7fa8439fe14b1b7f7e04f2c1ac554dd18ab6aad81dc32fe55cc6a5072b80488baf1f492f323572da12ad3f4a26eaed243f30242d05609eb980c6199040c6e011094a8b1f7c78a8680f1be36a16a1ca2680182cb0f40a308e559c7c13925a14e198793700299e2947edbb48a1acc2e3253fa9b3a35177600cd9004db0525addab398b4f132f6c3b9cb73bc9670eeea3cc78a8e126106c4edb243827b7023157e8201370a77886994969bc901242bbc1cb78e63501b56e6511cf688123b43b46178db92c3f299422b864ac9160d6d18ff5287f14eda5010d30bad2cce21ffb0bcb6ecdd2b35acd35afcb9a17860fce1837bcbe9e85d06ff305d9224890ee47766670f7243aefee843a946657549ebd728f0f9e3531195d477720528e15f324434eff590a16b1050e955849a9948f474dd9047e2483e3faecfd0517c00ceffb3d0a06870ed237977bdb78c13f656d67434ea761304f1a1f6c06c874617446750d3704bc3b61f02ec586776f6195f0a50d70a74ccb8a22ddc2bb755f17cd72948ca63a7049403271ca4f81f82056558ad356ce25cda5d02e11920bc9e867652903a83239e40042c9f0e325a3d46a4659e20ca0a24a7b6b2482b57d5655fd39836ac3d0e3818ef9f360c7c9270b5b9ee3b93d78033c6417ba834d51afcae6202b93e0d87715c513605100f9858a03253231fb93469070f1dea72706c95f23b954bbff0e76d2c5a4056845ed705fb96c111dcc02a01edf2673702be5fd273309502c254f2512deaaa78cdc12cb041e0da35bdb207b8c0be27a5e0b0618bd9ecb2b0c4edeb0512577724d955cb71e4cfc8b819183934012bbb6495c87699169822ab89908285fc008124a0cb679558a36d5eea39688b9d9a9dd4a9902d76cff939d019a88042df58a100c9cc281012fb863962c478726efb9ec359dee4c4450c82fe430bdaaf29067cb03bec7d56294cd8425bcd4ccce5e07464c79a1c91f84eb93116088234344add4b07c49885a88abd76a3b8972731aa83af8934f3c867a1f38e3a802f17c50f4b62a3e4abadae127609f8ebc72763f6a559d012caac6367faaa6687caf298231db0469b31252a15642e364f818027a76a5d4742a54c2471a266999ad08a1425534328c3a69e08f3f3b32ec6ace016ad2ba685b9fc6e65e1545f1022e566efe84bd981646771aabcb6c806d0e29281511052d0ab8a2794264137015d178145132317fa9532b97233d7f1cf710a54f352b8e555b8b54f7a4ac5b2a61d34d975521968721254c9b7e2e5cf523ee1252fea687ecf99a7e5665a0d7bc0ceaa1180b56a6e49c34d6fafa9be753f92725da01f5bff5b4a7e68d3c89f3deae0218bb2b25b04716b358b720a0507d49fee053fb8e5709c7e50935d443db302524bd2d60cbcb9e56d04912193382140b0ee8f22dfb2e9d49b8372a65913085138f278f41f88eef21f33c8b876811130cf10d93106d1d0e72407760e154454293c482bddfcac2753cc99da5cab65a584eb6308af33be38a5fc4f99661ec74e568d2a8c10065c1801c87497ad5ed2b6c70161113795c2c91cba0e1e893ed3bae30f47cd465d2f141f6fbf56110e9c88b0d89d2bc8353a3629811263f858836eadf4722f79d6610ffbecfc1738df029fb7de2a8ee8671497b48282d39ed676eadf9df1ac8262c06cd96c29092023c3191766867da05a2d23333863d5ac836a060fe54ea21531c293b11e3666d5b145d4c3b5575a2e3003c14e4d3838315ebdd7e3acc43aa87dd06a0d5927c1c9f944d4ee6faf48cbd97e5cf408e50791042722f17d887783dcc57a8dbb092fe92357b5411b628cb985d846dd012462f22157bf5185b04ee3bc1919a3b0e69ac67df8d8824f6d24747c794aa361a502f25d6f6e845dce22c63b608b6b13b84d14503ba5d9435372292d84b9f1d1d7eb1da6840099058dba317718b5d65cc1621d0bf4b6aeee8cac77af60da0aa55d9a38ad071756495f353179e6f7ca7844793c294b03fc79a9b6f75e4f2fc8ce9e928cfb551d6165c787bc2a74772fcc8b653e12dd32f6e507026a45cc605969cda4677371468311710a09000b1e61385a8c9d407331791444e69df587836972691444dbdde8efdceaaa9c3fa2c24488ea9e36eb8da37d2506b71629f6a5dd80d70b4db2491138daed7270c130c6c18ea48125040abe2e247070a11fecd4dd62b39977212e90ec3b291d735b86b772b80ff89ba502e069f42166cdeefe0ae0599eecc0c35cb1f202bc38aca5607ddd932ab901c7a0404a6255693ae5f8f473707c3460e3955fc53fdc1a3eb145a3b6ceee81dc1854527ec1911e65960f0e7614685e7c1bce330f5278f5782e0b491edc5a13f4b62f6df684846f1daa88147ace5c9697bc85c8bff90f47848776962966f4a20157baabd7dca558336edc42e1b9a7a0d8751726f6d7b72f965767381b8ad1a4232cde9157aece4743013863ba1eb3560879f70ef2ff265877691dd71b1fde06c5868b8f9512dd7a01d2d57cb6c218c5d96e1d9a4537b5babdfc2b14a2184ad1893a9821d058e656aa273b33c58ef6571154f9d0aa01ef67524b46a6d5ab1b06b8d3ef0f530a1898e1584ff1d9a8a25dfe9c62198ca8b5fc586b6ee7fc58f48e7f966331191672d0944c91c2559c37325f3fe2700003648f73fa06becead73facaa993a2ec74a095b81608d1db5cf7f34f279044ff9e4539766b68e24c1cebe4a68e005dc8253bc206d3be532f9dbc3e921317d03554ecc3465bc2311f15aab5bff9e33bf681be73f51932c1d64c1309b9bfd04279291b498b8f2ae7ffab9ff9eee37bf356ddaab6e0d7a1d9fb24f0ed5f7de88d6ddfceb2110cd13fe76cbd2d94b31bf46c9ecb296e703928beb9a82c779fdec8b94f93fc36227763adb15a5011ec0b1b540833c7661d344f6884d50a40aac199336af23a8788317f80c11e970b184958c54035104569dd40e28de772bc48f155d87e6a02cc4c981f13a7eae93015d63176d8971d8ba37818c2da43fb743ae160c4bb7eb5b806e7cb1c23036071a07ab9d5fdf7e37dc26f9d6f632cfbe7ed2f51822ec017ebb6d1675fd5920ecf442ff29043a457568038ddd78c608be1a9e001ea8dc8ca2ac568a41d6140b1e0988271e22f7d7cb3d49a528ec9a2a7436d028e58455df120c86defeaf62d9e29cdb61914537f4e72d66a4d6d5ff8b372610f7b2c3a8ebd7ae7ffefb53018f21b7e8a3633c010b67fb16012114642d717fbf62c8ed68fd84b140ef52c13c4494c9cdf73f6a2d325f5d10ae3a4104143dc53382c36f96c7bf26d244fe58b0aff1b6c4983040d1f1b0693ccdda85c37b043c683816ee64625390fec218800c2b7042a3626471de74448ac6f8bd406d58f56276a073d742fcf2492a880512bdc1e9e66533088c74ceab0de975f13db046ad92f2d3fe8a1a5d81d4e30de2cd8f0b5aff1e84b4e45e6f77472ed9646c5877a068a0aa3fb9a931fa5a707b62154e2f0502ce1b9907cb4ec776c99dfb4780259a85504521e6f3916fca3b222c71b9a4532b38f67e4d7ad5ba69133ac0bc2eb75d30633c4165b4bf858bcb539b39572e45075855074adf3d45c480ef37db97a223940cfa594233a4e6dbed0e5a85cc079b8fc90fa351b554ef2a99087c0c564ae355cb4dd11546d3e5507b68938d01eacb0556e5808776007cb8ae6a984845187b952f900a7e8060edf6b69846c711e7f25ae32a8557e2855080259dc31ac6963b5286b852656f99d8711f42104debd7df64708a51912fda6770182462861ffb9ed00f505145e3c998b0fdf1b0abd91f3f2b40701391e68138ca519d3ca92a8a4f13a74359914529e5fb90ea67ca8eef80519a88838067f5d9f4e6dbad3ea18cd7db0add1d8fc55801b4cf20ff19591d08dee8859b423ac33154d2b32b628f73cfc77bc42606bf23350f1c2bd305f41a448f147e7fee42483cc7d48d8206556011e4214f2db4a8645f5aa9fc6cfc29cebf9e32c1da4cb3f79f5033038985ee64e9d53c95d23d5599cd78c78bab0c83a4f10c5f99738631a1efbabffa40ab2895349eccc962359ff1589aeaa95c90ece9444c5cb4b8de56b697a7448df3b00ff1e8e44467bbd468c6a8dd71b49aff88f02d9fb23853bbd82b01dc6a48a87a251770cdd8e8416d898380d378320c61b16584aed94916f4aa1fe02a2dcb944794ceaf42184f8d596e7e16645b7501e4ba9324b4f4c351d34b94f8b21728dc2eceff0cc4ebd5816276a270d8e9b0a142e973479261c50c5d702c5dfe0e9e06de7ba0d191ccf7e0f13f3f43ada20c2763b3b785a631e6ae0c6c72a587ec9fb73d2bc5ab34678c05e1c868222a74a8ee3bf2890a942fc87e4a23a2fbca7cf211770bec621ab598ee22fbd13d788c92f7656c0b994d9e3554b51be3c50bf16aa3f86dbf59991140bef9df2d1c293a895eafd9536b8a0f7a0826aaaba90e3cbea161e7b54c541397276cd45704a5b7670a177b685957551e4f01f4800f116134a5ea86627653d4f87389615cd5e4b8ac5a6f96f608dab55b4094b4124194579e43697260a0ef002ca288cc76b21add364431bb63504582f802c9eefe17ac9b261c4accb590a2f2bab08c93007412c583fd162bc7d352bdfb1ba1d8055c943f5d28854f631cbc5029161a6cd39fe574b69d63bfe48b4d30b1cb0015f65aa9481225fc6259c9bcd4a8ef91120f085d2f834bee5b17f8c6c3c6c7ca84304965e79be631f35b03bb7c5f26fd2b83c8a1c48107016a88c20e1e09780726b011be96e27064017d647795c527b3330ea30a55f90d76e82bb69e785f55e03ac53b157700f4419baf43ef362f69814369fa399ac112c504e360740110302161e7cd105030ef0ed184105bec6644d327d2da2dd21ed06868e90ecac143d27d3511f0130fa33c57e4357845b80af717d5de35085907865438d02f2b883a0c1155250dc72df28df2eaee21817b5a6de78e210aa0dcf58732cbf3388d64108dea94e81f953817c2776d3d7bdd0da6bc2ed8006b112cb1829b834010c5a334153b7af4de341834b399bbdb95c1024bae97141d4a4967ba7388d3186a058457c2c5959117ae03c49fc62b64e0fe55ff5146038a2c0ccf9e73edc5e2d97bf8c902a1c8a0ae3a638d860766b058155ff9f7bd60fb5e09ffb3723116fdec1bd9a785c87192dc59447791935a2ee0ea633345db8581e29fc354c0bb05d25c18d6a5357f8246611e11be4d8dbc09cf498664b99bf72f9c1787fb902e827b83c0a1fedc6c00a48bdc9df60e1a77d37f0216e1363cb173febb622fd822775a09d781be6f8d770e14a058dc19096bfdb2d36c9eec68e0e35ea10d554b4fa0ba4cfa1385ed91034a5f639a850f894a338e3adaa489af391f6f316c09775e1a1531ec8ce51002b10545ceab692dff92a518111807f42e07336daea6a1e0dacdab2f237ad238a08bbe45bb626a2bdbcc16b1ae28c4dc68299ca6d26dcb3508eae30882cd2d2c8ba7cb71635538c02d4d523b0a077308c4f490dc0936a5ddc0270653850d8338e2e7fc15bd70eb15898033be5838c811230053144befc9fc754f694854be52ee49195a106f51b997961ccef1184a5073fa96763d41030544052c4197561b72437de34c4ff132a7ac5c88e0c2c573d8dcea940d1ee8b908b28d20492c5d9814518a09761da2451367f23b3ba4e3802db193a946004d3df9a6a137a0fb4fab20a5531dca3a4da210357e29ee56bb5e828c10f851315e57703f80e3034af2510b20f14dc140b764c1b3759967ef1e7829463824516e0e531924e723aadaa322176ff022cd232b2f466db74c99df2e56b37c8c85fb037a71c350c552c9ab2fd1be8ad97e75d556192c956f79225692c852dcc7a2f8053d578d14eb6b61903c548feece9e5025f050d796ac32482fdbde904252acf348b489e0b7c58216ffda4712648df9f5c3a26c2ee4191168741bb8138637f277d346fa036fd6bc7e255fffc0c272ff37d0c3fd4f26ffb4ddbfaaf90fdeff77d2ae137200d4f75fc450b063e546ff99cbf53a17c94440d75bc0ca1c161a8dc22c68dd2f0601f93800b3d09ad864ff39fd23054c9d9c39a2314b856916654a7a370b1d829d1b21654711f9e5654b7e4048af4e6e04145bffa52692553d8908c9cb6b4f2fd69c15d19819c49e3322f9cf710ba2af31965651474da08bd8416a7ce8e8682156fe4fd540448cc053ed81f1d5817155a0d148dca84da2741f95f5e3330483be7857ca6c7aa869882d219470a6501f84d26b15b2d5218dbda0ee792498fecd584ca5e90add2bed065de44b133fa47d8a7a59163fc3a452195950c63593a60ed0eefab143919e0d65c13e1b928b056da83218dad0348668437a41a30d85a48241ccb3609658d620fee45e7b1b530f571f88c11fde3378f82d87b1b642e68d8de10f97d9e205cd5f505707d982163d43c17c009143fc640f4cbb288940e60929aa03259057a5e3d54326bbb8325f3d2dffa8ec8321f39efbc67db5f88a36a8f70c7a45ac1054290567c5953ce2b5878ee264f48ccf1301828dc890c37a83b620df7e841afcee7b27505e4c19d46c238850f85a53f0e6f15c93418b29b63044b44a23e8440c488a432559860c6a8251a8810a51bed2062b3db68c4977f067fab3b0e9301a4ed504eab486ef99f1f4631038000707db9f0376a003f5036d7880f45aaf21764b2c3bb3309fab72952ab3bae56aa1cb0e7a70a74ca85fe8514d4a86c32555e6bae17089eed71bbbaa60a0bb02351ed3147c4f0e6f525e0045f51615ba013afb1eb28c00369b19e844231a7dbc8980552cd275fe8d5c37e8ab3269e662b4d84738907bf1fb2b9733c34fc9af2193fc66e0063e812bf002e9cac91c5d3ded7893f2f02138d4bfc01092385d4628e17c53251e5900b7b63f58ea9ecfff2612f5811afdc4d86ff4a31de0e82732b6a39fd50adacaaa48c332512b53f3d2ea0eda6396855b3bb68a71d1c4a2c486f8387f8dc19411cadeacba51432ad7903ac297a783003a06953644cb7e6a80658bc8752c5a1df81ad697a75935562e77447368f86adc0a4e58d7793ce2bd85d4fbd682c0746f589718b09aaac28a0c9b7f43e56c3ee300e5dd57d8527459e6bf9d4b293752c1314f0a989da7a768aca85926c00527ca4ad1142142ac9346526b49ba90e2ac2595ace6526dd2f0cd26cff4aae8a865b9046ca29a666fb7e09653d180616704aa4cb6250b66ea167e0ee305d6fbd246ef5c1848209f7ba0378edfc4b3da27c2c7b780cb8f71728aab0838899e2c741afb6322e5a6db75ef3ba28edf7ba8212b13bd1158b35345662e9c668800a5f1e569c32e76426df7adcf85e415374d804f7b2c65d99772b5cdeac93fed780b8eca1b26d421b8d0b8984d168d0f146d06db29267742334268be8a548d8269c553321d9d649db813dadc2a0d49db192a6a90354581181236436360b661a4c815ba0f02442f2b85226c8d412025b08ac78c5de8e9e78bc518ec2121d5ec1f0df697b5ce40fdbd842724d225d0c7b33ebaa6fe8703c31a2aa07a8502a13347ccc0810925abe6906c0a906a8ac958841943af4771a06dbca7cc83ce6cd6443a2f943a02b43607dae15eb7bf5d6c4fe7e8679b045d3e01a960d486f8a051f3d502bc4f7cfbcc6a8029cf8e0e1dc7e5bef7987530f01874f04c6606412371b763c35e6528608fa8a050c2a4c8b1a9f8c3dfa52c582809ece36690ff855474cd9ef84bd5a36272108d4637b69489c64ce2fd34780f33d44fe26631e1c6526915d58cf07abe4b0370841053923bc6d263929b52346784dbda735541dfeceb249b2095b2363a5acaf7c47c2b52535b454d7f691c32ac4b3517854df8266fedd5a76e1405d7ba6e9682278edff803a0da057c6c9a74dcb51f023ee2b26cd9e1ea26c67ab48dd9e4ab75eaa39cdb6c7ccb856b6843da339c8bdff3f061a2b259f59292f3580690d79689bdcd225d66bd60195a9f8d5d7a740e573a1bc48d38443441203805c9eb78a67c79e05b4f9bf53902bb2444ab068141eec8c00c284e4844d671c3c6534763b397199707e0db6b63af52dce4dade4b250838e23697c7d3788a8bcf64ab8a80772db852c2b74c5a7e51bf715587b958eb5c620f8d79aad913fbb288e768970e1d592d88498a3bf3b2df042e723ff03aa135c1719df284246b8c3b36d4adfc3fc4bd7649862e414e672fb01d213676fbf793cf45103780397e4c151843d59b562f4c638138c2ec043cb1ea070be8830e2c36daea12f499313f5b4be03b1b2bc3666c8a174a443b4d51d3ca0a10d7cb97a3037cafe894dd6503146af61da6c9df6a7913366af6ba8b31fb2884ba8d71b85beeecb4a8b3b2f4b6d9deb4e1f2908f1e708fff8f39ee1db3f36903607c6a6dd6973a7df67c249d2b96a3f338c34b2ceb8cf7f3b888b9c12f4404870c38a9181a22313f298fbb4a4b02568c794d663c22adddf4acb2700a1efe9a890378db1d12c0d1ac1ae192324107f7a35e92156383d9685d13d475ca6d0ad3872af1a74b3c0c7747613442df181760f7b7508624c3eb6f8ebef4ceaa2502b0ee23176902c0759620e4fffed60be967b29b4da707aefdf3bd7aca51d79f5cc2230145c50da680732c4a4f5cbe1fcbdb9026a043c893b24b37edc60ebe3543e946e582dd6628d7c04994dc7176a40adcfc78e08cc5dba8cdce43cd6ce4576218ae81922fc2755a4d57696315e09a3ff42a398f6ccc6fcd3035c1ae11c6cc1e5c03c25c1b92ec5affc21b8ca94904b65ce0c3536f78e2015fa166abfa0cac9fa8aead83fc9d3ddd92275ce3669e07a04f2fb75b6ebd1ed79bee378c21365af56db7852bfbad5ddd50b3e3b5f65bc2491760b6983c37fae737cfb2b7d0cdd6fabd0e70055c511848e1c0b3e27351d12c8b392d92626edbe4d42ef16f7cdc5f9287fa290fd3447064c3b4109ca7e8da776495f5fbe69ec2fa34a3362b39d3af2861a4a11d173d43539185038cfac2c9309eede024078c277dcef720c9f184dc39ed3cbf6a56569b0c6a7d561bfe169b7f891af3fc5d7bb576514a8fb933a3077685afacb831ed892144b5a4760a6f731135e3b78af8f5e32e66c24a87585028747df9383c4249c31940e6bfa5fa47365a8e1f7237b0db1f0b7d0356e4e6bdcaff7433c125bc2404047958509293e5b5a9e70210c417b72c23bf7c9be241a47225b7f031cb1c19c4f237cdd017d69c3be07643724340fbb447666bb19aebf9cf144c949394bbc458d423690c4bcd2158c3c8c8caa1f0883fdfcee215a6f72004bd6998c7cfdf433f9253991705fd5f9d4e544b0d382c7f834b6acf5fcb3adee9cac786189a3dea32bfe9941d1a2ece8795cf2325b164dde233130242f983cb824ac8ddaf06d8072b294890aab01e132cf08342b4e3e59276379bfd2da256b8cad8ff5431873e63ef6bc14dca6e7fd2b3a427df328606f95cac75b5a15abed2046c5138af02961f62ada6a9a5eb04967026565c0d2afafa71eca054e1b6ca57a7760d514e677f49894af7ef3b4b0e1ff1477925c82c50564d0ecce13c09c59308829df227630f4dd4632b74f78bc34fef852ec9410ffb60d31f033693fdb01e192a0599c1d068dc3958c004db085bb330dd266e03784286a80195cdc9d9bea6e146c940b0852283925c7a6c56c8e20796fbeda72529ec258c64210b75c05a1de8208cd7a7271691106041dd27feb587929caf90dd476c6129aceb79b5685f9d2a18ce1c3dc86a9e91d4fbbc078c95e366cb50555c5659ab92f34351945655fe114a6eecfa8d0ecae5da44d1f121533ec5870e95a8da7069674917afb2acdd818947455566772d4db8b68b8dac56c846e0d1cae0812b9975b413411e315cef75ce9a0c58c8b0983c9a08952a5de36e933829dec403b8383162c0c5946c8cd47332ba43995cd965898f1a3ec65ceb9ef55fe22a52fc65bcaec119ebf98c9a1d27bb1cb46557eaf02907933ec9bc172ba53fc932a48c5ff45c978ef4b8fc6264d527faffc8ea411a0c51d704da39c966f493fe18b2fd9a686b69c4b9157fe4d776f523a40da8c87a41894693c9953cc4b58ddb118aa0bfa747cac83ffdb719fa1ca1f3481274531f4c6a1cf8b2568350ebbe6b3a474e101663671e0414c4611be1944285674a20dfa02be059183502ac758becddc005c4145e7bd3c1edd990a35da64415ce9db2422c9b3ccbe2a92cb89ba9c4a489d6b0b4d4012b53d8294ab20cd5c301dfecffe6fd5b0532200576e87f7f38b435eedf48933ce02c4e45c27f2a35bb47f0891f3ad3eb20fdc199f290e0d09241bd90d9e852b188b1716f08090400af5a2e8acacf61c5490222582c500b210544be240fc5812731a591f8feaef9b817f7778b617bf6f7e3f32fc321f82bf4aaf70537bcc20e94fb40d1cfcfbb8ff152da40cb65bcd815060f6bb72b0d04482a6afd87d5d660598b56e72ffb4b4be50938296d737aa5cdc7d3b89154cf061c3c0db6fd72e9a70af177c1b4d603be5594b8b362e2d31bbf55da1854e58002c01fc34a019ff5e6392e4cd6f589d78e860dbfec506c8624d19fb57467278b91fea6a1f7a47663125d5c035909ba7ad6ed96cd88917274d311720e07d3cc6c78ea8ff6455922b6105702f1d04ff2ec55fcc94c2191789c5b20a6af62ce9e33d918d9af5d5bec752a3fb85a5cb227610449cd487eb2b53f57ff9e5b84bc8441f5c121c1006bf98ab61219586a09f56da79db408c57a68e2c47e2dce1481a8f2f4b1dce4dbc401465c31dfbf96841d40c362ec25a1b930699270cf11b81e321955061fa753fdec9a7b02d9214b8812e710c6663c52187c0d94e42a8f272c9d50e9a43cff260689b92a42bb7f474eb67e24093ac28cefb88cf18d1ab65b0f5d75a6a53809614bafadc149c80dcfef1040c8f36c381547c1cfb05446be2401a1a9e021486dbc0843936a302d95be273726a5009a388d5951fea1100eb8b70076809e343b483f7a39a255335b3ce5c3b335b54aa73410fb420edb961b19b43569d43a8027d1a392e871cc4804aa744ac038f37914d25f85a2537c1ea01cc675c6aa37477e04fb617c098db79283784a6d46b2401b300c58e22d5420e183d65afba9379f22b6e7948e704a1d1ea0006bd2e50cbdc34c21db6cc021e3f3fab2b24fe598932167c8a88704ac2c8431ef8f3438e92c16245c1493be13a297f26304184b42b8ee9b33399ba3d1b5af583e5a5a9c7e4feba1671fdecb2aef762b7356111c8c7189129ee121af5f4d52f683e42d50d587b73de50d695e4f170dbe464f064e41542413583651c9898c1182a304813e32da2909dd097f51fbfc65deffa25d218a5422aaf67b8fc6f4193ab50982c17a4bd00bd23451bc28b9c043aa9eace2dab2826cd571775d0b172278484410741b19b30440f06435393e22d2180e618235967169787b52b41c20edf64bb038781017d90ca497a233372801f95f2123e8ed3cae844d9c7350f5a77c3d4745299397909e58bcaa761c90a532a14a33c053b4c19d9cbba7243b90d8fc9353148c315ee7acaadc97cdca4a607d2fc3a380fe5fc39acd5109103b48826cc1d51f5baa3118262d36a4adfb1722a066a79f690b9f7d95b7d8be74abd81979405c72afd6ed35134bf9811878e63c1e36583b91425e0fc130fde10d9779171607d55c4c0bc6f9b14d14ccb8f961f3c006411a1ab38593349ce4817881291e0c0ea33140365845fa428da5ad01fbc6b9db066a02d5d645106ff96cdcf5ce469e4640cb786fd65db83c5e19560a981149b96e35f7ad95c99fc80e4c8b8a913fd5cb8ac1fe0bcca2e1f7474704dc29e6e172e09876ba9fd0b3ee0f379fd8ef75f1d498a0d03cb80196430c64ae3cddfeb83377c8836f531387c2e8d12952cb9db4ed5476873cbca3d20a8f8185b345021cf86fba6cfbdf49e45d8b42730a85f8f2434d74c4e866003d44003b81995057e520c65df186b27c48c234b0c5b0aa21e35e1f0c0e0fa9a04730064737e2cdce89e8f97d3d65d763999239a548f7f5845dc5c2a6d40d1e9200e9485a9d43edef96af0ea8365bcf26b4b14614a99d1db07cdb4ae3664dbb06d428dba230338fdfe74d1c208e06afa015816f234603919183d12165762689a2eb125e5cbe0bbd020677e707faa852558a12171d7c9ffed94d307a3b3681a2ece3fb8583bbb81a85510a936b549b02db2fe1c418c414c95315214e45a7416de442d48784d1f1bec0034fe51804113de7942eae55239870fa8bc30ca2b18a4f66612a591f8ebe1654c16702c101efe90843ea05424d9aecac207fdde456e623b3da5ed6c26a52ab4f96d19163c81c58f1fd832124ebf9b47d42b14f6f9d740a5a8ab9d7ef69ca2930b5c0ba762e1af9480d88bae2246e0f57ce95a94fc85cf995eaa5955393c13c3afcf2cc9a288a7aee2aaabdf4e00a28c25bc4ecf7b7d3b15e6413e0ac24b67c598416e62b81046f4183f8293d11dcb6b603e60a5ad19b694ba24f8f5f2c01713a4846714bb68cc2779356bd563a28a063b3370aa157afb48c028c0059ee0817f0946c09246e46a432080d00664df7a89096e21aab7cd3810b741aa7f0c121fc1e41fcc0ed7439f66c7395a98af003fd239503cd8217721e8a26a0d508e932e19c29940567888653ccfa0409770d9b56e608a0d210faa10f9320fb9d787a9388312d9c034dc2bbc417c9cb057bddf7016a4fb9c3f2d1c89e55e25b82b82c48cd57ea8a9c954b227f11ed6523793098ba3129cd4abfd977f638e25d0663ff3763802a7db8cfcdd1f62c185b99cde30e5c5c4bedd827b341e34e734063ec1feeb539a0e99d0a37e39306a2d93e78b961e2fe11bd687e8a32c0d5a769bae690f4b19de83105fab57abf9efe2576ed39bdad9785868f60b430a0a15a856d6f22644b87b692459a69a8cced52fb9bde9d4d34a6cd7071b3a7fe15ea2fb3a8ee661c53bc71fe0a3a05b602290a369ce7f901acfed7c86951331f6648d8725cabdebb1404da54a979c509d2bb2e7212504361057835f509f5381aab6dcfada22cae3a4ec91b771f207a689e85737d2967e6cdd202f36082599d3bbf16ca02743a1d42aac5a13c0b54d432299009fcd5350781746f48f2c8444e5651ce249d6a3c32ab69dd028122b244712420dd75e4118b70e8ddcd4244b683329a7350c2f2238c3238c5a122b78fdef99e8b463ec70928d97092ab83b7c2a51325e6dc28f58f57649484db91968fd19f3cbbc0e0fb352825ad9ed59a6d31b92fd6832a359d913c2ced83ad2927abcac2b751c98b3bfe38119774114d9b67690ca82d7462a061be0871bb8bb0cef728235fb6f4a70e1f27c9c4cce2481527cb0343b16fb62cac60323223a2ec798c84d162dc152361cbe22eba61302f7428334626d9f1dd099cdb09eb1135aff1057e62938e11acdf92e304252548908d7922dcf97b13e32a007d833f4a46933adbcb9b1e9719098dc9e5f92b09981eeeaca88f2b09a6ca4203a0782d0215e259925aab3b88684b59428923902eff2bdadcc8182190b51538d775a85f61bce417a885d19836e11a4283380a5ca0998020fd03d89edb413dd2a14780101d5c4c28d4f145404eeff8c995ed421168fc8c948c7e535834220e471f1192bb92b6142baf02a4a46bc10f16d38d19a4c5747a1b58537720a93df6e6c4d43bfd7634313eb2e64ea0dc75725b5470ec74e8065a87ccc1ea557df989290545d8d3f251bb62eaa1edae472a25407c1ced986ca7ce4eb64eff447033cfdbe28ef4a4c437f4b872db234e690f0be2e633427631b1e039d2ce85a33fcc981464475f5fc5913e5ebe548f6447b31765ad30f3508ba09b1e20c8da6be6f274014a2cc3c06a220631062aa3d700aba0a6f92e08bf5934f52bb9cd5ec5447a12ca58a398c2ea717b3040228d27c33db2e4793a9cb7c14180a18782f48a7ba40481a55d8aa0211f6d75cdbefea54e157fb6e818e78d146838be7810be911a5bee245029b28e2cb6c610c7f4c8be0029e5ac0898343a5f7e5452189d4708ba7f45a7a09ab5f094ba9610083339f0f8e427e5352c6671986ef5b841f8b714897cee9beda306c273cfa83b4d38161c633b54175d22b404d387f5ac59320e9476eccbb6f8b9a78b248cfb7fa3b8718af88dbb24a61459efe1cde9f0f752aa6a8efa38aad011d573aea822155e32444006dd3e263c478c28634a0f60ca3c47345d95b2c822c97f259e730435d09fd0124d984e07d63bc96c4f42d53a87e5066cf686c949623942f0ebb4cb239923f4429b906b8a137eb5cdd43ed29771675d49484e37a8d6c1e65d38554b338f626312edfa8dd725109aaa844696aa4a987bcb746bad8abb06627da5af8581528cf89682075e0773ee61665705b8f734492905728ada2fbfbbe4120afdb26dbf5fed3393b1e5bdab6f263ad60a11cd48cb1658a4e4f1226b91d085da9cb30b8884e22f76dba5eaf7e60fd435772e5bac9af6d036f2a6d945f445630c23b7acd4c12e493d867865975737252cef609dca5d4ca1b9d79295cbfa22891cc6178d7e5859adbbf3dad90d46165feafc149feece02216b419f7562e262b41bafc7edb7baf4a7ddbb4f2843542e79797b1c1040458f0883bb103d90d5807f98a5bbc48a35d2807e12a8b9164b6c7e211d028885f4aeed11a24024d24e3276af0cccc840423bd8eba8ed5159ab57aba9587e83af3a0961552ff5df42247c93e6f00eebcc8b022b1183746a79f536820a87f1c4164e3ae1a4e15af7a7e271ad5d53040b406c4c127f7cd5f4a0fa06d6ac65116108eb2764e340828ad46a60d02e5d827878638b759bfb1ef2b9144a0d1472058948979fabd5d9fa9d0ba0fb8c80bc82591f4fbf53660ec36ae492a362368647cc1416c077fccc3a7fdc9f72fa422db0aaba967eaa1b18b2a8a71789a51d33b170aae313acc9ac7a3e0ceb302368dd19b4870294aaf632d704861eef4e9a1efc05a8db6ce6d4ce2619648d2a96c5e00103a06650cf701a1a842ef823e5b6a1b6cff873f20f81e385f257711345a5f4508bba1f8e623342c9ab457e077ce480b821cf4297d92d4cb4db76763d33ece98eb136a26b01d28398d8884add3a60fcd4621b23ef52bf16cfddd301503de8d79ec11171b42f6c8f7ebdf98d7e9dccbdcc1c5c47ecac6786a3899f71fe9a16e75f5dfd25f27755a132483153f75a90a488d01e7792169011b9c760f95460cc420e6d253da88258b4344c54da9644e55c5476f345e8c28a4fd4f26a07e37d4514f6499e9504b6c88e5760d64489b7f6aeb1ba3e53ebca16ef0f0029527434c42e413d09bbc8b6c794c9146d8098fd9379aeaaf55bf028a2f7724bfb00234a09f1281746b2a9c7d1f4128f7de815a4b1ed43dbbe80425fd47b91048790a298f857126b40451197f80269d524ce688e35f6567ec468e0032385af7326c6f4496c60b76bc24f6a1ca5a3eb4d0c287a4595cf1b324bb85047a23c9c1955801f09f43272a0581c0b1473238a59e4508df200e438b57e79f4a592d762220dc074430819f75c7f5d2f65d2df73df2be9e4e32a632bf0e55e579e4ac34b8291e753fca50bcf705b0cb429e72b92be3bfcf75d4ac647b711db11f832a1b03f3ab7f19c88a05c099dee35929083ed9661d5e096bb36500ba36fb0cdb6b5c78b5857447f27c29401120d7b2197965ad36941c6fa71f292685a908b38bbf80e4242915f8a6b3c83ed690d3fad8f4d1d2b40183ce593a0855eaf0383aa9a02b0a9a116d0fdde3a7c5ad148b4c236f071903a219edecd0cf24404d1b2299d00ce62f1d48da69c1937fcdf3df44974685536fae13df2b1bbc10138b24e50098467323930524f87993dedd667711db4562d3a9057ccce152333c5daa750027d0d0c9b584250aaa345c741e99a1a0aa3f684e8a422fe48b9b4a0b6ba6a79958cc08702a0c13820e0ce40c5dfa3133e19f3dd0dad7c7eabfe6ac59a570c790a150cf06b2d1487cc5b51f8d268ab9cc1c646061272280f4a10405618b582b34634a344c5c7add21bfd611f6a9e533bbd4178dd50d7361328ceaa4b18413a0d038e9bd511b48c55966dc5b39f6b4fb98588841034e19d44c78ee469999c066228f200be6df087a4c987edeae28eada24b21b62ec10147b266b614652919cc19e34e9c0da4540ab720b3a8245877d80c1508886a1041c45c7ec80ff3476d8e26db7fe04048dde85b67beac7c32cd3b87f36a7add75016b5a425daa0e7b2aaea10c800e833115f9b1abb57649531068fa25d9f6fac2607068c18bd1625c106afd0d5f71bf885e59b493138d9c456dd554c88cbcab439fe714d982c929130215c3e629c0426a8a206870068176c3eb663f50a680eb7bf21eaf8d23e9655c665c24fdaf4c5ced2c8497474bfb6651bc0d0b83c8594e8f6b2b7e9197012d00de23e74496838f75bf40b3ea50617a53dfcd38c531614a2bfc8c78f2d146d4d6cc40a00a7d697e14714cf0afc55c549cbed0a6b7cf574bb81ed2da9535f2e69d89274f4b4900cea40d52a0fc94d61adcbe664ae00c6f27c59adba4d9ed3593d2d0fc9f27374731914118ca191e6fdb5a3032f38e5d0078b397c106ac1409b1ff6a65ec71b94d0943930cb9190638d18dcd0d9b483e2027412fe1063c1e8f4bbba4bf816d5dffa4c0d7ae5de70762cb0e77c78cc4e3c3d02783228d83a4262aea0d5792a4ff16b1cf403f5ee142903aedb2327fdd3a2540fe99ab9fc112fdeaca00d74cb24cd6826d69a08ddc6fd5c98ba2929248ec2296f5b6b7cb696174f47a6aa1b68f77d7cb1b30cd7e73e2b47ad54e1aaadc96336294b2457dec76b8e9b227802ee333c6d1b7d591ff5dfe9eca62092b4f25abeb5df9e46299e2868e48b240581bf8cf923cec2f71397ac0f5da5769c27367fa6941278cae25a4a5e61016059d9b767c1ba693838b5448d925d3722a3ba9feb7652a00516f17f56d4cd53ca1cfc4ee43da6d6e080d7efe54ca44e69078776dd018dd7a335d0d48d806b858ccb8eb75604b703d9dc85aa5e5626085c3e09ae208d028266419bcdbcff13da7ef3d978e46a6f152f0c4240719e88a0639181557bb2af4f83aca16700dc1b50289c7e0a00c78d06d2b98947b64760cf70fcdc0c2060e9e1c6326acc247ad4cfba68cef85be09c7bfa4e436e3ea77cf69b764b5375c756a984519c9193d42df02014ff2ff6762832d58cfd8269114929a456230cb50e9ca331dee55a42bfe940a543be294cb3339aa53eb935376e3ec869cbb6f1aa14f34bbee386e8e7bda9951a290e1c84b7157e577e7107f8ae1e8e648dc8971c719f077766f80d5b971f073ca2082ce6633d85a0b3d52601673695b964cf0adbae8263564a2c1467adb335b96f3141aad6eaaa8b889d332b608f5aec00f06c1bc7db79d4c811c98a35725186027624a8a3ae4a6d39cc2566cd8e6371a0d9022c9abf336549e4aaba68e506db6f531e1ed38a7c830dda9efe9e1025855bc2411a0bd1fb454fcf4ecc8c8a41ca435daa1317dd4dae205dd52100fde6fd5c20f6847cb28e6a32dfc9463fd62b2930016b790c032b2e639fceccba149af2596ace1e928d38b9ecba2f78585d807bf74af04f075dd448192d363f5a983a828c4ca9dc2cf52a0932fddfc0eb0bd11546edb07711e1c7575b4449e4375b460aac02cd3ff0253b896d3ae2d6d57ffd7ed88652722d0159de38724679e4ad439b83c5ab83c924c7083f6a5d25296a2f97b58ed34d30d76444b8aa34a6f4ab77d1ba52da14238812b59cbf31acba37d648534d3581860111f31844175990a57c6443d84a085bd686517e47b0227b152badc6e5509844dbeca277870affb9b5ce5b97a19541ad57525a21c3916b20c9964e5de544258a32ea821ca285a16f6039bcb40e47a2731543390deb39d2d44f4e022a6e738badd80f6bdaa060709398b0d8bc02127e0f17edcc321dcc65ec1b7102b432d2f3c3028e9c6293e1a2bf60976977613c0918d215ebb76cceb8b5b9fa6359faf77ab2a5a7f56a42b30683263a13c36ceefeb9b7127cb7b5f521ea0548f1099847b6568352552ac42c569746f4de95fb15652b6a13c136662cf686c15da0ebc75a2cf6f1d0510fb9bf60cffaa846ad192a3d7ca57778f7d19bbcbffbf679efde8b0e99aac90f827262a226618a6c11c431b17d0413a6abe8cbd6a28c71ada06dad57be39434b1a8a5961010364ad329a71ea0b13015f8f3b41d09679ebfa1cdbc46ebbfaf2fd8688f707a2034263fcddbd34750630fc4423f170665e10e38f0fd2184f6a270d6b8a91048ed48ba272a1c7e095452bb1b5b553c0a781ba4bc1b9d459f1434fd7d07f1b6a95cc292564348b6b22a41987564b30f981df53fb9114c44f08ade05747fb10f11a82e7e3e89bda8b123152abb00579c41b1d868538c833874581f9a558a9970d0c41c3cbb47ef26ea1526aefa9ed34ab74283d205e6214b502c9b2788035369e63790447ffdeaceea30804867f592aeed947355717a952209b4d699d2651d4f848a6eecaf8a670cd1a6bd2b25773e36016db64f494229baa0f46fa49ea47d599285e9969193d20da3c7be2a45e7c510124c6689aca4ee10d3564c2a6813f57b015c8f9bdbf8441c983da827c774d85659c9f0a30667cb3af2f712b8232f07e9c4fd5e47e467ee85fd256d612546d40cb790fe51b191cfc12cea57507387a52e01b1380488929d19af7c0288d0d3739bc4e3c5692ed9a6a510ba365e859559d548a369d6f97fe2c150a142d56dd70c039923181f6c3220840e2c7b99d2a2d72ecba2aaa339d469dce7bc3f05604d7ff0abe34c0593039d39b6efb3ae5a6031a8138a1927d2e11d3d18ea4854913e11a2c95d12c2dc144770cba99a68c78e1aa3de407e9c6e1f9e135f2bee839694d2a7c7ed2095bea76fcefe59e67c15f3e51677e010ec5bc3e51b1211d40f73e0297b48a13297852d0a5d9dcee35cace037fd33105015d77860000070cc3416cce1d2f230cef236d176cb13a3cacd8e44e82b8264483fc0a7e0bfc3b4021e6f469ed38488421f1f009213299475e39bd99c1274d275e36f31d1eaa26533222a224cc44ea803418b538848f083b5a45a8d0afe26046237cbac18e349eaeb7dde58f999ea0d2dcc1df30285e8711a65cc58efabf1cbbf1e2b0bbd1f83224751eed500361d601cfce958f58089183831396f3363dfe95854bb9dd772fc443921fd09fed9dbabda910299281333a9f456856a78e67e4729b6181809fa1ce24928f4f42540944ddbb0b2621e12862dc36a0074ea5fcb5ccca165bad5673b9985c7efc1919a33c726f475a388248c4da673dc4ace01e7506a69f48bdb7c4dfa0a341ced101e6e44104aaa7eee135333702849e38e4c82ec650c07a21e4448fe612bab881f85582b5a9d7211c12ce4f56e8e57328dfd09e8e4359437b3a29da7c629eed3b110113161638b1fa4c2432515dfea3ab3dafeb641cb969357308b929dc4c205568349c4a55b78217d197a1b856f67ca680d3ec84cda9fa72c3cc4d61e12c839d58bfb3eb3846d1e8843b6407553ea288dc828e0587b90d93f5764519fa9160a12d971550f50e2fead99d6e4eec12060404208eea016d63b90e494b63e947aa32b2b1f8e737788ed7801aa01635076229d5911f40bdc3e54f15170969a891b52da9a797f8a5d36fc3f52d6ce26ff5f8fe4e1ff8f2ede4e6ac8038884ebc511e43e58e850383952313f0678e06540bdf09060bf94fd8817e6cd74343c751bb9132d8be155cf336ffce2892485d22880726aa652cc9980cc2d062a12b92e9b4b56d8a744d6115d7d4293d6eaf6a1709b57e1d22a19f57e1c4c909b41698efbbd117eed3b3ce7ffae9d49213ef20216cb2f58926994f18b40a8fbceac69962c4fb784f760d4ee6960f3335adab16886a8aba846956d8eb8a4c58ed71e810b261f31062c71c7cd50a71ce5f36591b25b4f8c33fff9cc05cca0f990de6f53eda96488e66fc1264702e77a4b33ba78353b83e006d347958291faa162bd74d6ad825f1414731795a678519b34cd6e3eb9037a4b6e32ff285688922e3a2f3ffb27f96140ddac0648acb28c8cd42234db01a417b40ba21ed4043948c4b207f1f8ca473955fe2882b05c334d26f4ce0b7f846fae237a8eec405db3c9b86e299300016a536a39f8041918ce4f79260251149a4585bf9b2dd165a5f7c80543ab0cea43ed187d9ca62906f7da06789b250c711b9f0aa9cba88c0609e446625af69c2a43918c791c9c7e2eb8a41b4a2ec66603c58474e5e7ce18d29f835abda22affce72e1bb06eb2af69368b491400c5b9e4a7420920556710bc7e00fd22a68821f75c4be6de0b4d600d41e8c1d7f8c5bcfcfd590954b6edf722dfca23ea6c4e2dc5287a7c610c12e1cb9e2c354bf1b0f46bffdfe79ea27c156aee6d7073189afd7f4d6a589d03b7b7a4346d69e1bb13c344f06787c8660f8618a7fc93226294183a91bda105464ab658ada7bf5dd2f3a670ac264532847d76213704989908484782e59ca01ee198808b35eae13c8fe5c702561ca1cf2a248c37c719cec5da2442d9b0407761660182801516561be3a148485349661f2037f164b0a2c6e572573cab358675ac467e2cf121f54b27144618791775d944d55e07da5f4982cc2ff377f753f757019dde72875a153a4c0fb321036d09ffb3982d20c8d7562a4355b6a414596b107bb9429c2e2565f5d563e8a476e0100e2c9cc35f3efd2ef85d608cb3c1dca0ab4c7f9beb3db63d35aac955be55137e17674e76e0410ce9a3e71f9df67f1d819c212be2e7c873e5dc86a5d4138643bca475890be4b007ae457dd8113ce2addcdca788acf0000dd25a09cb2bab0d3756fc3197343548d6be58c60138d78e0b93a26f8fa268fe0c306ffc31225cd93c01f42c0b2d15603836878818ed1a540103e851844481171a7bc8ad2c035d1e2b3d325506f3bb58af4970f1884322db70cdf63c222ff4087d8cac4916b4bc22e0cb3a006372232414abca57d9272c1826cd9561a49aaa3818c2be523c8a8e5338686bb510b429c125d227baef6085d38b01f398da682c481681e41ec1e1d40ecbe2b117db678f87aa0a8340a5de4896fd57d305bfbd9734d3c19857e508723f4c483179c51d01403addc6941c9a6ac634a94f1e1228f046d1fc1da240d7a65b4eebde77188271b51a12f615e1b45ccabf9d25ce3dbf22d8d330e0cee2e696b6c986f7f45f9d21c4cdada479af0c348a29d5a690ea430dcded3637a0d6fe605cf76720810c4c8d6e475e8db3cd504b0c4e3d71239d97b551232c80f00d7eb574b34b600316d866560a2d69ff62f3809c2ec81ee20ffb134d602c6c702644851b0ec3cc37e6096c9e4ac3975964d615222ad99977a9edefceabc3bfe96474a70228b90ab4bc37df72b3deaa4f0c8a3ef9fa30e623ae8eb8e08417ab99db5946246f514de8cc658449327a75f1b7f76fa4605a6b4828cdd15031a6ab339910da0cca28ed81654102a3a5f137af434232a1c3a93e0bf4812e9356092f42268b3de6fc9af8d90b279e57de416859cc1d710ef7dac38807aa66bcb3c3023d86c6059f0d538d8779b89d3d64614aa6c395d1254d4a3b03529550f123c3469eb071f9e066a962feb5d09b229efdadb741424b16fa6c3cebc2d0a584e45ca37b425c5d9a5ea18569ef1fff93c431ac39dff812c2d4d1652be4d2c3ed0c52ebb7bbe153c214e042bd2792fff039340f7c1df8f8146eb38142214f8b420128895ec4b9d4ceacfe3ac430414bc02fa36683589f78653b2e00a9c6b4721e516d60184c78ed16631849bfdc48d53e0190e917089e05250f0cdccb6670b861138ad84ad8b95a8d0c938e086aaad881e3f765e4454b78a2e907616192b20c29be31793fdf2011e0e6b3e80aa57dd42de4b193bbb5a5788b8673104ec201f308ea0cac37c451e88240dd58a36ef8be742200dc70223cf0b738931bdc069ce06dd0b5858ec661649c8ed147b386dcd171baafebf55481848936c3b8c0d1b3ce6b6696752c5fe5ad3ce876e98d6efaca4d529573f0fd671bcaf42f1d540ae4a1d6094e450ab38610a8b2ae502a4bc30ead9b5a6d02221754720ac7bdd7b2db4ddc01b2a6d1f33f469ffab25bd4e3e93396146e14b57e4f83c886060025a85f1fdc9be5ae78a5657d30fceda394edd09aeffffb82c36d77b78babef17a49350ed181c1e3c083170adc06130e1c12cf439c1d3d7fc11d56d5aec95b30175e3a28e21ef1209ab01b044b1b416c3b3ee4b659446bb899a4b8fb12bb3e2e4c460f1ab81f1c83c07beb5a618a054118264b29e911e639a91e8c5d6746d30505ae9a5293d0cd98d79ceb78ab4489f576768ef4d428b73f6cf788fd60460501d8102507a667a3064bc614d48c7ca1934b938239e11e247c336e89b4ecad909fed70490c78c5a9a22f60465777ee1a3d10da920174531747b3fa36dd1682ac7e5bd9943e539d8aa71b5704ef2d204d4030de4580f63e478dd70385a32170bfabd879d00691f434e24fff545c9ee12df2bd853dce8a991fccdd6b03fc83f79222922c5add572070c8901aea15e1add7db7b0c01344289737129e8ac5d13f8f1ef7d83c3be80cb148788fa27a1332d01388467a4cc5aad45f4332b554f07175783b2821323591cbf7f2266c60d4b13647d023b1cb361df3ca4688bc07dd589eb6d573a6d7e00703f014e10d50e45f419554c77bd06293222ffc0f2624c97809d1f3e11b49016b87789eb6b8f47b64f9103791c81b7abf1df38c56cafdd0d64dec3bef72caf526ea7c30986990578b13cc4a1b5486445b589c19bed573738618e883688e91b46220615ae1e1beef152ecad8801bf5abbd7a718d203660257ebdb94419810deb3bd36f396858a65afe8b2edd6190b663621ad28f454e6f1661b3820bfb63cffc4920e8c8cf712ac7439b9738ebc4fe03b7e9e3b73bf7f38dd8383b76e6fc2bc1ae6732b48ad90429ddd0477b4210e70078f3e8d90c39cf388d6ba32381fa19be5af97862d4b25ea9d630d8150d12dd7a297e0120b27b6b3e76829156336ec569f2a2b15056244d91290b3e85fa5402470b2d2eae0c7536443786be7d0506c5ee8b7e0c18b7da9292c7cf6b40e56ea3a4aa61c924383e1be884c0564c244f24d2157d710f03aad1ea9888a8827dded987161e159c970e5694b9df5b6545cc89051e8c38954fb1dcea58c53cb2d2b15a2da287dc4c6ef258bcfbaf4e2fabf033bcf11a00c3aa05ba40f636ea4ba18e242fa3fd3772626d854c1338cfeafa4a889c97ac55c561514de432c3c8bbba29ec02659ad5078ac46448b881056db1c8c41b65fc681de4c256cf632c3f2d0123c11048084da1a6c322feee6779014884768e28469376985e9139c9ad3db765c446ef14a506b44e5cb80fe35bffeb7e3b35f44c4ef199f78711d2d1c940279b8e599948d603ca7fd8f0b8139b1d8501e919da8fd9209004fc54dff06b6b96a0d46ebeda76b6dcecab3a99fb7360234bb04aa9737b15a409c113507afb424542424e307c49d5282f09da7c00061c132a23edcd2ca1c91e9466aa36062a14e24007d95be350e1295d80731dcb4c85cdb44af49f2e198aedda5f1091cd0909269601f379bb5dd5a5213111122a594494a19060b0c0bc40a765b5b37a51bbb58459dfe459d4e4aa54b1852ce794b7a463aad76e4caa91685a2d61ec93e04ec7f03051c2768ddebc66dfdbaf5f7fa6b7d8559b1ce0ff6325b4d873098d6e22e2db5f69d33b9a5bbfb046a39f500a69b7ead71db85cb2db7308c33cd7dd9ebcaae3455eacf9b05366572b750cee42b5dc909b5095d8933753134db098bed44e975a99683e5639f183fe2d4aa2eddba94df95b4d35afd5d5f2660e9d4a9a47609377ba53458d788d6598a7199f67a3f524a29a594d21fe36c575242addf88f47d2caff71ad1f217c1cf773946a4f1197d84e0a601dc9d08b5737ff287fb743607c99ede9b7158d6c54c92d6c510c17182d77b5859de6a4a02b6b48cae8479a5d7ba34ee83d9a0e606e7646f278c4672d65afbdbc957b0b8b1c0bebd575e69cd99b9532cd6907f658f378212bb35980db82dad7c2b2d95455229a9858e0ef6d6c2ec656badd7d6b83926b5d5bacdb0ecf7de9b61797a97cde122e1b4c95472d7d45cfa1ee1a270ace14fb347d06f24f9c798e94e7b6e7f4adfa23228ad94564a69d5346e34fa3e2424251ea595c648b69d3e93947011c303c1f8988cbed0cca6719847d674a2172ef24cfeda4e968b1875e63a61f1c53c285bd365922dc26405524da6186f675a2d694fb516ee6997bb3dfaeeed8d0e4dd154eaa3a34eeba13cf433daf7041fad7d68161f8de6d09c2e8f10a1546ba18fa90dadd14aa28dad2b280e4e9739fc9de8719db1a9cf844b784c36698946b2205446a68b2111994c9707da48745885443aec807c6ceaebc09e9fe1ae84078409a13414486887346a2a426e69696f7196667154a3255ab27af01669cec313d2e8df6d6b22ad8be94a9da9051bc285ef60ed455a0bf7a2cfc6b21198f7dd9be423aafd797be32b9ce9131ae11a4722af1b69e13a3a5dd6ba229aa7525a16d9f634cfc9c94e6482f3bb8c6d12cd51a82e5f39d47d050e4ed795642c6a0635e4d3fc46fb4f6bd1fefb7290ec3f39c8c887b23719f9d188bdb1298c86a6da23d969b29999198ed3521f67f112269814363698fe0bada5fe8b2e5f37955eb813274c1f86d6521f4697ad4e2a9582d1337962c4d05a68972bcecdcd4d8c2c626833476ba1ff547b29a68d4d977d635d76226bf374d2729091e746b417e522e4e6dea250b3c4c363042e031d1291869e5a9b3293be0cada5be0c4ed33e6f51bec299509af6f2ed5da2cb40878446eb694686c585dcd939f15aa594602a951285b8008d3e8f67c33d1ad791945097f672216f5c274a202e66666678e48dcf246b7c40361e1a8c06f7cc60343315033282f6b12ccaf9b1568eb02cbbb75acfaa5bad6ad755848fad9f7b6d4e6ca7d386b1d672658ebb2b75a50912a18bb157d42526381f5799215419fcc15f928b907bfb5b92374a78640d27b645c91ad357b69393809c4e24587bacb5708fadd1a813798f39168570e8e797f0fcf3ece985b4a85ba206b5e776b235db692b21b13720900d4228f40102c77159c4da735a0bf71c4653019137b693ace101e9626e0d90cf54ebcc67fa7ef45177a598cc997cfe769237b4ef90883426677548743aac72876bb416896e57da23d547b476ee794754d5762949ae2dd15aae104a72a840f8bece44cbc106c1c42477a52ee64aff0f489782bd823d3ffc3eb04f2f3e996ebfd5d61716484c57c28181ebc7d05aecc7d05c4a32925c84dc1d679a31e2056fedb98fda0a1c2758ea32106bccd7728784c9721da38b99d91d109923aaedba2b4db05b62774ebc9643dd5d09085dc9daac6151b3be667fd738bc04a6be6539c947cdf2efbfafffe9ebca7e5d2f81785a8b7f2d253a8419692d5e33c95b99e3484c1d20790984e43bad85440a12cb72baaf7dd5ebab55eb55a9285fa37c513af2babf7ed48d686ad1ed75a32c7a8cd35a445fe5918b747dd444d848467308731d083905e5eb69f6af39ccc2faf8310c044c6928b38de2b84117c6f8455a0bd612a7ec2a73402649dbe80643dbc11d05bc351aa8693b3867e24cf4ab7e2c48f679c3a0483fb6d2d75a2a00ba92572a69b6403023692d57d64c2347ba378a19f5d6d46b3355dc7d5699c366645173c9b60c87c8485a8bbfcdb76682ba86fab7e646716d6a89d66249329a896668185b8d05406bb1ee743bd1fb9452f78cd56034fe42b693af7026274dceb49d02c0996e14fad690b41daa09d24c155bf395d03a016fd309c62c005af583aaa2501aee54005e39209a330dc19133a5540cc8141b6ac040ea95da5b518b5e18cdb40fdd28a65316e093d95146e643c254653002164f428baa0af0210ebd017cf8367c08a65402f8107b28e0b661ca052ee9821700b7864bc33db935557e70c37811e26d85defe6d85e0b652b615bab84b748d5ca3abbb66523086b19c975f6bb057160679249f9db4a34f5155b8003ac41e0174e8fd0074f836e8946a85966ae8b02ad18837fa2600fa6686beb171d2fc8aa4c30affd3a043f0448729bbaa30f6b20e3d591343d6d09d141d5fa9344e9a8fb1f7e9d0fb07414f87297bcef84aad3a1d56187b233af4fe4130a4c3149b9202621d82ffde29e7347372f62ee3322ee3322ee3323ab4b6749a2f8be39caa194ce349c7b12cb4546ba9966aa9966aa9b2501b6a436da80db5a13699b2d09daac2d8f3fe41304c71964a5355187bde3f08569566cf9f2c35654fbe92920282ff9e87716a4b167bb2277bb2277bb2277bb23efe5a156948196f228fac99336e513bca80b1c18784992e001c4c39274571325490e026d31b2a44a0458a8a11c84c2a4194d75e7ef2e34d164e3bde60610a9be64fd2186c9af1c66ad6032ba3f54f11be3f375a2861d3ec29b1b3e9e76692e66c6355e6814d7368635626f3673fde6cc104db3ecd9f7dd1d6e24d912b36cdd7c6aeebfad4a72ec854c804fd25cddad66ab63f4669eeac2d698eb1b12b23bdf46343a4e14f33c92ed99ad2a4c41b620a35ede95fb99632e59cf4bb194d2a714c34d8f1ad5db229cdf6ff4d692c5ae32b9fd471bf7a4bf3a8b2b79ec7c5be7a181cd7d794fbf36586f95575e8a5f89ddabb35b021d2e0405c19802956c1841229d70798c64cd0bf4ad99ec2136f9091c529fd4c4bf4b376fb17c05742334018c1901dda40b9208c45b67f182ba5a692cc5409690cf58ff26989c68028f4c6c250c734129bf3f2408919255217743aa947d6986f238987d4c58cd28cd29e51b3714ccf249e19a519a5095349bb022c9e84b494e32b91a57aba2bffebf49d7e48e78a1399247ff79267e9d504e764992c51734d2f0ff0898cd8dd2b697b70b8e632b7d56e7b68c90a583c09b99d5d1fab58bcaeebbaaeeb2fcf12a0a63df58eeb458f5d5924faeb67c6e486e343ccb6b3f91003e31f86ee01858eec617c0f4c7ffed8c7f8183f758f4c7faebf1f623cf641c4d01f048ccf3e7b180f636213bb1ec021a6b3dd745ff7755ff775b70af8c657b2afdb47df302a13b5f3c8949494689aa67d3e9f098e749c6010183a94af8ee774368759f5a22038ac76d5b4df28355197eda78ed1879cdd049e8fc367ae3c85c938a9d608234b162a83daf553bbd69c5d6178caafcef7038ccf5e070ced7578ca49da47275d73ea6dc88663b71b4c4766d62853ad65f4d86796ee13d8ff637dacc7e1a30c7a2b877e6a2da1df704afea5da24ded7df8698d4df6ee20df3fb91dfa88837be1739a9be68dbf172c9cf6cf78b929f6ff2d8d55a4cb4c4252525da7b9109d64c7bec35cdb58820493ea2da25da7534ec312fc9ae63a2bd48043513ed3fed5d0ab186f6582dc941b227f132ed314d7bedc36d673472ada5fb4fce66625a9e47d6e8af11f7a38c7f6a2d58fbea4772b8f960d717613a211c0e5161efd9c459ce266992e44f2cc7d511e96c3a578bcb539974ae26f00b70f618a6d3036acfeb87f09c7de96da75299b93da7093ce7942ec0fe55a5433fc413ac6f32c1905e9dde043675883bbe4bdc517ff377c88f3f755606fce5901f5f6a8a6d40c809c47407c229a540d05a6b05a25a6bad05c2de7befbd405c16fad896e900877edaa9d4a4d9d9b1b191255992130351b1d0c7acf93e7510aa7d6a17dfbe1c1b66472d07d7d1878499b36a62de77afea6319f6d607717da67b647fbda57b40a1a3c7f541d8dfec5ff67b5c7f3fede64fcb78643cacc7ee63afe33ef69aa6b1b75113451a9407143aaec7340f28c220a5c7b40f1f2e9de2a44f7b18162b7f9a364287f55be55d0f4464c97ed33c78440cc3b27df85ba631a6f134000e3274014796ebad0f23cadb302c568661d11ecbd8d77c84dcc1772d597f691e3c84884e320288c86244114044162c9425eb23cbdc7546cacc9cb09950cab4bc96ab3e421631b7f65996379a113ab2c7340f1ed8633a26d3f2cab2d7728d2c56962c51ab7a24d2a0b7caf525919ced7ac69ded51e050a26ea68a5481145eb0e7cb22f2c6cc719a793355620db5d611309c0e94b66782a5ac3802c39c0938c65ff941b2d44a975c9b1d2f394b966559d6bc35be722d9f285f9173bed42eb3dd6a0a64ead0758254ed29cfc9c9c9c9c2b4c45ce95245782ecab9489580e85cd42572b3d8f1ab84bc112f4aa7086186adb5357bcf045d27de3043324028dd3031b794723aaa72d2c466be91863fd5a134fa80e7449f982b23333fd0c2e4393466b443dfa1a690cac8f8600c4276489da0727ace5409efcec2b1d837de50439580c59315ccf81176fcd089802905b08183631902ecb884ac213fb4217b1f8a4ea0154470668251ca483f9f0742b2f8fb0aa28ac320ce4c15a7d136b217c9b2df441a2997dbd810d9439690375c0ab1c669aaf81122e8544470be53c147b0f18a0d415ee335a06f3d9328bca65d33552e07bc0651e50289e0bca648635201876e93815875e841709b0f7fcbf92ad703119c77ca087a20aab84dbcc610553c081194f1862baa9e02a6da717449ca6bf160ee52ca2794b63f36e59c74664446464f2aff64a6844026043559067e3270aa488b4a2a3719e7463f740c918653f95281162226e85fa780e38e37442c284f35e59cf4056a5209ba8d0d529e1d1c28cf05acbfbac77deb2fdd038a8f7e64c9be87f595fe288bbf494a1eafaa8ca7f06aa294f2b8fcab2d1eb0a28f55bc65b765f5b6a43b9b665bd21cdaf29bf345db5e5b66fb588cd787f6441afed40c91863fcdda9633df2258eee943bc818ee187b842c920494a6c7f5407a450358005cf0278301e1d26e8d4694fa5a951cc15aec668b1fda37be9b4dd85d84a89c0b9c05409e3152fb1479e4c956995e81cb5402681c51339043c278fef4c9067aad03dbd8b997918a46751abf5e77c07c39c47c0f2bd67aa542d7fe66c82f5299d609d9186fc2a230dc9c385cee7c82be0fabe3341c933dfb998736ae799a07cdf097d47b26ce93aa9f95b0c5c80677867b049665b4a75741206c372ff36816deecc5489992a31bc7a3656daf3efcc7dc28960d5dfaa2febdf1c823657c8fc9bef7d82deec33d6c78491b402893720807e3e541fb70ebcab5c39693e66bf4eed5681efdbb7402c10ecf69d07ab83d0a8cd4ade884562f68c32de107d6681654790989cee94d25a6bb5d65a7befbdf7e6a468766c782aade5d2204e1027d27099a37bee9e49cd9eaf838e93a912ad18c3cc9e73876f634f3a23846dc518b4982e633555a668cf292b93ef00cb28ec504a292930e5101c1f47745211f20cb1dad6ae228d193fac2e0d64d41608de1184bef40f42a50c82c5931d1b76b4e20a526cca81b852c938c99fbe5753d8d8cca0c6053429983929a16f4ea4e15fc9d41a3540f0dff3a2ff10592a6b9a010eb11c1947390a7314e628cc5198a3b0944ac657aaf7ca51590d0e2b2cb6ff749c78c397439e61571d1621cfb01d67f6200487d4f4ed40a98e7b6a39589b9a228d59eb9f6187df0e7507c5317754ed3891868cdb7ac11f870a933dd0b799101c7238db7169fb35031c7e724a42b08c8c8c8c8c8ccc27c757b6aac2d8f3fe4130c53f4cd99bcc86136fb8db3fabc1fe285cf295fa1e594a21769c2260299a5505583cb166c0317a599c73ce3971d683ab6963aab8c9a3a4b89c359bd615ebc3cad2d14954536a69b5b129e7ac543061ea50549c760230ab3c0151ae06702872db05f692af542193445f24b3e947cff607a4cc05b036c66281c27e186fbe6af357b15a8b706f5710c86cfb150435db628f39462b566bfeaeeb6dfeae17edecb15bb1cae6ecb12cd36acd3136c6c93839faa9996463139bd7a70879865d31f984d622672648bf5201cb2d4f575eb7d2406b80ad3555ae341dc0f5691ca284cd9652626614e2b069bcd9347a008795da884336fd6a83572a1c36fdb09a3b54ce5039437580654966409664695e1f600708116fa82e8834e8d387405ca92f9024fa94648795c6b33aac3ad8f443d0ae3abcb65569ae0f70032648dfaaacc0d54ebc41521d13a45f69aa10fa35a716992b2335358aa9128140022736fd483fac4336ad35389b56d4a6358b6ab369cd3a8c60c80c119a9c9aa912c62c367dfa52c8a6328a4de5eb688003a68a4b94a9e26fd5786705164fc2cf52f7a905f191d9f728308909b9ea0ba5a81d76251b6fb4a21771e215d7d6a010e1e210936d51f246094fac31dff330f69345b37a496959524a10602076c8354d154b8fbaff6caafb921c12b14b70e8312beff87e6eefadece59843981c3e3d7a91a743214a7ed403c9ff04431fb51c278f635aa1500893e81756f72f4459ee921727df9d9c7496c6848c46fff841f8ad188fb3dc3fb1a5c3196ff26f3d25bda543f0fbd17fdfe528798be4ad4ff4de7fdfe510ef2ef491e81c22ed7d6f7de77d490e45ffe2435163c0f79ecec280bfef9e866cfd974b4a7ef45f0e89e8c1d25fe8adf7befb51fe42717e219d234ed07b91f67448c4b6fe7b1cfee550f4357825d6d3f09edeb17d48eff81fbdd03d7a2b879f7ea17bd3ddff8ba7da0e273fd233f48b6feb61fc4887244d41fde21bf4307e6a3c801eeb506e1006caa18f8dbbcec2a3b73e0cc20f03e34e8f3e1dc2c0560cac633c0c8c263fce31de24c388a143b9f1cfb7dec20fe3319cb11a8c06bf8990c731f3c97b8fc9efad9c7f9445a20c834ed0973c06caddf65d0ee5ee40b97b921c7ef7dab244dfe5b97f82394059565689f5255f95943c0c9dffc57f7a477e2f6bef71b86894e397b3f551b3bcb7729843227647d275d51e753f1a753924f91a5ef47d7a87f5de4f6d8793f7deb32ccb0bbdffbe1fe590883d7a51cef17df7560ee5873e8e7248f200f890d7bd7812fd42b7f7c2933be7b8bd9c1f87e77cf226996e00bcf81a5e3c4683d5d0f016a6414b4c436759d6c9c98b6c53276f53be724ff42d59ef722d5c6f69aa7c3fffc67cdf675356470a38ac3355c854093f20f589a9d2fdfc4a335564bc21ee50595d36f13c4cc86ca11d4643272865cd54b9aeeaebb02b633555097c5ddda8fbfadfc8eaaeaaa356a74339a965596fed4b7baa04d6de9f7b7f0e834094d64a29ad55efa01fdaeccd55862348ff934511a45e24d1709bb928e680849c4762c349a914125a4de67cdbddcb1ac9b40c8a7dbef28fbe58d317bb7210ade71ec9426439f46bb5fb661ac1fb57ae2278ef77f908f0de2badab5a5be55b79d96b6facd5a8cb1c652a694666e4ccbdd75bcd658eb2ef3893a58c8c0e932613e7817cb395a301428e86b3f66a15ecf955a5d1b7ac203917d03b44ec5897d6f2d7cd464146dee620d55bdd6f279737ea8cac31df8e641c1c9025b6bcc17120d698ff04a7390f441af3e24c588c5365b371876e009b74a5bc3921ef76baee35749bd94efee176da9cf09aede40407648251c0d5e6c4363355ac3544dcd994c61d2985b491f6331919c9ee56c58035d2c55c7faf68f2e2e24c5da976a5ca1fb0e9bb7559bababf8051ef88656d5aedbb6b0e207dab01c1b92092e87f398824fa165baab9d4ca099920fd4f8ae9c24531c12113a46f391afdd9441ad5eb3ee466b5e17dfb5d163d66339733b9cacbe6ae34973355accee16a2e8b9caab29e8bdb136523e8d66d2814919c4d3f8b4dad47f961692d96e7926feeee8f43d0e3f76d7bb136c987ace9699bf669a311ab2920afbe5358b3f459fa4e512abd58f3c57ab15eacedd346239af5d96aa9964c414bd614f8eaf0c5b2daf2bcedbd5abfda8bdfd6adc2ec5a6b685fecf6acec79564b690a5aba53e0f002a5176b7b1fbe589697b75269ce176bdb227cdb362ed503bc7d97e2b68f5a0e9ddca04c4bbb4bf9ca97ea525faa4b7da9d497e2525c115cdad65aabc317ebf20047d495027fa9afc8b76352328931319900d1d9f44b7d3c9bdaea895e763a5d910db5a5b61dcccb718fe4f0007be4a9cc541969eaeeae35229187dd1ec7fcaaaa3cefadf75eebc5f8be7bdad337db27f1907a66d89bed7b79dbacfd4c6bb155e6b4e750e8bd27f584423fa3a4692d214f3af6b64b5d2782653bc0e1869a2a5567aad86b896c594c9522dcdbec3da6b57045ccbda1220dcec672529c6e13d84ac075b6eb1ddc90e9d2fa63f9b3714c3681af0e70b8a1c22fb5a14ab21d7aa94de56c077b916dbffbccdd4c951cb8219abb9920ad6f79a2f0bbd9f48da07b434d15dff4399ba9829f869c149b8e1e7fc80dd9f43def2dadc5ab2af76cef8f1ec7f45c7dcd96bb6b7c7576f8e277f4f82dc98b72dc556bc1ef917c3fb59612ffbc953f8f89b2b5bfd917d5fa21fb22fba22c77a733554678d8de86be720ffaaa43ed5d77298d07d15bdde9eca895f7568743b88e749167d8f6abfaf815c031a0eaea3ffb3577ddfb7b9e55bde7cffafc593a87fbf5bdbffe35bc6f52b9f7eff47f5ff50eee2dbd23f4f587708d9f6a3b8c3ea4e3887ef1bd3d48534dbff816f120e26113e55b6df5d5567f5f8bacff8bd7b96da73355444fad157da7d3a54680451f76a9aec804e98b3e23ef6dfe7c97431ea7cf6325b7d225b2def855e6bec4e5eacfe3afdad33b3e6f7dba68adb7ae83ba390b03bef86b0ebb37f9caf3acd15b56adf543e7bee6b0d32fbe8738c0b6fe85972deb290073866dffeac8fab1ffe22beb02353bc46ff5103e84eb6cee7108e365b93f396e1c6ee5d17ba6fb450e5f70367e931cf2386dfc1dfd4e47d35a3e2d7149b52b1de4fa4a0b627a964b1f21738cec1149c6a61ce0d187d43473a0a3af20d16f95af5c5fdf065f8f71349c10ae868b62aa748f7f43fdb6e56096974398ed79f6de7b99c08eed578fc32bebabd759f8c36c43e58dc896633d8ed97d36f429b77d3ea20f4910b683f1c4484fa32c37956282f4b9219b7e2807b91ef4a5c22d8b4d7ffb788e93e85715c69ef727706b4f9f02d1b0d7348ab3b5bf5a8ba625de66f6c4b099d94f2581e7572fc0d7631f761ccd5409e969d3a79fed52fb078ba54b6da82eb5696943f94af6f45a2c99de5017093cdf894dbf14767dc85d364e506f7a233241ea39a84d8da0d597b23af6e967e9fc521893436935050eb3180e633d881b60f124bcf76db0ff9482521a7a11cf022be239f425bd3733584cc1d906d1c7b6696badf6d66aaf7ae9d7bfb0b5edf558f862d52cab9fbd4c13d5a1d476b836d59acba7fa28517e98e2f5973b0f0c0ff9f7863db6fc1ba22cb17760ef63cb1cfaa64f297d0b05c8b51eeb01a3fc9037eedbb977588fbd9453da97fa5ad65b6bf577a90ea5944f5f3e4a49bed5f5aaffb93417d04bbd433ef696d64316ca4deb5f5f3517fa3bac0ee5adf5025d9ad6926196655996855d5abe95516270de5ecbda7ff2bd6fff23354a6982779b917ea55facbdc33e66a3b603a6f587bdf6f7edc6c59efff7356bd30f5fac8c6aa14baa658f52fa682d1966ad7dbbb12c77cc6595507e7c45b7945fc97951d7b259565d843c43484bf7094c3f741e2bb36b32741e9f256e47a44496954a3636343418e39943bc28f0c00c576f6316a04aa93c30c326bfc58c0070b5eebdf4deebfebd7edbeeddee7531c8862e06dd7baf65f187f08370acc2eb432f73484b282510e8abf0c5daf841176b941fb2c67daab9e0b78fa194507e602ab34428d3537dfa76bb165305ef3817f8f1831ec3b4165005aa58d8f23f5dd8f2b5c766c45c0a5b7ee6dbb110b1808574d7a1326e99b3d0b1d8170a1014d346f9216bcc4791f2de47315dade5da1c690b308aa9a233585e53f0980d641141596a3d58a16bcbb182ac19ca2188e378aac8c77fe5d073b6264332f415e82b5ff93c0804fa1008a4495d80de3e262dad45ca0c947d67825c384ff5b43c3fcb98fe95c3193120ce8c12a98b2a9392ee19256a7395b100cf284d704a1a35f925cc6d0d74d4a7495c9d44a5527399d5d45c1cbbe642b1c0826a2e75fb635b8cf2abe662b73f66abfd788ee7441a97092c9fc2cce922f09b6aa5cc9ca2e68ca94a67c7c69740134d55836dbc9bc7015133a7c225cff432e069ce489b1b1c544e4aa7c2de0c48935293c2b3c1f7705579f83df053401b9ec900cbca4fa18d9b9a71c74e1af94e53776ca84c511b59aa2797a58863276ab2c89c79e8a66d5debf32943753d8043e7b941882a36c48b79a42cc015fb7e7873a48deae907513dd53da0e831bfd241d01efef4cef84a8fea69e524794fb8d25f10f4e3cb2a9fd2443157748ac6ec6c293fa44b6c19d2d2694b130a764a0341906fab7c1ce6cbbf39537f41cc1ef1a3d600d737475f54c96124ad4d603fc071ff9669744e2d3780452cda8ea30aad2fda3866103740e4cc09bc665e043a49720438c4b84a17028ef4e39cd23ffe22b5e7df2038cb3ece6c8f804c283f504a283128a65a2bca8f1e94124a8c7b7d1008a584f203b3d97b7ae9506eef7aee5162e48db83914d354e1fe7a47b14129a1fce871941f3d2825941ffef706efa04e35ca0f4a514ceeee54a3fca099bbfbf5abb1bb7b13d875f8625d1e60518f261132c1495233c149421369ccefe9e9e9e9e9e9e909512d263825ddd121f9d8f344f52a724c52714fcf0e4988d8cb032cf272dc5cbe7e2493e450ca4451654255268abac469e6099a1a1b2986e05c3155ae8f8f5242f911514cdbca598629a6334d92d2e4a4884d1e385c6a397c7b4fdf5ae916fd5a2b09890e87a096a615c69fc4537f460987d7ac431877cc5e2fcad747b9473e5e2f7a528fbc11b7684669aa88fefa5ab3318c465fe93e0471464fea42dea0750445313af2770778877fd5464e53e5d2334afbfa39f2237abe344d95919fa42e5c6b19018de48c8cf8fdee3681c311948350391809cdac96468484266b1f6aa8119aed43122271037d5e9aa44c1338a4a14698c023a809d65abde21114c8aafcab65b596533df42108b549424f693f829a2ab5823ed4687ce5fee4b607a1a64a4862bfb2f63d5b5acbd188cc6d7b30fe50436de99f203788c972a5c95726cb7c1c4ef33592e316e5eb39102aac4e50102a9423a8eac454a94f7b4ad43faca60a04fbb09e669ed8937e5885d49a3d6b147bd28f52ec999178485d4cade5d212cf286d2b479ab3cf2a8d65114cdf2fcd030aeb795c5de9b85f7da579441816fa6e5b322a787f42051c824210e1830e1fc25864dad06182536582f3456ac2683e264cad284fc0e289c43e92b28f7a466982d4b78834b08c836133be82ffbaaeeb31ed310cc38ab8dbca1e8bd921f6894eb27408a2b6351f6710676b8f5dda7a7febadac3d46e29920f69a26f5c81a8ed5646cc649fe1f7fcc5f873c76f658d6da63590eaba700ccceacc7485dc81ad8b63a38f42db6e3b87f8555bfc5b5ef179665d94fecaffb588efbba6fe590d4b3efe3f08a3e7683cdabe3a7d4a4d9b191251c347bfe090d9f4f4a0ddd86ca4bdc1a4f0201906b8040a11a2734d4c0719b0068c8b8ae0a2500da5269ba5fc800200363eb8486eb02533a358cb8992ce3666c43d9645927c3da36eb6880d637df6d73016ce89c80120dc7cdb6868c041135fc47c38c195f258100c832302c9371a26ba0e13a4146fef9794d86e666b8991754034086754283dfd4a03b9a9b6fbcd96ba04146559d5c2fc8b879de2caf0c195a7734375f1b3f068c17265f0989d78d46445c08843b9a14ef02a98c3e6cae06c82245847761013af89003d2428e034ce1911de0e1f9682d77c7dabb45aaf3a608638f4466d5e542bc5bd094e0eeae2b1bbf58f0a1013a6c3405071bb28a38c1ca6a2d47b56dbd5a5c2c5c2cdcbf29fc229168649a78dec8c8c8488ab0bbbb53d702767ab310aae2425539f20953665e131670fcf09a2ed4448257efae7df6ee2fa7bc711fd32ade1ec7cce2a653056f91e5a3d5ab59f70955bdb7de20d767d7ad8fd5bfea5bb5d6fa93feaca68f7aedcf39ab6a9120a594d6d6eaf2a6446f1cdb4a2bb5c2a411a4940758a505b0385526f55923e818d8d32b7d29e5102b9ad45aeb5e17bb2f755b8a45ef980e3d7de9d47eaf7deb3797a425ffbbfdef013677f7128eb304f2ab2d638d55f68876524aa9b52c4b0d40adad94b26894d25a29a5d6565b997087cc2d3570a5d6039dc105c296d208f707ee33d260a1233bb6bfb4753ab5f7de07fcb6d5d6a71c90a5fa3eafcf1cd466eaeed51e3137d578f04db7b4028b2918f32ab2d02cb7bffb5b7fab3331607fabb3ea07583ee1d6a4f0cafd584956aeb69655b5d4a1eb00992927cd1415486275a7805dc748a3092e537371918ef1a4d43dcf0588c8e212b7bc3a5232a12aed8b62aa282594988a62b2504c3a0b032ddddf79b1ae2b5afb5a283f507ed02db01ce419b222587ea495635a3dbbdff971fb943870afb665bdf8ce417e11ce8319f7bdd7aaaa9f4fccfa9e9d7ecd2831745a4a514c28a68d6283520ab20999e0acd96838d4a7aa300e3dece23e8f63665996653ca85ad3a1f6fc7c55615c1272a87c7992c017088b658bc121f7e186da134371a8fa21c6a190c01ceaf33826cef8b5bf3c53e5f313ebc8e5fcb67de41b4151a1e7589cf79c641eef50dbb438c0e68c92ac3ee610cfac923f493ca49e59cda94bb219a5184afd32c319a5a865d587d87bf59f0ca276953d28472755dbce109e83b1cec9d1f5676fe50bc77316068c69fb7ee96b7df8a2bfb21adb55fb9018b532d87c6c6697b86515b28a5b45a9646353050d4d15b70ab977766c6ca49432d0711d51fd58d85b334a1bdb2a336d876b5b8d692e551733a6d652b3f52213bcde3e96ab4f112772b30cfb2cbb119465f70514ca1ebbcf899e6a910e27c6611916520dc3c387b53380ece0dec7a679eeabfe6527f7f5a2f452fa180d29a677dce79efe45f5b5c37dee7a9b2bc53e211e385d69f6f62f1e72d4a73dd4a7187d8c86334a58731171bf693d64f2f3a17f85227bd9ff682ef577603a945ab59fd7f255e98bac5befbd7f33aefa2b57ed41f97a6c7b99f193783ed97eaefde81df5b3af1ad37a47cd24fdac047ba9f19061391ce27a1abed09dfde7d25918f0109eb3b10f87a0970e5ff4d55cb0df91e950daec35ccfe653d89a7ca9e33c168adb572d707717c45fe8c5f9fc443336ac2643efa81d139ab09b03ffd9998924481283670b8d7bae55635e7c42193807558808dac01bae29857519137e6bb0d1b3838c24c07f91ea53725d801fd02164faaf5d8b351bd04a5c949f2e583be720127c9c7accfb2a44902b1192297a89ed8524a292c5b338983d42e90855565c261dc3989e07c22fc23381d40c4fc7f11623b1153c5f34c44bc4c15d732021394afc3b46163a29e608518aef09d94d4366b4504585f83e100b34124c00ca2011cabd9c0e44adbdf1a79eead19d4868268833f9737134402f85b7963221a40db526fa71f78da4c15973908f75636552c9cc66a6880c3ed3467b627ead73abf4afbb5c68f139482891a2b5a10c50b6f3af5cf9763d7af343082d4253241e731636db56b1ec25358141374cc06ab99e096040e2f2adb4e3a88f5285fb1b4ef38c943dfc1245623b7212e4f1583e90e910a9b7e0ef5ba504ef22f87fcfa55c3e8486dba534a6badd55a6bedbdf7de4cfb30ee7c3eb4b1b7c71fea00fa104606fbd087d6522181431ffa98d9f2b1eae6681fa7797de8e3048464b1341facff20d607e17cc8b0d49bda8eb24cdb7f0b2f2ab478ae9ab03a5d1589d12baf58581493e4d5be3bbe52b1f83bcfd5588d0670b89d68e4445161875bcd76f2925328156fa8ef5f6580c96cb29d362770362273458a60677b62aa442a9ed8d98e6d516cdf66b66f36db9bb0c3ed66fb0c154968b1c3ed8aed5b952651b81313f4a755e06d66ab5560e932960f09632d490d164fc20ab57dfcf85806eedbbcacd3b53ce9106b79f2aac29805b39747c42220225d4b589e4a748448491a59236d6e3a89023df6e5fb25d93e49b6decbd57719fb91f61c8ec9e5c88209e19185459e9c44b196a590be400670f82dc0741b412513f21469d017e1975a11a137c286af403162fdfd18fd8934fdf71528f0d3077dc53e7d1f7ce5f3fa0b3d77a3bf90fe7eb8f7e78738cda37afb3cacbf0f9302fa2dfb7ff23c6dfa3205a7a93237cdc1a67206d2059bcad396288ed33ca0087d48ebb00fd23ce65b9c7dd81e93dae783cfd71157392369648db4b9c141e5c813f8f2f4a8e9434a1f17ccac3224307fccf34f104c493939913f785561ec32453b94d4c464ba780e32d2902f238df85473a13ec42491844b6dc9ca80a7cbd45cb60a05d8c444cbca80e76772c2ece952c5cafaccaf5a98b4da82892d4030e774df4208582677bc60adbd970b55f86c21647b78472bb6d0c167472b765410862642990c430b70b66ddb86714877186a463b5a0186223b31a35017ba2d90d8de68341a75dd165c6c910546c2859c1c7c99cc3b4c9894ec684518705e806a6090501163a7099fc9bca3155d48627b139439927c3418541dd04c1521532536e0754cc1072ab07f8efbf2cad2b52f9f102266823a7e8829b965e5838e0678feebae83549584d9f9cba1c305b8cb5fc0046735419409ce6c0ab5e4a44c0a38ac2a1de2b0e354a9169477ca29f5a5b5a68e018b27a1bc1f65fcab7b581f7b441b386cd8f8195ff958e64b1af9f175c88f4f3f6a1e5050ad23bed53cac8ffae3115f6a1816fb5706efbffd3e7f1d72e78f7e0f28aaef21df7e0f28aad6713f7e0ffb51fdb9fe41be7d1d4eaab48ef8f77b5cedc3df1a8431e5373894a558051be4c4e00725380214502cbf3ffad12913bf7ec4d5cb927c3ba79499519ef694a5295dc7c88f93563ec05ca2ccb418a564410e155c28426681cedc910a2e5cb1bd096a2e25bb08581400fe64d28b1861c57729c41bf78f702aecc8434bb1647377b93f9f1c37f5ca573ca5d95d6526ab5ad5fb75c7499447e7a2745bd975a20df4b59cf996d95345f8286539eeb9af1336fd186b848ec55b99d4412eedd8ad5fa3bbe64f3349afa5d9df521cee14c50a155c314f68ce2826b74e5112e03abb3e7abbd6a7d4a9dcd5ad57690a156958ee45dc7d431f774689d49367949e7eacb90e2a438cd4a65f75e0d95a93538161b6fd904be5a8a157bd7adf8b9920e58a5833e0d08bd9f4bd18777777f7ce7234969af697e2384e67aac86daa35c8f551bbb67dbaad86d998cd5f0efb264f98e4e0dbdfe48909d23789992035030e4d6236cd719bc454db5a6bf5c7d13889c6f0dbf9b8084d4aa66b7d68b2c4a6a1c9c9c4894dadd0e4894dadc0f4b3a9c2592f656ac78a2628b7229b5a6ce5b841cfe9d02f09418fa5677cefb52cafdcadb51687578c5242f971bbaeeb1ea5ebb2f4500e654f85f223432945af6e2c14d3bbf536622194431199a0add6eeb0da752545cb7733412ac324b81a27d1ff6e9c44df8573410403ac96a8440d1676450b199a1108000000e314000028140c888442a1583490346dd60114800f8fa24e6a509d875114a49442c82043888000000088008ca64900cace158f9140a4f6abd936dbb61ac399a6d3ddac34ea62cedd907a9e96648f15ee832be3af016957e7d273b5adfa71e8c8f48ba1a73ca5c290ba4d615486f2900b2a105fd07232b05e1b73383749620a5292d63ee59a54a87d86aa8373ec841f0e1052a721d2ebad0c688d1fb6503eecefa0bf61d9e4f96e903a08e4088254413f5f0bccc89fcba8dcb89d5c53d59d69406e9886ccb6eec987fa3ad58b85655f91fe479d402304a99ad7f9a36628c0e415976971b1e8cf9779eceb4dded96ab44c43346f8c462ea21563e85c8d72bfe55aa2ce0371f46c7bd48f39ff473dea1cf471454ea6d47f695712f455e0565a3e71a09cdb6daea7793b2ab0b3b02d156d238d4729ada3c69226d0c93ca18c0ccec1d19dee0395a3ee16000b6fa0878f3eda40826deed083e664a4843a9696b188a3a350cced94c351ff8eea4bde539c0786a32224faee18c33200b58dc05147f89d87c3233309f320b037aa65cfe398a0df0c017ba39a8eb443ab37ea9c43dfa1bebcb10b74dae8255bff1b95e2bd2d2a2d8954e78a046dfeae3b5950725e62eb46b57f2c2a83104947b3e6e8e66cac1b55a57d8d7adce929bd966a697052296cd408224e8284be41d09f511dc51955d89a51e57c67823d54bc8c9a1df1ce8ae4db37e93133aac291b48c7a42d5a2d4cab2d954f1c38d2c0bacf228b83d197582d137a03d3a905187e57e491aa37e60e038766c7160576b7d45da0a278305bf160ea32e326984514fadf60b07461d041afa67fda2a2cfa06d398b24d72cc26f8ec1723a4662aafd15fbdc47a8128b7a105da152a57bdc58656295aea8dbb2c4c2dc9aea5d495f2a16d9f43104b08715f57621dfe11355dd2edbe7d1bd41a02126e8def7d2edddbc81d11c8fde0bd89fa29e4f71da53cea1cf147518ab74532a9d6e4411fba4a80b51775c7c3b0d8e159ea85c7edca0e805060027d20075459f5c7a4a59ea63fe3712d5889501f1735ebf7f4147d4010e3a121a512fd8b9b3b0bb4f1c6d1244120bbe6593a93c216ce1e070844dd02a4c9c784922a2fead596415a643d434e6ed49fd8e88aa2d8ad4d1216ab67c45b535fbb681431711875e362127fb871aad90b3160ddc4897653c0992e12e5fda3bc5d6459d8f8bed651d4f2843f250f3212344382dba286ce8b042ff67298838d10ce22c74d08d0a7f8979dedd3077e77dcb12e0c8beaba1fcde5b2e0b1697f3a0fa5d0d18fc178fcfbad1ef23876abcfba3347fac91137c9c943484c1df33cbfe8349d870a89fa79ea95b3c7c727ff286da1132d2bd8d50563bb2393a67da69438f2a687accedd9a1c0f65640be68652a36a858bb53ad4955b68ad8ed3ac9dd1968373de605a553acd7a7244b841933c40a343cfb58d4b052b83268569f608e88870d4514565626a9fb03591d7e8731a8c636cbe21d76e39137acd12ba579fc0d8b458efa4f12657ae6a6aa8fcb928577d8e794aac24de04a7735aec19953d8510ab3aac6638d83c655d7fbfd0cf5e8b182104b9bffcf72e89db5f70bcaf283642c6a8933824de1775bf52d7a51a7a924bcc38eb3994703cd6eac0c1b93420f637987d927f6a991254246153d1e2c42750774b098679e76ce61f6c22046b6b5233b0f928d125b03f0187cc8699c27b1a1fc8177270986e0edf297f9d4775edc9a48bd6ce323833c8a42bb527c4b78f5a2c3ecf06a55b628688c7f585cc6c3516150cefd45497cf10ba36e4087224d71b8b9910e35d2ee8904ddc3ce86008bdac39a55cdb67fd5dbf530eeeee8a57b1148afb9a77027d75d416415d4828b74bc15d9aee8a5a36377c9b2c50492486210d10b48f56a06949712fcae5c29af803a152764bc53af394249082b51ea958337e5962e9bf9ba1377dd01e42fd6d9ad9e12af8e6aa91997d6c48dfaa227b55233476c0f01a929b919927ee0788b037ab7ea892491d11a41cd7aa687977d8ba055d72bc8594b93bf457064f5e529e344585fc909d774361b159c882ac3fdb95931178d17a81fb4090e979b42418598e76e2ab798b5d2814baab15cbb42624d8d4ec74a932c46a49c72d478426ae91046b0cda5049d138a454690f933d1f1a152e7b6d169a7112f1561c51144674e4aae439dbcc6e8a3c1438c2f631432eb441d7de7321fba481ae3ebe188414d3043ccb5e15c9e4de2651683e6c82c6b60cfb6f045b59e30d553c44523f5b7295d30c58c88880b7311977b845e8a6b0198c915212ea52d9b52579846f874ea60f93c8cd47d6e8e935741537addec94cc9b8923f28fb75d6b0ea9763553fa2803cce1728b4f94e13b1372c8cc71372999523b7c94fa5645449600d4e70188d9a4749adf811ea5adae47fcd2c86353ae2ac1943e964ec9c20e2c79f3dfc22edc6c29f966e8b7f0521a77c03710e0034b7a01f401f07af2609d40b2d0208f886f8a875c835e95f4c1228c8deba20e231d80131547408addaf89a183b59f082410bd871baecdcc9f583a1c6babcbce34f27c83b534069004aa0b43a41e7265dd84a15f7ef533d74cc28a62c27ae03e253a34736bb00e1e63119432166b99b184eb074deba236c66acc42dc43f898e34441e77926b6c7a253d40919389c31be76bd2318014649e183f50be32c93e68f45655886e56d21fe8808a3cb112848570ae1ec17525823ba836a491031b688311edab28753bd15b8aeabae8ba0a9cf3dd85a18adad817e9c7dc99c2be88db40fa5548b788fdd68b09783582e5609b87d28ffac89303789ba0530d85db2dda2077a1da3881067cbe81ed981a80429a034a235f1fa8f4e5f68f473afcbbad4e17ae6f60cf961611c4efc876999e34aaa34c95ab10960a9f2b67bd9fb1d55e92c7dd3fc0c084a7da32b2c51b30f65839e2afbe8cf02ecbef0a386d25a8b52e751b83a5f69fc72bd6e94d497da73274eb0c91bfc8e0a3dc4a5e51828c56ee01fa0901a0c95f68ffb11512bb06bc2f74ac71bda102104631559ffc05a66884839df1f6592e24778d9fe355d894b0674203ae483594b19d119075a4eb6faca561de003d9d51977c0816d720f43f3cd56ec7b1d9c64cc9b67e8af5f53a974f40fa9486308a02428aa072c7fa552401a2bff66add0565bbf2df2893f9e6f7e8d7af7cea05747b737433cbca1884a23dead30d0f8662fdf1961155d7981e9dce6a46f315a7ed2e7bba32a6fb235e50b8849e57777cfb58c697e05ed1b46c4abb87e0b3639a3175580252fc06e6350bf95f534bf2f1d755f1c2236b3317ba1abaea214bddaea9ff8cd81ec8e0f9acca2b0d2652d366e8eb8793699cccbc132c84ca8ea3ebfd0a61bc872d7a9f7e1e6fe9d160ae348165e83854d159bc465c95d3b60b458d7e03f18520501b2c28efc31a1f256ce4b2f3960037d1a17a96581ac391ab3ea82049abeb856d054e182d1f9481072782d834c12c00fc75c36635da645d7720fc4f1aeba0892335e675d1248f25297b5dbdab84be6e9b2de5b5b395572b9b1bb1cd2d613d03f2b885cc8fab27dc6677b3c1e57d70d300a867415c61f9785c6552c5489d6c845b68b0c6ae78137e8bf500d0bd7bc41187ae9577d6e472f58f28d202e08dfad678451e75b706280a1de8d3d5ec69675eaa37e15bc67465b1fb93d87c40d90a9573979164c57dcbabb5adb146c9efc49514f175ee48036411d883af5f2c13bd9917bd51edc55602482d74fb5499506d0b8812accd632b1402bc3f2f7561aab9d0ee8af4a1ef9e3e54d4ab184bb0acddf547b6424f0b9a9b4fd729843169017f406ddf5ae0c68f09e62b65feaa738da601a8bf2890a490b610b687ead94de8d2c4df620f7464b10b8fef9a38ebcab9efea3857863fb68c349b3c1344edecfed4342237289708b27da7d80db5e316137d19500b9287eed89cc033f3ed81b8030ca7faa8be49b94c0a8ba8d50893851b866d14a3a8474ed8c77203d3e4ace95d6b9153a2f7b29c31560ef8f4eb34f3817859fdd3e2bc3eaa4d13a1140436a1f3533227d8cf686eed95e090e6921ef6ca98fffad0638a3e44bb158c08234aa73d4140f074a24feb91bb628b690eee80e59bc1ffef4977c9fef3eb7772e5c5ac3feed190cd5ba9f14f5e086f9c7b2124f5b1cf43d228e748327009adefa156d3e63fd94ad5f2fed046dd93c01fea9bf4a666aca3fadc8756f1cb61940d89eae2457f0578bd275c0cafa951ecea7bf3afdf01e61e245d1001e11eb7d386e2eac33a2cab17520e2932d38ae653f66e1f3548e220fb49aaa6faf18d61e7753cffbfeb213884b61668ca87129abd5d89cea8d1d36bac030ee36eacb157ed1a85cb40df2aad72c1335f4c164aff56dbd5c8081c5da08d976ffcaf5bce07aae073b223129d9933f4c147b697f5dee5a1adc4ecf5372dd747a8269b6b1e7a7bfeddac18ea1bed4b3194db50c24ec5d7bad4c0f5d65f250894f8f1c8573610d6e89bb868d6841280d11fd17ccda3fc6d890ade6777c8fad7d08ae3dd87fdaaeb5b5379d72afe7fcd1ac3da05bfb2d053ca29b76aaf686abc2e6603edf74a77d8d887de85f7dd3b4dfd316a3bd727e5d5521ed9b22caf347c08e668fbbb1ede67f6f03cfbfd4049a57d0a84e37feb392f3f1eced80d77f5f6ff84729b5f686e90668a409e0dea57d0b0148822936100d511ed1d1140e3140f9a4afbb3a3480046136cf1444d72fcdb5eb7126074485a3ef3db3f9dc895c2c777e175605de917f1ebbab0bfd0e53c923cd7f68584dcc21f1732f0d4f2ec14e062cf33305636c7b8c6585419b89a6640491ce87e2621708e8e0aebf8fa50bf064cd8e02dbcd17222980dc5ffd167b19ece7379637067a1bc6a22a82498631b7db5484c16b3ae83217826154744eac29cebeadd6dfdb75dd5efcf1a2bbc14fa2a64e3649e0da6ff1976aeb8a32191cd514b3a6ca01cb684f57813ceeba9fa6959dc700c49ab54a3b973eb2726cfc0607f2f495b766d76c671bb74c5af925b6e79c60b1fa2a42f825a361de1020f9546ad18806bd95e6d6ce191d7331d7995adc1a66cf99af3a8605ac5f5e8a037dd5a83be4370a47b45bf78659ceadeb5c2bedc76a3f680385b24ce0fb0373e0c79a4b6c4f2c372764272ee642462282428f9da1d5aa84c629b78f2557a2b70b9fe10e7e6c7832d6e96adf9d93a7aabde2ff5289c832cd57f4bdbe3aa140db531d4a447b236604194c732f82190735e8bf29cc7309549b6c860e485aca3cf6a77bde7588e22aef95a4be28369de0c7b472a2829bb711b3edaad0384d4f66d3f62b3f487b779b0d88ab04f17c274d4d2430945ec9e6b7bd6e6302ff6f2dc22866f3fd89e9f2bf151baf21a7afe7b5acd9f325584d22040fbcfaf7769bd885ae5bf10f7c15ee7cf9639af66165ba0ce52e0438fbba889bc41dd2c85dd5b76809ce921fc63eb3a78d10426c0b8afe6e4d75e8655646f8428953b629efeb08e33460733ad2ac7bc561e22db0731d29f72f1a7a5fd99aec3a2441ff23d107cbc9c58aa0f1348607aa6a443463ca8ace7e799a8649e53ada016bcd4790c9f748a64bc9b29252d7c4cccd2e929755994c4723071a14c9ce35c0c464158dc4a1c58a74b62c545310ba1232376ecab345d0571644468e0777555da195f73ed644f0f9d377c790eeb0a2ee5cfe3fdaead58b391fde87dce2fef68e06b502f748de535776b6293f713dba79cf5d4e7cdeb17f15033766274198f50479291e73e7e7e115ed24476e2ab9e8c28f59e5787aaad8be119e5a2dee98d575fde4138e2941c9c2a8328172fb6b0173b7b0335129cba1552edb846f96694138261db1b3918e66b40581bc8fd6371e6fe2f9df8706be076468ad103b20f3195be7ce34e874d97fdb678bd68cbbc13b6d2e5089750388958298ce6d390bcf12526735f9b69414c09cf9643a930ae42834dc038bf4b2d67a7de5419ca0b14becb00e783f8c918b9e97d8c7cce22eb6337f1ce3b042aabf679d791739512a1fcab7be1ecfe37c23392221aef5775ca6111bea9449299a6b28dbac4355dab95b9490c8fabd1f5dd8ba48c40f001d26ac14bbc63af898cdec11c6fa97a27acb170ccac556fe7c986e005a878b0650be7e43ff0d40a8c2c91c8171e93174cc35e8f83a782e51690464b15b043aee8e251a9f5e9e174f2f4ba69be33ba174582504d8e94c46949333e40bd70456655954234978b45bbd33bb4ff790614ee88b0b96bf434f01ba89113ef82927d6c54efaa5ceddcafe6264d4b21df1c7d0234ea9b81ade9b8ac876294f7ec5b5ca2005ff4f7f9113ddb261b838729a16414823b85100be6cd4f4d47d55388747aa761b28f6fa7479322a910d9cb0d6d8bce72dc927928944162bb62ba3ed0713a72989933cafbdfc58f2b9d884f9f13085d08d88724c153770c2db82e6ac310c380bab001cf4f6b4c185aa702087f4596c554673a00eedba458b8000c1a94dc3e39d9fbd94b5826c80c013356fe5419c3417b2488a67b1fd63807311e395d8ba4a6457aec297593d0c46af5011c13a62b6f66e7067126a0009e846da027398e745e7f39431001aa70f14977d60f687fa4c1ecc465395c9209c6b1ed7a57c958a77223cf2436ca7dfdc69de59bdb7a8e886486675d357bd11e08169043e757109b52e71f5065bec368e9afc292ca3db1e727b5294a145448f5089f06a0ea6c8238bd717cb81f01024a7f5cd3a8a91e4feb36c8ef601f91e2eb456cfa016fb3d7ff96f0d6261bd488a9ab7741423725b23844418e6cc98e9ce9cbb18e255b831891af2775192e8847a55d26565e08002d562419c258f0427456bf7f63093315b505ef6a9e7463cb64d80679661e77d8b79004c346344f76bc574f68c3907d952d508b2c2d281a0c9412ab8d2fcff66e5904087ff1aa8c92bdce8647ecb88780805117b63b68a134b152d6ae5dd052b306c657bcfba1b42a94b46344cb9a465a5c722fe3d9d0aa78ef99dfc84c2d1c205e7a1b58d2f2407f51f0fcdaa9c12487e50fbc24491e709e1e3b3723a90ebbf328b25ae4164805126ec2012643590c6d441d8ce978f063981520cc78ae69823396ee065a89a64daa0e37019832ff384ef5e0ad05aacaf5d0fc9ab078efdb65a710588c35f38c8d62771d6452643e504691251a51df6145dd87bcf04a325c84c47958798ae5bdcc6624c719aaf109b826190b9068b9b5ee32e14b8cd2ed181a2ba2452c00682a026dcaa022715b825944110f630c67a36167fa087d36ff351924cec2b59106b321f48e602f9a556519b7a055cfaed23928f14e389be2c35947405cca4b78df8594189210e0ff60353254815392242188b73031cebfe4534b5fbabf5a69d1372e4fb66c5f749c286353520cba0251e3195e9f3ad88ef392928e2eecc441801d9b9a84c2ace60969958b1133685173107cfdcc9ea1fb1013abf128bea4b1fe0a37ff14f75e0b270b65cc19c2d71604dc08c675c336fff3bf4db70cde933a6fde791fa161e89c44015127e4c0a13b9cfdb1398948d1554fd4d4620d16947955a344d219dd14f57cfef12d927af64097826c032603d9d25e4758ff80bc6bfd7ba271d02587accd4644d85d1615b9557031d1345cc8db054a17e7341f4d8eea2e71acf93ceb3062289a100bde1dd90519273b5b39926f8c45d17848ae475bf9c371e391241a2250502a5bb98155b0fbe12f44cb62eb5240cfffd1d2bfab19888a931c9da223efc3601a461ff75e798494feb5c618880946034a766f73588a740e28773ec3ccf44581079e627e098fa006bc287d03d947118d0f56c885963e5910a0e7dc418885ece0aaac0efdcde820a70508265d40671fec15a74b374dfbe2f2ae2894e63e50eb3d7d4fd0143392a1cce41f34288bdf06ccf2bfe1dd616fff6668de31a8c28fa7e06c7ab6afc706c96b28162a0dca6ac089baa5ca9b966eb0ea168677f8a489c4ba0cf520474fca17d6c30b2e9b66486fb86bdb92ec9d456e6a5a1202bec09aab0bc41a4f528c551ca096db3153b6b194f1bff8c03b7d6e9bdffe213106a1803db948142349467e6cfd97919884588de61677e2a3a3ae7baaf2e25d86b40fdc7823c9d3cda4408ef5e8e491f4c84203e60ef46ebb569d3de91cb4797ba3a54b9e127cbd6f3e709c25717498f18fa9055cc3de500b1d4e59db77934375a2335b5d838760577ef2741e5a6276ae2352138c5bee0eeb677425cadc17e3115982e68eb345611525d63874c407dcfa92eca3dd7718685693da638b9273bd851a340a0aa381d288ab5b766071d4827b053e1bc61f3fc348564c179b0077f1f36da957d12a29767f74cab082929705dcac2167ad28ed4d8085ab6bb2288a9546809041db73cdf22dbbaaca86c43478490a117d51aa9c5a80254e4cfc2ab15dd0aa7fb287a7d5f85e0fdc67767ef4e2d903b9fef2c64f1b830a875f0fbeef6ed02f523578ea7ef43ac9ce882bd0e80bf59c6fa9482c5ee06cb5381366255effb1616f502bd57bf2c20b4c9500b84a2ae03a123fee7dd76073be43d87765b1c6dda2208150a1e8210b385ac857381485a9b2f8c6b02efdf6b6253e06bda913125836a474448ebd505b9a0d49d0ab4eb1e6cb072bf15e2638e6fd86b01fa7bb96f9268211718d46822aef3eb1cd415827fa7bff37464d7f7c39c3d484002d5ce53da9c37abee4ce89c82e7c4c43d05aecefd0ff891b50cec83af209cc5ea6b87461c36683fc68918004242becb8a2eb0195b3d4cbda79c79d54c8522897e2a1d4eb7f553ec40556e68c5dcf25fa93de54b0f19643d1bef7310d5bde5895f04498e35b83933edad3f6ab53ae6d8ac901809894bfadb46d2096ff5358cebdf50d7871a3bd470ca34dd28ccb40da26d5d2d6a0577df5d48571ebd6eafbda11445392c8a4861b71440afb4971aea1be1074eccbb99cd0fa38ce2ad4061564bc7d028efc23dc80e1628f4889f2e638feebd39cf2938bcb3463a638d218661b0ae97c6e84e642e4769016a4b08335cac2331f3c2728922c885ce7946f8b97e75bf2f52b81e4cfa3aff76d0c66ecae70b0f53a9063a11eab6b5888d1de08ed9a30283be6cafe652e1193ed40a513379f53d5f2928541c80ea7cb313d9efd46c7ce231bd6da3cd9b4a7c24f09c1cfbd7f7cc6e2abf8f0d3b36341eeabf4f435ea607c9fce5aad1113d3c542cddea8237610e74f2f83deadf17f96f202ebda237bcea2704a62a374bcf1d84d41a419ead04a42d0b022500e2ad63a8189b3bea28371946b7fe33671061ccc3c982b2c47dd12794499204ba26d07cbffbaecdcd8f0115942e21040da8407b02dd00d258b23870c727ca9794030c98d65f551d7a0108ee9f5075e8ffe6b8947550a1aec1768c90dd4e9b381625fa12b3b8f2e8ac4e18d8ae69d869904ec9ccde7895b9b171b4c4bb2c56abc00d52f9b725943e0ee0c788b2b265447485bbd94b4a934a2e3c3cdbf7d0484517081b009568a5ac2144597e140fa26972e680c2b6b9301b7177661de008a2f7f756f47441ad566bc33b6672208cda1add9fcf8f46a834fa964b67b9742fcbd965b5ddb02c1771673e0b7e1ba40aea2184a351b130759be1f57dd605e6bd53e1e95060743aaa3c11bba9ee5d05d12a7b7085497d008168ec4f835f825b03bc9e45aa7ca6885fa517b7efe3e26b2a644ffe2d72f7d283d1b4c524f8b0c4358f5e7a16a9f1fc2a8d22e5f334c6785a601e6b28b88f2750c104297a545b18ad0c1040fa5ce2d06d33e482583322fc37e4a81252d1ee45a474ae68492ac4e38ca0975b64e8215a9acb5d7a6ce45404bc781e3d9d4dc126c6eabca22fef4b6b710a271be84972efe1285d60e7ae5bcd734c41612665b87dd5958ff3a2a8fad78843ff3d0127bccfcba36c817b53e1a633cce3da6c2833a88353d921634908dbbf653ae2965c6da9bd76552e6a08cfa4a549f1ed4c44d5e5e8ff3cac436b11524e855973888f8958b0220b9bf6aca32ebf94590626e82725f952e29f6d32262cc998be88e65eb43076e2ce5ce2ae5c3bb7a5c348328896a111e43dc55ab837ef7a4b94d574aa70b56eb4e13b8bb0ae608dd9435b550f6f89e28fdec1a8e9f5825b0fc5be119ad69eb759976cebc6ea27387a45a044825b0879a54de729f7988c8bcc23a3f9767c06f7e5d76be852572b1cd79531071c55ea742ef21bbae3d4a9515172fb30758d090482d05b357aa90886f5fa85a92f65e375b38e0c202f415261ea68e85dd4e857a4929d1b3372c5dfc30a314cfd62c7f31ee0c8adeabbebff9e3373d2f02fb05cbb5d50e63413e05353931d1d258ada35e1cb32d3fbc48ee81dda714a5b48efa39924542f4f3380789159a61307d8c15c4de696f86517a7e2fbc2ea15cbde86ea6ca8bfab603b38d885306942f672bc57bf9a64fb7f460403a1911c3ed9f780a8168a80709b3c9644966f46979f579e3579835bbe955ac184119b1c171f1b402f75cfd518ad14e482641d00609fc975a8ae747cdcfff5c3195f3f1a2d80fcc6af66d41469228b84bbdb20211f3c8a47fd54a5bb31ea385d5d8f5f33f517628c9064ccc7247590e69720d6e10b00171779a91a6a7fe58717858445dedaba3a99da217b8383f381d447f9afc93367e75565c93a8232f8ec94598388e3f383467b5ed807cd91dde78c7f350e760d615600923a6ed72a5cb02720a341b0a55440a13712f3b408d7024de7cd8132ba9bf73eee95b4b017d9499c16680a865e8cc4b299500c20ba8d07c4a81918862b25e589fe74f27bfdb57505c7fe6d47c05a06924b80e979165c27ade4ba5e19186bf95bb63b741f466994bf64aba9c42b306ac2d02417a12e9d3969cd9170c9bdaef453d269df27bc3fe544b894e81cc1e27cdc596e7292d74da5ab32239ec1a64b0b112ee9c833ce5087d2ade635e0e236491f4c47885d23f5cb9e3dae114017c0e03fd2ca2b5d2261e114c89dec295558959d97bd9de8b5de08f5ee91fcc5fc7e185e4ceb99d872a0ad38d95903d49db23aa315455fb4ee4686211770e8161380c4ede979c2e9a24e4ab0fc8f5d4fa2d3d9fbd5439bc26287c1ba258bd7a11040e6e0f4dee03ef199daedcf0c96ab71330d2b6f28cca2507412927b44b93ed098416cbc585070a50c14c066a14ff768a2af0707b3be12a274ec1651c36a4ade863516c9c89c938898954eeed2570ee436748be2864834e069766b936066d4048801f96189831b85cdece6dea552cf5eec0373be15638c568add39876f5b1c77063bfb40a0bab66a076e2a7a898261124c82d7511717230736410fa450a1fc51a2749334c1b3e19f7cc8ea6654a09b1fec964f13f31db6016a2a16552ecfcea9e6393920c0c63c3d672438e23fdf4c73fb012a5881d97df5605c94ea3b713291076861d3730381efa6396cea7062a15941652010a62caf58cd78607f648da58e9d8780a7d8ae2bd9b830f274c8a7b225815f9f1f398ef8c4a05c3b815048a0177aacef12dc079935ea8517050ca25d2e7737bd14b0d3914905afaefdeb055a69902b9f897881cc80b1dc54ab72334058b1cf2040d0607da54169307a76c7b05d964ffb5683508a1e6da2450915415c084c35a8a11632e4229b1af0fa5cf034f83173682a173c4fc7d568c5c136240079e7c1aee4d0755ede1e7a40aa3d4a91e67b20db1a30f067d3bc9a2adf833061d2947aa3ffa87b202d8a20a4a9d11e10e2e6e869d83c0fdc1451dcb5df46dc889be6c3d8e1ce2489c3a34fc9749abf606a8bad47d994c01405e186d9d0762542bc51b8912a45c293a10f37253a5678fbe7934c02f333c7f320549c8c4e391282fe5f57afa5799aee68e43daa84b7dfa032eea2142b79eca1b4ec9c1d38dbb1266353ad2a9d63ed2c5f8d6952406d22118de395f7746457f8ec1709947a44935bfe4097585a90b833fe621600f37fcfc1aa8eca6546f9b0a57858d37b3a05d7f2c06c0ab46e56430577e5c402b4aa811978486ec2085a41f3a76477c5a5535d510a767b5ec8e28610974527b40f39ed56f641e43c59ea3ad074fd0eaec461d6f98810902a6490aa2f19f0c77acafd011fbb0138ed928228b4805b9fd99de53c2e184b5a157d9fba05c308d77b3bef41d216faff5fe264e24228f8b6d54811ed2897b10bec42bd19c283b0944511dd6592bac2fad1ffea30934f04b9d77ba48a00705308eafc7ee85f91f81edb508e721d073c21e67248ca13c36e2cb3d5eea9d17d977ae3dd06ebdba00518138ad7e23ba22de6965d7990dc810f7401bb102eb07278a2701352d92e1ca701dd76243b60a64c50e6901f49096de7dc3e36d9ea99986c20f415b43b9c02e5d3a1f115c486bdea09081e83637e8be22a6d74f9c4b5855ef872186bb4001a9a8bb7b3064781c51c174e05561bc5b8cddd4a7487e30abdf9996741faaecd877c75c759ddacb84bc80196d4830a10cee8023e4df5d9d3f82251656c16b31edf24563ee5972405a300247d718df3e5762e1b0525a1ea651661a160b84d620be7033e35cb7d3cf842998c9b37e4815192f9f657bd53dcee4a725a31c47b8bc13d06bdd2b227b641bdc989b4c9c2a6f99172d6620beffc086dc29f07c290921792449fdfbe02c3f05147f49682519077afab778b2b7bf43cd2609331c67d9ce92c2f6e076dd6a6ec9a2fee051dd6d82a449bbe68002879dd2eb6efc62fc91088871e6410e821e5011ef9a618da22281ac286242ba34ca8296e3f37799a240b209b56c957faead6d9fc4de8826929ad8bd42574b2982d9cacb88b2aa48f6b72f2802311d08f222394bfd968d478d733ccf86026de37343c6534a52c5a48d2f1d7feefc2a78ca0f2002be8844999634295a4db4deca8bf174e54c83098bc5e4d0645df11c2fbc2db767ee97b2ff5e35186de47232da250a1faec5480559fb126f7c04a5c614cfe13970394a72b00c586e0fcf8134fef411a2f43fd81e99b20eb2f9a1a42af9df35c3595979e7506ee69df01f981b77f78595504ca63cb13e2baf865c0a03e8e5855c817d60fdb3d856afb7f3f98dac2f1b7f0c99937610a0fb88fb4fadfb4d24f14cf481734182284bb30c7324248126b39f20f41b9d83ba71baacd4e46fac06825b6686b37981a9e191fe95ed62bbde4f432123f315f14c3683a91cc1c804ad44c4464029112e49d8ab02536da431323bd50044b75b3504041d48769a57156c4bd48e688a884407c8c4c45dc561400b8caaad613338ac9d091275044a2c6862aee8268740a646bfc46bb1ea88d0074e2c0c3e7105b2c38b7aee610ed07ca9c03c28a63d31c54201e53684294a149e090ae22e8e65036bac9a385ffa9622b4f450e630d2871eb2d0aadbbcf44bf770d69443b70c5d871664afabf018294cbdc99b5639aaabe1772f36d0a0969033b198d6bbb2bad9bf70a74d955840dc159bbd61c6a11c0b9ba0490c614ae875e08940ece8fdfce72f6e0a4db581220214f2bee8a796f204b3b331969a1a812e18dbd4296f53d32d22615d92c1c5b977838973c9f9c42efca5abf876342753112c517f1d6410ba622332454a0a12b9b7d77255f85f2d7d121c78447aa9095cb0c45d4033b886383044aba40a441a451d582a9370f84046710c2e006d1e30927da15ec715103921f46bb2783c05aa5876e5645bbcfeaba94e2e2b845637d107bf062e1821bbe95c686e39355788a12ac44d2e1e6688d9c78a61a439f992855900799b6b9214ba36409e9971da757de4b706f46ea15dfdd6df09588fd189ff2810d849915b10bb7ca6194eb9c052489e4e8aa8f03e6ed6758a2aba37319f4f7b8f181207a6d493776fb2b5ffc0c8fccaf77921af004e6812a422fecd38aaf16c29368b1fc6f8d3eadec5ebcf3187e6dca83870ecf9e964454273560e1f92980e117c40da002d738b6365cfca7e7442713a04cc46e4dc2bf485830601df7e673270032dd04154dbdf086d5339dbfe391ae498e19d2cc762d48fd18294f844a4665100f92b8771699190cdbfeea868cafe1b500f99ba2365885027f8bb4b321664d9598e0af9a269f4c026050867d7bc9dfc9c3f3ac53bbc8d40e00885c41502c5866587a765c3c205cb8da472aab632bbb2601b81415a265afe842398de64fd32d9e2c5f3a94b04122b460caf400bf124fedfd057d722766911a191a32a4149853d393accada3799313e2c46bee868a379317755c36a4ee049b7316819f6897b603b627a393fd78d5dfe738c8e00d0c40a179463d0008bc61f0788d3fead4b15d862ab531246e1e1f401afa989d8ab6d36e7df1befaf51e29296ede257c46706ae195f5dfe57fb6ee08119ffe82f7a711d783bde74d8cb35b81195566b1118cc85ed0eed3553962920f8d0f3cd03844d2bf593698dceb05db36970a0e6e78b5e2a71b91265f9152c695372ff993aac4e985002715033e636a5d6a51862e19efd338789ec780fef39330476d1b456a2cd91cd6b6f999bd159848ab7ce1ee85c489559bb121a9db998b260960edfa059fa403bb17695a03aff98f310df0c2c411260bb36a5571dd95de4ef392408e09bc9d1ad0cecc75bae7f2af016f05733d2b75496277db540ddcafca8516a3cacb44b4251a27365c7ad75ada53e053b94a8f6354d9b24c1a04d15f58cd02588005370f8b562e0d445174aa8307dd4444121af28bbe40de07cbdacb187434c81a4fc2edcf4d8d486efa175eef32359aad51b87dbc5acec27cdae13040de3895874eeef0e8e99af9352e0c4ca938c651df84267c052163ade7aba51628f5dd45d580768c55df24405ca9fcfba640d5d0d5fbb6c5c169a47b716d71e4730617ca2989aaf4c5f28f86fa27f08adb8548fa7a66e6fa82ebacf690d77b6b19d410b52f59e72d4e32ec2a8cd582a0134199d0b31709be4236669c40a44050c39b0e6f80bd74ce2a8e06089f19b71741a5715cb52d25fbc1c1410c88dbf8fda2ecc05e019d8e588e2ba690dfde56d2f9e17760d01e2d8d6203010daf734070398c2baa24537eda0868ab8adf298570ab9d0cd3ac7b973d3e81c81117a2d31b531039e329ac82a33271c098298ec6c1bb0997411709b09bd03a069eca640934c1ccd48bdb156c9bae202e211de85dbbfdb540822c7e76e270d12846eb1b005c8bece5fe1192f79eb6190f21c81c5ad13059ab28a5032638a233076990d94591f4a7066fbecaefac34c2a9fee0d03dc656465946ba8bf51359a740dd5170c1b1018a00d315b46f04701e301bbf6ab9b9fd1e20dcb7d90f2417014c2ff3435582aa03892d64f14fd3d23fae907396f0f53510c97baa0284de7ee542d57d06648cec94ab15d8918b1aba6b5f6c77fc06c6116d464d6cb57544ae694603a68f9439ce7c2baf89056ce595a45cc105ea7ce8b850f897d14b588be212aaeb140dd4d0331da04e33134e9437e3236be59175a7565459479025316e36e28bf28d1c3f1707542e2f29570cd4b0212343b717f5ed8f21c88489a897b411411fcfb6ba7b25cc121d6f27709adcbe364775bc45038d2598e14b8d49be92d21f376f4ca3c5d2cbfb99e87cc6978fb744c73465675b2349f1472791d843fc82dc64f98b9986cece4d5dcc628a4c4a087115d1ac3e0b4cf227aeb3da2363f8a2fd2aeeae19c8bbbc45581dbf982590ef29d0bac2994140e62e7ae49c1e4be990449531f1742f9fbfc43a21974adb984a9de46345b8a26b4bbbac3e3ae18d3afa3bbd0ceda474ef463ad1260c9d66b9d05fabcf8dd666286b6ece1e9184c31ebb689a8f28f6bcf2704df3894b776a0525c32d05f9ae71b7e004fae5b9dbfae7a3eecc3b885e73bb2c05ea2a9a0882d8535d534324d2dc5504e76ab402191ec719b52dea2dd4c5a63207f96b27e02ac4641c16cb815760326375f0d1380363419ade1aa3d34fd3547df10e8d5a51d9ef34192bc972a3654476c8e55fd93dd8c5af67ff3a0d8b9461a517a99f9208bd3f0c3878ed02e9cf4975d575554e91318c58bb9ba961151e8afb23493bfe695a89364f42d4c39bd87b0a46c25c4a5e33b1f78fbc4519eebabe730f8d493aaf976bcbff5a0ea9b35fa9b7e3d8a24295ccb79cd37bc479671e4a59bae144afd361cc431255f2403544af17db9d3a79cfbe212ca06a8bf1924511e6222e4e125c36c488414054966028c527b791da06413eaf59f25ac9a628708fa1d18f3ad164856631936b1e6241bbac2091b1603a13b48d13fc06a1c8c5aeefeea2fbacaef75c17702dfafe98ac9729a101f98b1bff5bbce772a6f6db336ff11b69b4cbd34142648fa26ff6665ac3ee1f58680d29451883260b4352e83646ea0e587d334ab601e5db37f694406d1ebbe72ad3769fd287dfa03ca14466d67b62df89a0ab393815700888a0b7c24cb6d328c296081aa675647123831601952d4e29ac9b03d9fdf8dc46fc332d35bdd253ad806087064111d6324755cc9bb7c947e3335110a911c3fa994e139286167d99f7bf96aaf0a3751086607b3ff45942182573ba518915ae2a0a610ab8d648ff9fb1e0be9d4824a6ea3da696feed4248eb333ce9984476597d385763b8a29edf005533204027d2b5aa786df65996c65720997e0cf57a1c2ff9e5048c17a530593312a5f0ef4e32d9a7e13867f386f7dfc61c7ca2827ce6844d63036683fa4c887c2bca915ebcb503b4f9a0a586fd3985cba4bae382418ae4d2fa5185ca70d104bed67d3f3847488e74ba3b11ed3a6de58ef31591b7d452c3d03fdee3e266c0c88bc1f53b5aad230f242c4fc7cc3fae6f02ca74cb011969d53e0ff215a350b70f3874a4b0eddd3509f0fb33a4c0d4ce344454cecf7fd3cf80b8c00d8187f89f9bbd54afcdfe3664126d23f142c2e9c40812a9e8ec4c648a05106759449fdcba547300e8015b82228642b99af58a6087e60df80ba6c298671202bc7f87a655e27b241c64406fb116272bfe16dee1cb93226ed236745832859af0896fa33f2884c5beae31e0ed736323f26a44372e92f316d6886c769a6602b7882871c362353975cedde39894f157c1b4db281b3701493127422e3809356af973085372218297863e7714f903b300a3ae97290bfa45a37440559d84c9901170983936bd38697598ee7fee56009319c14e5231219719adb298aa1d1c0ff58d22607cc5e82c37740ff18018765991202ef70b057b0c297692ac894550e0223a4bcbe6d39cd50da849d9890999b3834599e1388c3a2a50d5431885472ad583cc76ed1f56ea778b9d5e370e0e7431bb5be3548affffc387ae2418937664ce2dca5be99ad2d04ba7c38859de7be8018fbad7bc7700648b07f953288aec5936ab536224d6ba021bab06cd867df88d3f2f63fcd6fdcda7bea7cc10c16fd72d79b858f9caa05a13e710b379a4803ecf7af5eceb675fe204a55953e75175ca35b781a4aef646b7777f47c36103c9a927c20c1a302bf07100a3b00bac31e361c2c626f043258914d25b058aadf8589232ed79a148d209390779f5d2ff1e83b1c80935895a5d38c00d99c0220f10a7994b388a6b792164a97aeee047587db0c7680660d990a5d152c49e3ea1264a9fe3100b048a2da8fec5fcea5afe9b0a43e244c0f446a59a8cdfd06c2ad1be4bcab5d3ddbb1b61a280f916312f9bedb7f0bb840feac9c8bf9622eae894ac82757882382a63d4bd1ad8568de63ede863c886b5790954033a5488b2d029eaa9cf056d3f0978ca0863dd9d003816ecd6fe022ac2917c6c20bdd29632b87068cf0dec611182961ec3155538f464552ccb975c8d60eb59c3a32c8cafacb6d7fee4afd58cdeaaad0480c42b57d2da9c8e742b67c89e7a761ce120ea263f881d19d7e535eae118cd4993ddbadeaaf8f7c35c1f82c1487dd24211a68ff141cb676dc410d097e4706c0c8a4e46a74a29483a0a200a355e7010445cf6ab441b2b9834fe28ee81408ffc7620b3f845ea7ac330e73332b8aa1498d53d72f51eece6263e5bbfb796a12316a3eb472a39101c57e4ad8b5566b7502b6d846f4b276a4c826f12005bd167aa54424b1001a7eef6b77d5013d0fa1047e2539dd77738ab674eb47fea5073862aae2a40d67c09e0ce3ec62642cbc3d902a744353b7487475ba6e889e35a5cbd77fd1a569949ba449cce1de4e2d9dc8ce6b958c7d70c52ae17636d8594836b986fec1914a79e8addc432f429c53fe459a9c239347c64dd327dc17a01737aecf099bcac0be043efff02289e731e4065e3d9a848aa8409b6cd47fcffb77aae7ba0fc9c1f555078854592f9bf26befe1dd650e432bdaedb880d70d61869a53c97155dbe6321bd9f0b6619cd7f110588e0b2c7e79a925c82ce848dd0b49b4544a50773b18a1f070ae296271618a2ba828466a083905860c00582f5770bcb136d8a0647517d2e5a7dd286ef7f967ec281ea5695cb5d0f48412cf30a901d2729271632c7d7fa2ca2cc5606c538e5cb6c6cf006ec9c1f6e892f13d6fb98ae779c7e3411d96266e13cff369febaf587902c1fd5e1b671969d791bcae327fb3872d4738cfd51b4e5cf27f0cee58a030b56706ccb2d708ae153afee92d94362d7d53e459fccfc7d3c58a176c6ecdd3dae185f005c88a3aecde0e467237b79021fe141552dc4f4ee90ac493a644d6ca575c43961f5a6443bfa53d7d9c612725e8fbedc9fd27daf6edfd77f06413a59b59d8583afb3ab0c4919767e17e928c9692b6d1327df634b8c206bbeab4a4090fbb48d4d88ee7214e24edb688dde8b91be52d57de421909275ea40a7c859ac6eceb685582a7e23561c7457b4feb40be42dbf611fd38f5d0283f3e620d02a82d940e13d22e642139d90639b27d7fa3e5e8103d5c66f23377033c9f40bcd3e73e1fa526b7b69e5edb6a38f57aa1c1db02d968090ca094f247273e7d86b57b3087d42ab43a89e03638cb4e3dfc3a4a116294f2ef161602b70e8d88506b8c2f365393c5b5d2bc1f7fbe44ec930cb1c4cddfebb2c08ea17d1959394e16311f9353919daecf3fd2006af3514c50de7e201fa11f1bb65c962340649035a7536a422b9ae6a8942c7979552d62ef50d1736588bec497fa9750346831857151a47d4eef9c205e87909bfd50ae15a6b88188ecbdf64828a42c7ac96f10eaa12b90971df8d9d45147d88a5f5776412b7540e0646056611fc91c297169ec8d3b387460a3530d8ed475dd9559fe546d1622dfab535f5da5afce69f86ae19000a459370aa3983d2dd7b533018fa441b528ec638131c39997e263238a9b7c4860ea5cfe83a874b23ccf34a06ff8af4cf45724c2043559e83134b37e024f2fe87ad5268cca2703e9270f81cd6b8f7423f10c9a1ce367b803851ac46f3bf10e8904a47b3333fb8f6721737d7a3f644cdfbe4bd134800d6f4932227926b9497e92bd63ec0ecb0c2252b19fbc3feb2a07353220256d7aaf97d1a6701d7cf50faea1ae49ed5724ad7ff33031389ee046ccc106ce40e0a6b8a20f4b0544749c6d43f2f0b58322442d5508e0d2289e9fad5400ceac39d323fae5b9b4404b52fa43a3113633ea89d44db9443270f90a400a58077a1e6763393c87918f71748e1b1ad73f6a7c8ff4ca59b8f259d42c2b7bd228be3914423689127c9a3976505f1a5e25232edaa472835806a8ceb9eec1c3bc41b03ea1ffa0577c4b5d0aa451b80701f5a2e7c69bfdd08ae6a7c3adefa8b3cc24776d14d01d805dca0365d7011b4ebf531842b7261db0010e45a13d94fb1c4fe089a002dca1851158a78d4c7d982e1adce491ef31125b77926beac0652d4954c3fc04e852670397de8f8dfddec51f24c85084c84746fe6ffc8e180b8af3c36e12ee0294dc6e72e5dea4f98f566665208be79cc3b0a5edd72d14fce6b799b51d17a1c3f4a67e663e93d9a4ba882d5687832fd351cfef09103028aeb1b71c7a6a634ec26e9c0831584fd7228e4d2264cb61f409ce5d69dacc1ce444de71b48fae51e538fc674d0531e27409909414f8e13dd6dba86f80471beca5d95f18700c4f0aac5de5955a89a8b22ec487af00bda1d9146ea0b154b425521a568f7f9ed351520cf0f3f0415d1981d2d4b1e9e7154b5d3c3ccaa8f9c252878fb350692040d917c0b1ff24e9da4d4d60c2d647befee560124a04417e8cf7a2bf2e50b279f8420aeadc63bfca4480bbce41cf2949c00ff33d25d617d5451c76a7b1a7c9ed37ba500995982dce5c2c3fdc6d76a05ba7e244cf63703e90782a97c8af76dfac813d0431ca04118ed1ae99047e78e206ecaf868b473c83ebe1440dfce044ac03db8542d9d70cfb194841af361c57dfe7d7a6482382d4da67e77be970791b46c613ad117b42fdddf07b86537ef643a4a0d3a3a1b5b0a9a829ac1f811edd8e8c4fd9c1a10f800b675b4f63c981be4c424943c625797ac08bd215781a853940cb70275eb7c5efca929ac83d0ca7140684a9881f0bfa66f4c253289b1b6e5ae2fab87c3e6c582faad1c995e171ced570ce7ae1d6be4712a143c1482a7ad36348c10ec3b0f0480be9320943d93bee2feffd56d8d53c28124913b7c9ea9e265073ec02ec0e646d4faa6874e4784fd36775244d7a030804c678c2372814a4112a14be1a57ae05d020986f357d2377ee9294701bb2cc459ee7957a430be3d77c06836b1b169b4413515bd693d803c8f95e5cb9fe94a477e928a19ef7521dff867a81458d2c91001abf574752c1662272fe8463ff1861dd1500a49a2b158f9f3b5ea25387c5aeeee83151062423ddb300d463ed2569870a0dcb42afe7e21faf717ef02fa6cba4e2768b5dfd703f83e640aeff2b5e01ea3dea85fda5b7d8afe145ec5133610db71e7e69e6c8a211baac7f6a0f112372b43970469342b8a541749013c4c115739c93a103dc1a6d7dde65c0acc7b4e73a47eab8c109c68d1aba2d8500d5f91b45347a3c9840ef6d99f981a53fb6cef1ee52cab8554ab5fa8409c3abf56751ad49d26ca08b82e0d115ed38a656240f6da9711279af8bba132e9dcd28d03e5b3c0404bfc6db4db6d0eafc2ed4887b161d2098e6099389f77b94578102d3c2f1fe79dcace5566e559ba7ca84a6ecc3af8fff12d5c29fc8b46d8e3af98e653c781a091c32d4524a571984b1325619d70a84e720ee4b11eb1808667fdcd358f695834643a3f52c8869cefd5e9932f33ad56a5d71dfd4277f90de1a8a58279f6a7af3d74c7e1b06e06d53c30d5daa6b825c6b280d3bcf93ff4376353c40d3c55e300b4f59d4c85348767394f574a51bf5c9ddec1d49bb4ff08f3c30c1a6d28df01b7824921525cf56dcb0837647e224dcadf8881dab34c94bbfaf060952ad276d9fbb94809f4e77ef355b3cb86d78f9d4255d9badc7f29a4077f0b448b310cdbbb41d41f0656755119bd85d725a6bc6d5ce8193c44bd5043c6af11f34094e2da88a463c2e63a6e571b8a885d8fd1384019fdebdd81bc8ef09d95c0b9455963e5f7f7759b46946c1b479aeb89a66ab5ab760c6f3aeb080e20d7e82c3ff37165fd1606a469e690f1798173e896f2535126ba4c104f215b349adbd180c90eed24ef1a077a9361f46870a30ddd633bec0207a32d27e1d4c2494e8a59540f514ae695c1b8fe1c379b9c200cf90aa2f8d28a0ffb027b654bc9add6651b8ae3c15e64bf1297d10dfd1d5adad693919001607eafb8d5daabf6142f41c2bb0d869ced9daab6b47995ec40174da8772fbcff75ec90b3defd348809e6a9b1914ad11110810d96c331b34b36a29e9ec9d927140832e0b2cf66e826eafff582e690ee3092bc4e0d1472a9625e3d185e9da6032a21e72535d28b5d2f55885a345c72965ae73ab40c458d04585b1b5af686adbeb05146c3c223c14c9dcf1ec7077b289d7e90053d53a88a5d84519962ac5bf7655f767cd7eace3bf0353b14b0f068454661c006ec938289a769966221e2fd600a54003636c3fab8c05e68e828392240d70b17f5641def0d8b73f1214db603039a1750a188ccdc461981b55e6be98d372920607ebe438f64a19207f0286cfd9781c8a71e543e4a2d0166c8e42d543edb9dc83e9dba132237a8c7c6380925d64e4ffc874cd2851ea85794aa77d20007338b66b29a1d0d2633ac57fadd5974656f7fe55a462750594e2a4297fd8324887b214f9136f0be544f86cec272e3ceeb75d4a0a92e27b1a27aa72daff8b55e4692a1ce40db3976a46d07c918b809c53f16b060e7f44b969557c49ce2ca0bb5e1e5b9f91e96ac1fa1c97a32f33dfea3e6262ec2a1742d389a784945350317a74defb1b7826de84cc8e0597606f383c1201012c5f31e935898798ca7bd0ecfb0a49468daf1469d18724515ad3493a0c10884920a020719d15a94a26fbea9053f53261391e026c73b87eef015187b96c9b538e39f0368fd7de2c7e4bb63211493106c66d67c10962dc035cfb2c1d42cf3fd1aaf4414c2798d1d2e5038d9a2ab91a05f165e50b2c92cb435bc59e22bb972893219ceaa70ab1f522ab8a1162567e243c64cf79c33496daa7cf9d86790f23ceef16ee5b51d7ee39ee99a399e6ec2278652c411fc0df31f75c1ef0b866923a230c4ab2ea5751c3cd49e88e5098d8ad0c224a646458766ac8c754520888599d486395b9327c546420979ec91ddc5f358dc8c24973c30cf2ef57fb7755d00dbf2a8bf701be57323dd91738afdb20c020a7ca0d1594c10067be0ddb4fe01c806508dd4ebc13f5dc3b4fed45581bff67ce1ca40d8181a6db58b47b7fe19c0d0b0ad3165c080aa4e4fa8d8cc95151fc7b8ffa2284d5dbaef877e1042a05a7ef345c8a70d4316b202e2fffbba789801cfe9c3ef6abca7f154845d8af5a98c8d930be8d8da9907f0e7785c72f76b44efe035532d4401f6b6a4c81dc5823802a04162f39600e9982436a6daa2507ef5769e92a0c6ae2ab8c464f215b79ea609b1c72bd1325e8bbb4a33db88b091b3ac951b8d62290a48587b037fb83e1aabcfc4115b4117ad82a69366cfb834b4ab576f16acbb18fbb8e2a0bfb413fd07a5f0b474f3fc8bbfc603e2b2b683c20fb20bb2894c46be1f539c96a84133644a9b31427a9e60de65fef7605d477050676b53dee83b5e94af841649704b4bbca31d9d6836bf97af983cf20b35b7b4fc1a65893076a9a1c9b669553f1ac11a2c447051009d8c258e7a16974b95fb2f5cbafd42c7654b07f59ebd282d05c74ebe105e13c260bc98bda186c3e4af7eacd07f2a19683059fb90045ed079cc8d4cb9cb1bca193aa54588067a8d145f1a2c3cf93890b041897f414baade0898be2b121647dfdcfa10d3617e887c653be31328df6336a49d5fb4ed9a2d307df60d00114bb611b61711b352d5d4397166f71e0cb57cd44994eb225b4af64b80d4e44bbd7b9455825532f381b33f38848d44d5e99bf66bc560c1fd9fb235230f7fa1d1ece9928bf112c8b381e40fb1039c853f5ff3f43b8e8b4c3a8325263696fd529c2d70bd6491bc9632776e420e042412da03636224bf45b3cd6eb391ca2448f73b8aa8265aff09e7a8b5521875d850cc2cd16cde569c712ec0b2b73ff255421a7faff0c08af7413ed16de9aef9ba87cb83acac47fba163c0ce35eee6c38835d91773ec94d499056ab31a170e77bb15846742309b45203bbf6c71cfb25d73c22d3f89f15b4074b18c718be8a40f391d0f255b6584eaf0cb2d441b751f5816740232fa5aca0742dab364e49aee7e1127ef53ea88713d6ca607334a112a9ac08a1ae5e0a781720e5d702bdd3ea5309ef3f149e485b98f5eaee4117eb8f04215fbbc148b1794c79d3f53465e2d75e46087c2c8092ac48c8e21550ca90bfb1bc2d20a95a9906026da4069c7b4cf20350e1365d89e100dfc86e4e83fcaaf9b8da9339c140dc28cdf59f096dfabf26ffa46d29659cc09840c16521dbf4f97a124f48c8209be98a56171ae63bc9647087aa8a5863480b53e8e76d3b438d578eeccf604319de640f5474283d3602ed0aed5bb2224023bed13b0ae29d413f8e3732c09c3e5b56f621ea1fa95a758c93f7813356df7091420d8800326e9f2688775cb21b2c688c2a1f8164defa5c41066840ce64ac2cd80c532dfe1e5e3373d57cecfbbc6787d15cc8516b2d25c84f8928ba0b8badce08035ad87a2e1bd3b1655b22d482bc08c61b369ba618e984565a60cd56c3e83bf22e8161b19859b3a8a3c24840eb8206c64c358c3efaa8394ce8369682bbf99494e968855670d5518eac04a1a32262df3e6768827ae95630a7e0c457e1eaf350c29a0bb44d0b62ae081f3a20d45e5fafa6ac246f1921bf91e9496293261be16bf7a3b75a9caf4e2b391cf57d170fc241001bb8b00e48be0c95b2e71b3a8e48a48769db048da1f97ac09491f8da0826c6e0cde4b6cf6237d68a2ff15c9168ed5189ba14d0b9ef98b2e0a25359352f6b61a92c89af553b15d416251bc6e1148822a6bd78c1a6aac1816ea3377495bd260ea89295814ceace8515e601dc908e77c55041758a191826e4d76b583206df6416870d778c19c94eaa8a2812ab6799fa51f022469d0a87aee2166394ab6c95e32e46dcab4216c977ba9adde111b2a07c7d1bebdf3fcf2323592e02f5c9599d744e61418b803e75509b11abbab545109bc25e127105d78d722711c97f40cfd576a807af4aa27dc97aba35f83cf1d641ce0bdc95a061b2aac56682014461eeb2b3c421c173fef3f6b9fba191506a8f2487a1df4eef91749f50989f051e68a6dc41edf3f4d9dae25e89a5f6f091c9801d4e9a023f31c908248e190d984a9b56680927924d9c79bb7abfb9c89dcaff4f55ca603558b6e4f9870d7ac5b30fda425c89a06a23984688d8aa6c105feb2bdc9d67bc01a26f098b4bb124c1c116e8718020bcba906461f2b012718124a0fe506ac041c49a298b2042f68dfbb7d4b7a1d6254ff457aacd03785f287ecda6d5924a5621ffa3ccc5d52e57021d9703a52f0ff04a7ff8a6950364710e73c80186772f86e8ab35cb70f1fad0b83b903568555e5bf8f03a908c49960d85551753bb64d6e761e1d24677d196f1610a3d5990bea547a1bbd85afbc1a9df5522b71ed2ae51564aa5955c69962282f15daf60ed33d687261089ff7834dc73db8269d5d40c8faf4268e7e2eaa24d69d18d22e1fc8efa69cfa397bc56931d22b47d64f6ffd4518104f8b8aaf44c610e807dd2769c71cdcc21db5b259c5a46627b943adecfd2eb25190fc3c8a5186f22dfa9faf368a8e0fadd6f6960241e1c855d4ffc53f8d7bc4327a23971c00e29065d3d3a4b0fdd25885a29934e0f062997acdbe63c77d9fb1024a9f79537a9135bac680508366a749e9bba9eba4e1c710aba2818a420e013d479115ca42004bab18991efa8ee3e251f6d474a874fb1243645624926a3dca36427d63432829ad74d5bc245c8e17fa57865f9fd68923de50052a37d22c764ba4199ab5726e509c04c098352f52f2f71424c787c01178a04c39803ed11fe2b6dc6b160117c15a0bcbde85aed86df71895bd37e8b01af20f7cedc60235a0d411f028ce215fa21b1ff433fcabb35237abfee7ddc054ad7f3718cfb8c97cd7d047d6641b3b5e0ff28850ead62f819484e158456cf014808145264580cd3982bb52ca82537676f4cf5d04a9aa0223bde5cabe7d79f4bf58873c7109ceae182c638533dce50c000b468f5ecd9c6b849f55811fcb4838ef016da306207e01fe2c2f480645eb982924d11f864ae804854ee9bffdf8173f210ddf7fdb595518ba3f0e98214d4001164e4e679e7827782ee236615b6d206b3daf74caee16e4059176b0be2f37f410f9ad8d86192b6b9e19e5e3d1ad1ab55b3693bc208e7dd5550ece3c3744cce7e570c66a8db77703c26b281c55b2d1b5ddd6e7b7c84b944932c9539b61e2c075f3ebff253ceba55c26882fb6b2ee504b283347299d5789da4fed70916becebac006be0b4956feb459785c1c760629674f97f52ef7728694a188b5a7bf007582e7f032f2746254aafb8fa2dc9444f4694ff225439193e485cbe26de2f9980f6ee3e8b8d65054b7aa87551d57df3ba8d5ca63b41fafdac66f26de7c67255234de4a764a3f5de8e522ce23e879f1f383c18542def793c4871d4f014ec69227e8a2cc53d617f730c4727e699dd51d49ffc57ef2bcd1bded4bfb4ad781585c45e3a9530c1bc42dd7917f43c4bdfe7a5efba2a2561a7d2fbc29b902bbe998c8262a4a1b2d07d6a1a2e58714e83011d97fd036c8d8d5f1a770c112efe3ea086e72dc14dc219b1c74ea2ca447b4230bf7bcea40c5bc7b9780a8b39ee46e45437dfeda081ad7c8d35cf77a99b1bf63ee6bf8c2bc5f71f386180384a7ae200fe986d8963333b286e2c2bc73f099308ae7acb4dea5dc6243f18a0c9b6bb0933855deb4e847318867d06e377c6d01031851b2f780735a7c10fadf0c2f44baf6f1045c1e1b8743f438aea4f2b060e366e202b3f1f02a97192095b8747a1bdc560421f8a196cb8a09bc757683bf9a82f03b61198e56e63f427a5b51b15b4a3cc5fc4fbad75eab2f68944985008766990bce8782efc541c5589a266047de4b3951471b55bd1676846eddebcaecdce2b7fea7f20a69e1cf75b425f43d9abd780debc42e4c16943b5d019cd65947005adf02afd4e34e4c16952afcda6696729f90108fcff7dd804ef50ef1b8c9c9d4791649b8e53a188690471e4400d3b7d8dff40e5cb18a5a260057284bfce8572f712c3fc9d9a2df1700e0df0af98dc7a70cbae556fa446bb19a48e3be3cd2e3222a41ff3f55e8dd876d0969e7a0292d66f11287a2b742224613244559d3ec22836cc8114dad67090295799008e904857020565a48c9820087825a1f9b56ac7dc3b7628c752acb4e81b8d58a9fc778b3495c59b70e3b70c95c7c2b16ffa63e01096e10e468b1ce29b1f94181660d9e40fcb9fec04ef5f0273000c1b7427a6d387aae07045b3a167321c8b942651cd5dbb43b0b4ce44c429b86d97589a0fbe7944a384801be57ea2165134399e7b006974ec9a1fbf0c8f2521410a79a8e32901d5a62a734e840eff4c70ed041b7051d33e83a55353f982ed2fab5a82f76dc071941538e76ae6088a98bb4eb3fe487b190c991af7966a1c1b7628bca2e0719c609b44051dd311ee5f85690d2be51a71772848d25f5656096c892e4ba005587c190bebdc0540166d84fe6220461925a751bdfa180e26337b53d6d81f6dd8c3a0001df8a775265907ae2a4df3490e01081bbb7e2388af4daa000e5a103da0fbee6da5ae2bd1554cbdafcfe8e138a3ff73fb53168f97db8bb8d36c0e73361321ba07dfd3c017fc1b1835451d50595b709c502997c1df4328601eba667e1e0b795adc07dbf00d6c15a2d93f49ac81b7448333e4dadc06333525a1e010a2aaae78b992d37ab6f0572ee8310ab73bacc8797d05bf18c5c956d12539b85e9026b5c92a6a193870514456f5b8fe2d1485042cdc0edd4cccf462ebd1540e0be8b8a3e591eefd8841a06853167f4967341be1772ae9117bd159f4d0b032a44c2e122f37e23f45630d0689de229b2de640ba43d41437a2b3865ac11bc96d65e7279c0394e5dce848f8fabbef6ffc0f63f6ea77c9c4a8443886bc850bfb729b1c68fd12fd6006e6832bc154fb577df6625dfce7f4e1f31b66defe38ce3f382fbb2e48ba986ae15a62fb0a69fdff946c5c4d3c5d31d079da0a23d5a4e46438ba35595b306b2388a8dcfef1136071a21dfd32be60ccab4cc84ea388a8d1114c560ad32d54a3c27eb0d9a433a015b4d5a61e93458f386a6f62a94d3f84cdcde3729122bc6d6cd65881d8cc4a24b6f7cb59a9f3d985596fba7c1077c6121a91fe5377488f6921a0e037ec1c2f720be8ad9ed3ed90ab9edae6e3b24b357e812f58f436d8988be0c1da13a8deb751e21b112723311512ccb2065499dbb47414f1134b620e0b6267d0d3135e2baf69048d9594507a127eb4790b621eae7e1afcd4ce16c0dfec2528e81b1f93f2a2c8600cc2f581b2c660c2eef211767fc97ff54ba35c06115fb300b6e5dfe812c867852bfefbacc41a6e78eed9bcbb0d16925dd6f3436daf915c9e0cbd155204bdb4b3a6844299e15e8fd3d76976251d343b484e02438539ad6a8d5b865abb6aec07a583560bab50e28ca1bf725b995176d06c7176748ab8252585365c5d039b4297055ac7f204aeec9656a276ce2289191431a81125ad8960b2d505f7a67fd0ef74918f72de7b6b3d1fb2e7e50aad909bd008fba591e3189e803a26c10d0c2668160a9cd398d2d3f7e6e88cb248aa005937bcc2729ef1cef61734e5ae64632db3080a7f4e3da6d467080fa26818a513af8a5196f66bf741421b9201935680c72b8a8e7fd458b654a39dd6b728590972236c32e18c8eead20d906db4e2bd422f7d2940049d81284d8317de47effa096097cdd2194d160284f65c77933b297f5c3da3084b8b69a9efe15dc0e2e508a2d94f688b6a4cc88a98f13a029cfe0d6ffb7d4cff900626aab919c10552434de084f2c4c8a5a1759cfe412503895a98869fe3cef073d4c9813e864abc88b9e78ada742fe49502dec2daed8c4d5564060c2b2d5afb223965f31be783a7dd2ebb5f271604c6644219894462e76b2090e0df213bf90dcac2f48e46bbbefa48056dbe3b8a695268a7651b218887a5687ed353b3134205559f25e5f9760bad3b32def95c7f292f19d9eb35e79605a74e0aae5edf04e0ff458a5fec55a621ae4a1641682a31e3b194c79afb96ef503554d2ab3ff1dab7bab28a27cd72b9f472996a5c46c21890d7fc713678a25184eba64193352dd79aacace130d779f39ad8a5e4c9c19a2ac287030aa5d04e3d1d014cf2fea1d86ad04aab991c06d008e99cee0e5426d6591b40e953801f58e9e7dc8c8596b5ec64d7400ada3b429676f7af743ff6203f3a67b05822d4f6352943a6fc7ecd686f1ec8974913587cb36767fb93543a422aec1da4acac991b7f029a94384dde3ba5f443c4249bc063ed481ed0d3177b2c7830cce923a364b3460f00667557428524221d181deb0e38c57d9c9495961c58ed329ba1f0bea9bd3c54900f5a937fa73830a66257d7ad8710e8f9ecf2910b3cf9d8c9dc8821de72ae20545a608469eaa741bad49b808158cae77f69965b90b10202200769c56fae654ca066ed69bff57c92962ad5d177632a774fab5bafb8f21ebec033bd21b73162ad609ec03310b652ca7a1c25ee38e73a9ca7db7a9c2a602a5ec1328bbfa4e951d04bf30f9d881dfa33763cef97b2cca0b71ef84bb4bbf324b7d8aa1d54eae452831747b3af3c3b6fa0e0b6bbf54ca3b0bba3461c2d4244791ba12b4f2cda5e715afd29a01302fa24d052643584d5bc75c530dc910803298650f37f9876a617b4c31c68384666c9c800d034b5205b5c3e4beac49c899512d593d7504b8b345a47a884b088c90d267116004f08a107a8a690155635369b75a5529ae3e6624be6b9392b5a1052f4481c6366d7a301d44c0bfa340d35bb492a6237bf961f004de311e4da331da0ece036b2025d55e62836c5f5e791e5df50ba65cc9dc1ee5063fb8ec106e274f33d46519de7fe931044b08ffcc4621a3c6e7427ef8881950283d5dc5cc5b7053f5192a47deeb5218940f9ac1f0659c8d3e4881488ef04c801e95a01111567abe99516ab4601676f01ef9a0bab7f1b05deb1b3c0a22cc1797a0597f668f75c980bcb2abfe5b5baf93bcff9a17234ad01027bfdb1172bf30edb8e068edeac06e0ebba4c7f93bf33a3721c91f0482139519d1e98a7742635ef74f9b97ffad572b8383d1e5b7fbaea41c7dd56a67e30d0f37bf67affeaf48d923998a6d649b82d4f29b11e858872c3d6b7f1277469cc923ed3700b766cbb7d6618ec2ca0203219d1dd8eb4dd4e97a2c3103355b2464c95c241174cd96cc966e4e336058b308fffe11eb0fb9b57668769875c0ac90c113c3379df19c331e0326ccd1fbeeeea555bc4a609a7320283c3cd615946f70498cc96c7796e4b84aab900889554b98fb3cd470ba8c2a1020edac3256aef672b16f6ee3a6a6e8e10fc3df31abdcecc870b1408e106e07df806228f0196337f39df449717b59f12bae809c4f2631048cd6b3b9222b9b767428d3a8d117ffe3db5c7702abccd2c09d33b00a1c55a50d8d5d185b9657c5d1af98ee9bca838adc924377ffa075ddf1401f77385dcfb467930f90f1404fd1e715a26573551846dbf4ad090099aef2fd3f5f7573c2bacc7e65fd5c15a35076c6f5a7bd3e937dfaaf6abcb2c4030e99de518dca7c696589cbc86addc59a259b07987fb87d8dfdc7fb0c2e5d9f488b983ebd1d9791c58aaca9771f8ad36d8bd14b622a0556aaa0322f2743ebd4acb7fbe1036b9f83967224e9ca0cc6bfdba0774e24c429981f7e5449d7a4becbd4b79a495512c2499e28f054f057b76f5f4c52ef335fbef8ddc61fd216eccba7f17bec2aa327b778f8e1d64a5051dac91c9c90662d592744556bed884eabb1bc3980734c1620c0c425f6fd7d9f05cc2cd90ebb65e8213c5ed8d80bbe81fa9724cd022309e2882692026c0669a7006a502052309e76503dce1c2b4c26d03dfd030e28a484041e21c6b1f75941f3c9f5228371016708dd4c727d7c98a317294c58b5bb776b2a813f92bfe335a9e13d279128000e4c5b6b7c1193a2f267fa32c8da520f8adcf608faf39e9cd1fea326d7a8b7692e251e90054c8000b03929da501689438a893752c473578f997b5de956395651dd13bb2a94a9fddc30cf568e450660c114b47a36b002ca7b36b758a637cc57f690540ea51327e0599a91cf927943907dfa52f5fd475b365f1194564cd0afde5fa9a3587a9ea2ff9c93a36b8bee6a5afb8f670d8ec4b45513438de02febba6a978e8f6a0d273c02e816829b873bb8c8b3017bd07ba2eaf9cb5d849b82488f3cfcab8b375771e358220f1d052f30b4d289a03d4704af94a0c313c81a1fd84a09523dc1be52ba897e5cf32d0f650cffe497c1498c3e5e5a0c259763541d21842808d9437ca2c17df2e22671bec66bbe9c967b4a1e662e8257ab2a77967ec0ee6fc65de81e2dff4f38c80304159a4864ca1da948140d24711d82ccb2f12f28371e0aa03037f9cfaa9b304282e8150f1912ee0115ad67da2a8085a08d8398e2d70c0659b20bb1f83e88442fcd1bcd07dd030d94af88ca36a680e7de62ab4144fb3446ac0efff90674750149a7aaa4fba6ea069f2da7d725ad496f05327ee9a6f78b897c225f6ca0c4e478d81ef631d907505af1b0384b4613cd1d19b52f988aba6a7bf094bff1f458a702f0c58f9d222ccaf462680cc392b881fcc97a48bf35a2fb763eb9e2d7076f643b660a9cf2a467ef0f187e81610e0f06888831ea190f39e9d2e465f2e8b240cadfe9409084f0f28eac0d51fb6618845195ed1c9e82d1eb00685527267a7db6b454410489a7de4e65a1fd780cbb3a5122dee2093d03a2f93fa8a3b93196b2d02fa305aae16b0e1795ee3dc9273aed9ded7a0eb5eb8923018e5207e5f315c761b94ddeac57f40ed7547ee50bccdcc037500e7502fd80b34ab4facd7c57bd3646557a0b1ac6aae4394315efc00c98b123063cfe4ee06442f2abbc50c6dcb0636739d495b8633fb09532434d05e8f10be3f4cf1fc3153dd7892f7cb5298265cc03d40771562660c7bc48099a9e5dcf5b3f1f36e29f1efa141d13ba16622b70659e77e173f5810eeb91f08adeeaa08e0748a51c1b2108a0968bbb1736a2a4e97b1b278078ff1948d965b138f2d89800b83953ad6f3f2fd4f0ea990f5f68f55803059f6ec84c93dd507056d9400bcd5938d935241e305dd9cdc2563cf1b8cdc1ae1514820ca8236056770ed9d31766a53af320d5d8824a2197d5b6d9fce3da9de1f91fb34ba249e07e0346c0041391b60e8a8ecb9ddf921638f103627722c9e8d8abf60daf887fef82dad1c9b208b53275d1d09724439dda34f83e8b44d73c34cb0c5606494b281526eb1509bac1eaa51bdc89ce42847bb64b648ba691804845684481d38a9d549d25c3cbf054eb940c53266d8d52a01dc607cde99e82ff9c5b816b83cba852531c7522cd5cd26ffb0c80a0d7a0dbef1a1681162defd6dcdc5fb383c5b29fdc4056b8ac952f2c784375080e53ddb02152942ec0caab17f236a4f6d1a9d971f76e93b45f2117d1de710014999021dca489668ca44cfeeef0293d0c55a9e0d5d205734d948710f42870a8a3401690b1336906625d5090063a4a948a195bf89663079398d692e837dc3fb372118cbd44d3940a83c9d348199369a822d0b20ff755d8413436d6e8a845c2d98b32cd7358d9d1bc5371f842d62d219d1585af03741d310123bfc887e626c678f0e370214ba4848d86064e8d36f58ad2c71cc28101eaa0074b376b3f064de01287f3498ccfcd1a1207f3ff08493eaa5274ac64ae15b00c6b1bb280bbcd5ddb2ae23e0e4c3ef54776b64af34ea27128034b7275259afdec5e874543d6617e5d22eb08816a0ac5747e83f6c72fe0b2bc5e578747f38767beb910c3837f670b77ad2ac5a1e613acf8aa0342e4263fb19cf36a50d03a9d57b3adaa69cfa0c000e7a80e82db4bb89bfdc1d5aa44e0c21530511df646e5dc4bdd4fa27ab8ca467518fc0beea65fcb646b7ce81420220a1f65426df8f77adb5aa4b8295b1f7e689ca95790994fc3f463c8a8c3bbcf7b871fc947ab4adf194b88a355341d6ddd97e517366e779c9a7cd987720660218f82de8548e2cf1cc06183847df82ad8277c5db88d8dc38019c31af6321462144b4df57930dc3fcc3961dffd003e4eb89acbb19852c798ce62522c7ba6b89afeee093bcd110f39c1a8b33c50283c27ecc34485c62669c64fd8d1d364d2f8848e80e6a01e2fe9b0156609ecafaaeb102f7ec56b2013deb0b94f59281eb5af03f1a216e4ccdb6420ddf9fefbeab708807dd6e3895e4f74d013cd00d31d3fb3f2b8bf83e3f9aa1b4357fb5628155fbbfa158aba4eff450704373e6278d56d73554f3c99c2ebc9f5a97e91e2412cc9f6c85fe65aa72340865cc75d65792bf54835a3cc13f195450d97954321314c4a02e2aa40c861b14775548721cbd8a0ba51baf9a9e076512e91bb64bb97f6af72735a9c608fb8109a1fe96a71a5cb0f4ca6adad88bee5c8d109b1aad6a3ef2d20a9e7fbe9ec214b13cf5bcfbed06c5b8f95d2326149ad69ab1880e666fd496f3e79f49a6c5ff0006bcedc08b96006f39839b8be1179e7051c68540e2ed6dcc13a55b66da7f1d79983463a3e965127dceb21fcc3b5b36aa8b8e0b3f5af563172f2605c39e37f9cc5a9c98f0aea828608eb2db7321727d43811704d92158d8f77a9bd7e250ce1a0e6c982ce67d1c35c423025492fc94e7389f49a7f10dfdc1087ec6c0811fed701607400ef347776294a2d8a0aa5986acfde73e94b15036ca0e0d080f88cfac0667e0a9c4587f59aa527a1bb07bbc6e0c0a11ec61879916e7aa5c612600428742c204827cd9fbc00782ba0e408290e54e801930d09fa018e915e414fce70d76768623c6526219724091d5837bf0e6e17fb3e4685f89e5dc0aa7faea736601b32e5f62631c2fcc8746278cfc0cd7ddb1ec5df4bca714d1b8656c152dad14bfff5050076fb6ba3efe7c04fa5ef713b65f85a37172b2204cfcf8cbcfc039add332ff836a3cb0a873efd62f57f0e169d2d5e6508b3570fe2f5f239195b66e6017739b11a34c9d56113d7df5cabd5af55d9177ccafa216b66ac7e9557f5eda70f6d465d649757ed491997eebe909203a0629e7e25d6fcd52ae5574aadc2da44a3ac5117a9a25fcda7ae670d2bd03a9fbaec5277d020febdadb24d08d6d833408cc0c5d12032a37e675ce834d776d40d57cea308e7cd039350694721f50b6b79203ae0b467a72a23c3056303c78cf2a0e9f751a040391cd30a84a18bd2a6a97f4b7da8f75dd43241665f9cb7c8f61cd82d0f19ab2d75ea002f7dafbb0a95029e817bb00d22d67659e3c5069b017507f346229f4f2fa92b2e14a7195d99c03e734eb50f9d08f9e3451254f7c4a73f54a3e1ca7a7af89f9707cdcf07babbd2172b2e8aea11c1bbfa167fc51f82d0d8ee5dab03802b34718e757860b2df6100a187a4bdf2f8777ac4fff6d74dd4d9cc7c366351cc01ca416344934b10529e0e0a34485ee3f8bca7b8c15f404a7e2b9f11f88df0e010552fe76394da047dcdc504578f3e68475a494e7080b2e474a2512e374f32f1803346a5c2501f369e25c2773c7828a4aa2562a97d993806cd47356a0928774cf4f88532cc0497f131442e4372e659382ad5393c13509e870cdda9ceeccca25a1be7d0b34d7828bc2443e5657e2e4c0f39962660336ce737b7b860187bbe3b71129e91658802ca3bfdba06475bfb2f016552591f0c66172fe1bc70859fb6c9079e209e540730b8cfe22b7f7557eef53c9fd7d70b313c0cedf9dfa7c162d9cb20d7e4275608f01f3d0ae312706c65054b3d040cca6660f11d08942fc90e8ab67cdc18619060c57f2be085979804cad15133ba6533f93fdda4f982ad1ff0a9c7d0552142f8b16dd6207080fb8c82803f38ba5fecf13f39ac984a983176429b545f39f4452d980764b47004ffe470ce572432d1a094689883b384891a7e39bc18fe7aea439900a16b418fb23c7bd1d7480ddf3a1824a94ce12d062fc9b967868211fbc87ef5042888894ac6a9a3ceef1ac24270e7dab138906aebd0d38a3c47406ea690e99c778d48c0a890451e51d30218e2b1d804c15b62964d0ac9bfc28c0161ba3d491c00eec93c9921d675d7275845ac3bb058405c07ba2087f483a6d7bb30ea87021c89dd14f648f3c022735f178eb346ce8be9ce038bdabf1946ed97c03c1ffc1dbf1ff44a7579202333dc3ae044abecc518799da6d30ea3b6b2aa1e23ed4530a0ece81842cb3073a738f69e64674c571750309774244679e4415a8a5826bdd9858282abbda67976d6e4977c5f29b891d5d661ab4dd506298e1d4742a85e7eec10463d935f9f8d7298cb9615a3e78b031e1ef75db852f34d15a7b032aa38c931c17d3ad575ab9ec6e4c5dfcdbec2be71e54d15b46b3787fb0dc24190dc46fc2c4a5c2c483026755cae5aaaf5bfc3fa154b21384dda09a5b28383da1feffbd88429022c5c96388cb935149f8a437b71606e89392c353487ed9a7f73759a96616da95ca1a53aec5a25b9778d50af4f6f9a8a114ec547c6a2341415bc508c357841b00d0488e046e0dc1f963c2b87fcb6a93861ddd24935df8de5f1d25e2422c77f4f55438bc4c5d7dad6a603baedd3a7a2cc86ed55729a9a0adbc87d0ca5b03218f1a9f99a2476f90ae63a0a1d8b1ce58d8d583faf8f15b4f9b2c139e811ed5b4b31dbe08759e9e370e684dc02250218698e3ee340be73f13f3957ca9b4f5afcaaf0a4ab4a0170045735ce5ba5ad7b4cc49db4804c281bb2d263aecebac60bd090d94a6ea64f86c62c5d97c228ec653eb959d547f03beb97e587febae1b0a8c7b7e98839bcbed10488b8797643d6f714634fdf28379f2c4d6714ac413a01d4ad47e9479fec39d4edb827b2989acb1b530dfc01d1ee7fe3a0f813af3c146fe7f35c4c6b0c6743d2e2d9eea31cd72b0f00d397cf982e173ac03e8f113937be47b29965a174342a859aec5dff4e266a81ded0db4f6a8f6ecb65110a4e947dac08bad823551b77509407c402122c857b9e3e648ed651137753b7e6fe66ee07928218b9ea19333e1d5c370e44294834254d167bf617294132346dd160e55e05cfcee60425969d4df051b2970181d4e69aaba23211488c046daa5849ecd305539b377925f787c6b3a52fe6e6c539391b7e5bdb3abfe9c6132f7abbd1583e07d2b7a9c574f971e9d231b1136183d421a014d1a5426148377ce219741d546407a134df26860e216820a050e4188c239d7bcad6c2d947e7cdbbc5f9e054bc91d8b5ef983838ff4230a3b4e0ef7ed0046a4102f207eeb1f720c1cfe6803d2a7a017643136b46114c5426e7427d40ae11d5770063da43795c1b073df11e27d40d64d78370aed02f0380e3b66f22d92c09f4dfd88168dc77bc9b41321eb5b787f8a1876a0b6e05643af6256025b406141c9ed006ca2017a40d5a8ca5c39563200f020bc3b14359a78bcfd805c78230b1e5031428198b5eafd5e9a7ef6e8fe12504a97d931cc90ebf4bf6a0308e018971ba713a03fab50301eaa26c2b11c60303103560fc5cef841af57b49104379833868452f183672772de361fd7a9353b7715b6e7043a7411fd0003d880f28262bd3343fbaef4b77dcf707504468a2ef5b5067906714b721aaa6fafc22f118a23e04c995c13292ab8dffdca1e59ba604406e28bf91d74b7df0041076fafb611fb1b659c6da6d9267c3cd5adcf578dce213668c61d2032a331495c7e0523b4b27fb5dbd591557e7520fd87adc15a5eebd50c955b1eec8f768f1d5c15e9a4033e265ae6aee8a12e9962eb6f8078cb0282f992397f7d1735b576c1377f5c5375782ea032069f516a5535344814a4d25ee4e52b4ee76b87bc036891c7e86e0a37e815d00d6c9c44bc467933410de1a7a19cb595280fc4b1b2b48481d45849d690e998484bacc74f0466707112d2e63b690e9da0256547d111a2a895b3161ac0aed9dbd1aba110605f7774e869abc6019ea0708838aa36cdc3542b02f804705ede5ceaa725222a3cc24656c0230554596485b12d5661326f1a684b8c08202ca7d886fa6f4bc5b82e0f7e5cbf065457a862184a2d4571c726652a189e1e5801574f51f676686b450960be688ccb56ad1bce0e97d57b42a4df60b513968a066be55801605b1d9988d99bb2e4b1d49577634624a263fbf5698b26d416172d452c92f5afc61de2f4faaf10fcb9504054d728594aa0f12d3c02acf39e808bd667e82bf091864f71fdb317a9e731421c37a317d99411e8618e50a4ab794f73fddcf298c945916d28458ab6a98e565d524f99d5f20e74cfb1cf0d1aa9a2a8b413c76c00a0493c0d2fb3a8973d6c092ad1bb9e7b9839a9682a63a41cbc23eb3fd65aac2de640ee427cc291c000c36850b244e74f9747382516c95c8188b5bb6f712ab7674326467e2b0e92c19fb7fbac394ca7263fddebe8677b8fd902ba883920d589f238e92f9f01d67ce9b35049fcaccfe4aa8d6a0bf8fe6166acf39bb5ac9b6d2d60eb18f5ec7f0ff6736841bfae9a06ad50f5c39f40385eead17a30e533da6d26bd9c4b8be11a3e4013798cac1d6873384fada0711720a812caa1bde1b914a4fddd5258ada7d9f33a7899f7ffec64c6b0b742b1efe67d2bd7dfd41e7c2669861906172f1fe25feb8e857f0882dab7a282d7a6f55bdbabb103a36f9f3fb13300ddfccf15231a2f22227d5179ebf762ce3f71c1018e142b3d057b731320e54efa3eacad4a038a94e0b0c59e860736af3a14ff9e56451f3cbeff270111c819450062dc83f218c9962a437399059b143e67ec285b179830a1828b242b83311723757af77c4f4f1a37a6627d2bd560df8ac218315783632e6157f5b44365dde50dfed5d43b4dbe9fb3c1a233212116662b2b22fa812751dece78cf93373e3fd0b47e799e5d8b3e1dd0c1ae43be59771f19ee016f918afcf967be97bfb2e4af0985b5e4c59b3f40d3f6a3fc333175da7d889623fa707e19458f8701a7202a5d4231a7addeaf767cc219164279b34ec185b1d1c1376b0c228ca9eccfac4fa612764c462207d04f90aa08b89c2a66d6a4da4dd8501638ece99443dfb6a14d686aec3bcec7f2bd80763fd0d3c8f62220ff0387c70aae5fbd9d6da9d50e12a371b7c8bd47e2a8c484bb60772d9c62d2aa8be31bbce998be61f67bfa0bbed0253f212fc7050f16649269d9df1d00ca99d83e34b7652a5a401869f98207735da31eed48ad2acf04847e2a47fa000e5ac57e80c044d95daf93046bda49021b14472c51da853d9c9bd15c364cc0fb87defc871ed32bcb66fdb57b51089b5e092f5833c96014b2703a7408d61e21058e72ca728ae79e33c8e0515e1b6757f52c2c190a08b1b7b40d3828656a6ea14b4d1eb80e244c639d90f6fb9a0c331964689cfd882d328c1aa30bc1e5b566f365c0968e72f010a74614ac9fe89fc31f9ae7fd0c09e4da7e5480617213be774709fe9e43e448a0bc73acbd81fe382d82c07681156815544c247bae40c842a7fd73ab8e93c4f7570aa26089d8c672930485b9089eb7549106a87f6944a9141e822bb173df6d8bebbfdee8b9cd0222402ec21841ef22ded97a4e900bcefe90ccce72803c54f08fdb77f296296605482a40426842e820eae1eb34e5270e161cca9732d1d016f07f1eef3dafbde07d8a51e1d1d784c908bd2bd0b111081f47ae27ff87ae05ded4ca8b4074c087d6eb6bed3440b9382f51b9c34b6eb7afb806215a9195e5439431794470fcb74ae88bfcc1f8f71b54b518a8cd6c0a08ba87e58fdd77aca9f2b7116b24a652ec435cd3582b2afa4b601688476aca7bbf4ba8d6a93aa825bd88eb5480cf5317453fad2628d4632ad232b1cf14e9176d40c3c0d9453e5d27427a6ed31118b3f5aea57b4c08c9ddf8ce03a6918de8db862fc5fa4ebda0073932f9e255c4d98faf07486990c93f8a3c50ab80ff39f3ba432bb98d4ecb91652a8cb3a58988e667bdfbef7f6d65fbb79127d2fd4f7f34c0f5429497afabd60344fa410f65d232c3986bfbac1072d984b5dac82eb8661826ed1ab218a22128abf87d2679e60fcdf600ac9eefb8a9e66e3560084f80e8c684c4d91a99fcfb62f03548702faa5e5535e6098cd3807adc791e31577288e6763cbb98f521d34c6669d6d3175278d6632d5da3ed5883f23345502cc4acc055de922e8459d7cfc259a0782e5bf31cf28bc1a012e5043452b26e7bb813fb6245ebb318ffe771311111121524a29a5943239054805f7042b44fe2020151fcf478a8e0767a3c96042f0f33a6ed332121de3045044210a51b081135e5e5e5c906dbdf514c059475b53aaa5608bb8f75a4b2dd652c8196bbbb74d82cb65c17a638df5def4a79e409e233853d1624d2d80f5e79a4b60add54b68250880626df7b6b525c6ca1553bcb28516acbdf87a4472c8e3f92d8b7ca4d8342ecb326dd33e11100cbf6ddbb88efb32c75d0404c3afebbaaeeb743a5f7973be4bf8602df179fb1e2c37bb9f8fe82140cea28b5229140a659e71fedc6927bc1c92c1643e118d66c3e17030ba09219fb75e888889e5912559afc3f12f6b3f9d8eb51f087e30df7dfe60e54fc6601886980ce6cb5fe8692584bc90e761f2ce344dd36834733335d6f362db4603e1a3e2f3a1f1b919dd84fcc91fece1b37fa4e87870369a0c26043fafe3362ddb2dc448a998d7a05a6bad75ce39e7d1be66cd53091a0902c01607d65a2f86cffb78f5bcbb6dded7d1f979dcf7799ee729c1799c9779d306dc86d3703a705d14dce9ebbc0e47c792acfd5039731b0cc3d0fb8e107a1a099e6e02b351de6732dee7e92368bef73e4f6b9b353360a148d8b20927b89ec56b8a027c79797979797979797979797979797979797979797979d15eb417ed457bd15eb4cdf2a26d166db3e020037f7d1957c6a5d5cefbb1148095ebdf1e01fbb9d7bffdf6db1303ed9e1b7aedf3b3a71b03343cc97d8b001d202ea08ef06bc66a0d0195014b033310e7482d739f640fb14ec1fe227be001d983111db28755ef7013e4dfc03b431de507f97ce10b9ca88afea42b8d13a949dc5acca0296f2e2365e94fa935d451d664963acaaf1175a8a3fc9bbfd4444ff6e4e3f3cccff2f0fd1f3cfc143cf31d8e79d0fb8d7b34877bb407efb26d9b917f9cae19f664ba7ade88365cd101b08a3157b30f1f01d987a1cdf806b79f614f3cfab304d89330cc321d863f553a1bffb0434d1d9a290f732473f62340efeba7010ef73535657e7f0be6c3bf9ae8c944cf7d0df5213f35e59c81e879a700b47d8689723fff01e609e581fa00847c456a9a23f9b511c0fd2135759e19e0cb3055300f3e8dec3334c0c7fcecf026d2184223ce10bef63432a2478b3430a24787e057c07e267a3402c00fc50ad407458f1665982a5365cf404f96943f43f5fc5aaae7dff2735d7e2f9b2c292760461de5cfdc0ef5822ed866294c112a4d52c5e2a529d5d2c7220df4fb4845cfd37a7ba8fe1381871d34e1f6cb39da4b3b71b827f89594bfb345fb60b71b8b22f464aad8dbc7ef3098a88c24265994818422ccd1eca20c2434315bccbb92e964a534f6e6ab73ed72b6ed863336e2b54dcbc43bee00d6ef64797b08802570fbdeba24054c811716e37badb5d75aabd9d9adbd18df9c6dbd37c7e96636873aaa358c9a6effb600b438cf0c6cb55aae0e59da13fc931996544b2590e790ed3db50ed5e4defdd34e18fbad0e19b7e1e660bbc7694b0b35d517f577b7f26559d5340b72daf2edffad5bf144ca62b76e00dce52a9d1cc7d9ccdbdedadfb4fd36e4a04335999d76dcad645793dddbcd197bb7766bb7f0db52a974f553fb7782f4e4d56d0459679df50babdc4a3150ea5297baa4e224afb5d65e9d842380f3c7a79506b88534e96f51a2020b232423128b1522be424803402c89849458d89a7fbc08a72fd70abd6205c97592c0e97eb0f9819759c1823412f1161f868f69111209c96446385521e1237caaa8522cda09558ed556a5529a635428793c1f9291152c482311070484a3221402029588708f077989d3551886980c260c31184c46930163b08f8f8cbc9dcee5012693c968361acd3f16a49188afe87452844244f65e21ea24e8d297b450a1b46d1a9291152c482311df6c383f7201a8fa9df867e3ab81f518810e7a1d83cf345140310089738ee0b72af867c2c0402631f5d19261c1e1761b96890c77f5fa189049d3c7cfd4e9e367ca983e5a4615b1511f4126ccf8993e5a7afdfd99ec73e216397d050901a32ddd58e6acbf4d6c5fd417f531d65ae79ce9de3b6fadbb95fdba5bd94168bdd56eb716cc37539665d953fa74ef6dda58507364a374de39cfad256fade9d7ba157d7376e93a65492047450d04386a5409dbe1c53c27aac9b8354aa32c29ef1fb8be514955a3605bcba8dd1ce76b03cc7982196bd4c56137162a6e2c738487fcf6ebc6d2b2e2c662493fcc0eebbaabb377bfab33e5b66b8e037fc6e2d6524957dc5844008e1eacd7f760f6a4b371f7625b69d67b6a1bd779738ed0c7bca8c710b6baf7054bba25813ff28ee5acf5ec67b52d86a61e00710aabd349c93216cb0519fdfe77f0373d69f542b193a2011fee563a0ef038a8016de87773dde6d0efa5773ce9f5b3ceb6c688d1af385fda035b6ca26c7b03e0684b5bb24c14fa3a762fb035008edbebd52b0fe068cb587963991568e9eb79b9dae9dbe94fbf2106daef6f9ac39deee44e637c2f798f007100b94ebf25c1716b8fe374ce29d2401f7fb624a85ddf8f5bebe653dcb55c188d63ca3aaa71bab36f19b7e30e9df2baf90469e7b46aaa713b532373a3bea8eff14caabee038edddd4332819b46faa3ad2ba19d392c616ea1e75f8ec65f7ba9bf13b72f52de35bff380ecfcb34ced5d1a6e174ff38c8b339525fe35cee1fc7b1bdc7eb8b4dd45ad7386d2083ca6ca057d48d6aa2ab8910d564cc6c608429ffb3711bb7692e43eb77f66ddef8c04e8666c92b6eaaf14bb554b4df4ce686d61954b782297b00c74dd5eb88297bfd1c948872a2ccfa55739a9c7eb2a975b6d28fa7bf7f70b1ddf744d15f35e5a3b8332bccf1c076afa5f3d2f976dce3a5e2eec0eb15c30ab517679d3181d52bd62fcdc43eed1b7ac7a96e53afdb46af5ad37bb2514d66127dbbd87544e7dffd77765ad7605f039845e854dc1cc727baa8a4ba5d5eaa23cabd9eac6fb780b49e5aa74b63b4fda6398b0370bb5d8b2c561305cc5ebf34ece334bfa0e64ffb7173f144af1c7925f729b5e34635c56ebc2cb9e85bed56ae58837d6508d857d7228b7134aa26f653477da39da5f4312c9a35b1cdd0fcfc3b4c714e7106fb59a4913d0d4df4dcfd3ba8d0394b192f59d2bcb66adbf7195a0272d63e8b9e5b81ec2d4dc9db97b6a753bcda0553f2244b1d8c4fb0b51f75b2b673e370c9086ed35680b59d6919df9c2be0edbd7392f4cdfb67ce3bcbb6cef596795b92ce1a3c0108113ce1871038a107fa89960f622f04c0051518314c4e504a5e90b848e92be8165ac050620106959e228e60a9a454225964a9d44243c108326495a09c98bc207961c4c363a4e322c50b2b9458f8f8a81f240c4e556290c0202159293289968764b144a251a6ccc432ae4c2b43ae58c042c58214e6000078faca3a52410515025022111f2449605085618821592cf20517601011d162c04039317941b262c5dedd8992124c2693d1902c56490ac5324756acf8101421afd2de7b720dc307e0051760e03815316094a09c98bc200181405cfc0a2c70ce61286331f18bc5485ad840bff027262f485ef0f0e8b848f1c20a2c943e3e3e3431b8470c06f78095708f16eaf34125d1f2902c168ae841922eb42059244996946cdb66c2619194646a684adca3e5da6cea862c113d48b2458b1625fea9e852098361955a68019f98bc2029e1b8ce8557b2428beffb120b2592afff0166589a444f15b705cfb0b8c7644962c6884ae252b4682bd451ddb6ba9125d1832449481649b2582516f6ae2b902c9245b2c812b254123d9268217a902409c9080b1500401a8944424201a68b9a3fda172cfcd1c66e0733dd371cb3e21822eaa87ec8311812d3eaf531afd17b792fefc55b3415312e180d061be2fb6aedf7b65b013f033fe335d8d80672ce8b73b22cfb144b290d1b9f3de7cb713e95c7441da550f4438ef14ad3de980d86a3c170b87ae3bdbf0cf38d5be78559460233ccf76519f759b7b27dd6ad709aa66ddcf665dcba14d1eb6742aaeda8a4aac1ec7f5f9f7e205246edd9c67173cedf26c8a9d6dba9d78d08975e3fd4601996e238515f70621c0047efe5bd98a826dcb643834892e3ba155af6d2a3d37a59dfb03846740ed9eb639cb8d13f9407b31f8bf722355835a138dc8ec3f55e7564031c3598b6e37e119c18a7dccf81719cf3da20e0bc384cd491fd4ab9ec9b42a0fdfb8cdbe7bcaac9f6f5394c6ccf895d4e3b053f564fa91858b6b32cfbbe4cfcde7632bc9e813f62605b267a2f10494164cf440b7aaf5eff8228a5620dd963f55ac2e68f9c06abddd4b6973d8e8de3d09a387e3a1dc9b7d3111d8d9c58f11665c0d2f9b5d6f95faa8a378028adc136432388f5a1b3d2b1eae037cdcd4e06fefd97efc79d0c15fd6a1d7cfaa75ff14bcd9127809cd844c97ef74cfc54ba956235271603a6a98902d2a90addea73a280fac8897d6250d1af8a0eea3706907ec53947be1588f5a534c699eedf2ad766a5d9576b5fe33850adbf542dc207d287d3e905db0c8d20ab2cbb4180593fdd1995f3ae13658f17a5bf529c694687d0eb539ee99f57d37e736d7ba2ee7e51f4a2f46b948cacd3ed895ec78b92b13b15331f00470f0a757fc85986f4a07acd202b0d031080f85a9df16fd3da9b73de5aeb6c5300765194db2e6baf5edf6a186f8b2dc791bde6a657c96ed6b26b338731eed9e6dfba6db5c61993db92b6a533bed65a9b51388ebc6bd8bc73b6f85a8cafd56ca5f3de0c0a6c645863daade06cb3b44c8cf10368a8af35fe8d3fc318e32ec3b8c3df618c1fbf06638c7196699f52eb7dbd1a8300b74ca4a17ef69bc669af956735cbf5e956c5fa29f67ede5eab19beb69e3aaef4e4b2500cd093ee294aed54d2a8755cbb0ed659c515ffad2618ebac62dc3dc65e877158b38a71749f757877a0e25ab38a6bcd328e1333cb0b40dab35ac35a2bd7fa6bc5db8fe2ab53acfd659928f877c777d3be6e25cb798f355c7cadbd5da5b3f3aab8d58cc8e901bad569b04f7f824024e8419f521f24d2a0b71b297b031044557b44add5c60975fabe1cdfea5bd14f8895ffcd72f6089073ef05fd86f13fee56408f4f967cf1b3e1f109f1a93ed5973ae243e58c2935dd9858df818165cd698c131d530e20f71b6814b15e5f773330304bfa6ca0eae8f3b3fb4e2b9edff4b78138ed1b08a73d3f1647ddea58452f6ac55b223a08bde2671a23d03fd3c8718d1f2d44f4fa1b08cf7dd68ea7d43d29c49388b2a4fa013281705c39107e3b66a5d268660599349f2181f0da45de3204c86be055c4ffe07ee4b8402a50ca9240a6ee670599ba8ebb441eb2a3bea8ff3c2486f9a85b1c88f6e7b3d70e6403610e84cf9e01993a90c87938ed1a263a0ca67533382d4bf2fcc85d1f104efbb66ddb16865678428a080971e9212b4be23a267ff5ca5fdce5712288ef0ec2756fe9991f3f5a32cfb9ab8e322a7ee42e0fc677efad410f027990c70784db1efef8d1d25122ff4e9654419e033db7e3c5518755ff07f1f10601823ec5826ad02d3124564721b03a0a3142481902ebf5454cd5640c314248594da0a826205f5f84a59afcd71769e1ff5f3fc40813657e3f824cbd823f72d717b613ebf5e706b5b9514df6de1bd4dd586f5013256f80d8a0ee26c706b5d9a036406c82d8dcd8a036a8cd6ae3b2296293daa8a8a652515badbd375f6cb5dd17db0daa2bbb27ba970e8aaeb42739e7bc4392566dc97b73bdd8e69c73cef986e42624c3234224c22472ce3924c324aac90e497b92f70e495748be2b24efc69a9c28393c22246fa82324c3900c8f0891089308c9900c5f212cdc11b64217b5d5da7bf3c556db7db10d494da5a9405b8196435361d5ee4a5ab52defcdf5624bba70a82bc356af324c95d0a92bbb27ba970e8ad9955dd9955dd9955d7937d639774f74e5f56a74e544b1bd2bbb27ba970e8aaeec4aefe4a1bc1b1e8b67b2d4566befcd175b6df7c5b62bb32b2b9197c83af0d654b46aabba37d78b3595cda2bda9a6f258ba0c5345e4d2549a0ab4156839a6a6d2542a4da5a95229180c0683c1609aea6eac35d544c99a0a34d5d58a50edd7549a0ab41568393495a6d2581aa925a1ad34974c6db5f6de7cb1d5765f6c3555e814f221f481908dd009db9d73ce39e79c73ce39e79c73ce39e79c73ce39e79c73ce56ffde34bbb455af3f55de6432b9b22b2b9197c83a66766557766557769565599665e9ba1beb9c5d1305ef9b77e4ecca4ae425b28eeccaae1ccb658622bfcab22ccbb2b4d4566befcd175b6df7c536bb442e9112a225443a442e6c43275a75be17df9b2fb66f7a130b076076eddd8185ddde9d7073391ebbb24b53dd9c4aa5529a4a5375a585c16030180cd6955d199215af56ab554886e406d581759ae81ca1b3837660f6e49665d981951d58d981951d58d9d9a0361f97baadfeb84c94ec325170be9f243e2efbb98fcb27061f197c8af8b87c5c3ead8feba3e3c3fa907b874e211f421f08d998acd089153ab158b0d089864ef6e4ee0d82a113eb592c91ab63b37e37d6399f260ade372444e834516ce742a7900fa10f5018f7eb876c54931d3a895ca15348155a858808a142a9cca39f523f442e9112a2253617e9d8f4452e7b724d57e412b74845ae3bba2e96b46dab2fce7697443151297a8976e6ed274fa6e7e17ba02d6ad411cff834d913bbc1ce8fdef4a62e726d22d744c93add55779b95982817e33b8a767cb65de49a28b5d71729215a82c2c05f5fa46313b9b41fbfc2308aa010b9443a44ae8942f7fed0a9d7cfa99cca29bbca29979c62e514ccf582c160315809b32c306b82f5fa78555378e582572cbc22f1aa855734b64b90a553d65359512e2c168b64b5582ed6cbc4b24de0a983fa494d26b2355bad576bc25a97671a6df199ce3cbc02e92e80fd1b68147ddf9761aa3cc70270ec7c5c601365f68f8b3dd1f3e3c2ea758f4eb602118490c566abe7c8b6d93e9d23f5330fd511d702700453bd560e548d23eaa2fdb62798d7c4d186150d168d54a73484e89486aa53eeb73d099f13471aabe786f810e8624f4017975e7f75438e790dcf80bf659e7651a86070641e546d1d84d913b005c27afdac5f95b59befcc6dae75d5565952ade24efdd0658f23ec78866338d8b2571c41b1d5ebcf50bb3ac8c1551d6d17308788a3fb940aa6ec0998ea63697eafae2950da4e46d7f1fef1aa40daeb4e91001c3954aafbfbdc6639548a1dbfb3bb1d3954aa7eb57f35d61365f690c55a80eeb05d6e0894762b1404458b83dfee36918861f71bb83eeb88da17364096ad6bf60b5eae6508fb1a78de3204572b59764a4d6a72b3af178caa5c4e35cf986e3aeba5f67aa30e77076bb51229e6a420b9691b95342ba6f56138a85e5179ab514715574b27c65a7be30e7d33757daa54d43900c7cd7432f514168760850448a97e3ae7b42e157862099bc2a804afb6f52c543300002000d316000018140a8a8422511824519ccd1914800d638e486464408f8b63510ac3280cc220838031860062083004285343423601303e2e304b32a4585c59d7cc51a282d1bac5a735c2ee7f1c1106e629a4a8d531de8594183ac812cef90f117c9b57ab7bd19dc2a19c26aaf7c29b7bc7eb64d6dfeabb65eec711b8e75083390a5dd9ddbdb8a54fc24e933c4067bc524a9d56e7e303dbd2bc7a683518156d60329176de9171042958abebbb728355795394cb6a79a7b0d003a3d5f6e45c3242087f57319cb9846fe05dad016e995d39d206522d7a4f0f63605abd1080c4f8e630142a08c1b64f91af2bad6db0c9b475faaec674da52a9a8eb24641deace72833dad2603acf4b9eaac3cbb5ffdfa9aef231e9aa6bbff0a72d130867e239b491eefd5be89e5c183511638f326cec2caa308c245294cb0fc18fc8bb9bc668dc6487e0aeb5fdd677cdeece4f46ac711a06eb221682745108f240529c00b0acaecd774a42f7b0eff0235d05faf8e1577f0f207baa19439572c07cd14a64caf4bf1595c8ab32990fa931779cb1c561ee0c6f38207a41e3c9dec9dffa58287f77fefd2ae9d480a26e31326d6aee08a780eacf6d60a6ad9df070e20c213f55d17557ba792900eeb71c332f91a5d1d462cc0b22fde34e91dea5177013e295d58f7833addfe3560826f388102a632efd988394d38118699343c4c4218583e3ac1c7abcd8c081e95369d4a44a250f9a869c0604aefce4f0af91021f1a926f375eff95a21e9aa56373b608691c51d17a67b291d8ce34993e9a734474f4c67119a9185fdd50c45360e18377fb62d2857590133ce62c6dfd175efed7d0c2954c04cee22f66f0afb4c5954e6aa57142d4bc0e413930ba64aa240b9ca2ced86cc67c74a0654033d5b4be33658ca0a042aaa6b8fbafab55feee1561c872e073a2f1861a0e78cfee98425494d36b2896a43e5ea170266d763606ce615e517bfee6a451304b54df72a3e3e433bed9a8af79282d82fec54fc8e6a037963eee62060609e8805ec83012dc4ac763eee154791cccb05d5c9dc31f98f19f41c23bd751de72b0626540d11cde1f3c0540802959fb0a92b198178c43a48097d401cf6218d0d239485570255ab2af7e252505c742fd1440def016b0fe44d2c114ce710f3e7e7ef33702dfeb4fa204a4287f61cf86fc6f54340ce0055f2891c68baa43b7de75d6fc72e25a1ef5ad799b7936900ecd1a091259576b8417ca2e0400ecb330bf0c45f01a11035e4bde240940f3deb726abb472ac2f09b3dbaae9afa44a9e910d1f65f1312033b1d16333bdbcf1eb4a959468f2afb7a0eb276dbf42ac3bf84580625ddb6843704c3a9754a2f19e81eb196fa28565073543b46a5c8421467c5074d20c96b5dfa24dc0d6a5beb2e58b2a28da92f89d1a3094fe5ee112d123c335dceb5eea37aa77d26647d6c9abfa0a3c77bcfcb6cdab59dcaf2b46e2c597c7101ea3dd2646e4a56a637a5a3258ab8a0491ca1335e29a582d6f5a382ed6adc76b9c254e6c1ad37389b3f4590059a468f55032bcf672dc82c97360ae90630b4ce3e4d5c30a90843caaacaf2fc12ff232bc000d51609d91c832bcc45686da936b0000f60383bdb7f447c6e69b7890d53cdd1779d29f2b6cba61299215d53f38838d8d03a2f13327deb66cb9c3be7e116b7fffcf2cbacf3613924bd0cc1392593bcf4fb205ffbb162f07bdd185a82483b4cf589b7ec03d016240751cc72cde305ca085541d1d209f017737b9d1a9accf12de07798b78c209b1d9b1de6ec2840c9e9256a2745108f200529c009cbea4a4853d9c9b3ffa1bc3cbce79be13a46478960dba9b6a55a15574176e9de5c877d06c8ad23a8a21c137d99f2d12e74200dbf3024e51104d94afa3dea3b4e7fc43e6a3561a7c8457a306c9fe815bda42928e997c8b36dffe83eea15724713cba07a912634918a5a1590838ae5d30fe79885b3df70aa92c84154fb7ba5dfe8d7aa1e3ea5c9ffaa1e54fc3aaadcf0d79833504ae93ddb1c151f4110ec5018be4b4f52709ad1c1b2420396a7d0289028bcbeeb043b9505656f8306aad1ded45965cf2a0eeb4abed9266ff08673761758e55b3d623575acad0ec27cca67b7125540228a4322e935ef412bde8266d7e0a4fe06aff547eca2346c70caa9ecf31e950e0055b2cbdd58e281d359488e05ba69f06ad170d26a26b8bc45af5198f5909a5d6f64bbe2c5a497ccca76fbea32f1f516c3a707a331bf5f7ecca0a0adb37bb3629b8e7a454ab324867182f6c976d17b54cb41103ebbd1d0143969fc97c3e0bcbb5156e78133bbf66bf282494518a6dccacc6d6b14422fe601d0349c85e225e7715fe26d2783ce9cfd4792b8183ffe9e08df5bda69b681d463ec5d8715df86e9a9f66e4877d63c260e3666f76558bb039100320fb81080f032fd2346defb434ae44763373d12420f3148c68d1c4bda19641b7312f2d32cc6422a48816dd15e081f218ab6721526af444819a6aad17587bc09718b8dfeca072c8d3a4c6cec731d8c148e6b17dfe70274c68e36ce5b010fd518cc501bf3c27ce3f41971b45a8865666a2352741fe815b9240954429c08ca6ebff836ea057a23136b1a707c27eb3471a710251df0641fea15b1a790455157bd094d7c82cea9425ce42434f687ce588adad9af704fc9590945974c66685838d86b7238f17d84565fe2e07b045749e88ddbc5357f955c096d57bc7f374be88a5799dbf3c27e077a796566a49da9ad019a8a711492f43a2fef55c7ee4dfd5e3cc4a2c340357b36bba9467a927fd6302b8eac03f9be1f071c95aa2393022ca4dbb773c49ad4a75883d651db2995168b7fde131f34814d9e02cc4f0adda0b6298005417c6d63ea4b6a7c60c283b91f5f8b64cff59d730a304df992d6b3c2d96acc56bd47fc704d7d36f2eb1eb41b72ffc94a8d5f5bafbf19eba6be32ba7a0619147791e691def0fc3a1d2a45b99b42aedd986c11ca859402b46d0c220eabdcf21503424f2980155732658d07b96898376f0a169f314795e57e4dd6ff891381f923207f5dca0d3305000a64cd1f0a744ab90182f2f00a0073079faf88c79dd668db44fa724ed769e86193a9a8b977c8322eed223b1b14e0c89805b02844091fb889858032a034f4ced2fb865e5800391bcba85b064f628fe84cdde1cf0df162962f0b408a18b53f4865457feaa72cef382248552563769857c1f8ff88e5e39315560241fd24d0e3f318a134cd4e4e16c07204a8ff5c9ebe930b884792821460ae6871e79ccda9aad916a0fd557d81d52831b385ceb2ec9c5fbc333120b0141ac2aeb4caa355ba056816544f179c63829545e2ec97c6a9519636adf863a74bd020877bc3741480bd6e7dd45111dbaeb12e370578ec59517da777ce371560e4ae905ddbf58e2f0d60f42a897dd379273f013cf2ae88b6d13a4effc49f18f27b8244460134fe1add9d781c8b2c8e3b956cd18f5016694dab874d85797c6b578b595dde626127640de3acf3b225b07f8e8917aea8f635df05ca4af0993ebb19ee202983cf4587cf39169fed1d9fed4dfe5bbaeb99aae36c8ec7764135689817af0912bd583e42e086038cea792f6f32b242b1be439069588306be98e471db378b0e30277d74ca0e2b46b74c46608f1991dd46638cbdebb505ce3f020f5773adf5c4ae5d989f1acc5d55d755d223f0d72bcd7e2ea14be22128bd56b3505e6b05ebf09f13c065ad9cedab654b871292bf1e69e7232702f25140fee619e123f9d1439abc96403fcaf38452ad6d02599bb617bbd138906dbc7e381b4ad7903136b4d8894ecb138b522cde9987cca9c1864f155f33958c9a3af4218649854fdb4332394cf3195e21c55b7eec770d8ea8dc1c9fee903c64ba4c84f8cef6d28566922643a6696ff9f5a298698623c1a77ea58a4ca7e89a43f860a30d6d5e7844c12fe0e8107e5c4a10dd9bad223d20e20becc35a1f18b9e13c2e904d8c49f442c9217dba7cc38bd23b42a5ca08cb82acfd63463d2fcdb87890f248e84a7cd5a54be91e851b550b19c175831a53be1056ab12ddc7e79ef1bbcbfcb4bb2ab495be43a9ed73f0e0b76d6590b45455a89fb8dd95f3e57379878bc65339e76d7bebb5ddee7959e3554a7e08e6275b53674e5a88ece1bbb238e282b557a785c9944c324d7a2d1d9425a2e1d7eb077aad1912a2500b853f15675bec5d35b140c97040ecc8eb1d30af701f87ac678f259fd15fb922bd473508068cf937853f709f6d74bc037a0bd0e27d84c47a186b18ebfe91da07fc1940ff92414e75d02be779112db491bb50232ae13bf6e2cdf1b87e95a7564904fbe8fcd8f8c51df74ccc987a5465fcc7b47e559c936126b6b912b9c141eea05009ad0de4a1f7f10bd68b77a40cb29345a404ee6ea37ad13c203ad7863c1d8cece26c74e69d4aedaec604cfdfe0ecfd2c90500dad4d2f2d299918e6e3a849dc5d12b098fdd0f46ed1666e6263a069aed340823e945574f527dbb432449d6e27fbb4d75a2451829637a009fc1b10220e2091b93427af878b708782b5e155fe3f04cc66a705bed4df10fa88110c1b7e45dffe1109661e9b1a054d4c906048bbd81bb2b93dc0d81dbc43aac84f609bafdec2379adbebbd4e35884491e5610456d9acd6153ea274377735a76f3a937a278e6a1c4df6226a4a2dc4657f5707d139d9c39de5698438ea03d643ac2d0ce019290b7d0132fbc784f0b28171318e9399d42eb3d91ec9151fb7e7f6ea17cacb6fad7f238f0b54809cd830719411921001dcd366d5d94ec2f8941711b72ffb610a9b4f094b094196a31d9a34815577d9ab14d52691a00688077ba5be3116f5e92d425aeb1f082e2dc9fdd94a2c9ffa87e67d5d7f597f2d5e974148657b841317e7e7d46ff280723d48551d0bb994fc532f8166468568af288f47eb4d074f3e7d354b2578101a4dd70013b24ca9434f4fc5f19e0c79dd6c6eec6fc56e1050fbf9293f6b561c7af1315d43a0e6de666e18b061125042f49b071cd3de2376e241c25e92ad5401384e43d75ab2f3e19119a6e5a81587d8ad60f9d839e1ee5156e12d11b2632764c88adb797d15348f5ed35e228101dc0420620a6d9dfbcdb0d27a283d585a3b2380cd7cfbb6389a40426583dd67aa39c10f6c1f3202178439950866b62ec5caf39df8f689d67dc013e92cd73a0d075520469eeeeceaad100088a252a21ad17cf43568fb45b5ad0aea269f7beb803f3224074bdd0b7069de0af2690ac0c399db602e2d63c639799d8eb889ffebe4c147c11707ab04cb8e83691ea781362b53663b86e47e0efcc197ee867f5bc06786700610ec67195a80650b3d30576bad9f153388581bd10a050f88dc672237f6b95203e3d1e3f07cec0b0993dae4b1b76ba2f465915a317466236086bd237a8fae1249cd618526977379049092e5700992610ad7852f969ce730a3a1c354ef0fe90e204e4ba4cf10a1197cc136a239ca931bfaf3284b5b4c176201e0aad0712ae3fcd414581a7a095897d5bcefc36c0e1c892c0d557b37ef250651d34b0080f47407804ef8e755d08eacdc9a719b08bb85bde18310c38c2df263327353989392d29825d579fd3ad8290de393a13167cbde7a71647a8405138583575136ed2da6e9467cb27cfc759b9d710e2b1c197b3205854377bdc0d8530a7926ac9b40b484cee7dd0b72be2cb4277b161ff8f48a1d1f82d74ea05448ad2b284bd6b143ae43a4f78e43c80e86cd3856feb2d8ea1eef9362f15e9f9729c089c5ef881da6a63feca3c8600eb210b4898a27cbff7496c7ba15b315ff418ec9220309c13eab805d886a000c553b94b16033a472597ab199bf368c1d3bd6331c91a2aef28ec2a5e7b3f5613f9b7a598cab40beba0c339a85bb15b63a6b9cce6acbb70dc88564927eb3cbc3f4da1478de2fead18bcefb6320340f5db559b4b813e87a6afdadb378188e968c9050265959454985693043837cf0161cd0750ea2b9a053849ddf363f04053908b328d53726243a62bb96304a1e8cc8021202fd690aa0d7b687bb4b04802328873dadfa33246c1c2afb0fab510ffe71786dde5ac238ba499ff95dfe6701f6b20593bbb66711bb966980115f41d2f9e3c3d2788901807a367c8fca23e0051d08d6afd5d620f73b12e307603dce106c756db90aaf357f52de322e5655256db0fc5aa061c6367d35d1a49675cfa4a1c50a422c974a4147a6af465cf396d367f3f48c42619f77be271567076fc086a4d89334680e9ecb0f0991349886041d3e64223ff93bd1c2e88f4a9a9a65116f321c405c2f305e725c40ddd7f13c995c4275089edd852c869a7850fda2e2306cbb765c689ed8b6ae25849cfdbad1fe4a573aedd4d27e5ca66d4e19ac2c35296977e7c1f5fc97fad9bebb3f0298c1d066580ae2dff9a6876c2a9425548b61c17e8efe3610ff84ed199bb60a9d67b9480ffdb21acc042b1cbcc03f0a0ad4e9dcb343acfca41645e0c223a71cd7d25304c95e95ac6ffc75fa67a9a08e5c6934ccae7b1ca42bde3108852eab6d1de82141335c5d69bd85144a9e0e8a711b5d0101ed24b9beec95ca0e09d300cc3ee7448a7725f84ac83420a868292409dc0ca1f7ff84117e02a80062d707f71917a9caab0a5524316ce6c263bda1d9129c3f527ba5b73c39f36f8c19bc430ec886d371491961de1f411ac2d1a6f69815cf4effb31339b8a23899f932ccec2b063b5a6b3892d193653b4231190a8b784b44889078fe3d192055e66495bc1f10dbd4e96c198b9f18e354652a3c15ead08c7c98d5d3bf0456126fb4681d2c812e44d21529b1637795f2241e7c42893667397990ecb3e02e27b43ef14bdead86ff1a35a8bafb2b546d55bd25708cbf6841dfd4e1f568e0ca88c8d220e663fff2f7b93b5ffd2bff2c9a0b584bdc446bc1598c5a5ad9fea76c28e4fa069aa70869439080e734d814282c40a7ec040ab529927fb98f8bdd6aa6cf69e6d222bf9081cd26f66f0aa99960ba9997fd025465c637f4495994b9812d411f2f673529aa602e77ac336c11fc3049054befb85b261dd5d2c3c61c2a48b8a15be00d6f1afd13e9e6b6a11891fc2e139ebb2dcf5eba48a58e601798ed35178095002f4c608048a3cca21fde449f42e0732a8b14283f31ceda91c0cd285f1a9c1567d914782e6613a909c5e63f44050745eed29181935ff33efbf8e10093e68e96a340eec148888b628e54f6977200b950d128997ec2f1b7539057ff0ab64fb8f9fbb1fb5db1dc87ed16aed61c62f5be63b4478af70dcef7a846bb5b62e1a2994ab31efcb3cf81da9b847156c5fcc19b2a4e0566700ccf0a0d699bb69a4664092ed3563a83d28f0a82d0ce66a444a5aa199c2fa1c34ba07e601139ae478c4a76a49910726f54136f5aaf142910e83c2126664ff12cd45c70c69bd3038052b56c8ad07997404530111347a27a98f5228285d9915e66b0cf7db8dfa1d35bf2f1f536844edb6807e196f2095fe37915bf92905f2a66536c27fca79a759a412e8f2273260e53e6cf5daed3a31a4f210d1188934c1e3d672427230ba9643d08182cd41b73c6f69d300da101a492e88e87818db8ae2870378bb3d3137f15b554030c4ff67211af5b9c7c4f0bb0929063fb836601454fd6ead47cfeed80af58b0a9075c11535c3eb0e8dab33d455b0c94a3d0b442c8f60560ea362214822c283a3aef62981388b9f9f2e66b6b8768c8f9e928d52a8f5d1571ee07b305878de565c27af7ae1b42f32901aa258308523553c329fde9bd0257ad96f8820942aefcb22b9f504f9516cf8ff1c8b03621ad50181023da795eba6c0aa7eac2d77e0267c8107675dc44adeac22f6767f088b66a79d06742abe7217ba27383bbc91e22732383e63a89eb01296faf8849049df3d015c25460dec72e85c280cc742bf335d0eba2583dc22a16004b54ad6be1d531e5fbe96b589d860dfe6751a473810269b430c4833dfab7d377a596340582d504c50bd5c775387efdfc7bc7770101ad020e052825818010487126c5370447da6285b3e18c6d87ab37f93bc221b747410f8a54e5faf70428389850528e025fb8652a887d1be0ed85a08f02e244080940e10d32532c4f82dc57920af776bfb3e5b848332752d26ac1df5ad4b9dcf1121093e85d1ef9f12e5d528fb2a5b4c673e83ce159b1a994762d0fa61c0523a41c743a32461be89ba24e8fd9f77beb9a67c8aa37012e614c30dcf92de1fec494953f815a7b1bf9aee7dd02239662ad9f386f0ecb940a7526d58f2498eb100c0f7791ad3ffe3676cadc128775797a559ec7881be86c387153d729e3331058f41b76a0a6cf8e78c5dc82270b50c761ca88df5a81cd6bae3ee29cc37b14eb18a0b82823168eb9f5aeb6c8f9ff7832854e13b9972cf9f60065ff29ffb19107119825751006071142ae669aedf997999cf13be93d993953eaabf3940d45ff801f3ff3fb82b76272c9bcba605b271ffa1d75728395544ff05aaf0c73376f0fc725fc7d0025a157c16838a8b26d35c28965003ab7584b2f245c5b0a29b5684231e1c90d558adb524987dc4acc5733a6b4723b5aa04423ddac9041fca5b42de763c77d5086ea0801684eda6fb3651338513d7572e6bbc84002a8940375c8373f4d075edad35cee2d4f4cb4667ef9bbfca57b2c87215a0e4f2bc936ee9f68ba800e3402c5273ad6ab9ad80a04c1f54ee6d676049ddb88c5707e543e9f340c62695619b78ee6353bfb5df5d13718b7dbb8be4d115baeac3160eec6c48460e0ca3901e1de946b3f862e4562914971a8b380c4a2108095c96a116e4114ce81869085c039f2719f16d5a4637e50dfc5331842abd74806516b710a323e1effeb1d6771a76a8b82abbd45a22dd52f28f0e5a5b5c4708dadeff57c0dfb605b8e7b163cd8804dd5960243c2833576137441ca6b77a462d2d49f3c460a6dea197434e37d8dc8a5a48dc0f461d3dc0abd9a4b96ae26ddb9a287852e59f96f8bf7724469e2a959c4d2d8e3f95d5bfb5c3814d01745a61285605a88328766a2a38de93708fc4eada0fa773df3d911eef8e8af101dca804b673e95baee1f0d02ce90e45fe1996147e580ef81f414181a19b73d3544da463590fdc1daea6de0a28df841ccbe19ab02e8d0de26cd157276ed3ef4588263b1d0512ff84e6d6a05ca394e19526465fb72c72441c52a88895b7ce0d81c297d85b1bb43e571d803b35b6aff25c84ead0b5c5ed009838be407b403271bcf3ae404c36f0be23d4c90b1055c88724e7d0b358c524059a5196b7339695f4304c2ad5e3d111a51ff9f2c0a25e0b7d6e6fcb1b53e13d95a4d0a8cca8e6fd22dc6386082a256849adac851de6ba7d9ff8ca373926c7c2e12671c932bd5fc6b9d3c00b1e50f096ca5c9532ea162926d840e04d41f7401f1af8501bc7eeafd9000123430a6c8d6a8c4719bc26ba56a12af89bde3b5454bc47004fde6299e2b64262fa9fcfd6f8dc36f53eaba25e1b5bab6b58a17645866b13b6102436c5fbd701d7690c719feb2d51fa4150ed9254ac5e3cb6b9fe2a5af5d9d7d3c7dc886732d083790fcfe5ca5cb84cbf6ea4606b8d978a77f36a91ec25b16153a5f4637949d5d972851987ddca641fa64df253ff53cf0c81e9eba44696feadc1e0086d7a3f2ce5b78c5f6217289b280fc596af52c6e8ddce24d96a3acc15c50b9d9261231836aa0626664ea163dcab2401d33c4f10022a81583b20d403d190bc54bc40186f303e48e7407b374f559bad05b0ddfff89e8d542575ef14a4067e9412bbf4b94550139b124d685d7cb2ef158d9f4c15944972873f0e8d1cc7f6c6e9f568438488c927427b1e8f7dd0490f7aa23e9d2729c9b102781e547afd61fb8171efe1382e105d8438ad2f0f025d278873263ed4b2b131ae9f9dfa1cc8f142e3d8e931f4d743ae5a81df41d4ac052166e9e3b9ce918fb7728415c641ea8dedc70b5ac3676c7a87d34b1c547fb19b853ee9087329f89110b3b3af217502a5dabb6ebfc9f19e5361637e5384faa1ac90dc109c7639ff7fa045e4659486489553de578b712e8f0645b5f46d942bb23a89a8b49b572df9fc1c5b1fbd9a9c2955cd3f84a0f3178db7af5584c8a50b21cab34e9cb28b39da972e30dd814fcf173549124905d9751d6815cc5261cbdcf661fcf5509af6bd628999e312cf815b7368b4a1fddbecb6903e6dd5547bab9222f288fb4efa259f3aa556917a4e8f08186c19d1e9e8f71ef6b14f64692b7030526116c47ba530fa1d8206fdfe4a34013ac23f393f34b7c9ba6e169c4ff790c820621e020adfc1f45b8c7847a8eb415af110b15100e99f5440cb283b8fc0ac3bd56d521d6d014fe22edb955e84fbd783e11dd6b22742873535dc90830d3018f9227dd105c4f108f58481a2d16bb59f37825111c7af73b05977e7476ef53d691ae08c3d44c1314bdf407479f89fc3dee6502fc7512e73bffce45848a7e7c37823d50221bf8ed93256439a6f3a76fd23e98f103971c0c6490c9b90f571a2fba20ccce3766b101d8e4e6c376dd1b0448220828e1ebb665fb0c041af819f3e30cf21a2723822de5a24ca9d2b34c9390772c69a854d1cdffc9b677de81bab38d284954f74fa58617191943c94ad383a6a6853f24787e06304896e0d15f658cbc9557141b85a21ac016936eac09f96b1af5fced10fcaf80f9f455d4101ea232baba56d0b60690461d185fa814c10c82df92bc072f3200f46af1bf7d80f610bcd8d9e45f6b13f516a69c7036c4406715002a389287ea995cfa2e1fdf7d1b3f8af0220e3f039e57c6564e0359542f32b56ee6dd54ff09d92266bb7cce8bdb60d8896fad421e5da260037f559aa9890ad6ee133711610c50af2bdec1fa69ac052a060ca2979da4ce9f4dcde24b47cf108d03d98e0682c8ab402659bccab8e7196c0279eeb4390633f274223b22a8175cd72173493539c2e44f9ca44f9826bbc54dcef18d3ae55a9da5b3e5eacee417dac17e36ef388a957ba43fb597687398ad6db6b7c16ef2eea230b7979bf21d81519539428de140afcfccf3c97343cb2f7bd2da500ec35b47e6e5e425f3bcf034f120236f2c3c364fb4343e53206e47f45317b82174537a5ed7e90ca8987dbf9dd615e1bdbcdb5ce1f61bc9f0e8e4a9244d92840bc43bc1795fa189df0ae0fa85834a7777abcee0fc9f28d88af2c76963dd0f45f0aa0da92eb3b968da6f135c94120665bd2df45fe3423083ab202bf95a61e3479151a72642e58f40d5ac4fe5e1405beb2e2592554e930c65c0ac52e51d44a20ab69c85dab12f8c08c35c5ee5b96ca7132eae176b8140f634ba0e98745dc3a6261d0e011b675158a622d0472897ba3aa3fcfefa7d02e60595defa77a06ec3057010870db886a2237fe77cce69fd2ddc1c3b5765d891286da1f7013e3adaabc961bdb3a8592897f583e10663046501e47a3888d95e848bb933439d670ce0b5319ebd227e10fa550cc0d6036badc1accce3b356200968219e5259718be56d108df678d8477d7223ad495cf08b702ce67cf5e6f458546310ef631ec82b39fbbaf276785b2130fad5f84debb574339a392df56db33113f999ace8152747f1150273cd51f67e9958cb7ff94984fbb299c43e40fafa099daeea7fd863a3e472571f5c4fe8fa8888c74b4f2a3872f44dc3edd47035871aba65c5f1053ddf44a884455b4f2407393cc4d4626a37e2568ed6391eee06874e2331071f1f4df8af7d6c9c455f97925dfc0f7d9678cb0d652352dbd7027e922560ab48ec0864f2ebaa0d8b8a03ecc8466c9537e7a15d5c77b0715d2f0f97938f063a41af0863a0f312c8e7780182b23039f646aba44841674f6c75c9cd4a5b182af86e524d6a08e9dc93cfb2e62db6896fe7288d23587952a1f81202e1c74205470dd95800c639adf11300df716b3e2861d75ebfc3d419972a44044394a764ce2b470184393a5ddbd5842f011c4b212a8d15fcb8cda3f812f5475e806b91252d32b33700664624068f8e4ef0c24ef019b619238e72777b88446464a82823e75da2591a264a3bee7b6bb35edd0a35ee4998c088f128f1888a463e0ec5a4015629f606309a1bd113f1d191d7f7a1a344ff572eb4e7aeb48f7fc1fe8907f316fc782a1ba799e727d72f4a7e54b11adfee115d3273dbbfec7f41fdd1c8ab309004c1c5673893e03b7d824cc0ab528254438800de112f58a99bfd7c0429aefe77ef29bbdaaff124b4e91888043733710d892711d6132f08e48fdb32eccbfc9d1c1cbd26014fb9596f504b75f944286c460a98bc35040005206f3147a438d6d5bd12910148b9fc109e22569918028f3f11c493f401a87efee2075c3bc671739a015a0edcf393448c8a2f71b6e2cb9e6e47a251e5a9b8572307f58b77e9b9e0e2edcfa9c183e4b064cde08fba3d9ebcb1a93cd3ce671e4220d7808f1203e5e83e20f9742b8b3131d3560b077e4c06d2de3545febd153dedd7f44a4ee94a4cff4a445693a8c5534144c5a64e6dce892bafb3ff0888c27e386c93e7f1e33cd34e768c47dee0220b19b67b028cb0008ea86bebf1e295828a272633a2843235a4358251c975a4ae7e76f15b12adf64a495da05e9ee2394752e130c987df228bba3fd2aa7a90dafdafa807c157e8adeffe6785c28140bb081ebf002f5d13371a4d4ec9b9945408d365e9c29d04e6a216fb98348a2c5b8a00f1b6b4a454a66b29a0f2a5a668e76fefcc55b6ac7ceb366c9058596bff6572556ce72249db2563b06ead010e286bb47a427dcfbc56d0b4a7c5dfc29d8c88a5378172a2d98e7a052515d35935900aa8b43f513c7a804543799438795fcb5e9d1d6315dd1a95909601189ec5f2f1c7f220f733ecbea5849e007ba3d47022f959b16fb8d8794235cd3aabd63053e1a063a2a48f54b965efbfc6d87929e4e9064074d6a62bc86831f424a115ba4b5c9e10d1f28f205476a9c8d8df34bb5f6d79a0f4b4e49a5ce34af763bf8a8010dc61f0d22d716e8f91bcc5e8397ed28005ce3ac40d2ef77c02845db38e3a09bdcbce5276f012cfec4c395dee32315222aedd7bd05d10bb2244be510acd917f86db0b6240f217b37cffadbbd04569a18f77fb72fbe636a330c0a10d8d4811416756bc79689153a1377647121b142c9f8e53b71de995ceeafae203890e92cda0dcbd2861d2a4cd8a9bd0905bcea56665107513e0d69fb5a3828a085a0721ce59895bb64a8b82d3bd88a9ae579af8d1c5d9777e1ec46e464feee61d741a3d6782cfa785349ef61a5329baa0ddea55a8e63d83c0fb3facc20eebf5a485dbfb514254e041cacb5fcf6e4719bbc51c8bc52181c31244ccf35473aab6313a48cd3bc4fd90a3152237c010f330d8801444cd0962f0cb514de06148da4536edf69685e21357a98ceff0c6c5331a468f11fa7b703ccf099c6cce309a070820c8f352a05d039bd8d431840ebf13de528ef633c690a4ca54e49168253b35aa15f422266ae24a269e123c5d4d350c62c7500500bee3262004ef65d0be2ba148bcc44c1d8ae5037d8411384f31d2d45daff881d6ffa4ba4eee0e304604a563e04cd9d486c7ccbd1240164bcef6946182c12e927c4b0a1aff85913c4027ee7d86cc9efcbf4b1cefaad28d8ae369e6af4c8875892242ea241955fdf37e13ed5fbfaf9e41a92868fa90f49b5642027b130542042335c23a4a93b64890216fd58a6ca505070ce3204e2fc1f8dc224c559e43108724dc02297b290324a1b0ab289844bceae8a4a7e2a8308f7288814564e4a900d8e255c90c85be380ef94e62c3a931db3fb6b43012b1e355cd77851e9d3552c5a10f724aa5d78d13625c70c09dd199062cfa2ee7a347bfb8cf07ffe56e994ae4d70b4d1c49c09e1536772f92dc03b80bebf521498cd1f5ad2189b9885ba875f204c229011103bc381cb8e657f384b2a622d36fe009059140d21b83719cab0ea49e5110b4184e4fd04413884f947959171ff1225a124bb4bf6969aa228d6f68034a9194cee03ac0a3a0af7053c12f6998d42f36ef13dfb578cd5e21e72b395a596f219383c972a23d8e0f2d99643c17ba40770884feb57652cf7ea63612ce3e63221de72998033eec9a1d07e9de00d76162d759d7fc6b25ec3c92ffada54160a5bf23199938cfeac8b0f7c9f85c93d4ecbdc12cd5968e2d5aed6bdf86d9cbc7d94984b75317c9371bd2b4cd656e36c6cd2664f0469d012d45b4e241481b54e6fd4007237ce42268dd050249055cc90d5c7d05808c53b208021a60f39b31d8199a89be89084d11a39a40145a309b5c338ac528932c16f531f0168b1209e6c067fccac64b348ba622d633ccf9ca7b3323aeaaa2e5145ac503f9e61cfab142b013f4092bc2f33f660ebf3575223e70ef6a87d00904648a7643113ae60831cde7618f4097b70884c17978c1c868429024cc5689dc35550ee7a81d4042fcb4ca8770c5e16f5080a470574c58346d0f9468781ece85916d6324122fbd25298ded4b2ccf6e2720e02ac87693da19a0ebdeca489cc199ca7b47960904745ccc084c1b9a81543b38ee6a946ed23d083855b7410b23d799318887b12bd6273e48169373a45d5dfecb44f3803a964d1c9cb380104ac6da68fd709620df0499a1b56ef14ebae546fec07ae209d68ee4e5be1af0f81bf008ae74330d32b68e4c53097436031e51f0f23fcf7336e507ea2025075edb0129281a699259373e3e448683fbeaa60efb79d40f060d37366636dadc238172eaef2061128a9a327cc28e4fc6342181e6a55052e76ecf556d045a38265cb0fb0a3a9592fcc9d014c9c69de39e9325ab22ea71201481ba5ee4c41c0265a6ae8b44737de63e72ae0642a034b20b90951937e1358a6535b8ecb6691850bccc7a0a041a0e00307c0cbea3094cfd8022b55b90e5f51402776c4b8471b30774edba5f8e188507d4f6e1196282bd4274fa350e10cd7b764097d0046df304fdce06ad02a575c0c5b91546bd4021208448ab075a97344dfa20b2f98af6d3b067b846942ced8d61ea4294e5ff0fe93c41f529dd2cb744124c024143290f4ed0f10949b753c4b50932b05023a0004dd06d742b96cd293d0285e0af686b1902133440eb106e350e8fb704b5aad02748e5c593374ec10bf4fd204cc01561b987e8a86eb7db31c85b73cd0f46cb2628412faadb5d0b4ca9a7374449669cda3f7e9f2e1d9dfa889538ef9dcb3c62f4777f21b18d835cdbea533b1ab6cc1eaa62b862038d8647a122e84aca49373c45200436ad1b3ca37ae9a8203f19306628d21397854727041cc88c58b572789876cbf0e140c9d20d072f19df917bec78ca31384703efb43b8e3494deb9816eee184b1b5869f4e19f1a71f0d19ca250e0e13878a62f1fbfe273ed574ec6ff83c6826bfd43fab451dafc44cdfde55fe022b8a6d483af2076ba6b7968900dd79f4973aaaf82a85fb3f76495dc6fad93fa90d4f0719e86b286ac0d91efe51357ae03c4d487e106b87cff63f3b8e43f833fc74bfd7bbf387d2fffb90ce402d6d07a05e08b0be1928bab4404af273e56faef30b521a4eedf9b34b0eb760cd802d145bc7eb44fbcbf99a900703420731d0c9375d7680f7400e2ab1ab096422de5b07db8f4225f405e7eb889e967d102160ec0bc38ca2140ccf9de128ec7b48ecd06889e2ae470e07cc0716e040f5c7a43cb74becf9f0f90a20dc522a622f1fac5999152e4e264d7e529d63d0329426a400a5d2a8979b51fcba63236485fb562d90c81071936f60bfd2a1fa0de58b42beaa985f7d87ff36399a119f7e76052fa7398b7536db00185f35bd5c8ca8afcbaec6aad4e49ef8b4133679a3cd010767ae8bab444f2456b84b509f98056ed4523504ce572ad4b2e2130a5d593e0cb44f526d6294b97ffccf077055c98d088bf85ddff2743417d9206c185cf1f063ed63ab401e486e369659684fc82a04428628e6e708995cb2b834fc87ec08f927ffd78981e151c8411f7e01ce38472ad10a49826a33f1f5f72e8912ad1a0831052136274881b680dcec5af2884f746b03b32cdae00f95a1f092e64d30540c88367b47c7fa319a79abf841ac08a54a89e644e2a5a7e52a6e58a4fd5416848158f7074068de654f836a2683c38b98beb0fbbf3e48d4262a63f8a77372e771bcbcb73080de591971630bf7ff8f59a2b47669c5c10cbffbab780cddb904ef86f1e532831af503c40f5fe629c58b38be897b365dbc3399bef79cb585d1dc3b9526db085d7912ea9b1a7f07b633868af0ee0635c385ea33e0081a2ef005dd9e39f9d7ff07703bd88939dbbacc9ad7c7fba7882aef11de586e4345a32daf54b9591f1bd061907984c70b7569b7a426b85430ebb963e13fa18dc387fafa6e5e93877ce5e2be7e623d85e63d3e6e986ad3c451927418d7e56be92ca5fd77bdd47e59f5428865cced56b692418da35a769b094f70105f77c59fda6abe6a20b74743341a0df5ad194e492ffa1663dd4b8d48ed63a1474a5b304f8f9861fc8467a5b572cd1d287187c6e603f75baa2e6084670f0c12673466ef0eb0840c314d43a5900104aa740ae3fabe4e59d69b9a28ee59bdbef192883c1d78c7ded2fe01323d2f4c40cc13205a6c2b862ceab447329cfd08d3262a18b83a5801349426e23b3c6a4484264dbbd4063206b3dae4b2b1a5c518e5bed03ea7795fd6fdcb2a7fbf267d7eb4552165cf117bcde8dfda18bf38a424482eb26d3cf3e822bdefedd3ff9d022100613bf5559f44d4d59ccae3bb285bb1547c115b7516470c415907989cc745c1fe9a68820cd86efa7ae84078b9cce5c02ddbb85d1b39c158598ebe6f2b209794719d52b9ff97b865c568c99292aa0a86862825891190315916c5eea4174ba234c4914f4359b4acef407082f31328da9223f928c098d15d0b501c71e245c136caabbd262457f5a317ab7a5519ec3f10af84b196ec50df11a665a1b3f42c62ecde03658bfe9daa056710f9b985a78136e4871ca4da0f4649156573dfe7eaecb394a15e98d75410191ea021ec27cc496cf732ab63724e615c134a0aaf8bee75065ab8ad9ba9003a9f5690b69ae92856902fc194a152915c15e7ffa57f6dc4a0a339fef547c64e31cda757c57cf2defb5949620ebb7f956f773116cd16d89be44e0a2f029b22f15e6dca62b637ba73a74af034deedfa262b49523e866fcc20451904e32612208b58207f9ae6c552d2cee33b9f212eefe7fb6fc53a0016a6162d76950d1d1b4cc396950d6541533f48570fb5cec03336e7782b4773158b32c0fd423a15f5c33055e6c14a4270164e2d2f1a7387d86c8f8771ed0193e3f0332c33e451c32a5a86668b1c3bbf699eb80b7a294665c6b229a21ef3883a45364e8dbfc55ee29d2521c6632cc997ca35a5791addc6244c35695df73e53106bddc94234e7c1d4e34886e63d100e0daedaaeb5a0a4e88ebc1bfa2c41605e68438088966310faa01a7289aad2e4eea648a52a227d5ec65f3529401d0759cf0b4c014d70b6b587660e8167c8d6e72a8cf5ea4d9677397b9b184091af45b5f293e8053eec2de5ec1199c6782510b124a717114089496146d298280fe96bae1efa95fa2688a4320291ab201578ad26ab381e717b8a8021288888a590c150387dcabf0701467818ae93348f848ad55feb1f4e3245bd0f85470a7626618c6151796c18d551c299616054befb46a3444750a90b67244a44b4e51540e88b4a981f79a0072403e12ab58c43a9638ec3a784e4c4e91f0f734c36d4b7d8847bbb2e2879dc0b395c41453de47b17a5d0083ade243713a02a24b7199549188d31dc098b314059af6236eb43345ca9e68f34053e40491a357f6dc1e42a2354cb3640c282031c571c706dde967bf51912897e24f6c29f20cddd227b314e729c580349cb63c4571e104c19cd660d27626c71864525c01019715197a0742e953523c6b5223c11d508ae7bc0d41baddf0b232cfbd28453443682169370e964f8ad38b9898df66cc912565d7f4c11c4c81ff335e464c3a62988ce9807ed7e7e5f876a05ba3ee4c8ab603c07bd3dd71a1f899628625c9c876a79bc1d140302a03648c44e1f4ce2c29cae1f627da6b05afbeace3b27c24c5073a137b1a1f1e48a4283ce13849ffc47a14b72e6ef3f2a1172404d95dfbcf07bf06bc8dadafe0e6297ef9d0f359edba7b3f914995fdda44c18a917ed2b6f6f6ff08644913459e96dd62214331a0ce63a11892f4437069ecbb21c60fec4a53144729bbf6e97e9589b8c6ccf7b3d6b4bd93eb4272963568f8259785e42c2ba021975c6e4aa61bc5ff0fd6e2dc0ee9da4204b82f78ca2f06417f3dbae029bf1004f5fa4893a7ba24d6543da84037a50a4b4bec9a6ced7e59909cbf06197afd554ad2bd48f08ca62bac0ba5227b1db605dbf2ff20eeafefa2d0b53f191b18bcc20a42223200606bb2bdfbcb93e4bd489c3cfa55e9ee0a58bdee34e5e1fe01b2e2687c37e59e0e2dafecbd0e321d11cf6249040bd2e41d48e040aeba47f4c3b9237c70ca7473bc8678058d90a396e8afda86f3a796c5364082040e119d7b878a5564a6760b85aa23d1206144645a4001effde578ee5bcca5360be31c583cd3f779ca3699e899fca5f16999761e3fa85cbba86b479eee67a262b7115ede8f53f7fb04065d651002ad69bf3d2cd338de3df88c3f955c386b928270160e2f1852ff9573cecb6ae0d1a3dd002604440768022c7d6b5491d649dba35879e10433138648e0c8bfbe848af34855f3463aa228b17274c35cccd2b668514d37caa36df73a3f5abecad621a2eca50e699057bbb20f92c25eaf15a38b45ca221198738c112ffeda2ae329ccb2063c19f9664917370398e11fe3d0840c35538125d46e9c1e3278ea671eb3a97f3cc15858d984e7e164734fd5eb9be627615a8f2bf2f21a4f67f18117e1d3e598b585e646801d4071ae08d024065e8cddd52c6ce3b6057e09d660eb9844fd5bd5a3f3409dda84e565e21cff3983d245180c6a055f1b019303af47877a4cb1cb0194310f57cf826328b6fcae362ca6740832fa0bbb61edc0a35211bcdb6ed149bc5e6e195a5189f1f4a3aa55c13dbdf2ee060e52ebefba5a5ab174ff4b1e985ae4fc04f95f5f3fb7573e31d5236c782c65ce5de0dd4444cb3b13b211e1334fceb0aa7d40ced46f70a50bbd643bdebfb451589e24bc54529ef36de8b6a707702809730b463e7f1acd00d1f51b863ccaefecbb25071e54c59442d47835dd453771124c0d56249259f66d2b192340fe5eae01ea8c2e61befc460bc5f85321720fc635203b2f2e77bacb9d3c7157e9c6828a07e4f6a8c7d6ab793aec025b49d21657d21825e11be9e889c563bb7018c436bee82d394a7a6256a0f14d3d88c0a219d307b0b00db1d5b5a2b8831ed7872b4c1b5783404d412ba602f98e45907f54a953804171b253cd2fca04fbabcbeaf14dc76c24314deff42cbaeafdc1c2b9173ebe830a8c3b7a56f1d241ac4cfe24c0fbbc0212fc43d9cd7f47523033aee0971bf19b9bc6b7ea29f1cbd2c7d383624ed1a6382ceb080675ba31740650d78a1e0b974bf35d7471c46ecaf7ffb810e5031f4bbde0ff1952a54567b87d82198fbb21b5185b2ba974079de787c6c2d627533a0824754ff4812a56ab2f5fd93265c3c3c376c0d5aee8060de3f4ce97b3ae85b16edcf32b55c3154e9096fa75e346ef2d485abf8cd2aa35f0e10e29b56ecaaaba8b8b9ed0e4ab48576d41b82441286906204615223c470a1756a55f43c76efa1cebf89f8cfac0e92bf488939721d8b84d930148ecde5e842ee86d92dd9f266630aa2783013aa013f637f63531568c3623e41f5203b25d8d98de31ac78d1f8f7aa44761e857a08509f23175db866938a16a0de538b898e1aa9e5f9a763a8028a4030638a1e4db3858d6732251de2622e37e5f88b89aff3376e5697840f6194bc381ddbba64c577c4d8280f7aa747159c04cb066918f9f42c90de13ddbfcd3531d11935858ed751c06f1ba6a9064be08b3592cee0f49496d06125b0376ca993a75f9343fb7528b4899f79890b7fc9f979ec4e27934215700b663a9346560af142d914324fa58bead746b84216e9d7ae0e7555fe338e25dc3514121a113a0954bf31da499b1dccf53c43deb42ef9921b54b948a9e16089a2053fd7e727ab3ef423e8eabe5a2cff9d7d8bab5bbb6e9c1e2bb9c0475bdda16cf2325d46556a0bf4a193480818b2ba91ff55120c336b75af52bd3ebd5292ea4ec6e42b3f5759dd7365ca155dc8c55f17f1cb8d46c07a1919b50dec4a2cd0a4d922104827f2e8fe701e3a180ed83974a996fe1f90506bad3a9de16396f4d5b7da23b187b48d1598c3f9c193dd84ad0fc0159a947b04da678166049480211e15a238454cd8896a9b40b6a9e5b0cc80e9fd22e9a8448edd1f6be38b375bf211aa4919e2fc8a64047a78fe6499ef935d5ac8c3121e5790c0b39fc30dc9b30334098f73d41f83e7d3893831070363c0c58fccbe210a87017680569f9acc2989b7534997c592600eb1f30239d16f2589261815492f255b8aa39fb62612e034ef588e612a801d021ce0c6e1dae0dc46cd56d61acb95f1f91078d8408815b6c40c69163860ef655d3c93c5764ca25e0696288f3005cc404e5feb01bd9b4e0a96d558f8bf523971e0c50f938750628de65e0d3669fff0cb53780116a944d1751dbad08815db6fe75e65f4c371cb94684c7878e27af101026fb403e30e0e437b66bcdae1bc2dd13d0aa5d46134baa5a04ecfb30de8d8ea8e0475cee5b40a6443113220febd38430ba2f697f0d2e2be350a9396889595c6d725e3e1c6a2d9da454e83a7f9ed249aed03e68ab274911d9ccbec4dcf76cd2dd0c9ed07b9bf9a5ba09bdb037277357f838e77ffff9b5b34b5c32aa490fb82a7fc4210f4eb9105cff9c520a8af8f367922546f2a3a94a59b5671676d4d5bbbba2c24e55a050dbdea2a355130a867205c102d14d37cd9166ccfff83b87d7d1785be50c906d52fbb8298a483da9bb677757d9a08189ce978f1655c37bacb556f8af621facaaffab6e89ad5bc222beaf664f4d0456a8dfdaa624177d56cabf447841d725ce49d8fd099169e37ee783aff69ca60889127756214c7872f3deb5d348ad2ba53f4a6e9c1416c01cf921a750ad16888454f523f70d0b819d0551e42c87f11a9a862e6485949a513af5e414ceab688b779545dc065f2ffa0b1513a309ec271da974ca68dbc94ae2c7365c466c4b52475d4f9f6bb5f0f79135a6566515cb691a46a1cf81b7d2b5c24759095726546b083d7410b2e516d3c290ed71ea91f834eb806d9689e1275d895cda31ce77186ef91baa3bfbeb6f5e5e978bb2b4ff25530f6fd17c8c591ea93923c03f1d87bcafdf748a595a03ac7fe888d564451156467f10dc823c31cb08acb549df38ac8a159f80073d553f144eff9217311b32dc450292bdb0b616ba4ca51f96e7b1e9387163252d706dbd79837b9ff338524bb390866c57eed2472fdd7482c5d03cf1a878a23b0bf48581d68e4db1bf8c1d760c01d2403fad12fcf9d8d1e410d8354557936ab7707652c4cb79b82563d81d3e86cc5968d59918abc786a0d7e09d400e7be79200c862494852a7c94456588326d8fcf2234928b57017f232db2bcc5fe3feb9b1069b53a39e535cecaae089d611b8f994c609a56785c47e09c9f034a0a77a5572010b1a20e82ae36213e1fcad3d0c6086dabc9c885e71e41b2b1fe68e872a1685412564f2393b9b35dded1ecdfb8581c54c4329e870b5acd51e1a393823bdcd9897f714d1c9e84d4c2b3af11b9a56d7b6fb9e596524a19e509890a210a21f49521e163aa993663ba97c24aaa4b897a437856985785ea107760e24e95944718dc558e314a3898d624911e54a2391bca497ac5edc121668f9c039c34143ef4e8c650e92143c25945432e7a8231c65ae789f2390baef21a0a92e78501329c214977845052da54992333e123ff3416906be829cbc9963bc0455c5e1365fd6584c7592844dc79c2fb82c49407c70f39e71092c83beb5731e319f25226199224aac898285ee2bc6cfa3bb1ddad9a9bb5dc2e6bb973f6d8ce9706dcd98db933c3cc4ba46962c09304e68b1224706228d4d85171c5e744123c3fe29c79b2e2cd068c71aa4b8930c6c31caf3d530debbcd67eca661dbe182044c61fc03036d1f438e79c31c67464bca633d5421da52f75e2184098a6690a8c4d343163264d0a356f70b99d3b67189f88e131b670e6b8f03a8e97d74039433e784d2567ea6ace8e16a8e664cd42bcd6c9f4a43a385242e88272b5ca831736e1e53551d6facd3ef318cb6338bec72ebba8ebf12c86314e752991c51663a0182301a0126a1943f50688a97517cd62304dd3a2ec4103d6a5b9d7c3546b5c780d03159b2842aa364b6aa8dc20d5279dea2e5ac59ffd59edfb97a6290adcf6abdb7767e6a2259670bb1d5eb483df7e53abdf7e892c10df74af17fcdde4846f1db05a82474f0d3c3754e07675f37bbbb5bae8f8db6d0fdf748a81ac25b2ba14d64c3d55818117e5026e7b9bdf6e95b0fc76ebe3a2fbb7cf00df44a1703b062e9a7d7b0a21d8aec245cbdfbe023cbffd05177dfdde0e017cd3bf2d6e9fe19b18c440d6b77fb828f6ed361bb82163468f0d314e2e709bcd6f1f91f4db4bb8a8f922881479f1f163f262086eaff9ede799df2ebb68ebb79b4a720ab023c7961d6bb2f068ea60bbf7754ff794be7c49fbb26c52a51ef39454fc388e39ed23e69973844eb8710b856f5d07901745d106f52fc79b0260a58b5ea734fd9cf69c3316a6e9e71cb4c1b79ee30888ccdb4c4ec7c0fccbbf6c859580ba9681bffccbbf0c8cb2e7557af1876fbae7a149951767ac585901474dd66b9dc3450de7193e1123e79c7100792ce6b16f1c791e7beba23e679e69b0452b6e7cf982759d424a32e3036bca0c5fd2f8ecb05627e9f90cc62aa569ba02637cce2250240c1d372b6ce4a983cbf90c9fb3991863ccf33dce39678c2f5296d756668050e5ce15efc96babd7ee2d5efb07edb61a30bcf6102eca80d71e04e286e0bd7612a06ca879ed256887c0452b54d294d74e818b56a7facb25150a1b48392a26218953d59aa1de52191c162e01e39c731631a691c2f62d281a465e8779ed5048283af85ce2090e364e4888ec193245063c150b096639b4c537c3c877d04fc225e86b365078f4e0421a5a9dbe759d5eb4622b2307177cce4c32d770b29354dc3eed0f0770a628d3fbfcab5966a060c863d4aba1a7a2314d54f9e11be6d1b46bc737ae4de9a2ba6671395dc34a35ccc34a17ad318a6a18f372fb75ee7ce58a79454bbaa77dbaf74b7ac569bd3ef0f3013e67df4571cdeadc0623c433d46122860edc99cfcd3e4803e5d4640bd60b2b70d5cce76caf73205e7b09285421fbda43e05bfe69ed4117ad54305e785dcbad50812fd6b4afe73bab75313d7fbc0a0523c70bbdeee1dbc659d7beab832f0f72604b6c122b5531b3895c6b8569d739e79c6fce39eb4c6b71cda4bdd7566cb188b1088355218d5faf2a246697ab0a65b1d5aa42589b6615ba63f955c8926415aafa65ab0823d6591433eaaab6ead8710d63d173d8eb786dadb5ea259a9aad15c58d33fe1388b58d77b06aaf575dcb9d2fd6aabdb512a2bd6246e0ea648358be228100917105fab8dc31add70fb9a010676e66ddc66367ab9393d4df5bcbbc8af1e75936620854e078c2ad392d369da35f8bf17e9cf3ff305673ebac8357acecf5da76f6ec79e77bbfd842084102c6186bb762bdf75a7badc5185b8c7150881fa78d848b86a88920fe5eec178b430168f919447d3c87cd68a878f8d333530cb47bc984a392ed43f3a9a2fdd07c801868a8f478f81a126d1f0d359fdf9e71e67ecc9f942926dc0969f8c0360c63b4201b9c5e59d7d6e4eb2989a65b52a727fca4f8b6c1f130dd908e523a51d43299d6a3ccf783816432d8cbb78bc40b368e2459cb7af1cfeab16bf8c926d105c2667a6dd84c6358ce989bf584bd328f07734b1bb79bb5da6c8998cedd13951ebbe6e5b2fc1e9b38fd499b3818dd05608fd538e8ae0dbf86afac1446343accb707c39863cfb1c7729646bffbd13dce1b808fdde7eab16b08fe1829f989f96069eff1c8e39df8a7f61a62206ca6553fe9457fd2d7f0dab099a617351deb5c9ee320e3b173d071d85d74749f1a7e0d5faf9acf8e71fa98d7b662d587663f46b672cc49d239e81ebb0ff9a3f3294b1ed68c18d6e9e6e9b9168b59ff496134fbaf611501fbb807c32a641d9b3e0e5b60b1c7ccd3c469ce4c3f9829be6dc79edb41b6bf36c6ae5aaec3676f995b8be5d5044052234c18381c94ce9f19e7c49edbd7763b649e7f688db08760bf1ea76d06fb8d5d7ea4cd766b843d3442e621651eecb78760bf1e1c945898c002134c30c1d652f8c2401f39cb2f1a115309d3ce94f10f576d33d7b646e74d237f866f78d6f291e672d8e8f887813039f248df18b87fa4e160b625f0167fd4738f5584cd3b73b3d9ecafb56082a39f356f7ccb4eb40ff28b7ff5e71aae1a77d8f509f7352d07699cb971f7bb3288993e083e36fd8cc17479370e3110d616eeafe6d5b555138882f9c34078ccba36bcd3d638c4b7bdcf731ce6252cabc33799ce66590a42ba0c639d30e1cf387c0e9dbd3776793906564b96d26444d786fd75d6ac8c3376fa881b3b6b27b00edb3aebe3315a909f1f29d98e43d605c29b88846eac17bfd2c7e370685d678dc3f006966c876f3e8edd03270e430c8491b0d3ef0261f701833ca596e75aa958be5ea5cba5c5ad75f97a952ed7b897f2eff255babc54ea615d20eca96ed4e6d84af7de2e1231c73f66dd05e0e1b56d1aad1403e1316b1cb660c3b445746fe4769d23ee263196f33e4923622a9d43f62d003bacc431bc68d6455d8efd4cefb9390cbfa724bc40d853dd8e2c635eba48c44eb7b996d1524b776db895c6684148cf34a421d105c2adf4da6eb41c36c437d2f7f63dc6c10b847d1c6edd638c49eb329d0ca7bb6ab91530d6e7a12c1d9dc8521991d9729d00b3e76ed933763a3e6b75c74e97c98844122207d9eef1eb759e341460e1dbda09b2c3dc84c1dcd64ec7ae135a1f133dc761f838566ba55504ec663b6c5885b263d7e7d2c556fa7878835d76182d976b2b94196f6cee9725dd45b66a39d96711322d6b5aeb83e0ce81c5fa8310e1dfbd4b249dd86f4d66edece631e7ce0dacf123edcc05b067f0f3d3df6a4d1105e3ef84fd18f8846b1b6803f8d75b425b87a6ea553fc3b2fb8e33ac2aa467a842d94531cfb27e86355b7351ec33acd90cb334b3351d18cd84b33533ac9b3b38597c31ce5967118f786711cfb06255312bb12bb12cb12a7c730d35f0ec1d312f677db3a881a781a78187b13c29173ab82be4af0781a8f244f4d749b8a8feeb3a53c3102b778552179555fd80c126affd9a69d2fac7b55fde55ba3d1f8ad7fbb55f1dbee954d7ac198ba5b5d67e892c506b9f26a7aa5f8fd7afd73ffdd331d796679554bc96bd0eeaa0760ca4a0b5d6a216b5d65afb081fafb59376d2bacbafb681c6d16bd0a04183d36bd0d0ebb9f032994c269349cd38f23f21fccfcf8f4dffc76b9681238c948c3841523192bc8f8f4f9a394458c1602c169bed590275e7f773a18a7977a6693a59877124659aa689d3c73a98fb58013142e3a5a94acd92ed995475a6a2ac9282508290663d618089c1625ac37c60b0139ba6a94db0e0e4053764d66c2102e2034b528ad54cd3a78d006c58ba1031b1424377e3c7e76c355ef8582f1dcc124d5b7a4cc171e64c0c2a7c882b4c53ea058e05983eef748405935d9211518f56129c9aeed1b4efeea05a384bf039a1891e1755535a48316279a063ec05f3849da74fcc2fe60294da05f9e034cf9fd363bc3730374d9af6e99e69c662522e56fc799ea64f4c06516cc824d1d01363c80ef35ce3038b9da7540b376f9ae6707879f927c7b084b9fc1cb5a2c867f373cea667b74dd8a9ea27c367d8e79cb35b9ddd8950f179c3e79cb387408515e8903efb0bf2878be69c7d84eff3cfe79c735195cff987cefbf8f8f8f8f8f454e8f898e7582c168bc57443c044e9f6942f5b829122ea61567bced5145fd197d75da252f8683d9b27557451452a1cb075b6000c16638e603022844169dbd379bd9c61311ae6c1dc63301abe614f80d594340c56b328e26c00411229658094d91d1163752480ea0594233141a4f4c871c6344df356a18bbfbef8ec394711c9f059e873148a1d9f67668e0d6db02813858945901838445839a1434d143c46cadc184d7d9e311317c8809d63b000f41002c3110e292b2c4962aee68ad8093b11a541fcfdb02e0ffb602ce1f0a65d1efb25ba68078fdd02634d4eb6cafe8c1e73788c310cdf4ebbb33cab74f5d8ad0f8c1d0329608ca70c3d2e1f631bc618fb88243e8f31c650603cc63e35a71e7f9ee7e927f04f979d4f45fef4f0e7799ee7d9eba179d3b3699a5490bce905ca8968bb69a653587c2c163345219494a987c160a6bf6942e1f15a6b0da5cb6b2d517200a1a2d06980d6e1f35231cfc9d467cf39bb2c5bf96cc5dff048d3844f12003963260b89af8b1a1bae5c83c83c4d2d5e59282736f43985c89821de1d2b606a8c9617ac0133ceb969a80b549397aa1378813a513445c7400aa28740ece0c5a927a21745d121208a6ec3a20785708af2a2eb455114453f63bce8b28b9a2ffa94931511b99af99c7b54728099a212e7b1152cb22072c249f1bd9e5244837aa2e2b5d3942059a6a6f86c18e708ef14cd570c9a20d1b125cb9e245078220f85d63a9b396b5df5c860c27104a786940ca435482e827bec24a1496269903509c979a7a4b000a12cbf94129ef8f2e7cbd26d65594ab9190366c86b5ddeaaaa2fbd0e152840d0d8a893628658561d4ef00694d0a1136389171d38ac0c5e8dd71863aca317fb9c8362d250419aa1f4644f0c329fc852eeb12ccb5ab63a78e7075e0b678444ac9c8182e14a91040425235529950e143f3e5f557a52f39b8385499e17e78928da470e0398185e3971c30e30c84e83d61bc5e64135a6878eaba71e783cb8dccc89f38248d515302e644946394f5d3df1d80142d66e8be13eed20faec53a5868e314e515a48d1e273333f93f464144f4a55af6a8246ce7907f049879dc7dec25eb5765b9923e79c7346b32ee3419ea71c2c3cae5263c85204e491d95155e468ccbc3166b94543d9229aa1dc4f38966abccb2b5fe91a8c4baa243ab026b5d61b890f1690e8a1cd00850915569ad0dce86254e2ca7391b369c53d8f9f8e383d761992168fbdc34537786632c705189cc0d41893c402858b7cc509865deaa6e65d5c4ebb59c3bc6bb3376af64809b7472b7e2ebb56c23768d9cd5ace9fcb3afb9e7c39f5e261c1d8d4dafa607cc620c881074e99395ce2c8592183523352a6620f81021cdfaec796155bc4a8c078a9e835d5920b56544c478aa40853c405292350268d188ad031030565444ae7b61f8d31c6a688d2c475faec397bad5eacc86082c6d00e7827450cc52f53114902e1a639450a1f0f2924474b626c9199e61b2d40a0ba91e40a878b1770b021010bdf744f055f5cc831c31018516050985aa3987a5d891cca840f10f2909a3c38ded82012076889ccf44e1e9ae1f163ac4b1821e9aee65c05f7d4c0d9139f9bf9aebca85214b9e06a96406ac18a0f24225f0e33d6c456b256c8967b7a04f8ecb614a2eb91e4ea052551ec900f8ac725c679babcf6d73acf9bd75ca2f4387189dae3a2039b99344d57e4242de162d322ac9c73d6152e796a8478ecd69633136c72ced95a21fb654b54d60ea03397ad0c07638c9704a04441260a0f0d0134b9ca136072ee2d9576ca01a8b8acf19531a2a6d739975ba202b085cc639761b7d5496bb7d5e89965b985076d683543464f478309cb9e92c84a6f296b8953e614ecb88151070e5395147a5c453acaace5e741a98ebea37e74d945cf1ffd830d8fa31b215180d11906501de500011d49d73aff5a9f03f1434b2c95d109047c768bf5d6b99ad861bc84f5c8224d079fdda2c23c75da10c1d0650a2eb7f37ceed42958c8a26551e6f16f9ba6da5f2fcc7be19763e0a2307f790a2f0f810a54676cfcebf57208bcfce5367cbbbf344d67e05e25101a51c1a2a8ceb00cee95f52f1f91e55fafd7cb09121ebe31c3387196702fdf171dc0bffc7cf32f975d74f6affc13f35aeb582c0363c058bd444bf28fca8c8a87c1dcee73533961b0990c9fae697534b125ddba82e46086633a310fdff699adae8d06f39206ab894dd7669558cf66ac889b7e4ddf347d8779d35b1735dff453367381cc9bdec195bcd980375f78f3a68760c220f5a683303d04092364bce9255c14f6a643a0c79b4e818b9e6f3a0a49de740c5cd4c39b9e82074210e64d1fc14535bce92a5cb45205d5bce92b98be02236ffa0b2e9a80377d06a6dfe0a2f94db7e945dd12519109bee9d6c8a48a41c99b550c8fc59b6e6f985465cabcf97ad36dcfbe4628e1c1020db0089737785e59f7301e45d1b54f86198c9640ed891345863bb1134470760999c23c81b24b539c56c162bdcdde72ab9b41abe52d4f01b73c042aac20eb5be6b77aad5eabe5b6960795dff21147bee5255c747f6bd66af9bea8886fb1a0f32d975dd4e75b9e7fb5194e3e47e59c7b3d2932eedc7e8414df302f9d92a15bc00e67b13801634fbb7b51988521d83c8163c58605262ceca42fe81ae6f1623c0920682ba10ca1820f27a53c5153575d8639100f05638cc7183ca0d2dfec7061a297278d945a47c4a3f364c839e7b28e238c1d8ff1140c2e8fadf830c6186389d293c1cb1a29496e301d8c31ce398f18fb165d09f36e8863ed7c71f42de2b32c8dccbc862a5d21cc608b5e7b0812469400010aa040a74ebdf6143c100220af7d04172d5fbb0a2bacc0f7daf57aea48ca6bbfc14543485d4021ba2800746e5ee38bd6a916705ee7d737a65c005fbbf5617b17ad53bba5d7b5055f8ad76e95e8a9175d5ebb8da29db26801394bba0ca96961074a840b9b089ee769346500f957b3e09879cbb82160ad9ad921ec76bdcb4f3aef72f9071b76d55c3ebb2ed7f2daf3567a2d664a5847ccd49b2d361dee00421709d738239d44dd1ba7dc2889306a8c6d8ae058d3befd36d7f49e6a93f5c1e7f8a6530fc3d71e62d06b1bae553f35768d71d5577bbdb6059c00df35585731eb456badb5e25ac58ac5a06a735cab59b4d6e6bcf7edba894be01cd82b6a315bf89682307892b0f9e9287ac1c2908259ad5f313b214992d4a2ae2adf32ae6616748659ccabac6cadcc29d7e1c36bcdc20d0b195e6f1773b0c73d8a28c4cc20e5b3cb66d93d43b1c8f2d943c823ee88cb62891e5ba8c00ad4c1b73aff2c02ac57342cba5c6183ab2076ebcc75f00ff2cf8ac03c1735a6618d71893febdf1c672ee8732b80f812e39cf398b1f0b5987199db88f914b3f045a5bcc62240f43cead1354df452749cb3701c7325b03e6fd9316cef0d2b77d9b5cbd2aeb008c85e6eb3dc295c9bc69e75ce95b8f666d7b46c776f9d7ec4cdb414b09d81dd5960b4bb6bd3b9c4185f6ff988db7a0d252d17e24bd7c09c73ceb9962bfd45d3bf1de7cb5f59e839fdd356d7a644c7086c86f8fcdbfb3c67eefa77d1975bd7561ab863b5dc79c26ab9d9ccdd1614f42faf2f37b18bc4cbac0738ad2b7bcd38048ea9ac7d3081cfa597355d65922f5a7e2557c799d3bda68b66eb7ae9a2557ffaeb286f5de7b493e6d1b44e35d06e346da477a2d0f4145ef49b7496631306d22deddac91fdfaedc29d256b0fd076e8e2e123f3f567ff0c1072e0f366436558418ac08b06e4db04a7d6d5ed881a708675f98b9f5bca60ae518dcbccd66de7a2e63619d47afda8a02d7366a8c473747cfaeb588458c4390a057a8c09144886b1b6bb8d2505083d801e0a6d3343ca60140c3bbc768b92a9500cfb514e0b97304cfc93e969b7dcc3f66fb58d0c7407c8c848fd13c56008fc5bcc34545f0987fb8e8068f790817bd79cc435c547bcc4754a19ac71e7f30805b6d00a7e5ecbb0720141ebb16f30d5ee715bcde8e692b043d0edafee3668b06c237ede7c7b78bb4dc871745d15bf746bae872988b64cde6328f23eca461170d2ff9f08d749bdd966e4db78ea52e3a7aeb02690f80d78b0ac0d192f6e1dab493b41906d23e6a372d2d17f4bab63db848bb798b561f44b5f90f2db742d0dbdcc3ed86f5071c93cd4ddbbad97cc4e50042086e7dc4dd2002cdbe06cc2380db019018c001dcac67905717892039a8401c1302bcba482000f862d6a2a8754541053e08377d680b70910602448bc3cd731dfec3675bd06710798367f78bca3c7b0821aa10ccb39b66ee3e4db320075fba072cb05f6ea0d9bfd16e1287fc437d4437384aab17086ba0dd24b2846bd32ea3fdd08250a822683f69aed658ea7a6d15f8ba267a90679a02dc87567f01b4dc080e82368207294001b49c4712704c23282001b47a6d41b47a6d08a01da016e2dab408b4fa21d0eab5198056afad00b47a6d40b47a6d3602d00640dbd7a61d04da8981b47ff050a3a55045d03548ab055d5bf0ddaf7770a7d517002db73f00b55ceb4503002d073365fc073414d8de83da0966ae5d13c93a7c4ea72582a88093c5250d14173b9c75717851ebc25bef8096829d39a6ad60abb901b6a112d263461ba62b612ad360e60896a42a58522a5a4099cc5a6706150e266bbe24c9c2024a558ad0417564cf9292346bc634bd4ac0509124048d9396365380e68e567d014c939dac19be48b51113c30be39c4140250995912435e8e4c0d930affd9cb9f0cf7a6a5ccbad60fb0de3b460beace5f658cb9d62edc9cdef732de7afc98c0143064a92245926703e1b36a6a2a21076f5d76159aec3805548017f1de6846f3abdb0aabf0dc052a30b0ca7312d6cc1dd1dbed53d3a2d68764854766470d761bc8bda2f7f1da6846f2252f4f02db9d9f1630cee3aac7751ebc5a704d604c5e4afc3a25c74b45351fdd3bfaccfc261151a01dfee70f852c237154c795a4ad3c40e550fdcf557efa2b6cb5f7ff9f0cd04666010a3e5c511224870d75f4d17b54ef856620a9319372ecc7ca113c4592e3f7dfd75f5aa515131f8327aed5ebc2a5480bffe4af1ed62b99cf0ad862506353244bdd0c607eeda2d7fddf5c3b70d7851e1c2478b3538a0e0aed5f2d75d417c738195123a499e3ce9220677dd8575519b4528e7a2e291bfeeca7239a9a8f8fb45f9ebae2597aba90a01fd759712be5d20b0f7d75b417c2b81c4891b1846f6acb9a30477bd8575518be5afb784f856d10cc9c0624d0d1956b8ebade145ed95bfee4af1ad6ae1a2878e93ab1e308a70d75dba8b5a2b3b192ede45afbb6eb4c6545474129daefe7a2b4bebd7025621db5f6f45b937cccbb5a4fe7a2bc5371ca461f43481f3064b1cdcadfa1254aed88082c574e70416eea2b6ca5f6f29e15b079cf81072a487a60a0bce52fdf5966fc85f6f29b9b71177ddb45351acc3baac357286558876abaa94f00d04199c76c3ac222222b86ba7feca800b9619473000f100c15da9bf6e3ae1db0a866024b913acca7283bb36ea6705e4f1d7cdab8bd6a8e87d7a7a6b1a99324c5e15f2bff9973389fe7a59f5c3370a14a138922606a43b4eb80bf5d7cb20be39111b645cf042444f0cdcf512eba2f649c8fb5be2ae974e2a7a8508795b2e954acaa62a2480bf5e2ae1dbf5f9c820be15a04eb0881224413a3bdc7512eba2d6e9af93427cab70645c2933440d942333e0ae93c38b5a2a7fbd4cf1ad0e87102162648e8c30297077ca4e46c9bbe8f5f2c645cdbf4e8ea9e87d715f90577f9dcc425a91c02a1480bf4e3ae1dbbd97acfaeb648a6f26948921062b6fdeb428c25d277517b552fe3ab9c3b712484b5a00be218af3040b779de45d9454c237109ac0518187cd0aac15b8eb64efa2168a4f090915e5a2a49d8a5a3b76b2d6c81956a1d94d6f8ad56bba68adba68fd5901f3fcf57db56b54d49221f3f6fa36da322e5aab1087bfbe537cb3585855c02ab423e7a27968e7af8f59a3938a5a2b56defab8342a199baad086bff6f77b1dc4b7123a26aa183f90825bcad827f85601df0b1b36d2c0a85306775d0f2f6a9da04cde84c161834d1434b8a69d8c8b8e7f7de4c1f9ebe38d8b8ea83d72445ffd759d455b5db4be86bfb6a9a9aac4d15210324fca18a9f282bbb6c99760f223498c0b3064244183bbae7917b54c3e4492ab2b4d566d88dcc15dd7bd8bda253e25ba89cc5fd7512e1ab353515ba3c69a8b0a657f5d0c5aac12424e1425c5915a3307084ec95f179b9cf04d041d3c57f04c99c212c45d17ab2e6a93fcac8062feba7875d1f2af8b352a6a615818e28dbf2e1a89327855a8f557f72e903d3d2712fdf55c958158422b7f3dcbb9b7170ea5819d287f3d2f659ff9d7f345873b9f267f3ddfb8a8cf5fc7632a2a02326f1d67b968cbafe35ff957059ce25b8924bf16b2c2c0b9226487bb16c95fc73b7cab7656b4193ee1e104490a9c3df2d7b112be5516a414f9f2428985a41eb8ebb87751ebf35dc7512ebaed543402d5cacdfaeb77cd9533bc417c43e1d7abba68fd590179fcf57b7551d75fbf352a9a8004dcf8ebd7c8ef0e5fde4d6f092677f2ecaaac58e1d10477ad91bf6e8117ad5817ad423936eba24e2ada41b559efe0ed75aba4a90ad95bc164093112f2e5081d1db6484573e687191947b050e9c159a607c8f032a45b32e605197076692703f6d73950515b6dd66f9b02285c4f81cd509e154092d61c05c159220c30ba41c6479494e011eefaeca2768806aa9c1062c547687de382ecd12bc75d539dd7a59b6339967b2c8a513949518281f5a462b9898442e2bc9b548de4f874e3477999009be4938950a7424b1c154749574f8610b539a25ae21b99a42ef6f6a16ac2520a3267305cb910aa81d11b92a7c88425ba13464a7a445c28d92969b2c8efb19491a3140aa5609aa62d869a76ad522aa4aa50c9ec949da76c264b614d48ad7032ab5b53f192f48d634992bebd83453c34464e4825b008e25961548251b08415411fc19074e61895e4385eedf6156f5f295df566573ebf6ab20595e5d0976559966559da58482f50d5ed4c6081e7f876d2f029ef299b5d053150dd5904d6efb1b7a1dc7bef2de6ea025533a50962d6cc4eec3d3ed5991203f63ee0aa078beeb7cd76ce3c68b79482c6968964935a7fd05b6f1faf11579224f71ec791244972cb3849922465a59108aa1c514f6e92a40293ca9ef44d562f6b24b94992244972d46449525909cf7cd66aed054992243945a6c8937b3c835ac32c411a5b7b01ee1d75270ed218a4ca4227861e472b27adb5a830fae2d332636785a5e5c70a2f422129be683162c5d342e5c597dd8cf6f5290b4d8b6987f9bd5ba60947c216342a3c3d6f9c3ce9f174e2f790aa85092ff19e54a7cf6b9335edad9311bc6194f68c5a00951c99e062f8b43361a7c4a20b0c135a34cd3af8fa646388ef72a824f7e6011bb5589665c9d33ccd33cbb22cb71ec95d9aa62f641c69e5169d292344bf755f2f5aeebdb7d2ef516b92246d3c4992244992387e1b0770e3086e1c581b8770e3186e72efbdf7de9ad4fbc8e8a5b5d65a36430292484112098b44129248439257ea209224499224b5d624499224496a529fb933ea271952cc6dcf9df4bb4015b88327d64ce849435b1af49bc40d5d88df5e3a1991533edea847adf58877699ad63862da7b9f53407c555f2f2aae2841848d1e29749e0ca972c78454f00d997b88e086893d728451b65ce1f6d053559928e6075d948c9bfc5d77269fe8cca5bd4fd96c89eec738d6bc975469ada794c478ed79cbb4d65a37f9685a227d8aa88aec6162440d141665703a7dd2f4e4caeb71d45a6badf5388e5a6badb51ec751eb514529d659de4c76e4de7befbdb713270c54779d1f3d97793ff161a8384cf638baf9711c9baa3050dd6eef388ee388f4e3b8f7de3bc718f528c3b64d74249aec48921cc97124a7920447124ecad65eb1f77ef28b3ad32347921c35100c515c6824c1bdb1b0d0487a6190c423552cd8a8c843167460e0243d5d8c2b9b1dd125cd20e1f3b5209104689d7cf61082387c7d8ae3f36d2e99bbf5a4c20eaeb55dafcda65fa7ea58d9f4499a0cab400384c1e48554132929f6584d0dc5ccce7356f7299b7d7d9a61747a4661ea56490e195bba955b1ff40815bb674dd69a336a728f3bfd32b3232e391e3d5959a12755f3532babe878bff38c1268502961126c23a7066eebf95d45172ccb2441ae16a94d361d8c24499230529d59be3061fc7edc7bbb2e22dff4c0cc729de5fd42c68b1b673992bb4ac5f0e9a2670a491ac7711c4717c1b24a8bdd8fa3dbd3774e336090f991dc558e863c8751e5b6ff127cfdf88dfa48b8f7d50badc2a7868d916854a5c60e8e2c9b19e93050dd346ce01403d5ed2bbab2d9914f9f70d4743291614f5811c440755f89318ee3092c7c18a8eebf3224c057a81341df668fb1345b30fcdebe65fb77e9aeb29cf5f06120b324ef08cd71040204089071efbd79bf37e9a39be4488efa041919caf10e9e9666d2655d9522ba2246294c316f1e430c548f5ae87105cd962034e2ecb07998e830e1d9a569aa0206872c9b55a8de9a2a5d8e56c82e49dca273d6e057a825a2dfae6bf0c70c5544862e8fbcae6ce6a30a03d52d9ed84c5755d4e021a9689b3793920b54a36ca933cbec4b262bb7690fbffda4f2fb85139ea9726f1fe24eb177171856434b27acec81ca624ac3e4e689a4f9ebd31024b32b41aed668bed9db35b6c6566d54d244ba49e6142693154c5ae8256fccb872dd792bd9912c94f894cd96a4e56672a2ceef513b97dfe5f5d3e6ffc1f66b39c17cefbd7de7ad048881ea93ba2c7df411d73fd8cabdf7de504c66fcdea326f7de497cbf7ffb2e7defbd97f8305025691faecdb58df61e000d3833d8dce0957181db787efb09fc0db5e4ccef5127e9f987272fc2cf7990d9c64b52ca62a51fc751fc516bad93a47b2fb9c8b2d91003d50d2506de79fb943050dd2fb6e0b8b299912a233f23c0f3c4b7fa428d0d244d489c663f3a8a1f5de046977915aa3f8e23f002d5d747821757c40903d57dd16a4fd9936ef8b9d337e9c30e4bbc9891f5054c1217d8b470a76806276ec498701305378453244bcb9b2b44629ece0ccfaf522d9072520c5251bc231731948eacaae9fa2a7554a5c7b8f78b56929b295d6e0c6963c48e9e22d857a92337ba4ad96697527c88902d1d2ea92315af33c9e5a5e1ab94911c29232c17d4b8b5d65acf6b5d948f8643466f5e7f031e2e3cc132e6088b275c1ebe71b9be46a5664e3d5ed53367de6c3d8ee3388ea3d65b6fbd759535595e5169959c24a24087fc18b50edb1194264431505db580d37586980c4519c72123e30b1dfa21d66043eef628ee4d6aadf528eebdb5d6daa5b59e09ef9843795a6813ba918688436badb50ef25a1cc7711ca34cf0f8717686fc94cb4bf6352a4df1adaf51432de81346092a40a69c30f182c58d187444e040c99cdd8b3c548a80b17344881051c2878be1953a4a3ca2b8e0ac9cb77e9e1121b4af531c2ba95b68ed5b43392255e8335092c6a8d4854c034d6f6a06d31a3d615ac08d719ec4997a5267e6b6f1b307d53373c85af5c4ccefaf534fae84a58719453ac90d9c5d1c9f101d1c393ec014d1a832e3c79b2e654992a56d136496963423deed66edbcb6996cd76433f2b228f544ed172ec049f31b6327ca1ea190198634761dc7d12b981f7ff42dbbb78c1bddc773cc44b31f85bcf951c89d1fb5d65aeb749f58ebdc397bed4f42b6bcd6f9b53eebe7ce1f5910f9e0b696de699d8131586176325e487105a7dd14c1d839f00fb60fd736d250810791144be2bc3004056e6cf3e3101e55ea5cd9dc67a5f9c1fcfa24a4e9731e44b6cec0207fae657341d82f50032e534df4cc39b19403876b8e813cfc887bddc30759361d7ce0471baa1f3ad690a1c1a664c09319741419499b345953b514552d7bf213120a3269b2ec7cd4c159356ffdb43ebba887b7b66e80c94acf9ba9a91f36d2542e2c3889f2a22ae98d8a19ce94e0a53254f1a2c4c44a1c2c0e708009903c7a6850418a4106d858b586b75e31164beca5ecad9875496eb36abcc2cc73adaf359b6d0bf2af307b5cd31857a9e2b2a54e903773d03041a3c55dafb298f0d4c0f9c2b43b13e4e12b149e16befc0a85a78b78dde82210a4609c6accf191a2076e34f3a35192057654508200937c4370b90c99369f5d8647cf670f21c8f6152aebe85f5fa1f0ec112f9bd28d69676b5de6754e318e6af6f0f83ccba26f903714ac936f3f06a68d3879ea9029b2c2110307cc9ab5a6c9340dc6b080e4846715030d4e93897aecb21976c76e937aec217808a7ecc37561eb2261ad9cfb6b1b286fbd859d666e3d3b459979eb1deeede2ac75a0f3c26c4962af213e7788f3f9b38b96b44b4ed1ade77cce1cdf32ce673eab42c60dd16c866f39d724a08446c5100e112439381bd441220db37ec89d4223aa0824e8927493acba963a273a292ee01cb7883f08e1f707a246a8f42bd9ea72d62163680400000000d3160000180c0c08c682791e46614e6b771480106094505c5c3e1347a3419083288a81180832c618638821c818c34cd56d0313920587dba46cbe443d6e6e942f8ece4f97924babbb140da2325554422ad73b8d6b452934d9def0fca1d6609f47c5f69867f4afd4e013824e6b8429e4b4f0be994470ef3baa28e800b788ef7dc33fe5e231df325cd714b163c821050406641fdd0e19168e34ba021e22f54a2a3cd56b02d62a46f0012539b71ac13573861bdd34b72aa0ef7c29280590f624ceaf58c87dace1c596db8300747e1c3429a89a319ecb1c77ff1f55a32ef383395edcb05156e07b5d2a0747f0c51e2e2866d021c62f99d61fc564a24284af0a576652432f70c8e0c4ac82a4feaca9031a96594f6fc98d0b78da49942866f62f055822014a492f6a14a67d589a4e42fbb496caa28f4f53887bf659a804564289a454082c55160e824628c5b0f9b3525d5158014c3e982556c6d84a37782d97679584f4aed951994cd982318c953e4700226f67843e8a9c12098484e2fad0b172d424f309ce57759ef68d057f9a4043389412ad4094edc42c7e35dc823c830235ee926995a29c49fd26981165ba954e6e5d8646cb05ad53a0dcad34c4680786c5a253d299bcfc47822894880c7cf00dd9161bffcb22e5db81aa27e75a578af459707875debd40b0500a00b5acd62e2d0e8ad6d23b4c9182e44733f96149140adcc7115b3eea912b5175a542165ec2586ac922659c19a850f611becc9249e468a7119661497b2e329d4fe91d2288f0670cd70dad23014cd94562a99a2c1038a1293d6d67b7c8327f0857f8f72b3d7a398735f1d493125edc5373f2825a1b920f0144dbe800a78556df181df750a116ecf450939a2a951b0df125fbc2a54979eb7bf977c878f29853ab655727613b2ce8035a380e49d7278b839359116abfd76a41114d834146f53fdf68a9ef9995f4803c10dd6e2e8cc283b89072ae19960d76514cf6744f7583cd865b63473c9c1eacd6449009b8aaad3441978f28dd976005fdd845137ae0d20b815d6d676bb28c2a03228657a54c1b772813a40d6c23304fce240af6f1a6a4d17bcacfab22c7f33e2c4a48480d778782687d4162f13c55e49fdc7030b784abe27084984189f4591e2fc245d303a0062de1607815b8225cc2af74efb26c84e8aa5ea12ebf6eed8a121944f18684e70e349f3173c91313b9f43bba9bc888462e0f3280e241b48dae7e0620c11a761e70f713edf0e2431538a214173c3c7cf70a9c05c3549a780cebe6f32ede243ed8c437c4831b31762af4cbf4353111b1b2dbe639b903741c4c01a9abbfc39e44da0bbd87349f225ab8641082d3189a8682d406de0fd15d3bfd3cf726dd5e703aec4cda6e88dc5e44eccebdb16cdcca843308bdb717fb963710ccde97a50185c462392c16706771185fedb83db879559719d023f4a03368a1e3d74cab1fe54cb4505cc08b1fcbfa0cadcf784166885f6e265a08f98a706d2635f4f90aa898243c27e32dd69ad0d278aebcebd685de2345fb320480681a130f6a5d7c51eb7257e4b8a55c6f278b5f53221b827535e4b6707451018f450ba578706ce94a366978c2511377b28bd81c889b0cc10e2ef758787b39f8f2c7342de3d2c16df76211a1907b62c9140953424c4debb4b17fb7c75a8d5156255792ef44fccec26d3736e07f50553eb134b3b08a85cd4762163459f46346d57e8da4f7736f4003e83ccabc856686877c6f5305e941e59175e6fd57cbac284f08b4bb4dd1b35f5b2f9fca8d3db5018ff53109979ff51444a60984e71b16e315be302d437f55722aafd9aa868c595a46da01b789efced12472f26d4c7da6444eda0e5dd0b2327a2c57ce963164e456049c6b91e54194d280d57c6bee9811194920e4fc140d2f846b9425b84421f312e319ed577719fcadc1c2dbe27855ac6ae9248b77aa11f8d1a0968c7454f6cf6b6fc0dc556a085a269d642e22b1fae3b92ff9e414961ede0e276a4ed2b1159758fb1da5193513b653e648e77f577c5bdd4cbafa1f6d0357ff1645dd6e39dd3f25352be56947ab12717c42af474e3fbebf5082657bde3efc2fa207ae7958d03c3989fd734c64518c919c97394c2e3ef58f1cc4fc3b0738a3c3c6fbe40694fcf567c20891df3e2569f3159cb40812fc3f1b5bcf75e04a169938bd6d83252fc3f4ccedf8f5d45b556edf1e4818ee43c0d6e22d0116d6c9c69b73d28a19183415726d1a20e4fe6a02a33449a9f88b8425b3d05fb2e89031babe90dcda486a1fa81468076a034485248bc3177bbcddffe656f52d229f1424ed4764863c9c10c38851310e9e0067654cf85efe861a75b1ef55812ac7d8e0e2ab60bdcbb9dd82326133d2eebac0dc2a91818838175444976a5d3b8f05a53a3bcb9e7b019b271fe9f3e53a963a892f16ec218df514638b3e9fcdfafb33c320cd76fe6e47b0487768463d7fefe02c91185ea57a33e8f9a596fc299b25f75e253081b3b3cbb2613dbc50ccc01992289c82efc3361b8a63991ef218743471a4a66557b3dd15755daeb4de017cf5a3e9a6532cf586ce2a6a7b27bafb13a2dd6687f14e73db9756f3c4b8f9f8ae72ae7551fe0bbbbf0ee86e427cfa53466748225a3499bfda4139311e55a359c349278d7c33fd4b16c263c2fb0da9b1e216a8c6481a819cc84f0b4beaa64112230b79a26865189b5bca49753f3d409b18b0d2039a82bc7c6a9aaa6c7fedff0caaec98d341b72ace73a054db0a8fe7ff22032877260d26cfa08b6980e4b77739132d04bed222293f92fb9c73821122941736e90d16443d081b335c2042d5ee7528c17ac831f26506374f7456f92171dbe626796cdd61a3106beec4f60dc87d9af94dacdc0bcde96155ed660bf1bb4cabda6dd987af58381a796157c61f83dc58e2f4284e5e915ca3c01ac84aa235339e8e6ae1b82e4b1f7939c8b88446492df852f6278655c3e24d206203f6ab9671385b8d9ba844aae832d06491c235035c93a7c88c55ab52fcf2559a58bb2bdb9156842abfbd0934f6aa1168ea7e094d18c80219fa5bb993fa90864508502465c0acc858045106e9b2ef0f114972adfb0b4efe8f79648f2d11c352d4cc963c9092d113298dede558335f968d24f3ec9f514ac35055f6c52dcda29ecc625357e1d528ecf798bd912a0de986f6525845ac650344fe519084548a34a0492e5f2fd3c8130931331ae6604d3869fbc954dad4ec54ddb267b35008b24986084555f2c1678c97a668e167a3cd7273341270395eaef1feeb975ae4d44ca2d6ca230c84c80b2b5392bc1c19859928d9570bd7e092c784ed0cf6d2bc09711aec4d0e476d55bded35418f3ff43cf56ab07d2a68d3d29f516cf9c3215851244a62055a05b72e0332ff0a735a6fd3597760d6aa7a48400a5e0e54d47dceaee60fc4def27b33250344b67108336874215d8ccb6869a3e6d9cb41407a5408041b2153094921166d1c7198ae55f698cafb5bb1be8463c87bf0623e032f530ecf84e65019f8e08b7fa4ce3c2aed2ec260c007df7254e30fbde9be1f0798410db947fb6f124c8211c411c76212b814bfa555528a37247ad0c398f4df2afa9765f0dfb73146aaeb13bf03253964ca5026d02969b6225e0406f504714e7013f0d3cc9eadb3c3ee9f1ea04866efba18957538521f5ad25a73cf4916a2426d82f8f17131fed4a3bb25f79cf1bd6083111d05c895e4b54254088edc4132c9ca497de77b1e11361e259d9f8d1eec441e2c256eeb6cb74e6979b0820a5c90c0485724224f330c50d531705115b3de0795e30cb6c09b92c308bbfaf0f3478f0b00a38e40ecff94901d001617688a73df1ddbfacbbbb86481245151ef844747c9f2aeaea61205a5423a58f60459f50c6c1cfd490ffb0d0f23cf5219f05309db401a7e8f151a54e922c4e71dcd0cf5a8fd3b3812f16f5e2c30d0a11d4652698747cb55c07860da02165d77e225e07c65022b32eb8e0dc14d92c1854194eb6bc3a079af25888dc364493bd0813324838b83da1b409639687b5a7fb86b84e1c66eb20f52990a97ca98ebd7839ece4149e7bf554c493b03d82412b44c3969fcc1a665527434c009bff0e07d170cdf4ce8953c0f8be24d05e611603d42aae2975fa1b899764545c6214b102a2a7a33c19929a68e86413599f4e0dfcb662098b1040f42387c377037c494fff88972a110c2c2cb03bbe34003e2ef9fe7d004163ac6ec196f8dd2ec81fa2664b8ee29455fabbf2fcb916d57cc89b3a7bbad212a17cb29358bf6cdd2716a198ee89325be18d72a624876518163d8dec05bc98950e9c64df68a1cdc03792f53866aa04c9b14bb592344118b1b3eea30461b7e121c78d797553420fa080478a8cacbaff7c95937c741af822be11730445572056e13ae8f5b1d232f2c5ef2ae92844546263dc3268eca169437eea6e75c8e7d32105341e05d0ccabd0ccd37edf5aa498c3c34c842e5f5c42abd0a6f10e5bb03cc040af6d1daddf34817d71dce86b98d2ec6a29c58a5b5c8e5c585a4f6ccf0c9a16d02b1467693aba605291988e511e25026feca10ac227ccb31da5cc67f8947650320c7886477ceb53ced3accbe2d5f40de3ef32eb5690251821c3893ef210f34f125cb1cb8bf2a86a3e173869f93f612a638ea088a87d9d19575f4d60f45e171ff21b5299e03bf45946c912ba4003fb050d07b4d8c82cec7608642b802efb34e2b340718eb1cc5be8b6f419693d5e0d455805a6560549b45af3e0787c9d111268db25d1534a6e1bc2f39b2cce090fa43757f2efe227663d600db6e08d887bdf360e5ce5ec40cf6456c2d7388bc6dc39498ac3468c456b53fa7dd181ca03d1e03b4d441892622a4c5a290ed66cc96be459b7ed624e13f947b298df7eb6e2e1374b80cd0979bbe882c6c83cb3097a1658411e6dced13632e61016d0328955948a92c3081460c5c824e633f8e11d7d359240abe7db4ca13645de2da6174dde5e88431cca3b8158ab728df1a906cf8cdf5f1c1be378b01f12aebc29b0bcf1708c10d272fae9c6212464d71931585be1a54ef2988c12959174fae0b918e2ec99e984bf52f02da168663f9e99c9569af330ac431cff91084340165e79eb2010d45b455a9ef20710834136bc602e57621a29a1be1c3a7f24d0d3edc4bf01cc8aa2e4d707d97a55abc4c3381f163550d69e6e22d656d53873533756f06dc42d2175178a5e53f6e55eebca111e5de3e7b6e9a0b06d1acbd4449cc08d1436c62b2ca4fe8e54215bcf512e11bb38467b450c578a046d29770ee642895992b925fe92f4b296fd4cd24ae8cb18c610b0cbd163ed687c498d9a14b6ad56a98e4f441adf102535fc689a607d603568aa5c29e6b2b65a2982d63a812740358c40e24f2e9281a968f0f85eec1c4604e67907adb03dccea323fc04e26646102b19e99aa53c121a2fa5f706b8fee0cb597142964b3878511e16a63f7a77b97fa2b9e2441a3b0ac220c44a0cf49a32546db4fbcf1fe60e8d320ebb1fb577d18e33faf59da7a6921a279ffef8f40ea7138fe2d91b0fa5cbb53f68426a69a70370aab09e6f27c604316b47be3dec90de4d4342327d269d07f26dbd5548508a2dda3c7cb0d3689e96985b8ba8967d2080580d32d712500c72cd629be6d8f1dda741c3a1b733fdfa8b4a36e54af65955e2b9c756e69f6746435b7d86ff1db716d55425f7bf1317bee4068d7b8c5d20bf0d846c091283a162afc4b4e7dbe4c293c8f0589532a5834a26ad062365436e4b31e3df6da73e518a3628a66545a9d8ed592cab4c854413f29b44a96ec095d928a39aa4b6cc9c8067eb3c339aa0d03cb5e85f31b8bebf2e51b4b23308992eb9975cc193e60154a6675290f24c1bf771f0e77dcdd7a4b23edfdf041451d3c959d241d5c6c1da61c2eba5e3219e494c3b79d800c14e8d619273c5668000d74464d0c538147f4f96c35a329561900843926013a35bd0b1aabcd2fceae75d78df9665685dd00308d4f52a1ee7ccd04151e318be22a491a9e40e7cdadbb5734a51580c74aff4fcfb389209d72aebb8e5249874c34a1066592b9d1aa28276c046e948e8f4697d03b5efc8359a31ea2bb3c13e5a1ae218e7f123d8bb58f07ee049c5f542e023a02a2006cc5dfa583c67b248f166a61ce464ad529458dbf9627414f61ea623bbe944b3ce42058251891c34de1c1f935841f89c94f0d18e55514573b58585894c107e30ca8fcfc2db96b658a73865fd8a8100b316d6957d2527fa5eb31fa4de84440aa7d123d33655118b82e879208e21e65630e42d05b47907313878aa760faca617ad626ab6dbae3f924a5a84b6224daea37af488edaa50301702880dcba2b8516c90c7d3e20cb31de10fa0d9f01978c6c9f7a281cb1668cb9a3aece29c0083d114a5f83b1a408723b74d348d42eed54718d22a6a0a82753cf7dd54535d6e722e9cd9835ee91844d49835d60285d260e82e8e5f7d49cfd0cb9872bd2dd5280e3eadd1d9e4a501734c7d0b8d12f4a7a7caf767b36378358822a6394d42f082c4401875acbbb34d6cb49f6640b42c0c9b7b175f21c9205838baf584d8fc0e2ddb6c54fe1caee7da7c21c4d8828890ed36abaef32ffa9976810fd3b3e6faf398a1de4048a8cee480db4862cf1b4411bd2098a7559135c8ece659092a62fc2d4ca86615603c29f78c31ecbf672c00930716ce1a914f23806c00130a3532f7e7aa20882db19a93eeb501ef425e6e11aaec73262076bc50a693499f6422b8faeaf1451724051847d98684c3fd78fc11d761dc3ba8213d74a34b9a74c7b916c25e47b7f993a6cb784370f695abeb314a3f20018e72288ffff86abc862a1367bc37b754d467f4ae939538ddf9089d1814efe494a8aa4f3846d626c9fe2081195540efde2de1c260ab891ba07569d34bf557ea2fb0d91349889156cfa7bb014a9ea98c3be1e1933cbae7cc348c14814a40002b582d7a1ffc4fc727d86a8c75f7762ccaba2d621240a55128eb0e6ed816e02cc9906fefc9367db8b9df0c93d7b907e448862da33d4bc15b5083895d8d265b4fa8de7a64cdb6268aaa9614363e9b5bfbb79370cb295bb3e5e6930f95993a01a2e64f47336e4986650ba00d71a407a959c8766f5a13cc96b82ec9de19c66942c05ac03bb770c0f57329696571702dbd2d5c4572a4e04ad82ca7a06e2b52c7b127d0f251a32a029790ae6e339e97c40d32cc95b537fbed98afa94e10b552433b72c133d5498f98a08844e27187fb1a56355c14fb849e35f8bf2d67f69d2cae43d6009c8d4911797d00ed923c93fbb1c834cef894ed66e8d8faa9c475c78dd9394f308889718e393f3a1367a077e6997f41e561ac76921dcdcbc6b9afb786df07ee40bb9d2fe301330430697a7ce314d9030cdf3951bc18e70a117a35dff0ffedd5f51e76fb016671df0ed1629624cb4c5256e70c550a96c705ebbd4f59f1a6eded99c27f9da76e7b54a279a25a0824ecfcd00e0eb4ac5e792ae8186761c8f33ae265fd45e559f290100b7a5218684e912347d40b89f5395c4c85865466ac9bd336b6fb564bb94d40e11407d1e20fb98f545feef6f9211636689a7927632433efdb0673134dce10ec3d7594024d6e3aebf2be4c2e8e560ac187f54a3e92ba6dcb5c12132bf22d105927738e308be02600c3bca9016e12e87d05fe1d38a1c64ec4c43f822747a268b30a2da225be56d624135227c197e6d62e0edcbc48b60fdb5d719624d80a69ad1e8b7294c101edd4e8df8a80a27e1ab7e1b4a3a4b7579c3e8c12767139835e5ecb27b72621699e90af5241da10fed9a5ec333832449b1b45f51cd55e5cdc59b06abfd68245cce26a004c52952ed659493324fb44ab9a7128bb31ed8f04ae12738b030b676468c883badfdad1d380b3cf1abd5eccd03af61ea6b2b3237c83ad441c2c9a314dea8ce4ab8ae55e6304e799a0d9d733739fe1b25b2f7e302cd4309f8dc8c0aa7c309fef7552754d7e9818b07a5c6e963bb93dcf8508a333c1558332c2d6e9bd5e6aeb68b3c31ba57881da743ffcaa016c91dfe119b8ee442b751677789a5d5c10dcd5d3429756dae2a0fe402b20a3e797ef3e94100d0feaa297ff5d48528e87e51c044c4944773b07f44e90ef6dd28b98a16b6a3837a8a9b6d9a4d0f91b4fa347844eac53dd3bbf67e1451f0fc931e186bb77808e117b1fd746544267c0457ff74517fc626d51821f85f5c03d4c4c128e34cde91e78d5d1150566c8ddfa0710ce19b1d141bc7914ac4a610f5c5bd0b5419372e276c5c312a1793368e2a16bd64f95a0d5925249b480f71cceddd1aef05615a9e5254ed886222647af1652aa850a218143a0727e03c9e93d4bff22a10aca77690cb4eb77301a50444a58950a3ff19a2f70e7db140a120f426bf938c06d1107aa33522f4d32914cf6a5c72a4d51790bc2150f66c80a31fa63286ed13d404f5cb0b9e94bfc58987f3eb1ba535a2a3bc5a4e54d4fe30d6aa9fb429518c1619cab9fe9fe776d6b5403736522fd641708a4d77cebb14197fcdf27e35da487cc7d25b106401fbbf04199328614af726c2b447c367dd89bb0ab22f9b7a98e7875a6702a0678166291c59e4a6f02f5b60ff25f458371c14c673a0874e8fff49b30f8f2aa7b4f0b742acfe28eb8cdf0aafb12f4ff3da8df577bc410f59aff41d068b407430cad8a18e7ded31e463c7ed03e14d5dec20363518a3b1b80284137b95a3372cedf566aabab8089962442b4f426ea373fcc9f88adc45127deb497b379985a6823813c44e0dbea33120a2608fe8fd653286885541a38212c441e37cc88a0902e599318dbd55bee81d15354a00195578f6eab3c831d2d50cbb506c41da0324da0fb4d3fec7ace37da4e6665ae9002602619eced370148409dfeb9612fcaed134a7ad6e2e46d718b4d3c17a5c24b7ef9a16f5c5903d5797ae8efa40075692676f73981a7f1f8bfac47f0d35319b0030cc4d8a35dbb11040d0d81398afe0bd467d880532fe9cfbc24bf379d0c850ec5cced1db299bce6410459436cd22e9a4dcb944877d9602d0900e07347e031a3948ba0e444eadf7d6cf882f1456001b9e44546c885d5cc0ba5bd5003a96426b8a7f994113e9e24894172520313af52c6229124c9149a45f7a7335d266f73e6064c46226caef5a78bdc1cf03cc2b0fd8a8860a105437ef38ecade9195a20cbd38e7a1bbfd5e7e52b2dad28d69e9fe021e44bbaf92e1dd604761b7f2d62d8226938989378bde13171e248d9e71647498ea2760ba120d3c5f13a7cfbe9c052b35ede1b9ad44f08fc21e30ba56768c8e3aff977ed9116c8a125db80df2a9663c08b23d001a40c2465e7408998403c9e939a0754562d88b97cec988d253aff4e3aeaea89ff11db129b1b1f369f6ebf6ff2ad9a3b4477d4c221822af3627e1f4e1d004bb5656b31efc191a9daf6aa1384b9700acd4c43e5cc755b454102f62edbc4e6254593de182a5fbb00d2215b79b5c31437c4c2bbd75da0da7a9468007b7f7a06a2f63158d6d08a8301c378d56a582c307a83600a031e5527b525d981edeffce3112d4ff34a9d5e028ecdd2d56a6189368df16cb764837387df2de89c81b63119e4604a156013efe6bb16588508bb6688a624abdcea104fc5ddbe908b505132823b4d917b48806e292312f5dc2ec644beb8300bbe37285eb973d577bfea88aaa4079e5d146b9da4eedce7b17455f79f0314cde174a8bbffd81b46b060f7ca5dc91a0537cdeb73dd457cf0cdc87577e860aa04827796b3539a382589248d038bb979001c590e72d453bad80bc4dbcc5a1d51906c055a5b6eb6a05514fc91ff034dc0159732714d26cfc26262ea9b19ac1cdc1b660ca3cb264c2b01fb122f304d62858a71aa62748bf6abc27e5b99be2fc53001ea0c432bc5c05ebf4dd167e351e6b86080c40b3ca55b906b7d65a8683abc1da0449c5501b81006989deba3c7b0f8306cd70fc3439c61d6c867cb1918042692eef342e827593c8887db6301c449dfc155262c0334bd4d50f53d3796bf29d096d3b56e83708d7e0d3b5a42e613a7126c5e32194343d75d6cccf1347398ab82d2228d8d307dd14675f32310726ff0c5a87aac85b81a43b87de0a5376023cd4b62a1b350bd3f69136a72ee9819258f78e0144e2b7e4e51b80b8b3904ee9ddecb7d7df0f2bc0c0c47d17d30265dbc4752c42fc3862c64f8b40f1faaddcd146f9384f29e78190803ba4b2ef9dbd7468f2b2c126fecb66776206d2a9ebe5f211a076dadd16800ece87976fbf25e9629ce2e1ac67048da99a97e111fdae676beee3ea5545cc5c97c714f057b7467934cb9753a6ef18b87bc4cb80967725f00bf2cb9aff23f9988a8c3a2c2aad2a8933bb049bb7af774300dc246003775bd5f6fdf76d506a12cbc1e43c688935e54fd8fe33d7707688505ca06650c68a2e930271b1c3b06480c5da07f99f4c6296d0fee46e33c73425c6154b4518af5cbc1bfa3989e0458751b597bc2b8de6b54dcc2613003f2922ead1c6a8ea72aaf169985a37ea6707df1083f784b96a73d28fd75aae32f0845472cc941b2815d435c2c869d95b2090a92c08ba41fd30eab8b7750c01b8a9e1393412338985b0304cd7a8c0360984294109b49e4e4ac67143b8cbc6d68a014e746f34e2d6d1d4d7b5c6cf7ecdc5d71625790249cba58e409d1be013bb5cae5b7860133a6c33f73ce7ea95e8f5a6de207581a3095826c29eefd0928285f006b0e3060a0185028438c11a3f238bb6d7ed54e5b701c0581d811d79a223db5d5441b9a4402972ea821292c6b25136f5d6110fd53f58daf37b9346496aa4f74d22ba8724510aceb84105b6b8a4b43e6fe6423510489d809cd97652502c1a921232c9fe18ee4f92fe616071d1fbb1939304655715ace6c5076b4b1565c0ec94a53b7b4ea25c0de92272b459c2df6b57e692ed95f13074d71061772e1675dd8c5894d485931050e0aa5a17b955e27c9eff3b29cd8db3fa5f3866c5c3c22923e29c9f1f8bbc1cb8a5a5e22ef1258060f595995176adb82dde085c36c9a215d28e56ce88398cd6594c79fcecd16b8f53dadbe4e12e8e6e4a3d36783b49f8c5e09c399febdfdd4126340ffa3dceaf741e0e5d0d5d2b2d4800fe842e40340c05c5ce4327994609b2233e488747167f6338e38203e07cf4cdf96c077d1223f9b26fc7cce8ea535d6b6b71bcefcdff69aaf199919c751b14e26466c7cc1e82fc6fa71504a834e09b4058cafd706d9664d60f83d2371f59e20181d04e506db90ce2fe439af02d23f5f39f0ff04d7ada38f5948b1b2b3d9d2c1b692debdda4eab999ea4606aebf6b91f71f488638ea8771a2b1bb017fe4b19dad1e5935cc13292d434f1e93370e54a2ae976c2d15993d697439bcbcde8ee8bd2b4e5555bf005de4e1feb19127da1a0a9703dcf48d842ec68ef04f6c43d93ef895915021f3531aa30895824bf7c0481aefc72c14353a634faa6c8413086cd6fe09b0ce021a64c11b84822e76ef1fb422418ef1162202c2ca6af2b8bdb38920f88462f6145cba725d685c74d144a7fc2cd02bdb24d6d60f00a5e0e9d2b044a10603e74c3ba0ddbdfc6130465f9df2d34f77559f6327c83df66c0fcd42dfdb46a3e006adaa498200873f66cad5fa31b3007c5c76727172f4deaa18233926384533dccccc423a6aaa70189e2842ac8b64950998476b2694844e6b174570929ca1a5c365a1550cf1ed157738fafc21af92e3f3a03a929e08a5012fb370e2f404655787bed7ea30e2380e8f1d0b71cc19913ba5e7d0f0453a72afb0bde32b5cfea6469675dfb77bf9faeb40cbe3f2e28b47b89ddf21e8c716816ca46be7677c013961f8651aee3d72ce113bb5160e3e5acbe3799ff459058689d47fb05e12c682dd7f5366a808fc4f65fefea8e3f2ff3eb22091e04348b05c309f20aaeb7fcb59f19b0d87527f150fca393aa6c3d305de369393d0273fa706ef3189908958316a12e491e2b5041ad7d7c32db397e6c3df43b484bfb6bb051ff4bb6d7121d645f09ba184e92b4d26918c1016c10ed04e27eca526f4ec8135bec4a9820490007f8d9f369c6a3420f725a0029ed477e435f96625db192a6b91703d5d6138a3aa02f838d2b37a60ce072fe7a934fb547d6dcaf57ddf4f3999a860f6d848807857605ff299b678f88f97003a7131fc0d01ee15cffcfe53e9ce25bcc221406ebaf580320fe763113cfe9939e0fb1e086a9b597e3460ecff187c628d0af6ca1034c24e036224709a64a839db5f5396c0a31fa34823b06c05292df4f8f0998f9ed9199ee8c5b0117fb04c92afb5f15b2fdbc1845e55147d6dac1f361c0e93496231a573fb59f547652410a8a24197bd440f20812726a28af52c04118c8044dbd16a31424a07cd9a961076ae18fc104458c167a6e2c565204d31867e3a235e790eb6e8e21a9c59a1816f8e46cafa05a649da2350b65501f49db16f060823bf2d9d9964301e7b738199d26fe490015c498803074ce6999c522504a87fe044a7402849c05f7ab6d3009dba74319b5a8b7781992465788ea704b80ab17d1be5b3fcce1d0358397b7c29a9d04c2cdc07421867036cd7bea2be3d657bc6e255cb59b950b5c45102f11e666b40eeec10d5b8995ffa8186b9e0196cf2c60b45a3e309c822b26ea9a7302789427035b27345863486eaefe6ef9c4e924d3a1acb9bd4483d1287a683e322eec208543dfa1409fbdbc8774a0d8460b6ed7f878871b101a81ccb86014ed74207c38381148956ab280b4c8800345e508bbe5766850d8ccd8fac25043b6f160b32ba9864658087bb5ebe91633fbc1a24be926d55468279ce5b8f61909f4d41c94c662ebabeecc3397918d5c499e96abbb4274e060a850e565a60b7d4a5d8b3c9fd1c7d3297f6fd66b395ba5af14d08ff3b59123f6b32273f3d793266ff48dfa61d946e9eac279833ece966f7fe56b37649d1e831319413121722009b808c943f3670c8220cc3d3bc0ffaed0c0f695c2fef37e324e71a84eec7c85ad534cfc2d8351e18ef05e62c147c907e3dbae24b5472391d67ed74e072a5d49137d29ce2c119f72e699a7b9abd5d8467f2d7f728a79f14d383daf52ed3df04eee1ffcf147b1bbf000c664cc34ed6051a4f516c4610c3dbca4b16d1abee89cc3df119d462b3cabacc06bae403bd87a762e54760c354c566d5cbb9f7f96c9ef0df4a1a6c3b2222df7580a274987e19c7c3beac34cb78f0f74d38519527359185fdfbb404ffda9ae73e5dab54770bb98ddaead457dc915d42c63bbef8846e012b94073c677a0c77fe82a421fd6590930da6fd4894608a9ba1c069f9ca8d5116ad1a2d5c43245492009deb4b58288ae8a6b02399b603342df2f63a6d800338b0ff1ae08d3dfbc1d0ce27c132a917787d4e1e1ea3c0cc176a19822448f14428f0dba16b90ee119caa6fb49b4db1272158bc3b61b6f7ad0851e5cec834d873b4793506c978f14a9e23134781df27ee29dc4dd8e500e903065a6a464cf62c318446c11418c369d1bfed76a9e222958c2f0aec919cf3859bafbd9774ac5e4041445b78ed78b9bfbcc890f111fe16d64838ed8ed26a5f48f15848f14191db27a14fcf7c5ba1e0b7ce3b0eef97623517adc8c7060e3e5349ef5fd8f01c9b67f08f047f2f6c65df1945a3897963df7b913d4e2e7d7356b80bd91daa99916d108f8f650cd930600ebba836fea1948d94173e149cc0b785d60991d0e87bfb963f62db1be13a1dc4bf644c6cfc54ce0972e1171ba5704ca59146250c97785ddce0b558daa6d183ed8c9495c5d04494abe49a25b75ad46c103fc2353f1262c6d77dd60e8fcbee962c50adb6f89906c04b030ba35ada49daa2cd1cdd5cd21c61274bf2df4f36867cd11d60336009e6751dfb48ad50861df01cb320654bf8139f6c9e39c009381ef1adc4bc5b81682da2b8191d10739d4d5484f1defbb88f78ce7f7b46f62e54fbd9a3dbd3d0192c54a31eb8fd17696ca09800f18a614e0537d93eaa0c7a53933a073090751621e43a1ca122c94b2f5847be71a4f9941be93ad3835232d641c856f72e3dca72c1d51602910f4467f75adc57a31dc9004cca3fcda21a2af2bf5349b16ee3806ab037f0465a11d004f6c99e1cddc95db5f7ba6b7f3d6e4aa4740708e00e0d00382ed14e4f51f5cebb212c23ce201f2173c9f8b031d5db31b7a1cd708c43e01bd92511fd11d034ffcd513744e1ffbb377942775819fc030959198b57a5d7fee16f0274f7e5c9893ab569072a9c18622c7f2c2acf60633b8c4a84570f91e7286f3bf5fda1f9b1065b80344dbede8d5a24d11d1544a07f3650c7c18f131942af934c53350491e6f26ce8737ec016ef953fefcbebfebc3a556cf843b876140e146565084ae878befbe472e8f8067175f51b5efd597efa603432d4c6e8e29d38230ffbc40926c8a2458047671e2267ed0bc89ddd7a63da1229add817a64acd96ff64990f02d68d5354e446b51271bbabd2b254e855fdb6a9c0c8635692871c47f5178c7befbd154347c7690d678869401a6c3cfc483f28b3c81114d8934de87715dc539266c6807ec7f63dde32d424abfa2f9ee82f851287244def86a4766e872f27dedd418e9aa834cd53e586e85b7c9a7a3e16ae8878ccdc64849623c4fde6776a3824171267c4e67bd7005756ca1f2845989fafcdab757cf7414e38914a40fdc6aa0c244dd33c4724fc3aa28f865f2e0fc2a048bfc94790adccefa21e6a419d601b10089f0f494a72148a5790210c8f06d1fee7a95ce801c09708a26baeff11bfc45c26b51f0254d76fe20cc996b5da2cd4f4e32157a3d47db16d9ac714a0d209737ef52585fbdb0662b1a4b4a63282fbd8f3fdba4148f2fe5ebdb16e62f1e878425b420c3e03ade76e2ce9695824d78ee5630c164f7db4d304b778586aa33b689422f5b1c41f7a5cee47c385b3cf3e58911d8ad505fc524a433899073a0d4419a4604372a3dd7098d197c3c09ac197527b8301e2bc4fb8548b5cde97cc962176232d94f69e36b9217b995ea133fa0f67c8979e96a7440b3748b251f86357f24ccfe3db33e1c9e2b0276e01d3476202189c073af616b9a3a347bbcc0f1c6f953f04ec687e31fad7086eea64bf865a1c4ffdf1de51a197f8a74bddfaf8bd3f7a53d63976ee180390d6ba48dfaa31f36529b2653378a4922b7413fdd23f98c76c4315088fd04a363157cafc29502dec3de81103aabae9f260dd8c313699c7633f853a84d35452c20d8fd21a9ab6143c562408c070c027c1c38fcd685f96bc4cb30e56a905da90a3840790371dbd63827944f6cc78fee0ce5aebbc66a2a73c215dac06ad60733abcf8e6f088e977b47f23d0599a6eec263b5b407df5d5abd341061ee6f305bc85ee90af1dbe202d5fc11e77dfef01a4129bd0e17421d76737fad875266d7c89df0b2ebcb4f3d66cd834368a7cc7602b32726e321623288bcfd35ccd432c2dfb1d49b03bbc90084ab167a6c5e2b8c779b8230acd10125d658dba15366746a2118dbfddaceb028322037f34113d7844e683f57a8e985d2f2bc871b86fd6b614b4e114eff02b981243deb0ffaf38be98cf1ebe0501e0af04f503d0f52a8e94b52fb062eb5161d058e450c144cd860871fc5962a35d07cdb6962e63f9e0782166abc095da0d5b2c1918b026c1c7bfd9a285bd31b319b510a6acd83ae0993bf05434dbda2225484e1cea8345ad25d79ac9e2bc1f05317c3ecef40bba840a926f5f05588c0ed762b508e06815b2f87aa1783c8271253192a932120a8ba5f29ac4a99775a6fc520e918ee6662ec0b8c36f0ad35d3b58257a25efc215203c9ebdc6a8200838d784d4b3b77bd65968605399b791227546662137e00b421afea6558e5e4e6ff081436c3f81861c8612f02b097f96bb4301d4d9794519fa7be48d77dad560684ae74923c8f418f319590afc59f226b420ede6f8e9fa066786d333bb93768c7ad8f640ddf2469bbd469efaf896ff3e0cb7d83946ff68928c6afec60096b141bdd747e29d0c16739d56942fcfcf5e9ac35d39e24a40fa39273e38b4318c8a5fd000ad5d8268395029c23865d5089ff1500e6b7fec6110c7777c8c035cb81b0c683ecb6fde3152ec51645a933f6058d1b21f187297ab9556ac7458ef18b16419d1093c060ee5d012dc43b42329bffc8fd8d311452dd90c1608cd772277c9672d13e4c8ed2840130812132763e3a9cb22da41839de0a1c6bd191e4e5d10e3d7ea57b2951f32ba89562574807e17cc63cc043acf6ca5b9cadc40593dc348592219b9506fb0921cf2c275ad6d4ac28ca5ced3070fb921ec232710b0ab24dbc6ec599c44880762999fa6c0b231465edb898dd302029604c637a43b0450074ae61f1596446b463c913500f651d1ef9d42a7837a8483962c526b0094333642780c0932272a4f0dca5c4a3ca71d0f56b344d19ff52f48bc8b36a2c4b6c5db96595a68ebfa8b1b09adb1a5782ec28d3b348c2a1ba22cfb5bc9ab772485f5a9e6c5fc14d7f9e0b953689731124a6ad48799339e2cabb95708d758b8a036ab4a339fa351b940acbe6d7a111f826d9ee087ba0a953f38ca08593ad75562a043a4b8a2381c1e68dea8a2a6f312122ca53e916c8c9c3cd1ba054b824443f83224a0d554f977e32e61940f3607eb0f22b6bd3dbbcf2eb007110a055800deb57ca9440f2336a548d7b1557fb89e0fb10389e77c1802163c0071a024eefa22b95e1618f00eaf08d1d3fcacd28e9fc1f6843a65ee9901f4fd84fc3ebf9ea3a6da50a5bbdfaa65e7349d61879fee165fd521cb5aea671624b2cc2dc034f9c2671a8bcce5eb544368fe3f77a06ebd636d8d0a24e788a67ff9d6d93af066a5da956e07c97b607ccf2eec3617d0408a5765450c8f5828479d25eafc396a26f15599c7b109e47caa4afd9ab1e4f43a0d9c744dc2e60796b9b7ca3d1709b95e1d693678f374d448af88488fa4ee0fd8aaae5f44a4ed6a62f408580f9807fe22dbcd51373ba82e525a5f107b2f94aa6d923dde28ea54b814f8a48015402e354f9561cf2307b137dc8b88f42aedd720db7297814e726644e82c2d777a61efeef784d402475074c250c49648513f3e7108d27004432434786555e8050007dd539423508b59ed5f16a71789c673d0889a53b97f941f611a1e8f38372c566ff05c216efa73fe1169a37ed39157788618068c89031b49b2b1fa7d86f301e2fd53508d6eec3f31bee99b239768a5ebe8ca8b3970acbd50a2db97324351d237af1c44cfe585cc3132a423a0cf5e94d618ec458f4b231a369321686a0f22bfd8bd80a2da4acca863c1fb4a9cf06373cab37102a5a9707bde86df558e60741d742331fb73fbff036a11430b3591ee4ce6b59f2a5b2cb0c358d9687a93d9ce37292e474e7169900da65c6385deba2a2844cde208eff017e60078024356b6c31e4cd86badfcbd6f8acfd6ae2fd6a1e0440aae761919c64b832d71191ebbc31647fa0f780044cd3a51f1de83ceb0a60f633d342d142c3365aa05401a60c7ccbab65a7bfd6edaef60898aaae4b61c7734f946e1737c7ba77d2f6ae1b9a579f4f5b5929650044605a998625d0bfbcace05a1893b75f3aac879d65f50021233eb0eacc01b7f5cc2034e50f080fa80a3bf23513136e884b04969566c4626821a8d1378b7d1146e10e1f417e5fe75cebc35c561de1592a66497d9d81b6439cdd37f8a508ac1d1fcd6f199b5184d2dff6ad8e41f4c2d25b17750140e95696d5215d1c57cc8f686222298512eac15fa69ac1901692cff2692a40940ee52d5f8ffcc9b4d37ac68cd2e5ab8a84ca2cab453a655d05f4c66d764e5f90b5d6792545f154e664d35ecac89d82fd9ffb33fb4f50304523fb155bd8ebd9ca7150561aec59685885031319d18b551445baaed1cfad7d0967187922dffbededc37e9fe1cce66615ecc41b84ea93f4e1056460c77b4a04f1b3c4296dd76af425cf50ad8fec019f050f4f16529a77e4e2700930afe3a797fb9a786e778feef17cff8f49b9300936ba21b55f0b7cc39dfdc55467021f31ff4c00694d1d29f4942d1f3c261f0cc50ad7b109a690176a4eb2def7aae404466631e228af6f929fd6031fc331bdf15da70b1d91cd52bc5c56a71a9f7ccb26dae799da2d702651548478bfb5158c963b134d953d7d6a76627a70001b6392ba88a5a49ca0c29d224a32f05a52486f24c3cbc5df7f34126daf5c27ce0708f89f2baecbe7a0b58938de0515cf4deaebfb53fde41e5a1cebeece430a7c3c272728e1a91334c4d0e4d0cf4d617aa81305bfeb210a5d159185e8c6f79e8b30c76d7a54a743b7c5dccafd4f8f9516bde67f4f3bd0f818b21f447f929fffebd72cabb1dd30bf55a839891109d779fc80d20995cda5e528134e3aaee36d39d28cd28c8155f746f25f557b3c17f4defde4d3968f5d8ef4d1ef1eb7c5ed5fb34cd82156447528014f88148113061c9a310b7f14683bc3ac159ebce493219b7dcca1a6b001739cef1f5b78ecce8f201ffec7737a0dedeee1d5aadc4101ff75d033a696902d9b022c97d08840b82aa05c2038a6cb6110168ee540aaac9c5fb52463f3306ee373ce0e0930452d1bd86c4a7a783297ab28e8fef2c476a4ee3d4ddb8da6bb767eb2a0667401abbbf91d4c1cecc0c295c53431b40b75ae8d47fe6024c99c4a3c9ecefd51018875f313e019f74d7bb4b7d8d7218da2a33119c73a2ecd407e77dd3fc289e3a1423f649c0e682ca0fafe19670de0878bf87d189714b4e6572fb3805943541a67a0fdf383cc0df5aef434b13eff103cd3b3547cdf5e2b3738bdc43fcfa29564c31e5b9885c37c0c5d7c85682f33a84511f264dcb6b57ae47b256e32a72cf10a48d99d5f836a7b81973c29ac6e70a77968bac0015c0615fad59ccc4e8ceb739cc401285b84b7c5c63c7106f1d9c6468b59469085e43345b1183e17858c170bb21acc771e23f519c81df7175a69cb8ffdf1c69c1fd32c29d893ecf015d8d9a7f5941f675e6941b699a6f46e4fbdd6d53803a2d2f7ca6ca2167227127054975ebb4aa92086b5d4ca789cb1101065eb3747b3757edac6f94e6879535f7b0c45535b132cf5814c730ecb0acb3e5c18ac560d212bd6f32e7cd00009d395745c09dbcb5cbda656de9c366041ad82b894dc61a688d8c7ff3d2d310e16acaa439745369e4c1b23889f54f600701cf07d4aaa7e8a612a2dfb920c5a4e05ced114639323741480e4393f39493936b9f9981509aa524330cf475a9173e54a60e496f7705c589ff5f5be8bd7ee6ac658b42fb9173f0fe58f2735b7d82611b22b234fe7356ae5bd5e764b304be2c4de4d3e05596a2ea739d3de0b4dfa34628fcf8fa1a4ddf4355d9605641c2d0113787e8c34e260409e11334810ea97fe07a32fc31a9dc6633e47030fafcc036796c33dac25cad6e0fd7bece2aa374cd7b23064590d67ab4dd309641c2e9bc359bc35fda7b900865f825ac9d0e359e9151580528d67aeddbe3402f8815974fa9b7c98db3a94d09e1940732b28aaa107f2d660e3c21ae989e78745d04be367c0b3160a5cf3452bf931f8e7ba8a4d60f9c6ea517dad4f69016f6124cb24cc6879a1b3310798b7e9439ccbd320531bdc25fcf04b14d696632020e204321211c206fc39cb5390d4915a85e31c0293268040b50364c52f538c859820a993261df3093ba08859a146e4f8a12b920d0b2443c3ec40bfe890fbe8583d6ef6106153b4fcc76c1dc48b63304d298909756c27394b20c3ec13650404f1658d1b51c604604de0681431e7be27a5a670f7c400d475dc8ed9b16f7e0491bba11367b700e3c2592bd46785f3640d839d439572199662b49616afe6362df0861db7e921cda483db1dec271149f0a0b283a8e703c53cc8340d90301bbb9dfa599b9d99469cd310eb1a3f0e9aa4a9019fcd6e05dcdad812b8b1d46068f3f814dd587b145ccbf871c2195cc785316d515c5dc863f73082822d135e60bf03bf9851a3e3ba67f829d62723c8a7360d7082d0d279cced32b0b8a8ee31f685acf07f48cb775a0d4707cea3aaeed0a3b93cc15a4750d53a05e8bf58f39ef61c5418b0cd5c22539f10d5e2c8c8e53466e2c580145f805c206276c14b001bbe8dbd6e8a191f0077a86e24d975ebc28022b43a9ce40a415ddb032f6f2f0a4edfc0d324acc75709d6f1d5842c19a70cb3a3c3509f40678a557ceca5a41f0e04e0d691b770b35e1c66c2b152482a708fed0993c5d10f80878e01a3a2b98d592f2eb6112805299e0a12b3c7c56ae578d41cee41f786d2d01ca4dc2b8e5f53e6c8042af7b026fba152903596d3ea4c211b3833bcc002bd91846d95e4bf48d5ade352881bfa9957ed7d306e87cecb1163feaed83ce9c6abb41065f0e70b5122aab8d0aa7c125c9ab8896f7eb22c467a8bbf7d48f6395bc290a5e54c9f65498a7c40e57bf33111074edc045b6dbdc6a52d370834db2865ffcae31eda9bbc87a54d9290c0aa2c6694194a3ef5f9a1d3d353c6c4feed2df8187a089be855ed22a187c873830f45980b22b5b86c2ae87a34fe5fed1e69e99cc1a39c250d3d760f7e1ea6f91fd80e14f68e94822f04de53aa6f76b6ad64739cab207abe34f056a8cb7356151f6341a62bf0d5a4fed40ec41b6904b69fd4b4f66a51cd56f6881f2a404236650f319d6fda4849f60ba472b8f36682a7a14140d17f00de180136a0778092955ad9d733186b51bbf75ddb605559079eabc361228ff3fead1e78718782abd9575eea05057810f36751d3173da480185284bf70a9d1e078681f9e9b5d7ca27528574e72f68a5330f89c2a049eada54bf865247e1bf26435811b05930e4dcf154fea4f4b8d4adfd75576661e718acd546824e6c40149fe1add82a7a45759d422d37afa02b3b59ca17239a8b92eb5662a07e4fa65818dfb317a347998dd27e8925f438d54655e5aab18adf5a53c2352133df1500c0e8036c9312808f915a0ec74cb8c07c0508069cfe7ebe3191d51a112221911c8db6ede7b82078056daba17a2826ca7add6508b134234bab03cb60d70bbc5514c6147f7299192e31650b98c8d2c316f21ead07462c2a55b3d26e768aa2a12b80cea00d0b4123be7390057e28155c84f000195b56289669303e32ba0088025458421181d074bc5db84a8f4a02d25a43bb6064aaa2d64a7ce78203ee56f4d041fae16780c0f7313d255f82eddfb9d95ab321ce43828ced5199684d89c26af82805cddcc9b669268c10565ee9fcb303ea159797fd080cf04b62dcbd5adddd3a3cce1d6789b1e051a4e450911e2ae46e1aa87db200d4b41e219f385b242b207d405ac345f38a1344c4ce6bd35a5f2d3d5f027278ef79da270324906cff9f1af283680f7fcbc702e087a153a821eaa9a3424fe5062bc984f11c2e6cf52ac84d0d20b3e16a30d3c4b1b46615ef07c297ea06112da6dd2a3506705d397c90c3c0212ee5d1191caa3a7f16b9c98de953e5fea087f82ae28ac0ea3eadb1171724b84f9ee1c80f41670b65e7246efb713bb9bf4af884a7bb31d23f5aa5d8e8928d01697b0e7894ea417f2064bf721f2706ee33e8341bfe8634923e54a4f2602acfef25928d1d64bfe966744e72785aaf4bb696b7d101198e794a35823d5f4bf8feab50f25e4d7654a156b09e15dca41b5b772a54daf0e028463fdcf141a042f5e2893d46da06d80699a4ceef70ce177003c114766ac9e8ae3358aebf771ff5d053c1bb3bba0dc323d7b4543bb49ab6672bbefa8e30a568a04dd3aa274ec02fe0ec176d8102028453a42074a0e22c6c14c53e8b0b7208220f1c479ef30192de412d944829865e586bf084536e9626ac024ead4a9333a29fa36aa254d6c009da0a2004c223bedd4c8879e9399e3001e5706a354f1723b5f06206a25b00b43195a37bff53b9178757480f717a4b3964a7c823e8503952143dc5d0715e220434dd6259395f0d890fbd0d699ceeb54f80db8086c967b98e24c0f1f40ac4ab53fc712f9590d6ff9f9c4990b1e01e685efba17ea8b4b80df00d0d004c74036c32a7c04dbd8809504ba572387f4a9a58e0e5a9a409c2a071fc8cf990650c5c5045ee6ad466257e264bb33cfcd7406c899feafe8a4bebd50d60f6e50021289e6891453e523ab850a0d911b735aca034c56595bd7d3c42576cb165f277b96eb772488876daf32bc2f946f6003880e69da7a9e9325aac02d4f10228aa8cc658c8d799128d93aa259e5417be08070d4fd2260ba9fdc36267425f1c35b12ca7417b41550d2f0d79118f38facc33d121174709b20d7495ae724e383b0bd3fe66db01c80987afa9970f9a617ef577bde2e1db2a15b9835421c556c836ac1fd3b4e648ddbb2b86533bf7da5f80d33e5e61681701edd9fb546da39e9ebc1a925474bd26b6dd39f3a49e64d45d76f8f4f9bd783f7f8cc312d9bcc36d7b6bf54d44aaf7ebb76cbe3739cf292caaebbb00c89a66eef72827fad3c2ee0a1da92eed0b9c61278cde5fc2c0f89250c04fb70f9be41b18ef7ad9dd1b76fe07071b147f147b54671ae8a4df834c1e02d5397de40a368399d1df05122c30649bbd98d0c7c1a64e7d5aa858015cddb541117cc513e48cfe0e401082d2b6c6fa8e61e0598fedfb530d82d9367936b6abf4bd130bd7584d5f06963e2f33e3df889abf9ea1689078b622cb0cbdc0dfc6632e5a78e4abd40c6174f1357e5904084b25de960e151b992acf015dc62f445d65fae1224bc9700e888f168c4760165a3c5aa6d9d0264fe159a2d24e058f2e47bc02c0e88d9a7d2b1612d5d2266db266afe58bf7823a346cd4b17e842c23b9f34b8cdf598bba1ebb625183e772e4775420b6cfb355dd3f6078bea60fb7e71af873664bd92824062c49331cb5207ed840759f9f1fefec2d763a78e38a597a6a1a5e1aca9408c4dbd00383730f095a946d1a321c6b38fe6ca57de709e68ba816be4db78412a9f707345a0fd32ffbf28b56cea4710172f002c41d85f1c8e82f27167b6282c54688bd4926f58586b6884ae43b2703a5a940388e03abde2f2d9e62b46c6b67a1c513021e0a9d2d9ec42003b27ddc30c501882d3c6d52e79287f5171551b5a813e6cfeda321e951a8bcb358401f2f2db5d8a66daaeb12b24168ea5a8f8248f6b9da9cb13aa7e39ea78d14cf7ff6568de06169f12a74d10f6348d9cdf7be53bbd29dbcdd242a897cf1bdfe900e3bc5f2d35134170424ae84ba26023b9b1f20b8e47a9c08b093c24460b377ac0372cbfccf2d4be50a53a0bd7e33a717bb8c6a566134a52c199ff891067a36a1075012f21b09bc2b4fd1d720ea85a5f41126206cb499700e2fab914e880c170dd0c73c1e42113e1d706b6846d88f2238de896083660350f98849b7422270e5a9f45253c1440873b679e569c59629bf0b3b2e63dea9a0a853b28b69a44b2ad2db27007955a7817389f100c3c4e619a0a12b2c53b91cc20a2f2f8b36646dd2030627a4d0181c6455a40fa961e4203539e47425c58652527052008940163103781bb3f235498df47fc7661b341476ecfb91ae3ce799a7f685604271e0c25e5507e51b3003eb5c23fe0ad03b9aa38191ce990298d0364f8c4d1ab5d06fc1db7966c6d44cc7d5196005e2637eecb383f279e628c9f3ac6558cf83f870e769bdee337dde7b3d3b4ffed8872e6c1b701058a740ca6f54848d6135e8377a11dd4f1d1ad494d83e2710befa81277e202d790eb41042f0b0aee68f3961480354e7a7b2ca4969893220a41cffcfc1af492318efd0640d6c83967d8be0943e5926ba082e77cfb23b8377c0b9f493c45b3802bfbb94eefd6666d64dfbb3ec6ee1114c04a0af091faa4f0613a474326371402e73b3b7420650e832389418f6de15896ae2cbc888ff20bc9ddfe566bf609e31eb996d70dcc2fc751fcf9aba13e5a1a9a54f5f1ee3babd5bef403862824a7d94b41284086f0c03d40c46c1ce97f57f3230fe33ced7f62c818f0edfc28f416df200c5d6d6790e6d1da234059b25751505ffb08a9624a562a0f559668f29b4a103f6e0aa6c06a00df12082b5d53b381cd2d28266b5cfe6a6097db18f762ccc0fa9fb9e4dec959b4c837c764a28fa3327595516c15ea04098bd2ab3905a407378913c5aee8eda00774d857df624a270b50f3d31d891a2eecdd806d46dc810697a2979e3951049da2f8978c878dd58eef10342c6bfb35a745d1195724ac1af3b4df9f0c78870632912d55052c9f3a798513e66cd6d716af7b345af26a0c965c52e833bcd079172d26e50fe11a173f6d10bba28138292839014bb6c52dc02c2524cb91d8f7cc46ac5ab84f8d38a07458265ff2c2d360c402a4aaf3f6bb89c605d003add09447b15316deb33a68a538d2a1629fa4131c1b3017460bc5f4cda017dc6551a53ecc1e2be849ec1f0f673facd241d400232b6c3f0dca2e1a82488f9f94a62c97b7fa5ba70c7aacab5335ac1b62a2dce4b05f40480e57db6b4cea82e05786331c7fc61eced9ff27183cd0aa2f39311a2a659b84b74662ef09b3f8da802e543ce6b9150f642ebb51ab97153341a2421888c7ee059437c67d8b572f38fc9fb060bedeba995fb526642e24e6dc5fb137e182bc23b445a3e04c99afc67bcd30a9a7b54af3596d74d97e723b18262d7afeb0ab420f99cc483c39fea626f60992f9e3eb5d7030c73c1ef09e25060f808a5fe9b492e0127f0b67422f6367be1edc87f0ab02b12265ef0531dae1f9bcab2187403ca7cdd968bffa0dbe17556ea49ab7ceb33d26ac92175ef096e8166ce3f3d35541da82adeb981088f374037ac2ccd4a032caa9197b80d6b55ee4d154222160b75812fc4c23a34cd480ac4ab28e144b87065b9fbac496fd9574e56334b17b0e5e1b1885a9c860878ca859760066d659f5b8958bb5e353df1611515f57dba3f01231a08d067791c21f94979db058bb992c787edac9c3e4cf8a32bea02579024c93d51140bbcb9261c47ae0251f755d495c383723a945f661621ea6a8ed12d5f14d75be43141c7dc684948acbe598c93e7ae91a87e3aadb5f2f84593188424629afc1267bede6daf879807d35becee2ebe4e1e65f824de83acf365991dca07c8ea57a04a6578f6459cc87ff55c1f99e02ce9786640c6f12cb8161feffece1858c68122ed658d17300de39e4296df3924d3710017fbd49dcb44b1cc8f2dddca4ae1bcc7f5189824897fba7663183c92f277b4dc3bab177ca00ae607e4eb78fb7f121cbce5d6506cffed0aea70ba6a0ea69c4d1f234fa5c178784b2055966a35713fd13434800d98e4d072552b1a719a62a0bb772a91e132d93c688c16b7335cae5f8ae5d110e277e5611f91de3b5998b836d156dcb24f4197e823d75477e519586e4f03575c858c9417e94143416d24c52951957b1b2504648124af04c4f5effc40fb7c845c6f52d1a426f497ab16ab9fe90c255b63e2b2bbc1afeaff3f2b85a2bc05824b1e1bfb313d68f9e9c6b1e4f7ecd7b626f59099dc621dd29abbb0da3855d07c9aa26e1bf202e89eae0d71dbaabbf4731d08637cb516816fc6e76748d10dd646cc4bb4ea649143f5b79ad8dc241d36852abaa88e2a96a04a32354402850e29941854b263f8b00a2f8748759ec1be5673320ecf61a021dd4c2dbaf449c72b7c251537c4221b8478c61edcac17328ca2cef44a011bdaf2ac6b77947b21d97a9442e2fc4751f158d79304d3b4383eecd1327d008104323b3dba033fa0dfc2e3e983eb8f7f660d2bab4d40b9ac725e011a346127be3d5558b891b10db2552ab72fdca9528e032482853b0c90642e83fe75004b928bf4d1a1eb181c8487d14b9f6507b9340cfa1ea0927c300b63bec2d1aa2182a86adb67b35b2a74145c2d50c72a8c4b313654c0ff2535ac9a446f1be910eb98b60a8c674eeebc09966c013fd530b4286d850145d7eca486435294290ce98cf20ed959c050f1f624cf7259832ac30e19eedacb4aef3c7de8713bba1a77e6de8d9e9d70858bbc01b448b6c2c8151706cb8277cae006a38c32fa2ded7305f9ddfc9c9f03ba579bda11c6e4fa8d02605f0abf3bc846cfe2255c26bf90333149093325c7614305a0eeb2d39fc8db55c5926862bf558a55fb83b09c8ae15619a0076609bcf389740cea2cc481a6d56866e53d9385b2900a46d154102d3332db4db2412ef03e52ddb01ae04655cb453956138352a535e15b97417440b5b4a868c8055599f8d7f2335442242e673d8d2ea0da977c8a52847b5a9e23cfc4120f1835c5652117a2c6d92259df70f0289b6ee74c50620a522d21c43015fd9568caa2cadc9469bad978292c462200312a966976d428c24540abac757369733ab36ef2dee99e9b87cc70be8c3abc49602c2f3e2f908ce86f128809d4369fb579f45a289368012355234ed0fd7252fc74c53db6d8764c28234d21c6abb5be29f45fd8a7360b39801923627f2d2d619d0f6b03378088f6fb98d8d5f0412c5de5893b23e47d097d9bc97697db711dc55bc46540ac55bc53d10fc20c0cd100450b283efccddb0efe6260a94b979eb83b376d4013e8e759267792fbfe35cf9b64b24ff93ecedbc188bbca5a8bc0c0c3236167d3828a0cc332937c6bd35d888ad787b46a561e5f846bc7361a0fcad1ad836fe966e0b06b34944ae5477be107857c80838519d34ef079962d81be64a92a1f2dfc113b1c266de22df08924113794c0419f77db395404e64dfd2daa119a64b71355b4e3604333493347b2f286e1c15432b0f3371e50522e33bfe68933bd06bc75376530a6064b07c21fddb64a8e540d9fa497d2f557b9919373bcaeea6e18c391945ae939a2e87878d742b624626e581c5d194cac13842b20f5e73383afd1ec62262d42b0120d1837cfe18e95de520028b71732255d0bee48a9413956e96d2b93d344855d975da8c2135a69bc28e4dd5971c85a0faf33c510480893d39c7adb55db7173b060b74a887bafb8007cd59fffdc88983e418ebb891e1ca701ba45e5415d70ca604e3acaa21e02cb5977d0f340ca749fe1518ed5d4fb3b41daeede550f3aea7d087e39d27d88fc2fe79c649623391e1716b00996271eb6badcc9d69c5c350d26de27ab7e4be250023e0c0660fd307bcdaed40f4bb69432d16ed2482004ee03a7033deeeeaed0adf0219999f966074bcda64248858f7e87545a96822985d3eeeed2a5b5c8bc32292b7613d08c0893891d458f3966774f48c95a422e6b48348251c91367293352871ada7b7775baa76386f6394e586293759cc49670031d28de9c2d94337387a10d3a24750cff94c0f415196e8016fea69eea4a0d7f52c11ace0a6a48d48581268b15a1e4cfd0acfc299d110591b859e4eb73bbdd727e4a0880716a4804e48533a39980cd97d7d00738b72e97dfd4ff98086df70f86f293837c414c414e41504155415abd452a33333333b30d1f1b3b1b3c1b3dca43bac51205ccccec73f241f9aa7c5a3e2fba126b92749504465bcc58d9dddddf93d8124a0183f50756936ea18801a9e245f7fffe3987d966885293ed8df16eb71b4d0b183b39242ada552ebbc3a7e0b2687242485088cf06ab4629a84350582ad66c44beb05bc782b7dbeda6850a8d8536a2de13580d450c52fe3f47fd873f87b321ffff2beabfbdfde5b0056ece1de6b0c94790478f200f6e405c98664689c38698498261815c408659933d2858aad2ddfdf4f4f444323333ef0f1bb514233e46764678467a94527a5efeb182024ad5ae8a57d5ab1aa23f7224d8cfa450882de14f95029aa14a2fb69736fd326dfa6343a5e4154e6c09af70f84a47b3e9e8f4304991034b49e7830c180e4ae979f985ec79f33258e5725230b125bcd520b8a553149a99999b082ac7cccba35246d284e409891412a00d49b0acb0d3810d204370469010c201cb85e2889080514acfcb375828a594d2285d944fd42e8a17d5ebee37a59452fa9fd2ff4cb8d59055925593d5d3fbfd9f97cf4e3d34ba2355d552692d95d752856d91975d4ae9df74e9fea74bf7ff7f4ae94f9952eaa453295d4a6996d066f9b29868594e364a29fd7fa71894c9c01fb125040231508806f4d9280e0311355234bdf84dc1c4fc92dcf6ed6309cb3233f3111db125ec41f1538f0075c7ec54eeeea6cc4c97521f5d95967363210341b1407eb60201ea8db90a825402a906570f170a5329f5a994524a29fdcfcb3537253b4aa05a5465093d600b03f5016c662692135b421d5a89f4d874382cb1c1539231358461c30af2820f5108271c6667da31e76c481c4f3d2068cdc663c783474b31d33a7a1f300e1fa19a9dbc63a764539b7a413654a626285de5d1e3557748c1e06a361d40594b6853f7b1ddcd0195a38a26e203cd6e0fa9d71e405ac92b302ca02c39031a006d14252fa5b0a597a5dc92ceece4e9921f01581b5a36bc6c84dd78b9915bd245e1351b928ed81222f530120a1ad28fadc45118878243604437221c110e090926ad66a35145438b86178db0a0170a64ebc9423eb125647282da40a8aa697f31d5eeeeeefe41fdaa7e5a3faf5f5885f24b6aa7634bc10d96c036c071b335dd6eb79a25265842245f4f6560577577dff858206d4b96a2986279efeefa90cccccccccccb3f128a1d2cf43d29980e3fd734dda8a78a6798997b7b459e6156c0ef080a105c59405972c625c4b2729cd949caa29b56bbbbbb97e4441d1ac9559b4bb7a2d2d5c485a3a524e9fe082a285fc1ddeaeeee5e92d4dddddddbdddd7d987f764c7777f7a9482537119a06a574f464254f74cb883c7f0dc95a425ae393b982dbff6bb6244d2f66a3970f3333f3aa98415d7777b78fac0bf7eefebb7b8754b2ebeeeeeeedeeee8671fecd39d893b5844c6eddccccfdff7fb3d1166ecfcc5ebddd9bab6cf40506c3025543322947749c4149066597a147cd0c98210a47660d65b89aa160b296903374d1f4d62d43d80cd76c3e624bb8e3c1d84cc67ad299f119b1e1044c06467a31195c0573190081321920993193c111608c08c44ec913ae76a7d2bdbb5b04bcd52e495c7777773333777777777fff10b86663f25a9ad0748b947ab73311eec776352c12216cc7ccccdcfdbfff16db2a65f4a96191915ccc470308b5df36ddad80da32926af7ffeeeeeefedfddddddff7bb3b25a0cde6e370f3d99f66a58e4c4545f6eaf76333377779f9999f91d1656f9b2f24551baca33b30a4550c0a7580d4f171d81aa2f77811cc286b10849a732586fd3744020c24643efe6c7c98bb89395244385b213f0630165b6e4d38c26d9913a2895853656821b6d6808355944da055dba6f9ccaa7472d26012eada19452da54e9ff91524ae91009242a9dcccc2c4347e5f3f720fc7f97cfa58b69bbf6ff1fea29a5340781181aba273f5aece8a0e3a428cb47293d5dba43614a4eb928b84361e62438594bc8cccccc15800044b3bb1b34d7025bca8d41203293ab294ae612f43922ba6cf15c90f8348971e1bac958954ceaaccce776bb8188a15269d9eece9a6a780475ab2fc96daa9377bbdd4ec474d16a365d0d8f4610a6cb52f2e61d9b6eb79b0b1c066e2a026b78e4e4550ffcffffff3fc5553f6b7eaa10253a8051448415f44561a82176b8a1a3f7fffff7f6b6ce1b27533bf235f5ae4c89a8e0c802caacc9ac152a9bcdb26e249d1a42fbffdf76a4a9fbffafe406160edaffac21594bf8ffff77f7fffffe875f49fdd408f5475419ea77f75fdede3dc21aaabbbbbb7bc4a77129327a6435715652d653650a3c0cd5a09caa8939c7cdac6633f204d54103ac1e974dcd56641744028d95140e27551442125c10a743d5d3891d20af97a34111a9250d8ce88670d0e00aa775b31a58e1fc47424e7034a8c2e92495cca23ba9c3a1af0bac724936f54eacc8ee870129889508394f53bdfd42a2a958b39500dcef50d64742d8d479a08b094c929d0721202207ad0f22345050a4c5d32bf26eb75b07a21710465d0d7d604dba3aea2a7469e0e9509aaa5a82f375747362814411a26d737777596b5e0d30f0e6b220994892b2d16a345acd56b3854cabd14a3a8260799574815b991f05a861910caf52a470355c80c88b1424601809e1133fccb868a961d1cc4b4de98de2910c913a2b71005e4da142400d8b6684545a902bc82af0026a58440353596a48c4d54413634b28a7e491daee4c4658e5925cda7d0e4f6a2b01f509d1754e0e4bed48a7eede767777f7ffeeeee248f9641fcf57b9ec6666669eb1fc5efe6f6ff7ffffdfddffff9f834265a58653ddb27b777777f7ffeeee6e4e0c145acd16c4fbff7f7bbbdf6759aa72ea5b4aaa2ffbff775798d8dd7f55527e80b5282c1a8a53d5ffdde69dd56cbe13bdfab29b6714c1ccfc6f6f7f85b090be18ba7e3f67882eadd992c2fa394bb36ddf53d237c3e49a6de8677bb73fd93744ab72d9cdccccdcdfce01d2f735052b97dddd2e785c01acbb20d0e9f302dc16bb0010f184c565951b4183cbea76242cef4e2adb5ddf08a0eaeeeeeeeebe777777f7dbcbccecfbd01bc17c458c7ce0f3fdf0f0efee773fdbd864204cccccccdfeeeddede870876c02905656655a282a613a42ccaa258b058c019c939cc4da652f02af7f62e5b71a049d0fbffffddfdffffbbfb6f9fd58659ed8a27e24b1622ab2746ca4eeb90827a13b2274c2e6b39310cc0a90edb57a12ca40517b492989999b7babbbbbb6fddddddfdbfbbbbfb7ff78dd468595240682abdffffdfbd23709c2505d8b4bd32d9c89311a93e8e36cbeab99085c24477f7c9b09bff779fd66ccdccccbeadb0ca38ae9e7c554317b6a42663dd9899999999f9888e999979db6744027c77ffff4f4e2c5effefeeeebeec82955437bfe6ff514401bd4568b166bb7064684f15bba085f393efbf7f013892f04511f1c8815f6f861ec7dc45bc63aad9e009985fa8ea8dd8305e254d11662e50dd6a2e14e915c9e580497825a774cd6893bc2fdb28a54180624b18cc2008d80d87a3cbe0c987fc106566662babcaffffa5913152f8f1944413b432810a299cfedf7d1a26092458eaa9ffff5fe834532a35a31b38a609d22618c1d0f9bc459e1b4b68c4412ac6fb99991fdc2d8f881526726a2b2dc254b0d08c480075e31c66e6b673bd94ab18e1e02dd2acbbbb8d3c40f56166ae3bd7834f51babb444fed6e212cb39acd839fdece69d19393a36edd44b9afd929a54631bc2a97ddfdd84c86493b9ccc14dcd80cccd988c58e99993997f20dca7577f7aefb7ff7414c780f1dff3c1a41dd2aaa0684396b36a32a1ed877c66c6ad42425f5ffefedf76b6a6c3333b311915ce572976d7e761b9446f8e0a104c385792a1bb955361253b9fbcd0ca3d737e35827e96a97ab2399bf3fa30499bf3f93cbcbffff4b9acc39e9d87c9b2f5c9ddf2f3015319c3a1e448d8022894b841b542eb357e764a2ab73bb9a7c8e734e9a396daa56d06870314307e83243a8737abdd40a6585ad16657941925b0b9e1858131914403844f990f10b31644eee13234f9e73768980c636eceefe7356981fbb7abcbbe5055d43ec627eb93e74a060ee72e5c4d89ab99658260586e9694bd261021a6d2ca70421ad36a786b18ee338d7b665951b97eb6702170d1c96a0099b151039da978a19952f9e4cca922a1e94e0cbce6cab2b87e4d27043b9a0767aeba98667dcec07997f258118791c26d187d1825f50884edc7277c30d35f3d79543fb7d519501c891c968e31e66a79605de58af8e6c4159e182f282727451c7b1e4711c4b0e2ad449019176cc389e4fd4711cc7ff349903ca1063592bcb2d2f50a9615109609583d2c28f29a3a94971040c38655502840bbc5e7e4f9a605501016d7500242364333485b523881863099090214739493654220c1e5386a147013d00a8e1afc7a2a7a35dd6837f9a25bb864741286823e198323a9b479f8e19b71d890e2e6254bcf8fd7475471d2d6916d4260822b7221fa41076b24af0909e7c2caa210590c300a914187ebcba5a78f800490be9e82266bc18e1064fd808a65c5614415da41d4833b84b90cd24f69474c7c9e467c7711c6bab61ce12a66d4e2631ea9c73ce716e0d7f5f5d95ac1cd04a9e262815613ac0c10271a30adb4df55cc86296745c42381f247e6a7cfc7889da91834586af164d642f89e238d630330fef2b628006d110214274481f3ce0e91a660a1f8804d59031c4838f0bb3a8cc3c272aefc739abe18f676607d93fb4b00c97ec8ad106d311e91c6bb9dd981b75c78bcb7f8e8bb7e4a70207e84493cbee627ccc1d09ebd183068387264e2bc056ac540e4a0b2566e8a487162e86d694541251858e6c312693fdc4f71ce7389b39ecee6aa83b97f7cb44a92e870fc428da0a3269827ae1b229ea26a9fb7182ca416981c7121972566677771ba586483f8a4a0872a40334e5740385a881de910a191f2377d7869967a22aef8ee38e3bbe20cde050a1218341f32b35449aa151536a8834f3b332fea4faff67514fffff25d8a84729e1c54e50c3a212723e64043e52662e5d8fe36be388d30004885216538ba221279e7c6f5a16ce947d6f4e7691365a501b63c690b97304b0ea818387c6a7d44134f1642f520b649634065b4f6616ca0bb6b678cc9031abe53387397bacec4c4f04192b92818de9c083ad9b1a1ba8119666c4123437343cb7d9dda5117144f34243f637c3eeee96b6c9352322adf0d50935445af1c28b66930b16b1ca01da21fa78b071d361664948c40891c4f26154866e4a7c78b2b50564c44efd88e1391c1cbbbce386302b57424505ae9a7a828a30e1c14214812346c6721b62eceeee4e3018628f0730666885e4b70426078c278718c2086c06ed912261ca868b1c582e13449d6506462923b099ca5243232660321f7320811a863eb10ccb06c842143104b4951afe6a5cd5ade1af28890766109bdbdd1d31541769048b5aab2151f0761996016a48e4244495d4a8d4ab37d98806a0802000b31a04000140612008a2b085f00414000c22966c98fc645022934b033128181204411084500803300cc4600c436118cc6229e201209012e103858cb1fd08b6cd0efeb97e9b0d603f37f54d3122cb57897b69c404f3e4a507bfbd5dd93da5e41ebb0e56df465090047fcb1809deef47427c6bd7378432f87c3038bc321bc5e4ad2728a3e88b1e27a085a533466fe04416ae6497826ad727c261d6da27a3fa9cbaa7d779c5356cb22ab5e98947cecbbe97e9dffe0cc83f0d5017edd7788ec90494cd0df342b99952c18d9e777b2de2c5df649443e96cb940aade06ca3df10f3ebd714e2d4b690d69ffe0b0dfcdc2bba7e91cfa413135da9b9d2ee7ad48de6b7517b415aa7f1ccd07e7e90f1240feda68f2391f4c387a498a15ed1339d7ebd7f382fb12b0d22e1d2adf725a44fe1bb45ac8aad28711893ab7bab0e18be706be18f0bca0e4483b6a65040bdf6dc16b1df209ce2fbfac3447021dc2cae385371ffa032e32ff10f3ea37fdd182ab895a9eeef00f27bc5a3b36c2485044fd25b340fa6453b4099b79cf6324f822b9d98b2852df279f259f4df653edf941af49af378b2a4a4ac964815ee83202e8ac0cf41a63fe19d6792f5433c349078cb79418c0044d5cc5ac0ed92143f07dc1036e82753234206737ebcd1d446958c394d42ab47ed60d0eb808f6d98587c96cbbde7810a13163487015da1e5f0039c8fb095f3fe5542703cd48d2cc753a8206fa0f94d9646d87af86b24f95f5a5803ed6e88d8f010660d9cdfb5e90444b731dedbf261436d9cd966d1d9c14e3e5367ced671f77465c8534ebe662848996498497050106121e887a3518a47fb709418b1c4836e50e34bdf73cc9a0a36bcb10360236b1be086c8962d16f958e160c63b33a760e2d1e2b2193abc311fb070cd4caf86d1b357f0bb5811f7c9259c2022101a9c9308c2cf6b5a551cad75ada0f0326a21974f07e382e4cbcbf80313e612c7da421b2320297023e5a5ab940d36aa90dc070cf83ea20b1ae4250a3c386b460f4a8158d2510f7a882a58f197bf6404a04f7a1f0c1e838e08b96da5948c11e392850e8809f9948facf63ffcf5e25681dacff6f554c4e7aff26d8f46a4ef81cb5fc81fd198da40a5a65020134ee2296f251cbcc164b70880c9150825f441e6c995eef3b06ea1572bd06d156132ce83e1151c53d8feee791692e59e70f9d0f9cc8fd377f899d82bcee2e8bf84522e92561803a7877078262e9d96b950de2c68adb5f137e1c555fa6c9f94c8496ef4ec72dd59f5aeff0410ea467779ef64b314297eecc086cb42170079ba0497b9f92dbd604889006a8756c2fef108b71745b3e4548bf05b81d821ad0b05687203720f495771c27e8b47e667f84119b06fbef8d146db4f1d9f9d5ccf8c5c8d3a1d12c1f9cd41b2f4d4e5f06eab959fddf3daba026635741206f359b94b2a0c20d237e2582f3c8765fb3b03eb1b36492de6b35b873e6c60f390e44910068946a99b0dcd143981d55ed68ce9055f215d039817d26f358ee8f9c4e0866627a0b4e0acff70fd3ac5218df859268fcac65d20d0fc8f5d9ebac54103790368fc8ca5f1da49fa610d30d11bb43784ca45cc729ea44c9a10da2e373237f591fd41ea8d0b7574830e97aaf457a53b2d22bf7b2953da19d21ba9ded5eb8276e4cf382ecdf233a45066c9d5a2777a13c64369a38a05e8ef23fc5fc08a2e0bd6a056e5260f2d53413a4022833176ce185ed0e7a4bafdbe290f6d9a0ea092c747956aade8b60f52176f7a3106d3503adf36afe72c2667261b13741cdd172fe636249b6fc2ef11191d3b4f304b2c3883df3ec4012459a65c20a741267e0e574e05d7a74194b263a20e529e8530be4def29115306495826a61584b3a74ab74a01e229ca65b5f41141aca4928be15ddd670af4aa04e50b61581ff352ad3c50f034ab7619213439ca36c9102f920a2c7a07bba5f8a3d88dec39a070fa2f5d7a6c6db0f3aba7b177d97ff84c495b3f1f703baf1ab40c3bf4b4490a12bbb586f5c8a18d9c4d89053d60c9641bf84252466645c9e0277f9342e402e37251aec670f33ba85960b25294f6eae2cff24a2d9c36562a4c35be52f1fc8132a01b2bf88d31730479c85e2680dc353e46b7f538568d68918c72dcee244f21fd80d58ffa46648014f2ee2402735328e8dc031cff277e806a23cbcc56e3ad5640fe25e4401f01bbb09e722cb58fa6ba03708981545b71301f83c7550404853193f9a1c1561d7c4e65ba16bca415522032c97475d7313883f7ce91b103ca66a2585fea2b81aecbb4b804483550b25ae9fa7cdf29ff57261d98d06b975d36af61f04a5bb4f82e47eae613860e3f886a7a300dc68c61d8ccdfb95af2679b49549c9a3b48cf1730d4c60e4e8c43e22282da7f807e926e629bdc52ae378aa097fdc90871ac62fc79e2ded130f44d5fedd24cb10bf53acae5a837402f3e31d8b289c29d1088d633255ccac919d582c482cb8109d427c479482f79520d878f610f4207c334fb6de433887f8466f498ea243d4218371e9d83a2c9de60338188038953be34812c8510b70fe804eb97c6c6389510091cdef08073e7cbf2b566261445505cdb476304a013f15088e9bc206d3987a20c0227cfbbe9ec0e4a5d829e9e7b602c5807b76a587655845a871421aba2129108310b42f434cd19fe1f789338888ac89cabac81627d61d780023b68c95adc0eb10157d2f44f6663fc0ec97a4f072cb17f3eb13d906de83b2b94258949e94c353891c471df7085c0f1b29235736b6e9f9c8debdcf0e0070e0c521871d09e3e6156b4607cb09a8decb6da720a8fb88a8961d210bc8deeed8aa08e78f58e076a5e7f2ab715560a20b6c4375700fa54727dd4f9d2364c133a861cab66915e2a865cec8fa16fc5a9b72b1f29a70551bc17723081783c449e6e0b15ea3ee81f815d69b9e8a05af54ae094aae1512ab7984b49d9bfe6e5d6c34ef7a399845fd24b19eed17858f3b2693ca93e05969fb29e9e765cbbc7a3634b7115d04dd931c855fb4b5135af591991e81197ccbef8a52c2a740e2f122e03b2e729948cca181c32c9d92d570b2204db033f043e47e9eaf278260e0be3f66788aa7d14180d7789375156941e97f982c967030bcca78044f8ee8ad763d0c4b94e5fb030a2578e86a8fc4a49e17c3e961b1672f27a45fd21d85269085e99da22e85869a2a626b5caa948b8c1af88008056b2c3d5a10d1f58910704053ce832f4aa83d286a45773fe7a878f22f878bfd3bb74bf621fae55d1530376f4db46ea41850ed777875bb238a70d5ceb99328db8cca71911af95d66d68a8e76c6a339092cf149b7648741ee817e2c0200a922831d3afebc070ef6cd104144bc1f35ae6c6cec42d951a3568b7630a6026c19b42bcb51887044d11371f89c16062b055ec7d883f8ddd16286169b41ff94ac67ff20baeadddd7006b2536633e879bd4ddb61920bb34aa096ac64a1f110d35fe000b458dc8c6a215d2d008f4d09f13bebf90b803c8e36f6f993e7e714b5862891ad769e5569c978837d3c1dee839ecabc77c3ef272e204efa3ed3cb6b6edadf654976dd0efba1e12e5c4c3d589232cd54bd41c1fb4e61bc8d391307d03ab8d82e259c4d52393ebcf6f6c6af5cb2797cf81fa676580b80712bb7d68d2b8d386c3ae9ff8e7b4e0139ac97e4eb7b60dc46d1fe6c86b0cc85171f7277a50ba28747bea0aad187e0f6acdd7cb9da5bd435b3ad115c7761eef2bb5ac11aa9e8e960df4859e1b81e8a1f9b6b25b4f9ad7530db1e755f0220636d11d8ecd9d9883623362f5d05e1e4b90d5b8d05c371d00c5e765052229522b34ef5557776b1b46ef87a16138d09196fac33cbaa7706e551b56656f5540ddd629fe74057c142cc7ba2b0b4cb882eda8eeece3e548e33ca0da33d61041def4def41fb25d351c530dc82391bc1eca6aaf5e156d16629f49b00866cadaeef0389197ba23cb30a2b044f91476715c3544d197c6590f8a1804b629fe0da152182fe19d5f9ffa6f431e9b48e897412a156617c42c59c945fa1f57808a7bc77adcadc34123ec86b5c04ddae89c35ea8b849a95207b559dcc81f08c61fde0e8495905c40c51ce90cd21d99619b71241c60fa0286c3d2b3dd2109d590c48a5b8ab7a00cb43bb8f3bdda3886be994bbc076381132cd55b0ce0a8626bb934b6c7f974b8208f9595f58833569adfaf2c8debee7e44291c410e76f271545373b6695c90482fa75b5e01a5c4e13524b2dee2d95816d3f75ebf8e8784c0e6e0ac061e68839163c5a0d7622ecb0c4ed1cd2597c8be6b6c91d6139351052ef923068af81165789a665aa3af7ff9a9a6524b8d26413cc7f0b766f696cdd68a2ce2bb4dbf6b5726de72aba0e879a2b5526199647bd985ca0904ca534cbfc8c9dbcbfae4b30b778de345a9504585f9c19ae48f20003dfe58a68b3e49354be97b9515a783b17dd2eb6defca7cd515974b43a5cdee659eb439f77f2de044ce73966b3c7cb8b61699ef1bae965ae1a9ad5d436d1b47c4ea2990ee5d8ba283813ab2cad9b50e8936eb67615e45efaa8161185b79e489101d6c6f5b1d2c92d9754a63c9de52b9bf43273d7ad190b183599450aa2164f8f4205e38d1a09de630118b28efbcc2f4e2547e3cb6d94c2a1557078f516562bc670d4bb1b5cad2761e62303d2d9117751222b62a1ca82cd3d06c6e1c0ca7718d8adf6f53e5a2c6a6f148303475c6052c0a26a17a9d2910d601891ea56a93e967407042a69f5f03abcf4a2cb79431563b6057079d7b29b677b6957c5c79d79e1126b2f726ea68a4d3345680d91804178bb8e834584514b806fb865a8a994cf6b93f958a314f282de2b950eb17780a8ec7d07a58e6b3968e0d709c5091e45d8663c66879dd23b51b52aae9ce1b4dfd9a8825c021b1d7807c69fae88b281dd47877a4aab1f1d283d8ccc488a43978140fffc9ac4edec39e0fabae55edf9ba9fd81fae302d51f5af8a2897b599bd70332ca045d21d477a5d4e8ef7cfc591a9a153feb99b29bde662eb93d94ef5c08b5f7b8495daaec269bd147b465d00562c9e82b4403b628c509a7ca52b9eaaef67009f4b9a87c468ec32a80f4c8b97a18adedb91b942878ec7317f0c624c1e615d5b4b5e7595b72aa94b8748f86190633f75483ecf76a2a9663ffac21784ce93229d9585099837518c34f83063d5deff76db698383e8b9ab5a34cc7148e1eefb96e9784445084f116ec2626a5ee61a5aa796e042463b68b3c90c7eae423bbd53046365a670df9a0159976c1ab78f5af23903e357726292a1321ce073e1d2f5898a4d3cdee74415b8148afc4b4563327db8ae2d036b372bde9f22168df85324e527994d4ae9831a58394ffe4ce9eac20ff2234981f70e88c52fbf983e4b1ad0249ab91f74308515c8b0dd702ba597f575c941c672fd37df8af20701217ade2f7059bbb516f0f0cc2deb0802438f2c37cd0b8fb7b0c42b26548622937a114b9a7bf5c0520edcb226104399ff0390cc1f0976a60e29fbdfaea0acbd902c27f4e0e41c488cafd86c94c1bd53100aeb484bd9cdef586271f504fc374119556807779d4cb6184d4b49bc44dc311f66e9f5dab25dccdc77d439d24720e0ba79b4f79271f96a7aca26a128814fafdeb1d4b596495951590c0fdd991360f42d0c19575c845ec85fa5135e8725e681ba51f5c61354d064cbac28d89e832d10bcd5f774e61a8319ecdc25261ed361c1970a77b44da3c1a4703bee34bcf5b4285d20ce8f298f397b37fdbbf788dc55dd019c68ee5aca9eeb68030115cd33c924239a2e6a315a80a0a0832a04f4bc5285e6134716d64722f43dd17d41a0deada44bbeec831e48be944307eb2f3ebc6478f687549ed24b0dbb8e41ef5339ac449df86ac61decea30b9f09704eccec95a9b44dc28c47033f18dcf8bf422b165de1127801e0e5c3c917b49de49e5bf2380ba9c0eb1fad7fccb811f576137a9ef7c78b8076e419ce183f0cf526558e6e7157be05f1839fa88a7e0c468e3de98af0daf0512253d161b3369d688461f8370d1534ba5f8ef8b0c9c92a0e5a7380ecd99df8de75c4c70060ac93874f511791bbad43ca5e7086f2d44372e541469390399e32248c7832d3b83e14ae1edf986886859629be06fd6a487d81204b6842b37216751850f5c05ec65cee194a1a10748bfd0e69abc0990f8c30f6d47db3d14542f54f1449dfdde5fd99c0e95dd966a9b4fcf2742f8aeead5039ea1208537aadbbd72722b83b0f120e4d9b019646d4b4b41191ab3b1c1ed8ac6758c976624a0da36163425c19304e6b7b773217baeb05c66ac963669a9526c9eb67dc3031fc52258a83504160ceba48c0b0e68ff58eafe13a471631d65a52de5766f415419507ba9f9897a0516c33b00f78de58c35ea195fa0ef602ca8206338ebe3c34f63c3e2ae53165aead7f8b26bbff537a6516f25c76a665b7c49983c60a986a0e3b3c3e534ac6204f92d2a990910a332898ae58fa88c7bf3be346b24f4a701a6f424ab80153f13eace4e0c6a365492a2fc1353ce06ccd09eaf0ac46f857deae0b952e9f48242e6f24a0627aec1f09bb517162b9b5f7cd16c5223dea27a0c3a013a7a71b87bb525a1b18ae20715c22d5d68e87f62db760891d23498d20ca83d8506d787fc76bbaca0b2d01b6c0da74b7a1a6dfa9d5265bafe0853c08ac28b20ad29f34059e647834231ddb0861adf43831c5e4470c73e8b7f9d0e824043cd1bd2008e7c5d9c664d172d843c2199e8d89549ef7667e98b03ae964fd10d0ddfc55c9a02b3be8da4fda5cb96dec68bc55072c045212cf4846f33d703a82ae3864188865b931020fda356bfa7121f6a8795e3e213782c2733935b7a7bd352a053a13e43a8759496864ee2e6abe37411c404aa8dd204aa66577d61a40888c75a08986073ebc69d3f4c327e4fc65c67321560527d4d38a09de4f58f484e7e8d358cafc2e91d8766e7f1dc533c3dbd22643d13ab3741065af7621eff1f54c083c1cf3616d3a59b340001ec078881d4ea12819c337373a7244a81321b9ca2adae2e3458009d3005ae66b6ce9b6857a8d11e10b58e2ee3cc74de4da5cd7b1e5446130ea78f2407cafd14a17740df658e9d94c47b2a1d17cab2ec127b2034baee0b0aecf14babc8f00812360f419104de7ee69054d070c4f3a373a3080a9c30bb351b42d0158206540daac033785cdc68b7150baa9a85c8b37f6491b713617e03cd8449e7bfc9d841db2858a73aa897c8b08443c96769c9e00d2015e94f79c3d51d7ac46db7e1f1a8357b8c598c2c6619cb12242fd267e4740a4cdd4d87b51dfa768a1705948b4776d8d22b0c44c52b70b5569b3e4f11338a125279c2537452418acd20f68272fbd67368d727fd5ee711bf1263feea6fd7dbcd067a7f18c80be762f283bb359989014e6799fce8b6d66140c66da894bc3dabbead1d735430249a6060c0c6956c123b663ef6c65509e1e0bd83c4ca9608f68e2fa839ac7a54a39a0bf3e21d80cab2243ad58f3733c4efe910d2b23e9e7b5c2501738f67ea801ea76e56e318f286df38e7529494765a3bb1086b1d902baf8b8201f02e58423932944047bd52535d2427033a8cfb81a88a8a322a4171594e8751161e11037a57103c5384a242c3497ee1f7f30fa868bfda2de2009d8204ba2515f2a0cffad87507c0cca8f1dea3b5aa94630dbf9a3bd725b49dc01602100ef982d3df5580d03e829f34663ca10fdbdcc2624e7c7822fb4d32673681181404b10e69ceba2eeeb571f9db79c831e5f82ea0c77a85de58f09b33c7005707a83022debec9659a67d4991e7b723280a667a498002c97263955fcdb227bb7d48bccc944cdf36e7d244d730a8ce30d484f84af28ed6f32e11e1d07a52386ea6024f34bbd298031f983e87dd332e3042bc52787243bb80df11d83d083a80d3d4b82d5eb81fb6691f5c9106628e03074a6be0dcd0c714980972c07c60c0d0aa738c0f098a041b8d30f477d36c2cbf5f05faa538a981123423d32b2709b76094a00880e043f4909c92f8d2897898aea9466b445f23b1087980db7e404605413f74015fd436a64e4c366f792cb097b970d9b50c5d279350b0ce2f5dc58a41ac464b163a2e560f2bd919c8826676fbf3d901675e27032554ee275542f7410bffc9bb59759c68bf33136424f39fd0a471731d26f63ef71e37db9c95dc639f30433d0d0f3a1750304370b1fa9271b59fa9d67aa832142b09de7d2270136dd8b9fe070e26831722bcede6f4737fc46c3f33de4cb6b9e7d97c3a36e9e6de381f3114587b496f018a246589caafa16c08f9b70409e96f9331be1667b795619e8e2495563fb3631c6c63b24d6db481fe84bf7d23a75bec26062a07235cd9df83e987caa2c14eedb05a193512db6ce9c31828d2f483c129ddb8363caff21180f655490809ca5c9ce41933e5519fa1d9d88613e49af95d36ae18364688a8442783a6da4483b34bf843facdb006ea21bca55c1e0677812235c65de42362f24d093d72918a3cfe0a5f963286e5bd9c0187d58ddfd79d1ab5b652a260ee23377da1c8913ca63b01fabac602152869a875d032d2c18b6c29126b049851895273853c08cbc02e7e0332ad55bd3baafa08c0426399853c230c08369f7223a05ae5e9ea3b4e615f75d9a5a02f24829a9635ad5ceddf60b703b6df81286a53aa5d31fded927a846b6650ebd86438eb649abdd8ea81a68f0bfabbb8f1275a33a5260c7c5ea041348aef84f3cf19676748aa45531a71ccb506f957d6b7037bf41ca5b7ae3ba182d6f6056d5a5b3504032bac6d16a1677e03b4e5046548673b52988fb60107a756a004d04d00ddc930526cfb5e8688f2eb87fb15e4863628699cde2190120a401aba2e1c8b9811feeb78969b03a76406e984be5276fd7517c0e4069f23a660f327678c6b2f6d342e10b351c784212e0902831ec765f0b22f83b01fe0bb631db4f155144ee9d0d7e19be132d78d7ae23bbc60ab33d5abea7b5740230ec622cbbf334d9c27113fedf3aa87d2357fc88badd979905060bc815c026b90ec3281e90e5a61839c9af58d3b0c5c90dcd0c31c73ec13298e0f04c90c25b4d0c309300929dc4e6fd175c98d5031c7702843e0b22aa388b12fb853afccb89952abca314bafb8eac1650e60d1ace1d612988384440949fc872a15e6a3d76cffb05ae664c4ca95be2b84ae3efb405a6a9bd2fa7f009a7c3841c8d45bb9dfe1c66357842b2d3a74078d8443e252e842e1b1a00100f3648c7666a3303f6431dc642dbee34fc69d7ec2c02a5c9bcc7bd3be0718e3eb98452111aff869eda8b9bb961dafe76824cc432535a8e297fe750bb171b22f05bc57fe6087145b59582ad184452b03de70e43f7f4a18fca31726bbd4640021a2fcd49c5000ddf3ce7b11f95214d374cdc0a526be35b604639593f3fb6bbc390e141f136f74789cbcbe2591f33ba50a20ff2132bb242b8948ad5eb0e0064f816dca83758dc0944e36c9253e30dd4839ed606eff84752119446833cd19ffd8fc5b601bf63725f954a033febe58c8bf432d239927d2a2f8c042e47ffe243350615be9e42e75541b7796d9858c422826e87453c22caca598acad07b0beb92cc2209b326dc23f9c9f152f117e0c4fb63156f43a4b4fd8e2abe2f846e855ebc05157ef4e6feea3d55d3926d5b7147c6a9b360baa962dc7f937a0ffe9d195b57ed00e205ab101fb623333d3265ff33342300c6e8dfb7c1b49a7a541914ecf079cb17c18ec37078575a71b1c3cb2b4ccf8ca2328bff6596053083029d3c6ff822dc9939191e98349bafa19901860ceae999a140bdfbefb9abd303ae6f8103673a98efe7c66f75d4f6f34898afcc6e2b5fb764f115072c3399ef4075bda9c13209db96b3251e66c4acc3de6d95e049f16d22f02ef09e32ce1c59f8056fadddad87ee44427c231b8d90e3a82242eefcc4de6e89bb1e846e4ea189ac921cc637ab6afc8f294b6b202b5178d380078a38dd84822ea928ceccff3a9ba1b35f53cf7d5ea19c5b72d54037f1891619201205b2c1fd1bd5051f0317a2614a4280b3214e09e923dd0287d2b3d0930ebece31e9e6e2bb19073a0eb6bb50c8148ded740d1819b21aebdacad9acf06433a05b3c6cd8e2f91ee13f08140854a5619f225e29a133ed38637115a82ce115093c8792e19461b75235d42db677cfeab71d62310b63df379c72b70b119ddac2e89c8d9c85580ebfa98e45267b210b0eabd46176aabd3a0524f419d78f5f5236ab5befd1035e7eaa5f7e7f0108ecaf7fb88d6f08959cf49b535e5f03f60d81562272857cad301a8ef6e387a2a329b7c889c21abb6bd3e75b959cc1d7dce537796b6ad05380bb4a12c9909476d5e6a1cc815b616104b811f07abfb99f792355cde0f3bda2fe31b36f87008adda3f2ebae9bd1f5da52fba5c8938168f57d474e05d3734002558cebdd793954a95ba176491cd94765cc0f21cd7c138f8d33f1b0d4ad205e11a265d96de25e87fb0050f27767c4faaa3586226eec0ed4b64773eeadc92c840bba3a38c1c7a8b28fc8de440ac787f427cb17d1668c135d2cdf162f0a8b002552464dc10581ac010b271309c282c6533783289fc611b9713d25af8d141e2b609918441a0992502899a56eb7a3d737cee763c73d7aa886f24a67aca5eab55fcfc23fbad18ac79c40c39f3d6356b1b6ac5fa725dc6c2fe4016ff59ffe4c59dc1dde8c018072e0682a17710ef1d7367f6a8787177ff11c98b42a97e5f1bf69ece705c9a40482a1c1a0b96c28cf4168288e72a5008bdf63773f146a23913e5761f548c05dc51a3d6a1ce3ee117971927892548b1356f5f706ab250b693dd60806b4b791f45ea7027c88d337ac0991a192d2927e25130ec5d8271bea18543ce0538165838502bcaf306bf285006f64d81f93afe212a906ad194b0762bab0e462c4d07245d7e9c0ddfe406d2d61f072033caf5169e300ae075c973bfe6848824c84be2faa2f0ae4769e7d27dca51ef8ac5530748662909d398d7a5170224ca214bdd88177bec7430170364ae9d8b7e79d02f39013913a6992a781039af33fdac80a88bccada5bb12922bd2a3da7f8d9d22a5cd83daa6828966549ff8cfc9ecdae7bcd5830ded1995e32d3c863b992e6981eef1823d4abe48a232ad0efcd7cd65b23cc193fb49a102cbf2cc5adbf9f9304a6f71e9830e5e649ce7d0c6b7d8410f88787df2f650c90cdd1f80688975f768d20a289fc0ca610d071d2457a3cc226d3bf8ef7c680bf267b58ec3fa67cb20921675415ad737f408eb2807e367ef4a894a84b9c42b0370e9199e2eb402b4d37eebc7f6c43ddd25aac3d8759b3558b665c6870b8dce9f39f2e98f63793481982228905078c61b81e12946a900f3771486d9d3803ca62e08113c442d5f2e2ffab752469f1071f9d9617d3b69d322c4645cb3c5705e928aaedb54d4fe221e3babd8963d76cc1badfa17bd840db9c9007da7871ea04ba992a6e9b02f12e4ca54d944120834824ce10ee8b3c81ddd75ba17b3e0fc854ca735ffe78a044e22e6a663f8fcb11e5144fb9028b02ce4150b9ea3a7c40a80ae2ecbb7dd12dc79ed2562860f4d08fc79b17729406dccf6c933df57aea0419be034150230280f0abc941923a753c8738b337c60ed698d7709dfe83b256d1f25ff737b75f3d6c4a1d054df5246f55414ae0ab515205fd69dacaedee30157ec021a18e63c96158704e3657b1504f7e3de7bc34b056b0b18f832a9c6350c7d2589931d69358bed6ae19b9f4e3185cd6513f2730233f3bc98464b945676d5406673a74949ae58519441a0e96a2c529f13c292ad09db8b3d84edeee73b385b73a83d70975902f301d80ddfc183e116e55708b2b6c53d3df8e0eede47cc0e36597b6a7979c99e77b4e01e8aa40171b9fec3a918d5ace7affba4cc94ef72b052ef49a8be3ddd2556476f4ae5c9d5f3d03e46f50528c12fd92a203ef0ac95ba6510657fe278189216b16087f2e27de1e10453afab3da10f31662cc34dc21e04bc0d0e464a8c303d21ec947f0bf7384b31118ad456bfa69e53bb850f2d2ef833b8e008bd58b51ac8cd2b02ecccef94adabef5dba35cd297ea2dfb586ce7b926dfac85ab0700e88809bdbb6c5985635c5148ea60f0669048c0e5b59b5eec770c30d80832c0ed3ab52642df17d51705725b4e44782427859a23046301ac0e734f42c7cc3d5480c92e8065f507e45de8a6b229a0959f010c00aae0bc11478b39e021ea4cc244c49a85a310f9562991d3f90a594898449c439b2974b6f5019174e0714e1b8fd8740b9a1c114efaccf4ad38f5d2ecb7a44a400c578d9575f96b1f5aa7a089cf36c245176dd98dc5662988291fc85961ef01577b2a047992f9a6184e6a47685de17c5aed9db3cbb94e22a8ae7f3c51f1216ed45cb76069c96a9f583a98d7c80bfa8687db9d32f1a4fa123e9b3ec2d403238b53ac084073ece13bd5934a3477fce7a527a542714437570e7e4cdfbf33097098d203388380c929f38033042053c79894493aca4c826604be39c0e43638b80c0614e94e192eea10474650015b5676412bcf493306e80d0d090f20d3563b92ce7922626729a1374f3035f4480430a17d1cf072705d429693171424c95dca63a1bd4b81b910b78df636dd6406c61092467edee709f10c1b639c5f4d135e637ddc2a4d142c6edb7e2edb001a310df9bf5acd5adc2139dace5274f9c4504307aa6ae0e99f535514b9928d650f7881cc9e4a5d92909eca4b327a8075eda52bfec3485aeacfc634b5d731cbf1a9ef8cd5734dd345906f9a879072a3c2179c5b605f11d397c587bd88714c9b7b4a7d86cb8202ef7ccfa834ec4ae3e34df579c5fdd8e9e830531aebee109904372cc593d1eb6653c1a0dcc3855dac61d90d61eb39ca0dd9930c620644794351a059505be3408ddb6881537960ba78fa093872b7b525e16a5eee9056216e17f1dd8af43972277aa42ac00081cf3b65f8d56cfba0ad32701c4fc83d1d4a18fc00c33dd95d4d3f4347ea9a80782dcc4275de6c3ce61f8b05518c92155624d2239ec83559d328482d768f852979477f25e4ae653fa5d3098c025c05345c37bba4a1ef63a969c4a911a2b8ca80aafd9836c13594ef0bf956c503944102dadcdd5f5c400e4a4e07eacb54ade2ce21c99a1dd200556dae4a0088284a2da599304442741ddeba9161f6888ed825d9ba68bef67fe27dd49cd87140c14227e9a694b9b909800295adea2e5b0bff8972b90238b76d12136c42f6de52a624a59432e905f905ae05dddddd5ed39cbcd65a6badded5d65a6badb5d5ddddddb55d78adb5d65a6badb5adb5d6daeeeeeeaed57677775bdbddddddb6d6eeeeeeb6bdaa724bad5dadf55aabbbbbbbd75abdf6c9a37b77f78b0362adb5dddddd5d5dc9c99520fa3252192a3921011322f9fb9d4d06952953acb5d65a5bddbdbbbbbbbb6bedeeeeee6e6badb5b6bbbbbbbb6bedee361060010b63bcd010c4081992d8542001990f6050c006082426c0545a6bf51f2345caa0a939b1e608161289ad091e59fc60431624564a70645665a8acd617e9d452fa4536abe5eeeededdeeeeeedded947e91f48bbbbb7b77bbbbbb77b753faa5dbddbbbbbbddbdbf7cf94229a5d4d62a04c6054ba610d1421368bec850424325a3f2f73b76e78ab75b6ca79b65bde00e44537a59f7eb5432c214570c5139e28c10258e784208284896b01266861b4cb0048a114f94929a8e98e2e5b6dcd2850b1798650d129b2955646982052e4c45b51a416120f2c293305ca65059a1b6b4e403143adc9045992374c8626967830561bd6badd5b6b7f7b51d7e75bffdae6ddbeeb66e9be89aabd52ad52ddee170945305831a8c68b1c2110c257841902d5582aa5861a786988d8ba1898eb3b6a8d6aa2557a22ed5b6556dee6eadbbbb7b6d6bdddddd6badb5d6eaddb5d65a6badb6bbd65a6badedd5be706a4f406dadbbbb7badb5d66aadb35aee2ee35f3940bcd65a6badd5b2da8fb8bb1315a9d67aadd55f40592d233744819a42b5d65a6b4d014a5e56cbba5dc2651561add5dd366a088916549429b20609129158cd12031431d4dabddd5fa8d59bcad860486f3bba3bb74de1167675d63604b76eebd6ba059a5cb7cbc2b28598bc6588658b23f2775f4cc70305ec90365b9228b61b2698e87a30e176b5d0dddd8ba836a8abb66e5cf783957cca10cb0f32252ead0d27112e56442005113b9cc08919641154d4a800439b760b11c0972b4660c4941da86801162a90b237e532543ae304106ac0d02364947870410c18144c09baa2268b9a265be566a8b4066887b37573622dde64a8ac160dde144d0db259ada6686c90d4ddddbdbbdddddd6ba5686e9093524abbbbbb29a5b41b07092d9a28325e965007552419a3a4c4c90a4792a490620d4d698d2c6f192aadd9b283825a6bad4b80e45abda3925a4665a8a4c4892b91f8ea318d1210ea9e86cb9024869c08722f2b0d1599cbdffd0ed2c9e92f1c6009262740b2a187362ec45c12911d8d11d99bae32549ac24cee325452134497d4b6b68915d95aebcab63681e2eabc36b7d65a5bdbdb2b7d012f05e2ddb568c6796bc36eadb5454e64eb5bb2b5d67e770bd1e53cad9b146badb5761b628b96c8d6da221ab2b5d6fe9645b64f57d65a6badadb5bb6b376d624a9190259e68c10d25a8e18c135ed39cdcddddddddddbbdbddddbdbb9dccc561b5987071d1ddddddddddedeeb5bbbb0909727b5b2643a0acb5d6d625b44910d59d490e2b777777777777f7ee767777f7ee767777f7ee766f26339c50ac568703e744cb904f94278a00cd9c2c5519620d501725e94e2b27448a84a03a562bb1d61e205b273354778245b6b6372faaedb7eeeeeecd5a6bed13d9568f0188555b6b6ddd8c5e5448ed09e87677d77203e9ee188872777777370cdd35c88c492293a1411a8ab595dc444f72887ce85c8068d2244d0104509228468450620294068a8e2188d553487777576aa4bbdbeb0b50d4daba240a94cfeee61a4877b7d72ad4ddddedee6d851035e92472e46575931260b0640894b5d6491a0a5cb1018921e20a22110c9122083923b7e6053ac8637fa805e0e866db4c982468b9b613804a8104983523e80da238020c9120c6c0e8992e48cc90437d99599af1f0c47af48c962f5a8c741ab06a49479c2068cb80a219c2044f4c5173cc04e1a50d191c0caaa8e2a505311ccb053d745942c572909ee1814b1426dbbcb556eb8e26523142885cfb8a0b371156ebae26eeb0a4e4ed52441d94c6580dba5814262cbe0774ecc861820d11e44bee503136a498f836fe8ddf8afff15ff177e27f207922538e6f23be08f173c425727c1df177c447218ec931b6b1f4855aeb14304c8982872d699894d002041b15b0325462d3c5063a77fc039287e6f0a60993d75361a74d18764520c6eebb4ab8efde347b6ad7346f7bd38cf8fb549337e59e4a9330f927168c7e1cfcc9e060c39f0799267b7652f8f3e0c5c1cb8041f11859c7348cc98fce2db99f6caa5b6801148292db4f2fae7fdfcee0d27349eeb7d1fc3f679249b3a7be7cd92497668f9d4d7b97f02791706bcada8cdd3f79dd46db9ab2a44104702809c81c9b6cc2b6a40d294bee28251463a494522e8708d96089b420b2dc9a78c86636daecb1441326bbd423d95aedcedaecd95aad9910d1ecd9685b0ae3e0d667892470611298a6fc22c3a4992c77f234c5dcafa7e7c201941d2877f374bd4d68f6dcbf783b9a30a9faaf75127a2155ab75baf76e1bad36aba9d0e3664e0758a303186effcdb7fdf6f56deaa7a702cab648bee4649ad8ce7e6689ac917cf558a48f5323dfda7b5b2d24896443da30f2256bb387532361f225279b30f9add7efbc3ed869fa24522c2ecd9868b29625773461d232d999107696a5ab84fba73fe11faabf0f63ddf57eb070fafb3e2e7695a0fafb17ffe05ef530e6e3f4dc4b548ed343540e7f1b52e54d715d967cc9a758ae448a0f2fce7347383891467abd9f58a4f8fbf85d600df9dfcc46cc2839a66d8bfb359468245ff2af3763980bc1ed9f7f39a0cb1d71b2d9f31393cf21713388809825c51f17f1c72d65f9d773a609a34d4f85f83d6ce672e0a2c01a40f793484812893b823590dc6f3b72324e73268fd6bc2ef2881a4868c2b6a369edbd3bdf76941dd3269d1da119a5740bb79f3e17317734745d2d18f225bf96149256b2a44bb0867cee85fb714754ce5ebe8edcf8dfe34410cc1fca6dc0033dc917dd617a3c5859763cf2fcf63e56cbe55f4be6caffac91dbfd3417b99fe5c1caf0af09bc647181284fa638e4424cd251ef93b31fb22c2d8d49088a50518b0543be6294360af1a03b5cf936a6f578b08a047d11a8b31f03dfa0484341de91574899fc4d2621639a8884099294e3cf31b32947339c0b1768f6d8091b7255e871f3644209d841d43284286b19329424c7efba3eb1baddbd568902c14eda006badb5d65a6bed5413e3064da178d6e48b8d34407c59e6c69f4c92678ce48934c9f3b38ce48914e3138432c618e5cb7b217cbdbe9865a63ff3449dda5cfaf6690366a6df758abe0d09610d4b9f0b924965cae4ca92afa006c8f79f35c9e3f87242deb5213921777b2ec8fdf14523086bc8c7f66d48296759629f4fcefc87ec9333ae851b69f983ddc7d7018ac08c75587eb096bf0834ef67310f39d35193e1ff55c17f03316f5885edbbcd0b2166086b506ef3b295f379c8596e0ca1e4895138b5b93fc7c8d79d3d7105088b3fa485244620aa74270d4fa62d17042ee8420a9403d4f5f4472c5a00253921c6187378c927ebd656d942961c3f0ac524b227358485991c1f463639361016466a4142f2178bc89808114b5015393e0992c7796616810875c38dd4902d2061f13916ee072103644057c0a42b5618390dddc380917541b8f205ff67c6589b0980f395e1d7ca70e727f6dd321152ac42cca71c51f6862ba194914e216772d6c95a00bad99e21892d4e5832ccb468d11b149940cb0a2c8c062e5a8aa82f254a5a767862bda32c5a821071ff044b96329d06ac264464e1b26540a358a9618a9a73594a80c852840c0e06517e28c2092a96a361044564a132a50825453960b102005962c48854400fe24fac69734304e7eeee5264f720b5257ce86a915abb1aad7604e710cd165838a112459224552841afd49a64cff04a2d098d3374181305c9102149ec90a48a20a66a6badb548123422d0ac40288827311793dd565babadb6565b6d3581db3427b7d6d65aabb5f57ab35a6eed10a85997545a6db5d65a6badb5b6566badb5d6ba7777bbb5d65a6bbbbbdb7a3d4556ab1b0826433b1b16b2c3591a7d335364c5a25b5be19c56a766c0acea46a935a2812d8e9ab6988162ca10288082e64875332cb8d57a0775779b11ca4d2bad94ca6a664d4ebdac3e4364e5547677cf90d39745cff4b0721aab0cd9dddd4d5de9c8649d3941ee7b8606e4f6cb503a7346a7a99392821c96285103ed4b123266447002ee548fb823f142162ba8e24252192b310fe3e44b931b1a35843691a1d6eeeeea356bad0d10f7a0d9b1093847951be3ea63e7e2efdf789f8bbfc969e9b45ebcc8d1f1be9ffce25daceae905e631f34a55bb2afcde7fff571876ddbcf1bed4dffcf5bed4df8fe6a6aa87afd2f9f6befefbd0fb1af79019fe8de7e30f7387f3d0fb6e9f729f326caac27d5fbc0b2f85995b3e29f8c8ad87f9c6bbafe3a53033c43ef5617e91f278f4c8f57aae1bf7fbaf3de1e02f669c9b7781f310fbac60f7c7e3a482de571fe775cc1e79f3fed283127683f33157d40d99af8e098bdf7ff3abefd7317ba2d1f63aa22a55ff7af5713c1d29fcf9ac56d7fbe0df1e2dcc63e6faab97a81b5d76adbe95bf55ca67f550a26eacf0c77a1f0c1e3e7c49933c10fb6cafb23df2f6d0e9b765f859f8292c993c1ff82aa83ac1d8c1f7a383ef03193efc7e32f4be2da75458d256de87425e559c4f7d073d1fd5cb8c63435061ffcde24fc7eae52bf59d4aa56a2a27afbcefe62fe7592c181f5120b8a00ef93a41bea2fbbfa87f531f46148e9877dc3cfef06bf0e2bbef3dc4dfbf06aaf757dd583d84aaededabda85836f6c18ca97eaadeae1f7afbc6ffb9c77c0fdd4db900f50a9be1fc6bfca5bfdeafd55de8742567d4441006257eae15b57ea37ec4ae11b50be50c82864f8db03c0faaff0a98aebb80785f116fbdc4f619f17efdf83667fe87d2adc394f513858ef3f51375e608c7bcc0cdfc53bfe3c4cdfc54bd4083710d79bdadfb0fa4355bda9efa256c72afcb9f81e33d7166ebd8bb72175c817083a5fbdd66be0b968ed903c2df8107f2ebeabde0e1dd585a7c143540827e8b0540f3d9d776fdb74a0115c7d77e3f57d285f385eea6fbccfd0f1f6edc9fcf2b57a88ba31b3ea6dc81b2fe655345abd0bfcd90c819b8355d847e7ed0d1d6cdfc6dcdc832a1dcfa2903bae7c85713e1acd68dbfb701e00bf791d8859a5c23ef0ed4b140ed6db87a81bf02184b63d146ea830f4be1802fcd4db985907e733f894ed9cc7c13d68b63936661d9db731753cd66be0d19c81f7e5c8390f004fc70e773d84b803f1060699b565a836d4b47ad5cdd7b6215323508f09507dea6d17d15cb8e5284c96f94816653ddc90f16482e461b156ab15eb73be63792678391ac965b1be1f07f92acfa57a17afc2216408a83e85b9c516dd11aa22145537b451aeff0d15ee8c541fadc8a5d913346b50cce4f8f148f224c55918d913d4b2177cc9f1e318d903c318492993e347d9b4aa116244e9bc40e1e857bded3a140838c8af281c8d5ff59be7ea8fb9dfd53de4c6a368245ff5870b4780efe2bdf52acfa75f85a30095b75afd44e1a0f2b5fa2fe6d5eb78304795677fb3f8ebef40ccf671ac4ef3c0f17ac857fc179e077cc857dc215fd587bbc11aa9871e8d1da4de85e7b183948535521d3db1bcfbac0af30d065fb164922f0c3e070926e438bcefa806dc7b31780cb0a4c957845fbf3ec4ae7e98e1175d960773d778c7f340bee20e1d6a010a4ee7de87f3abae3d9c879e7d1c4ff51005310e107fa786d0c37995a77a9cefef38e8658b43f451fd2aa21ac7db10e320df4a0b7198aa873bb819aeea71fe8334198410deef220ac7eaa647b6df5eeaa1b7b9f79d70f4a7b00f942f140ef83773f5ee598fc729af1e7a2e1ceec2b1ddfcf630bb7df810fba4de3e76c187b113244ce5824f33c43a3819ba7b164486371aa5bc08254a897fe4c3dd2252b4928d82228e084bb09051063f4216c04c20202bc8d128ca87d1c83fcafca36b911b1b458921362aba2e12a8a438caa2d18445a3974c6439266388c271354e2166f8724c964c64f9f0a5377f42940922d8c01f4c587c1c8f6611976372bf0f6a19c600c1e9270310cc9f482500a683325a36de813bf303c903f3cfcf3bf1bf8348c917522c4ff20561926c8343cbf2bbf933cb323c6a4f28d7211026bf1255c9b22291d538a21b9f3b923c11bbe4d31eeec71d1d8d00f24824f892dfaa65b944cb52882cff3bd1a59defb6feb3ee5121204f354273219623b5dc5f35ca63248fcb623942cbf2a91729ad481e48264b3a26cb25f227b36429b9a3598d0214c88a226892154e3ca1b369946685494be364ab5888b82b5702c98c34d084322346ba9407a580a226a9d6ea510d37dbd2c50c0793b674d142b6c5cb931eae3b7daf29c731caa8edb9a99c948aed7f9ebf7f944dc751168f629459f8a27fe39d3c1684d1b71e85376efe7ae41068b638051f797b18a5c8d78c47b47ec5761ad1ad6bb5175c41656c986451936441d870352144aca035929084315a21698abac928162de8242a20837393349443376b5284180e459b6caca46a6980302295818c1a6101123ad1b210524555a342d6c98092a062654dd260f8526730b0e0092a95348194144962e1cb8dc964832aa012041493f9377f7829fdefd5c19e49046fad32254c1985b1cdf45a0c252a46ddb7dac95a80d2834f5ac3028446b72a85908e6202628e09a0af82fc452b793ef5b8a4fb4da21996365662cd05176ef2fc4a9f6816b58cae04a9c51c99744588cdf47294273d923c7304999724cf4b2f92c7f3fcdffebd7cfeb4fe477fc3f248bea68cca997ccdf7a158cae4eb35e59299ab0245e2ce79346593a84a9e6dfe69a3de066206e1d4e66e797ba854822819a21ab0d11a942d37892651d10c33a1c8a31ef29c4879cea43ca7973c67b71d499e2f364929b3d622a33c271195b9235f1ec8ee2785f2944292a788f4225f532ec9d7fcf9b1299a913c8f44bfd611a51547841892fc24a294ca886495a89fd69f47f5670572c5249a8d29e66620883f5576310a0b1d9cc0855a8440c99f7d0294e75b9ba7842f6362e028c7bf2d189287e5802e766a9a720f29ade41e327f7049c950ee21b3cc1c68e51e37cb9f5e076c96f847c608d4c1035c88050950864a34a8e120432c4361aa9050eb05230d2e4198047f07f63453beb4530ec880190af7aca54116a1887cc10c3353cfe46b26b3c42e1cfd65c028f7a35e4a4a2557bf839769422ce3c21c34e5a6c3a0be99a4fcd47ffd37b867cd24bfdfa77133c9d72b4af9ea99f41ae57d3c4e92c8ddbe6792274c33890069eede86ecb697de779212e57518098b8f8231886adcb3149e343c872efd6f32518ec3f176b39b5b87799c287d486dd3e4d74d3de36cb85f15a2cd9e4602c2e22b91e393c9f1a1c8f1695fa4f56c32f56c363149c974e5ebca9e458a675dd7ee2a24798a481e78a54d911cbf2265913d9106594df2821a18b68b7d1f1493be57feaad0d09022f9f320f6dddc54da208a455fac21c72f3ec9f18b36e4f83142c9312ae5f87116e5f8df2422c78f5f27e92a397efcae021100bd8481913f9804cb98f1207f30096211d4440af217937893d77ad68d94e37792266aa21c7f12419168d264ca4bb3681a4d258800ae86ebca41cb4b13166d68c16849299fc8a497f13540047046d7f5e2e0f54592c7b5e3c14eb7047222d3d9bb3ec81f34adbb897ecf249eb9ce5ed09025c7c8506986305d7a48ea3294e39f8082163452a0c42da57ab823b65af7f65bfc1a6c4ea50ac27e78551f8d54aa5a16f1885be1ba27ade0030b4318be8e003cfdf83be6cb2f21004f7fbefc21203a4423887f489074c6bfb00f1f3f3f24d0788a7d4c81ef43c6d378884980f988f1b0ff897d900663d2934fbf8419ffc23f5e3fe3855d70c6ff70c17ffd4f475f33de055d10bb224083468c87fd0f194fe34b80c5f820ad02afa7323c97c7f05c4ec373c11fc0ffc4609e0b3e8dff89cdf05cfd0178192f3d57fffc18df6d50c36bfc06cfc10b40f534bc017870c29a03af86e7ea17c0ffc436f05cfd1cfc4fcc7a24c4f8f92a2f0231503426a4a8a9c2080828e6825fe37f622ef81bfc4f6c831a70c6d3f8194f830301c05e3eec2706837970c2a4ab84187b18fb3185840d1ef630f66303ec824ffff530ec82b884d7d37f611f535c395e2f01187b61386125389b2552c820c31210500cfa1092b1d7830088de6985880f471c51e6855990ffdd19de4f8c060d6f86a7c35582fc77234633463dc92499ec84b99672fc227e6201f07e625d3c05c08313168da40e17c6160063312683a3e17e9f21bd7285240d31399db8957baada87f8bbfef95bac43be76405abf8f378eaff276c0d7215f3bfa4f487d7b3b523a76c8574442f254cc019a71fae39f2079e0471568c6c13ea9f72416a040a85241082107b08f5c7924c8577f0751f0d2d4a720ca039624a8d4eb5a0a6a102aa56600000000004317000018100a070423499044410cb3f10314800b5f984c64682a8b8822f2280c62488882180441100010600c228629c49474530300af83857cea04a3cb456cc0963ba01f9ffa5e69d823dcc75ccaeeb175839d4a7da76851f2e0ea5c4f2b3c88efdf606f1d61028e707441ba404757d3bca821479606f8a9f04dc1d3a6e4e1825680c6da973b772d44df864cf80303e9dc90c2035b10348f11e4613bcafaf7d29df2f6e143af8e5975c074da37606fd3b79f29502544ee5fd12c2fc18635d3c8c705fb662a84a4b39391d59b19b058af05d2e67769526540bf085e02a8be1bcd46eb9be41b79b23cca637f21040c510216d6a1090841fc8514325eb2e73dbfc936c3776b3ed5cf797ab76cad36aa88de3889546c0cb39ca5ba77dcd8c58359d34abc0a4d0e97448ba6540d82f3b73db21d0ced528d258a49040708eae32f9b2fb875477576897d676cb621d210e8d78463f67e851c76fdd257205e73a0a95f8ab3c563e83a23a997ae04de18c8ed9eabc7338ea809cc13456c6b00db35b188ddeb96b81c8ed735cb722e7571a3a9bafdeede1727ca07e639c8cb38cbf486140d5e9979fc59cd55f5b060d4a07b84758c59cd531fc25e2483d47cb7940f14853a56fc13f2bc44e8e77db510315c282a9442abbbf96d5f0304f4cceba82ea140494c30a6eae276cf32ea69eaaf65aee4143c56c486256eb81f93283872be5b888339be6ed55f263b543c963c58e0db21332862a3247832615d117ba35255bdf16cfaf8c0ad0f54ff852cda1a7df3a29b52b4fc02190a119aec7a95008e8848e4cfc7a2b0f39002c032a4ffe54708dc4a612ebabc5c5a51f7716023a2e881e0ce2fc6b9a96826e18eb3ec6b12ffb593d6c9d32c49059b2afd642e9a1fd2f3d1b60a499c8f8dea3c28a1a884fabfd204aafb338b96ecb4c49ffa991705e29a6c902c0ef3ded32951f012134fde04e35012f89b532e0d7305fa8a5735674880e3316c6007ee6b6480b821428c396bffd5f1b3640348ecb80aa8e53429dcd3bb6757abda078504939abf19ec167fc282462753e7cdeba959918a175c41d3bd8491cbac6e1953402b3c691709d33232923bdd22eb109a7839f120011ff6216bb3594a10e236446e14dd51db4e81534da79baa05bf9f3afc46ef0ee046719ba66c20d438f611cc7fc3911e1696a7ab061bf2ac4cf4d98cfdf31809cf11daee37a051ddb232c4a4c3591462f1603656575e2a5a46ac3881cfd20dd78f40afdde909bbbf752671e7e660880a68021244c706f81316ae3595f69cd8105be198bb6e07fc69c53e371058fda793926ce6ba1c4d870b916d5909706ea699f270a8d509466a4768e63571a0bc18105f152c4e3ca557a7682b30142aa9786169c1795c052f6c10be17e6cc476019aaf2996878b6df9fa3b9f762bdc605e622047a3cde523edd504c7ab21a4228c4fe45063df3998c064b1b7356eba6432c170d8521f48249055e28bd82a5b781f0d8f62c14be138588ef395c405f20ac4c4d99063c6c759d5f5965af104806315b2ebe82fef92a68058fa1753424d96230bb38c8a7bff3893818a8d31b3e5678ab824d67369849e069c2830bee8ae0ed1e74fb7d6b9b841dd1db820c689a43dabaa71ce3c69467de85dacae9a63f03540b325af147c94fe845b2391ca8240fb58096024070c25c7d7f1bfab1a2604a1d168fc96e852c535216828e691e5d7fd0bc1a91eb7534f6f43f295171ed262f0956b9f0e803300d5d61230d0f1a2b97d7f12711f02449b9cb75baa9105478851999065e9fb8e980b8c1804e5e6be31d2e57c2686d1ca3216461c2cc40807cf51accb8ffe8440b401ef30e05cac45550c6e58db41a4d9228ad848535ab6bd035963241b09051d12bb43a68ed403c398d7503f53c1140e00dc97674717eb19bf77a0a9d279bab86767c1072161c1ee04eac074c2a4fd5380d2b56648d6a12e87677c60a651215f15eb9ec3aaaa70cc48295ec4483228f7ee080ad1f57853300f5172c7a00222b22e808e4b1606eef27e7a489abc61d64ec70e73e81a2672e48ecca5d46097dd0512f8ed7a247624ec45f7da773a82d9818042dc046b94a18be6f9cceedc2662da43ea192317bb6220743fcd8d6abd77ba931a0cfd697122e44e8f7e3af6e650324ea95e457f9242f12c1b02f1e2588a142a4da368dabf2b27f0dc17087e2201d5304e9859c688209d9dae31bf40b80bf9f2657cf68382364955feb46ae93a5bad883b43ee90ae91a7b3541a451c92c6e8cf987c513574efca37269e98e7a7758ed515fe0e86be666c9b2a5da3665426838f2a5c013bdc18fac6541e7787d7f454d54c9f2f2223bdf46c47660c0070e00938335082cff93ddc3d5452cceb3c86da7830beb68636df9866fa73d6f254b7078928e0958e9a050bb01b25c407d58521a9c55ff1f0e589e7603f265efdcf565c95615570aeed457e43ac23bb4e01de382988a3aac33b24c22feffef4fdf3eb423d286244cd939a4844cd212aa0ffdc6aefa5698bfc1aae4de83e0ad870068cf1b492b348bef392a1a8a0873ecc115c373e6921cf05643fde241a0aacdf1f7175f2fdc9cae106e48e633b5f055459354f2967f2ac037e5bbb575dcf66216622d054ac135116e145c165959960be1e1c9715ad18221b75e04f405f6cd747f6bf01081217accf955c1255088b3df963a39069e38a2f6af90dd05f17e485f59858baee5566ebe7694b9ff346e7f983e0f33b1cd7299f8dcd9708e0af5de64691b8b09837551d07d0a2ead67a29bf83f3c21c62e03977c5bf025a8596d3c56f90cbc01c5252d96656660af2f26d7060c284fb3b9cf2261ff9125281a6bf8441abaeac8ea2907cb65d6e56e88e8e8c23692a7e8e45f6beab8dfb75047ff29309f980792a9e77e6ca91d4c780c68d7872315f84a194a6eac11b3253e00177307d51fc9f41898ae98a5dc830c3d3f8735b243c3dce9ea2f68cf98ee2b1ecb13527d5c9e1fee1bf08f0ecee15ce324adda3d70e7921bd63299553f15da1285d0ef210e9f7c23abe2c706bc2b41c2fe8ad05982a1dc99596a121c5c4392ab365aab116ad08f368fb28e6d375f01eb328edd723037d21bda501f919c00662c7ed40273d785c38fdf7a14eef1ed3790526934c065e8f772e30ac6b890c71591aaafd84b15deb4635de02a314ac92338a095dad9c35d129c71dbb9cd4f22f2cb6dd0fb8820ad1ffd4bfd50eb8203f05e3c60a6a880494997054f23afca19b7141b806e2613528b54554b218ad7988c1818ef3e391168bd52076c97182e183387f9da17a833f31738132d0739b99a5b345cd3bfe8ceff7d9045637656c62cb50651b3782ac6f28e95f5e2304c34620d14d0e942c5c4e5713e662d713244bc9c7ba1480d6b4e55df7c41339ef540331bb1c0162120aa6910b61341497823ac011d48993f31a9c9f0dab34e3dfd8663705d67376fc510de64364dfb3e2cda78d0c945f2886403a81d01086822a5c4089db5cf91b079961b10ff5948695a674c8ac067e6277272f8af11812cbfdcdbb1e110d452c44a821bebdc65124c0c6ec38966c53e72bcd4c767ffc408dca5ec9e6e8c32a04a16df81a83723350a3a9a15cdd3aaab90e9a455c88c1d76badfc156f54a13fdd95edade4a1cb5548ca9c32c924a42449db47578496655d00732c6a19b75fd9d456b1cc0d6fd27e8f951f21e71ec8fb07782385a79a6272dfe0d34794bc02714b461267b0f64994278f840837083c105d8ec23bbc6eaa7cf48166a09a711c2718164126196b646aab141be0a1fb15ca641331ace6a3f8b18996bd9e363fa3addfb4d95e571d835290cca79448b35d453a5f46ec54ce18c35728d9b1fa981050afc8ec603fc1308c37b5a4f08b25082e9b0782d1a82e114b59358b45e10f0b2a16294ff7d60a39c2b4027e101d03d1ad0e08a01028524a1b997fa96731cf61f08ad47d23bcb2500bf9814a83074bba2cfe18cc96a256e8c20bf8475b347cabba05ee901109a82b292099206a707875057ee6a5179d4e539905683c94e2306c3f9200cb2ce8b171f6e6631d4b19f0b59ea4da66c06c8f3826b5fe9a087d6f58948bf2124f185f3300ed2469a3aabcfe64c3cdf095a09f1b577e2d10acf1275b781ad3918a90d61f689fc79c7a479555bb4412f33077bad9b119ddcf0df688a9e009fd62c4ee1f61c40f59d8f6e2c51d8342a56f69cc17d5155a2f40c27d609deec3a34fd46c46149884e589de6bfd24e6d5af50e4c06a5823b29991a83b2e0fc849180011295cc5995525e0815866696be816f256ba60c89a768faf75a13a1d171493030b66b02e3b6528db46d16f856e837bb4b5700fd742fc0591f7e1a83073ab4022bed472388c64681e47af49b91d27d8805b865563e6831afd98cb6887493f9b7ee97ac541a3aeadc1ddb566493213132b08b465f0fb5dc569122883a4834187b7479206102bc7bc9d485d423c84bb2d28c94b81670757f67c49127b0185d2c17aa8dea768446319d129c51f063f5dd51d4202cbd8169a12560d0678a3f8ecdca39a5ca963d80ed98f9ff98ca5fa700508fc2154b2c77316af4d9e03b69768a235d1f6d36e04264aa55872c7cb39bef29eb9fa0ba5b716df3112f8f1296ef621a740a94c341a18b09e526a0527267d4990aaa4842f59a028a39c4b7e30a79db1e1339ccd017962187d5684c31ea0f6d50e8924781d0c43956f7296d90cb786fddd1240973ee3c90e7c744b853848065d159954d3a591b55fb83dad6615d03b40ea3c6956c7a941e7e6d589a0fa911771d8da971ae9422baa5ec77522db841ac608ac34a0c248262155de0174a98722dda80682aa5b84e7e11ab96ec03360d3f1bff1d7ac25d3d809362ce11a9f60fe5f92b399db518e9e8016d98e9d8c3d280d2992ab0f031915a2471717c13598f4ed74e8774535279061cc87a3e26a203de3cd09d7b535250946206748944fa1fd63da442d48eb7cd4de3b2857181049afa89b4cbf9394aa13b8723405a36c3870c855b6bcf38d147673fde2c85221326264a5d8c719ce866aadd31b9b018f333e04d2413615ade8befdd06ed49679569a6a833070278032413c17750e9443592ac715737d02d5f1b1e0f39d592f118406ede73e28f8044a94d3ed45bd78ab20f886021dcb38a6d86868a2407b84cf441b51c4977cfc8d23d6c3e098df69ad0ab6afcc7f0c2b0176b7831c30eca06aae26939bdc6e5340a17cc81a61367c515442cfb30676f2ac2e70feefc0377d470a9949e2f469e00bcb9a6ed19f456d9d5273902381e2123e71225b4ec1bff1b2c5929241000776bac6100171a7f6f92000eb5613168260394245d2c72b41d9e0cd8c06e9633afad8446038707d92d05c2e9b187d04d65883ae691cf661431114ae0d6161cc56fa49544a35007fe4e0fea341f82436cba0bdc2815e54b4090a92cd22e51c213348b2f54081987f0add56c7880bc5083098a8340f2a6c0dba93b784ea1a97a65d97d1986c13f012e90b2863e21f32cf65cee04112cfee317e5f0238c79698773aa70fe6094a3defd406f3cef073ee246320116a94db15252472a45276148f98ad8a4926a2cd4b01e2bbfd949abbc904819da6223890cbe9aabf2a532cf4237ffb36e391ff3be75de8abe21b1a5cb7580bbf948646cca978b7a3c99df2fd0c16d59309d68ca1228eb4c5aa03bb8a64103522cfe5787d6a866091cb84645569dbc1fc5b17d95b78960f9f630a1bd0c88b16406295d1a8ff00d765931ca098899260de7971dc3a98f28624cfdb7ece3431c2ad1be1b6c66a387c2666275ba35d4045ab823a354e6c424309a40f6d5b29e7520dba73cb3109af3f164ec9d0d93ae7b3fd8990bb1a85e2f4afcc32b1155f446a839ff7a2b91a7cb247c6590025571f7d1957d546bc82bf1cf572bbd6edfd53665262373728c26eac6f46b41d7d477161afc44e010a28cb214f447e1e58caa3a5b91aae61766ea3529ef8b9702ae1fedc840ca1dfa8b2e30089e7b502f032b6c68c61662c6adb7c1f76452c020f815b57ee48905aad9e643ed2f73328ca6c4a8d0c12d8476a6f715981e2764a1c8c633b2d0fde8232064b1a4c40045b59f5d572673693aaac99881345c6e7840f96c2e1d95694576249f17d5333927dc146b9d275af8ac4d2bb3eb8ca75ccf6f074c20e5a0ac49a992e5251683ac0856b913fdfa9f2dc0e6dc94eb06b6906ad6c038410ddbf8145fa0f78e4cb826d5d6b6d9b3db19bcfc8fd31db12c3095afa07952fee985849d50023582d9a77218d3edb1c4c57a27c3700f360e0d8f08b159924dfb33915ea23345d6c32fc0653c49c10193375161bd8515edb9baa808231e375cac1ea9bf8130d46889f9eb35c5f90095825cf16a1ff4001896f5ee0db319168fbcde615a539d0c1dde0c85a1098a204963b37b09270d824c13896228346a9517947d93c8f339255c8d04845afc3b9715e35ab9af830c9b0407af5cc47fa250a73c4898292e6849566981bb36b1b3ee54c3e2bd21f93f4ad1b46937663e097c8c32dcb27551a6cd0d8d465e4255a89010c9784abcbac062d29cba70c8e828776365a2f36e8fc9476cae019c35ac31714708a1d90eae0cc20c8f65eb8b2b44598fb0ff6346b829fcfe0332ef86cc5361ba18408c7c81abcea48900e685c112a915f57eccf6aa1c2d6f730c9879bc62dea705f604f4b33f233c5cb71b3827866ee362488629b1ca8a06a0bf5e043ab9212adf5e17f143b4610cb808aac1a451430519a1e9402a930e0a3e2d3149616e5ccd8f9844f71a678462289683cb2cca1c04100ce75a0efe1c841641bac6468c0da62012639853a29ab0b4ddafb52aea50b80b77ee9d6a8c744c1b8afa110bd199ea956af7364776add7dc65ce5538cb878389c731b3285abf8431457ee76aaf039774b9364ba9afc9e01117116296eaed9340ca4fe19b8f96b21a06b6ac896749f70385024604892da43563f09b512874f177466d2547cac9166b62a859bc11d6ee938b2263bbe87bc12e2ece00e546f4764de11918581eec1c37b5401b58c1b4ccfd9b5e2a017de8fddc942be1e12473e2bc51915829db0465134bf4b990cb865ca0e29968aa8ac5590045455c89d09f819b7d45c5521fd67286e11ec1b308c0ea973c1eec2638154e7721e0b38ef74b81514427065b1ceb30ea854dfc094637c911505e04996085ea258113cfa2e0e80ea3fa850edb83e683f2a978eee250ccfa71e77f9954f62f5741e5b6f79f1ad2de9f590a320de5b178eb36bd018d1e43c632884825ebedc4119c0a66e2009b5403f917475221767ecce48eae38f141aaf11a41e83df110c1b6142970211ffc2b18f48f121b82cc438060daf144f767f55bda0f445a16fba61b2c6b99ff84ce9c85e48aa904a3f745f9d455832714da8ef55daed0e08dce67bd6b2744031e7029ee50faa7980ed22d544500327a3a86a23805cb012a9045cc2e618c2b5d4c2ceb612eda537563f36e3cac51435551c9d61978e2f82614c5a8eee142c4d248b3dded8d9a9c264a6001a328bc988db6829e14af1d173463bda7685c965ea1d9c2b50ed2e2ede486101147a18063ac7e971152438f6e5dccbf2af9eee229611cceb42b775800b7704551c74043588129282b38796bf3d478aa05a0c92abc22864aac7a4ff6eb679540b2254966295b0c639909f1919892c4ba19438dd9c1b674162b62c19451380c3ad1a12662a7442dbd55c3c1f83f62b5aa316e6a68674a767c132cadc9dcc8e286311b987d319ea053f70276145d7f0517b51dd8c7e012816f3e4eddd47ff101cfdfe5146f92bc82aa58f785eaf315b05ff5a02b2b29514edd2d4e1a6f1c62b81fdc21815722f7c3a9fc33086e23dfeef313020d961bc381c2224ac19a307780e99ff44d984731c62d977e810169d25e0b242e4f5dcc988976c3ac2fb677825cfcc302f7586729e5c5490f3464d3cc54cd6c7e8807066f32c8eae11ea1c594427eda746f24f30175a2888457e41eed8598f9b22343bc888af4865c09eab96e4068430de46f489e82d80d5f29700a660226a334f7708be20c91758d3ee28e5fc26b9b723e57540dcb146a110d488ebd2d2ca7b0538c10b4a5dd1d479b721e4a09103d93160ded211a53846025915f923019357c9420c52bd4285730a3a200a130e6383bd565508b2649d8753c4b6c31fb1fbf83cac725d9b21d5167d440e25ccaf0f5287ca8cffbac962023df9aa038d1c64481e82ab6441bea19d627c1b25cd4489535001d5be546a5b28e0720ef9007323f6cbd92b8e2a80977994a148576b732fbc525cdb5670f1435aac356006a7b798cc8f4ad96977015b84439e61465b0a1d89315d5d7f3094574445c2e879aea138631b77ed25c89896dead1697a30133de693d6f7db0a6365db14bc0bd72bef97f8f1b0894098efcdd2e32049f90b6df9ad395cfa060058ba75a25901b2610784fbc3fdd238f51d930ec9584f7261c20b4445e44b0d8b5ea081a1043b6888b975cc895076acd80b04ba05559cbe51090b6747c95e5ed8467d4d0027920a0b77b921e4d5beaa844a056747de032bf57099a2dc032d974354af56f8da036542ce67ca14dd46c7f266b5cc02d801c0748247511403b9cdecb5a124700f074e6f174cc9739abff8e4bb2849841dc2474411a991dbc0d158aa9ffa8c10098fe5d5e6cbd907a00668c703da4ea332ea3676ef1d97804237d2f43af6405de7f66c31df396ae758b15b77617395a1ff19c713d764054da60135ea37e0a3b82525728f54d03a7bdd0d718aa856de3f6fe208814c744d662409bab5aaacfba6630ca9d555da4c79a0d3529bc491c91d0f59b8ee5f524c6c19a9116df0c44fa65e2db8b4560371d4a47e5d1f851cc3b93503db0e0c9ae03b5400a7a5a418581fb6772499dd1ce7903c0ef50c56276de18f402c2c1292cafe8b7a1d05f052e37f6a67225e4340e83b93520d83308b1661f0112ac57fc2c30b9e7b29bc4f654fe143a4bba070a95e37da4c8f69814ce9e0c6dab3d96170638d8014b0dfcbe0d2ed106317028e3cc53497fb915daccb00dd608329d463e8602d8fbcd966187a620ab86a81938fcedb68d021633bdcceb5953786395060e4c3281015837c9fc7afe38ffac0287ac1b902cf46f2fe8479a998f7054e9e0dd55e66bbb5bd176ee8a73b985db592fa8d9ab042fc12bf2c7420420ef747602fb57b8f3e5bdb80a7f19b3f5e4e80a5c036a9122b5102c3a0a44e190a11bb114b4555f130569dc362b788076abf4129baa7b1b4ca09d13714f2135a315bda0384d3a4b8579295aff209e3ed62a0d310672d1f8d2264587d24e063cf0fbfb64e5ed03661285b9a834bd631e604c52a02bde36466edd3107e030905d2704e41ba73712bd2c4c9999706c2fe636e80ebfd01f6b9b0a97722b9c6ac94d6310b5e40200f48429b05b47ed40a448e5f296ffa5e967bd53f29a9fa81d05219d9d481d509a5106cdf31dbb21d9609d5053551585d4547acd65b342dda20a018f331bd78235d75352c1d01268dc915adce6c345758333bbd26cac6db7c454c2bf92612a54b88a50c2ba2311c2852af34c253166095e820574fe8a60bbcfccd50e08296840d975ab3bbb7a6da4be958e0ac43ed06a44487cf26f3b6181dd5ebc50bca5aa16e46ea77ef995eab1130ca74d53d4d4907bf38d88a634be4909870843990b1d3080500c48672018c30f22f286e2baef4f4266ca2f552b454a9a9d96a0eb08c68d82e6039e9a818b4423183feb7a579a02c79458d928b2fa3996c47a5e831c6a9485f63613fd22e1a2606ec9aa1c80ca91a0666704e5ce032add51d0243c464726059512519bd311846e2d9c8469b2f36e9ce5fa93c72b2b0aa4c07ac23fbd0d430afa8909c0e8de24810baac5d5d35040b65a076f636e990f019c23dea239846d3cbd998354486ae70e6506caade39c8234a0e94ddd0541e15626624063ec6dcd26dbad157ef580e696bbf1d3e0327c170cdf0c54b4e7789662dfb301f8de56f9254ea8094e5600351ce9b80af920d611c78ecc9fb258a19cde71b5fc57b29aecfacd690bc26cd51d66f14f06ed8981ccff9284ace5a4bc1bdfe342bc9e820811beab6ae0e44d4640ba13b0928f3d0c8f11efc1e769998e31ea27663a1bd0e4d29e57e664adc02e7e2096962e8f04c9ebaa73950a1e4725d4f2064d3c79c19012ed22f63acccb60a7b3dd4e03ed5a13f940f35e83a04df46da5d5c460eb4e1c8d74e8b229a63d40b9ca87c470f591bf522fe6c90815f9d281c1b8888367de3c5560732cf53d28effff012c3de9ed8e938d9de2d0fd524e153e25d49195b8ca38bb1e7dd1cdf115daecd79bdf844fd878004f8a8796bd999df8fb9993632b8cb3bdd4a76b76e3f64084717e524e72cb2c73d53a077add03bf66a09ced77e97aff5307290e82bd93a91c0aa732c57c0980c82104a5d4543d80a96e73384acaf942d2a06f76d5d43106f168a636928552b0ba691bfc2ddff3ae924cd9586407c53956a5720a6da823f28af71574375a077015162b671a25315a4e5a85a9baf68358f00f803e1ab0e78aee205fae167b92e650a15800dfeefc2cf451f13339a0fb2743592baef681dfe2c22504a5dce9b8b56fc60474b916585ffbab816ee4001b613bca1b5d0b9d44ce570b0965c12be0d18e4f4ac2482f72facd0a50cbc18aba2e3b16a8813781d26ff610fe1ebee053b1a31353641348fccd3ee1afc3173e7c1d79972ede8f65312c5c2bad63897af049a450e6577d5575e8c5d251d42fab2e4f960b72c2a8d601fd0a75642e9097985ff6b04a4bcdbfbc4b0cfe0182693a32a6971ab2a814e91f17bff43cdafb6bc4681b942f731dbc98a2572f979999c456d6d18324e26429d4e3533fce1d32572e0ad17b3384c7bcf95da804a0bd550e2da82c7c8ee60c06f71978585f944e2580265f8710b28173ed2e14febc0a164b9747ca9b5760dd464a05ad8b7348dd938818ba4213ae661c70f1735b6e795888efb685749122caa22f6731729a18cefe2fc1c387c2b53528660493f5190059236aca2a5285d340fbf8630c211c352002e68adf5f5b818c2874dedec9ca5fd2e251934c9da61722dd7de70ae07707c0fb85e86222a61edbc952cc7205286e600a74a6c5885225097e10539bd80de808a904f2c014fec09eee5cb4005b1873ef5ae6eedfce81ea8e4c0ff8eb3085bdc86788fa3c2ebb92a1e0e57f558a39302fad7daa9095e49101a118c3b0051be242c1874e73a108cbb285dc42d290416b1d1001dc82172e34f50f8b0513898180fb5619303e91f345a7f99309c681b5765e222740d0bc7f0154cb02542503682fc122bbd2640c611bf7de35d7c36de029518d4f46501fd6a9288aa32a6eaacabfe23a01950ecb2a7a65a0ce60d090464a9a42716dd83e9fc7ca715f2005fb69213c1a6bf03eb7a6b5b4e774eb3ef6f7a26f65316b84da15ef40980c076f018c42e0d6599eacfc183e9e9e85bc29f6aa392d148cf7f3114d1c5f346688093c50cad0e27e99204d39b38a0d24bc136822241c2312694ebc0194bf7a2dd7e42b05c456971c8c012989f24721b17c71cf903a678061c632443d9baa9153acd409d221c326169055f59dd91c8de9410e75938823bb40d5d49d0f1e6bfa34fccf47255f962dd1cf5db5d2ad5c92a790346acc72d20700c99d15a42e33c45f964da05480d6acbb9f490aa278a406d89b5bac8f15ad31526bfdda4c51bf74761e86fc5a4062b057ace4c95bbecfe9fc790849e4c443bf607a71477ca3f9c51f44fc91b449a7742e10019d61b0180e6631b1c886d7fb0e15bbee0c32a11d2cc4ce7e2cbe56f3c30a9ed177f4b46eef0027241c603def68813bd203fed2492cc2853a254d9aed8a2e8c0b48796f65d69121e5fee7b74946af9f65bfddc595984fbbe95425476cbf46c746e5a45cc11c31f4442ca2bc596047d7a81734695b92552a635b46aa45730d09ac3bcf0bfca7fc6da30e07e4901628b14608277048bceb55eef505c97bb97723322d04bd20f9f0856be08146e60d048d71c88fa2a7f026ada6e70d81fc945e6bdff737a6df1cf81baf9ba5f4c7db25a3de66f1d6e336f0aca13308bb8eade10e7358d28546c0cbfeb6503bc5d750b64ea08b4f11f0532a59187726025abd3bab9b06223e625a7eb8a757f26edc7a916c2bc7431c0266d83e896e5da5500c6a17f988fdc5ac4d5e5fc97a52406326c26b5dfdf893ab7c54d1c2d8888d9f82402ffcae1e9644cee438617984c25bf38ef9add7a65c2f998cc81a04daa4472456b6a9ecb84dbf1259bd51e8f45e967634c09a22647aa5cc85a0c4b942db7d8f21d0370ff75fe0873418ca5cdbcbb842ca8728160c2f1fa07a9057af1902ed82b0d6e36b554402f3d907d03cded84e7df7fa381068f61c15b0ccb833648dc1fce5a72a010151f8a8084d22d077625d931e170ac7b2604c8395c606e07009e5004d758c47f286a4415dbeb95ae563fe4be599c14800a4e6c564b3e9d6682684b5527f9a4b8b259ccdfb087236b2f344da5508c586350cae18fafca46d74fb3e8098e4baf46417fd64d7a6e6f33c025c91593b0d551342bff2a1b1438601bf87489e7ed82d54a9e6407db736a3c751887ff7ee5a11892fcfaf5fa9ee1f92e0ec7bc8b5801fb16a7acaaf9128dcb24362c8c35a85b1afbab236a77ecf53f1c773cd61d749cef1389bf8c6e1e19efbaedb21fd43ce44ad78ba625885f1f08d9699912dcfd13edd5b0d25bb95cfe2e1064b32fcbe376587bef37d255aaba8482dd8dc9cb1f80d490715fa406f0e16e5376538c2de00b90972398031f1e8ee8926dca055fe266c10202301af28b1623fe73b0fbaa66700a069bf4c5cfc214cc3613fae04df1bcca899d726dd4270a2a464804b6d8a108ec5b49d4ccf6de2a1ee0953afd4dd87ff3dada90856a0b76be0e1ed942760ace30df6ebbf2611031cf52942265018a9b20c3c32ac55af78310450759dfad70a64061b5e092cbc4f55daa1ea2fa0787f453d60c0a06a50ee3e00ec575a55445c77a732ccc0d2144f585cbddda7fe62c11ef71a74bd807e95c32e231698d218780177050532f073d805902dca29ee37f55c68fe0d6ecd5a6e004565c2f5f2bc7616f71483dccbeedf5dfe5f9b7a6f0834dc8e95849b700b354855d1a834318d1713cce83e209221950d362af1a361c3b1cfa05408c01cc5ab368592661062be53b696da4dfb73f9b3bed3e49b0f0cd282c8a7dbaf2bc0f9cf6326b814f0a062366946caa290221af8dbfd647e8765aee6869cbf74bf8807fb4285339976f5c8b92f5043b81f85e8f4ca80b9d4f89b9d839adba0a27bb9d41e2e086bfe781c0a6603f16d4fa83026d2ae1e397705a085db8a6a62b9c20eb7856976aefb84e35798145a22039582c7707079cf28212dc0964f5206d55b68697ac68002274400bf0c4e009cff49ea5846b41636224fbed0b048a8553b3b60acd894d06a90e08e0297a427f2b15213eca19435f7617545cd5c9517e800dbe7677dedd27ce2e9cd387603a4fb011fb8af8a28af6b91b651071716d4813a2609c4aed8f4ed4ae0954cf765196b7b7f6abda07f069d0cadcfb77dd6cc6ce3b7d9cf3910890e4dba858e4051fae7f818d0067c4b2f757c559fc3f6dfd3de61ac4e5a24458a9c41c88d2c059a5a0620350190aa46d4a01b2135ce6d4d09cb73d720a42b6cf627f48ee4b88add389cc69d45d98e344c119d974059a5d32cb89a39e3b1ccd86660184fc905ae800ab73c3917bcfa156db8123dd13ac6af56f72fb828333e5f8f31c9b5552c1c101e9fd7dbfa37611a232336be2dc7a91a6434bb1e8bb296249e11af4bdf5c11924a1e753c9e36559d8fe32b940bbbd1ee831c9c5956a97d3b3098212079599415261ab8ff75f3165ae4a3fb5895bb52544a39996d2bcada8c9393f9af64983ea2a2dccee5295894e52dafe145c20a1f4d47780e23f20cca8805a2aa56eee959db516693789ef5a3ec6e90b8d246900cc92887a4003f6806445cd00661351b9a561dd517be0908e44f311b3707bd04cbf87b1ef2538a61e1a9000e7e1a519f19a1c02b97b937c840b984efddabe130d4568c8043d86f4e624d61a1be9b7f34565c54fbcedcc791c5305a3ca36c67327bbd2add9e496e4b493bea671d2dbe8c6cec4328aa4bde49b36bc25758217152439c874ac0f5fd39225ed9e71499458e0589f9857be8ae74f0d61fa521e4aeb00828c6aa2fd675fed9703740a409d096ff4e511081727f29415bd7d257eb44b8857925b72beb2d7c8f8cd7930d80bdde543512a576ed346b00fbe938cec8a20af55fda4ff96c1aff1c74ec5f4fbf021a54ed77f9bfce904806ff40aa01fcbc79af9653ca3e0b5afd30cb6782379f559097a1562fbdc9dc9dc612f799419390ec395abde58e624d1dc9478027995e900db7dbc384721646eef33c00dacee4c2d76652b14a958ab312592a8aae5dd5fd2d3c458420cc9532736e54f7ebeda20d003b0e4aeeda06c862c94fdd712ae80fc66fdc2104ed13a87d912bcc31fc6e6e74eb43c1aed6496eaa6b58bff6292c4f24e6c1aa236f38590a722fdcd317f256ed1ae15d993fbf106fcb60b35d156a2e53f543a068e861aa5759e7edb29a9a4119dad1316d83069b48a1cd456d03c463288706096f718e5f1c195a87be4f24c96e9bf5eb4a19c9c2f6d738e725383b350f9d5457260dd83f0b72da3928e074da85d7b024a5a651df32ca187c0192dec55c50b29b2ef870d7808dc375250aaa17c42d06676ca2a896499ac0eca8257b82b826ab184f43cc80e640742abf2477751effdecda09010b1f2bb522563604443af54f157b1d95f4a091882b813f54e96ff87d5e5721984e3d223601237419fdb1bc5daedb788cd4b8fd20555202eba515ac70ca565b8692e4ae75345de265ddff2b667960a3e108eae64e760481114d842c3a79f2054aeee00a4761cb1b09c462b0a475c4fefd726d5ef52dc665e201f74dc770b05bf22e7079d7b36134545f31a8507a373e1351e141a7bd4ca0c5cffd0ee30ca00410fa2dcc5b1bd2ee6cac577f4e9001318dccb95ab942cc549b60da2729d688732f65c030e50dbec5b574063f94d97329217dab7d675b8d2d29db8b405062aab959264bc89cf07c506c85be5020a37839c10d8e1e8956c91f6129f3ec5453e4552e35562dfc53cd9e31ed3fbfa34926f65d57467e54c4df39053feccbbdea5c6550c46bf952f1792f21c64c2a0bb8e41a83052466eb9fd478b310f0493752b5f46be9ca0fb90aa52459aaecc7cdbb3bb8a7d587c78e53c59a51b1dd114ccf25aa35b857a0e0516eafb2858854bc13ddafa65d5cbecec0974d4b1e1bee631fca0a21447d7d58a137b579e45c0aad9ffaa2ee47b9ccc45a36c14e5c49cd9da1538a5c01ccb4221ad63cce7d74ba71ea1c36469bdf36845ce99adcba97ba60a075e62c1c741f433fb9344324101c206d140b7a830a033c1fe10b6ccafe822d68f1c655a898f4133813ed0c097bc961498aae1631434a0eea0c0de07145c268bfb936df569006640c39326981a8b05c71ebc5e043c7d5c5fbf470ab8c4fcd82f44cea2e7107b4186170983cf4ac9adef4d8ed79d9c2ea973fe4353e4746d9f847f24813ae16c17154cd3255721ef59815f88b3c79881d7890d45b05e5985508a1ca1324143c3e0b970d3ab8ff37b4cf66a0f94d39e431cd69a31f87679bd982bbc82e5108a28744158e93dd62e628006293ce50813ce4aae28b3ace463a0fd146e8454a522ae7ace8f5477e89acf872e0541e227f9a27c3727a5c9c6951181f251612100a17943c7df8121b5e6a77279e5a7a3db14ab0a5a2a8030bdab6a5a057caa6f88fa2bf9b747c2710a3fe8a4e95444677af31c37909454780ec4467d4d2f89741e1cb0f5bd0c067c68fb415da903830606807a2b18581cc38096730ab1d2a209d6d7bce009c8062260897961807e1c95fb4e198104594ae40f10beaf2b8e7a6383da6e4918c6e46b6d9d4f916ac514c379fbfbd81b2c54a74569725ea79095c4a16e88a7cc4985716e65b741591eb8f39feb6403ef562688402ebb4296ad2a0026e5a19b8d7dd5d02425b3544a3b2467e0ba2dde1cb628372eda1c80e3a6fc3eb0303604d5559590745d89fa5f29f54d19fec1451a86b1eb63ec2f9a983a0f1d75a5412173346ab66b4d961d8ed622efd6027e7019e724fffa1bc8db812b2de509b6d61ed2293f729e66b4087781e242af7b6866907dbf991f06f181818a039596905622e0b342ccae64f8261939dd7722f71c7ab6fb3959f4fad59fc469101e761b1d10793e206c720eaf76753d8169b53367a632885b5b860755a68cf1d902f92d31c900f0e7e2f03af7502e0ee73f8d8770b3db25f56e238a02a22ed7c0b6b1f3184d31bc103c0fc19d068061814375c301b0b1e7833f54a59a0b0f01b4cf71229f84a018f69f59ef59c6786a4c47215026cd02812e53910538bdceef075bcc3286c96c612ad5128e821753030107d72cf74ecbaa19aab29502cf1c1c4591d16f23d8131a1fee486a3529c35705ee7a6aefc28919de31be3a7058e4dd567ba2841cc1ef50214a1b83c50d982536a71d88bc153de53928e9048be376979b1f8f5879ff203679812f16f8f50767f106e3db246bff1d6e9b026d60cc3db7963354be8ec384b5fd9d6ceef0cdaffae30f97605e2e65cf5323d66660efe3736120ad44a88605aed1951f0476fe02391f17bf7a5b0212762c575baaa2ee3c51dc7957f16f5ed44bfd79fba5f018a001d787ff727b1f3dc62e45e4514db609324252bb81e4e37bd81f29721465d99999e2951efe252ef4c68794091dc0ae82119134eb40da2c1ecedb5a9c0ec06472d11db7c3b7879dee633a4b137897c06f02920e3d52888fe0f6a69c0d00aa9205df000bea3bf42524a4a9d9dfdb4d698a12706517ae411a2476f84f4770383493c94577bd0f4f1b5edc0e683ab9d76de14371b397a7014d4dee7a977a38dde417b5a046d3ec5caa734a4bddbeb39a9d04a2b0b965a1927af1b0de0f12de40c9aa8fc87b6e2d3c428870e95479d7e06b42c53671c3ea1c43c0b50122a862eb6e5f0b443882fbce176a168698058f96b460cc06c11880a8882971aaf43c3fbf8d1bf8a8845f2b233b80547db05f4aa4751664ec8496e5fc02828ab1b8c79a387d58e360c8f4473fb59c4765d1fe65e8c0cc41a32cf2a896ec0fabf6f9db5b4842dc2fb2c36636bfc0976edf17f47029b02f605de88be96931b777adb2e4c3f241f8826a1ac3796047fc5ba913392e08e787ab2d6949236fbd33a3657db64bda826207e2f914aed0b8ee490883192eb4a53140f58ab92e06393dcda065b1444a21aaa582569aae08847c057e9f044c0e58305c15271dc932955eafc78de3ead83db6ac4112e1e6d8ba54a24823a22a822ba2b419be1700fd7059d108c518b0000cec30600084d8ca1e41219f4d81587948cfaaecc6e066c67995adf86dcdd65a4288b44d08d95b6e19180ef60d250e21cc8ebe1d7d45ef2fe2783c70f4a97d79a1a736b22c119c8ae9c7b48da1d6dec9a172e861645d0d7be8a344e2b9d8853e4ed52e05eabaaf63b8771a67fbd5a0769d5016a961ab6ecff413da5b46ce1a98d4f66d1ef6e44d835a4a74c914ed9b0cb4d32feac814edfd6934f584a3a9952c99a25d2a41274a98483bd63c270020e20d407589b1155b2d1d1695759098ac63bbc6cc991bbc32efc235b4cf193216580a776a5fe419d8a76d4ee1b368bb7ce9c229f3265305af10f24eafa53fcc33d80ac1ced602a086f4cec993bbe5e34c26038e99e5e4639631dbc3952cb750a314aa0f345eecf1e6e071ba01bad84117c31e8578207b8f7985a84e45c494f698d2ac4c97ca2c8661189beeef6c823be1e8ed05555e1e26d5dff6821a0ba044091bd810df9accae5995eca391599969f3593c9265998a061d3683a1a0b69235ac41e7b61ad4705b270d69c06850e35943031a92dc3ec3196e27318319ca50063290e1f51ac318c4208630840109123080e10b5f9899a9d67f88804b4883c602e4b7c36b9bb867e60fee01f58309c1ec7c8c56257fc2618156a5a655497b2a2225ed0b112238050246928a57319254112919c9c031113d3072b98a9a292e172e576173e4d21e342ac4812557c763b41c903fdde056dd693920ed29882b6d68832f128ce4c67380ed298878e3fb0b9c79348f87661eaa65d8f7d5db438342681829e7093856a936b28c696cda71da1a97643788819c129391d9f8f0930132662fe56c25709ce2c99d70c8c747fbd26f2fc4c7afbd70e3f936aaac1bdd368f87b2fc1033ecab0c44bd73da1d4a5029e43c820c10b48fb5bb9b9011461d5774c99513c713cb17815d5a1f4470b48fed588a999efba3f58b57c9e831ed719e66bf88ec8ddd877c664ff3d1471fb3f10a9e117f9912279206e3cbd5a0c935448cb46da94c891d75e2b401c7a355d77396117a58971e3bccb7ed987dc1bed913bfcc477b6298145399421fbf89844a77504ffc8db76d7be47c44eef34574d889e3b713df07f6faf99d787b3c8ecd0711b638eab1fb88ab4be2f77441b27165a9651b9a4c1ce88ba9b8922b1e954ca15781184983942a6990d21daad320c55455e7521ae394e9c378f3e2b1757a1871505e5fe8313ed3617ca3bff844a78ff4165fe9a09364e9161fa74033f4947e86e6524bd9521775719489cce389f7513d717bb4278fc7937943c4d46fe7e89cd8e7fc3c8d47a827ecf145608f766ec78e591ff19b3d35777c22d2b48d33ecb98999b6c6b3f286f0d4c8147a8f8a029c428f05192f5c4a069a3b04cfa0dc76847a9227694f14e0bebd08eedbbc8fee9c2a626e9ff62491f00c7a4f9006a967653d350d6ea1869e9a4b376b844c196208996284caf7410447fc761ff598adc78ea3e2d88e7d238253455822f1dd63b0739f363471112abfb31867c388b130feb68f864ca17106f3220e78067d7b71c533e8e71136205788b40d3d4674d3d99ea41dc2c53cfd10728553f4469cda13bf85cea5361432bd857d11ddf497d14387a121e3cc2235f680dbc4842a451cc2a594060bb846bc9402f3a1e3980fc5cfb7c501baa941dbe38ba8c7ac8fd0eba38ddfce292e7a43c4947e6272d2e8a279108e06e9a4177d2ce9471fe93bf958a694bed1c729510a44e967116ac838270ac46f37221a118afd575b1c33ba640aadd42322a640e7e6173f9c537f1e2695736aec38e2b14ffbb28a363285fe85257db4a9b99229b4cf038878770011dffd4481982a221e3b164615a5d5a3baf4f5639129f4db473d0a740a6469c8147ace13d9233f42361a7c96674df495656ab32a3285fbb20c6a737858a2794203c7a35ea6cc9b640aa718bcd3644271c1d12b2f5832e604cd385d5260f182198711dc4c726d94ebce4fafa56b94fcdc5ad0dfa988e823857946c894988ae7646629cfe0beae21702c239caabb711e95731e97c7ca1c7aed98196a28735c39dbbd2687f08c4d85932ccf8b34e891b155b1aaecf03d0d11d38f0fdd883d8c3acce219db76cc4a9d4b9d2b77b6b74aaec8c815c9fa7c7bdc912bfdd6dd24ceddb6ed02b15d8f95395da87d4399d399405bb440db93c70243c894ed1feffd22bcb7f5410447f6be0fee5e11ed237b5360a6a26d954cd92e59db375648b76362a8d5ca9b06b74b2b6d1adc8e85a1623677bbdc8e21a9d4820d6ed7ec1bdc1eaadcedd816eaf64ca7c1ed590a2a5fc6746c689736b865f6e4e186c84e04a78a486576f3a20ecfd8be15a1ce77074dcf468c89c9ee3d86fbe727cf418749755fd7ddf30e645f3eb65732653bf717cf6e1cf7651fcdc9f3ee30a997ed1905b273c7919dbbe79c7d21e2b138b877f64526eec894ed2fdb33abba1ba7381d99b211a16ab7c1f79e8751471597c07874321e46ec2361967b18ffc5934c8d8ad654b9c66853c5c53e5f1bd58f316236ee48c6c167196314929d3d23fa8463bb77cfbe7436ba640a0efac2d9f8922952a6c8222611314559a6b05c39e1d8aec1a4341cdb35fba27db39e2fa6a835c99479f084835f6052dcfcc2de099b155d7225469cd87251a1509d6ed81b775a66eec49d1977aebc9c1e23cc8148aaf82f068c172827172d4ca51313d24814aaa08fd7719b876a193665f38cbe10c9b16dcb18689aa66994dea6b4b16855c0067180ec48b9824d7599de5c49551d571798731c538bc58a314656d4096764f5a38e5ce99c97ab65ba61994c3ab7b15683dc35558cdb10aa76288268d5d52c86f3f1baece37558c63536e8a1c9d334edbc02aa378654eb3e0ca751481aec681be3e2178fe11c69b0a7eba686bd735b984baeb04ba51a414caae7ccb93d7bdebc6ecf32f810656e93e0f65dcc1b62adf6bc644aff83ade46bd5ad3055c58265d8c02b9b8c196e4d7dc16d6c05b74b90c5cd0b57d8dced26c3e2b7231bced66a10b342b6875b111eeb0304f29ebfd07bec89b33ee83d96c8f428c0a94973e2d68a9b8c8949ad32b7db094c601eb6235bcb08a4bb5971fbdbaa3723b47846efe834d89f5454be1a129fe7f57abd6c3a0b5ce38281573a4ec9893e44e6410b8ccadeef2e300a7b9b9a6486db97b30ce324dc50464371fb5a9d76033225feeb946a898689d8c9122c8631c619dff231364be6d4fe4ded87f3f221006ebca4fc62293a46665d491b6c193c235e5e11635a766a03dc8d737b5ec1f527276daf45ced813c3a49ccfb029bbc8a8f9eed6626590b1f8796166945de058c64653f9bec0ec094757492083550a260593aaf6257e01095860a55eea97f0e1093e60a588840e93ea0e93021d26f5a28aca619fac91292631b2c8228b94c9250231609ca5b98a22c731c9906e39b1d07cd82d99f9b9008902490dbbd592b78f342a0e91f38b71c523de30aeb020c22bbde2141c302a2b0113cae085abc5556c1df08aa441d1fe81ac9134b246d6f0a7943435f4884be329f35773f667a65bf2481da265b3d5282c30bf45bbe7dd92d91066c6cb8f3a2f266a185fa37315c5c9715f1fe1ceb2478d43abf6786ea3a26621cce5f66c58b78730aadb23bba42338c5e43bd7e49c0d4d26a736ac266f1517bb7967a4319e534c6ea262f2cc9e7c364a247af45a44261f8d1ebd96d12c525b7cf4356c169c3456f19ae6f9b2b3cdb655ec565cc5d823bb345e18913b73c8723d34a60a084ed05f7cd2b899cacd404ec9aefdc507fa3e9f87be4776699d40d0d9967ef1c6f8b8482fc09f3fa251946a9927e36ccbbcac94c1c8327aee1cf719b1042969c0b0210d15156fb3215bcd86269433a3fcf4d5297edafea87f1a8dde2b4a33ab79780bc1788ccb228d82f1911a3cdd02d1f730e48d64cd61e648afc4743a4b9648560c1872a65161efc8273ecde369795a9e9694f9644c839e670fa5eacaeff49246796cbf9c20575e78167b6141947e6c7cc56be33733e20294722836e4c0cbd1b81c77d9aaa674c52a34c29f4c3efa4e1d16dd32f9e8f1bac86c7884c9a5d7c263fbe8dd62dbf2d856ab0a6d3aa186bd6a4ac35e891ebf30bbc80673a2efe4e21382d99366e32a35e7d45983e8cbee42fbecd6e705f497255e96c87030839d14c812895fe2b4e40d3629cc12c9a13dfec3fcb00776e7339c065bdae773cc7b7a60573be799ef23bd82c5219d22bbd5389eb862429d73e2c880c60b9de76b1b4969363dbda2a9f16aef2143e28a456abff3e311e567407170a5ecc1952d787b2dccc5aa7ddc47e2e524cd3645e7cce358d1a85087ca8d9fff9cf8ce06e5b32ccbb2ac651aec1f47aaa701499688e1ebf6682f9b6ec979bd405ff32d6c96659e6b9fdf0f0dcaec934de622c7518ec69651748abca4c9a4681c66a28993b3f49c430db955e3d18688f79955e5ece0e8b45e2c978a25d39ab939acb7401c959006eb776633e3394d6eb2435ed28e182420da86d94d6ee2128146912e7ff2edd06ea3af264a22922c67fa3865f2c5cb45cf6444d2a6a665d1e4932a936ab22346165964714d7a48a7c8c798a451279767b9fcb6a1dcec618e4b2a77d2882b1bf6c86e7693b631f97ab529a1573d248660c986a00d55e2ea216d1b568fc6ac85475cf6c4248de2ffe4cbd123bbf1ab46991c359f99603d32932fc624b2cb362691a39e217dfda341f99651354ac634ea397386a6dbad887386ab31b307b3619c9a55cca212e2c0f2f014ec851b959ffdd028296fd22cafc143e22393e2b6282a7659b3922b983de1c05ea21a864086550ab3722553e461529266c6249206756a9dd7921a4a1aa9c9f82a2342e52b1353d86344e00099983a65f684bd88cf41d607111cd83ff694fd734e15811d74907d59a208153a4861f694d92140c7ce294e653f7880b49906e533db320dce22481a1c708a7c0fe810aa142b9e81841ae52aa47166517364e7873a788a30ae26ed8c9bc21362cea87d3a788ac6c9baa584baa2dd204d833175ee689a2667a2a06559964d1ae9840f54acd48cb623def9fa3516b27004566a4ecdda2454cbddf7f239a6d9acc18695054d10483a382e60c10c0b8b2864dd0ccb8930a8587208d203ccd379a2250303eaa951411754d0861c785422089d3579b64ee1f2c86e18555f8c5109a961ccb9a21fbf2cbbf6792de7d80322dece765d7ce2766729b090e2c2dc2fec2e17c66f74b3a1123037f69097da4882c843863dfb68b4a18eeeaabc6b185551d5a838537365e2941163e20f2fd410bcfd1d2e237afd394194d91972fb2fb453312831d3341da44e09d5196ac83b4ac815954c1d41ed36c5dfa6bd89a0b2172f57c071a3de316e97935d7ba8070476cd661d966197a39d46e5e5b6cec371ddd6711e10bc792827613a624e60afc1565ca8549842245243ac26f2c763de55cdaac18e37c46ab020d10a9eb16a14739cf6c4b6716ebc2cbd35513319b9221f5f8d83e560368db2c213580d16a4573a8515b97dc5156a5bd160e734d88d23e78d5c91d186acd338584d4b9bc9c8942c60359ace651d2656052e864816ff107b66ab0923993abbe725b73f2ba9573ad55d19b7513c5a7a41c82caaa97de0116ff482e02cb2e8b01a3dfac6201c7063334e0d2be5410d2b0a9a45ba3ba8613c1f3b8ac398e35222ba9048723b5a1191dc252c63f45aba063bb36174c5f9c59c06fb1cd64aa25db3648b63194ccfc90dc8151a3a738c4246c45f0100cae51525644a47286ef7f932b8c687f2cd15ea2988996336c87c593adeb8b8f99cb3c3bc162dd3a46703743db65fe1caed2291877ee522970bfb15e476f461b68079e8171972fb2fe019fd30062162e107ae17191c999c9b1cfb43fac7d7c48eaae8f3ec1442a3503d76fb64b477cf02a183ec12a722620af4980259992e15bacc4cc5802e029aaaa75f4c490fc74c85ac0842004a81de298fc700dca5d7d281deb1015a8afb79d82fee9eed064b71bd47c9b75f92060d151510fc4da65a3f2dc5e58e84e99dc33ab2fc78ba8f790637a368706a932602309a8d7977701657db805c9129061b6c70b26686793f666e4b8c74e9e70e2a7dfc7490eea467aba3c1ee5887deeed33137cff621d1dfbe01b9d27db39d4ee5978ec6e1e8874483ed9943a53ab887bcf3d23a6ddb427a0fd5d12df49e6f030dca5467e74aa66481456edf800e24361bc6eb797b2e7c3dd4a371a0353ba7c72e2a590db61aec235da8d90cb6848b2996b185e08d8a4ac296e9468551a5b2e2c6f44aa7fa89dbe73629d478255fab1aec182cf455a778962a24703173884e409f0aa16d7f88ea62e4f623c056b02be26008110d9b34662cafd9f861971a9835f6993c17bed3f6c0aeb467c2051cabd42aaa3073fbef2ac8dcee2aac78dd4ec1e1863240315115bf05572ac61b5420d8363139b3ceb296d6580846a05bd3ba3beb6cfb22d0292e3f34183fc4467b4caebf215c22f05dc06bf1582378006a67d1e2cbf56ecccca551d8e3233044f7e34c625ecdfe30afec3e6d5ae3690d071ccbe03ad565be8c2362d81746999071eebcb37ff44f37b0394d189513a333a87e987d32636da7b5e1e49602c771ed8844833e6caebcbc42ec8e31dad6d14890e8f4babb9b3d02aebbd875c7cb9d6725eec482c0bc6ddbb66ddbb66d7d83f40c4dcdcae68695a392a979d16a3a886352a101aa1c345d86255b33392c9a53c3a2352f167dd9b0a80defb028efb0288b7aa49724075d0eba1c7439d038fa6d3b79a2d83c9eed73a53aa99945a6911f33d243b71db9a41f399629a66bcfb19d3edc6e6c96b5f74f14a551a104fbb36ff7d05f40bf6e9a8e927e86c233e2b96fc67c536653ddce3edf45a69e7b416c96c689e304ba845ba12153ba77ae447143f5a2646949a34116794c6218b52cdd324a1a2cfd821f72c681eb0f7b285d573b762e02a1bf88bd349bdbda4aa660f462581833cc62b3ce195f5922803224e786342e7692e9623cc5c5b01d2ef619bb5b4e38441d399c70d0130ecf8b0726c53242173a97b17eec23ac110d8258a02940add1856497de941f8609c161b8d1e690e7fbc26f7041185429edd1b3e1e282584aa818bdd8cc217abca3c7ec13b2c99f4eff9448bfd8e7d2156d7c5f891eaf7b7a14e2439217fd924ae1e8339a30f7f485dacd0d47d7215d5774c9b78f5ecb67c405a4d722e539d24da44f93231a6572369df469b974944f1bc6388cd3e7e75388ec7decf1636f64d83bf64f2f611388b77496965f88bd6dbc9dc7bed3e935424c7b3a61ff5cbe317b43892bff79a9e92fccae43974e2efbb6394affd81cdce575481756b293fbe8d30b427479e9dde042b687bcf3279736e4d9a0b4610cdb43b62701d349a4874b5c92bc9c242f8810fbd440e7914ca49f9048d2ce68c313d2342159939f18d120e933398cefc4c484a73c8171f680b84083dc9d630954d1fb5c7c9675e7648ec9a735fde49ce99bfdb9fc4e9f5ff861ff9c6c28e5977d0a513acd3d8927f3269fbca2c139852859db7d149b4566d8c771f6a7c43ef985a7ebf0ec4bc2e6f08210bddf737efd0ebcd444f9cf5964179e2e43d2dc70f453bb606ec7db75a2c3f8e695f1854adcdcd175f8c2979a3bba117265a648d6c6fad98f5e16e2397b9e24bc1b26576485c83cb5d90b740a9fbd911dddb4e69c93e3da75f39b14b525e508e78e6ea46cd4ec384cba44ae46ae6c0d62cf02a492e9db4e229d904a2612e905b7c3e9703ad8c6c92ed660b466c41ab546471a15314e87d3e174402cec9bac06a7a897bba39bf8d38e784f2e184643aed433d7bbd1a87674435b582bb626540c0355c163629f5fdf1faa945d8775ece2dbce9e055abc857d892e581284124da9a614a451a7f34bab4691fec9b806369a2208f3c09fcb651fe8460d274504b3a08b2da1968ed9d4cfb9e66477227da38e5372639fd18d775928a68ed3190dd16a4636a3d51685d1ea72cb74b9d2e27cf0825858106a4985712f9ec12d8e3dd370ae942c9d50e5e3295651e38743fb665fb4b614f0a440ac0d0a35723adb13aafc9c2d7e8b6fdec81456ce6c192153f8480d695c0e47525cfee43147adcbe7e88bd1680483830103c6c7f7e38d50629ce340a0175f6946a6b4f7060fdd3c5fe05062bcf37e685477be8b5cf1ceff616b42ed1bd2e8340e3b0ecf357bc2a17dfb86d2208f6e26caf99344ba39056990bb7feac660fcd843538c71329aadd98a71792ec677138a09c5740e792db24ed3a7a52b9606617ca78fd6d8a0d6dc908669d5a87014840e3181ce7d471ffde42506b1463792f58205627972b6903cc52b6404bd4053805a8d3a718174404a404b7a85cbe0021de18370222671a6157c29716a08624594af34837349dfac16ea648e3d94dc4e17c36da1898dacf8480d6611836229b288b93c6235eae4f247397225a692d49c815f3afc510b9359773f7806bf3fd014a016682ee95431717a2df3a68feffc76c46b522969901f3fcfe934c876c4b2dc0ef68d8c34c8b38b6990cf2d6990b946d8b774661f4891077ee99d4ca3da0d97dffde01af1ee346aa2b02c3b29fa30ba611ef8fcd14aae6cd68868c3be21e9f268353bce8806fb18861d71c230d3cae8c686a7ef88cf8806f9f2bbc073e68db8c011a78fafe7b5bcf35cf81a218f90a056831ca9508d38e2e43c5bf5f21f3bab0b3b87fb19dd700b4b3a8b94915b72f9a52fec4c70f9275f48afc917ce4bfa42fad11bfac2792be81b0591dc1fd5961ab1640a5f2aa162d7669f3e9f78f9d817efc8c8e83552c21f4dc1cca39ccb23d7e55192cb9f4cd21ac666f4be91914e613bbae1410d47372cfb13399df8f5e594342a5ce2ca67717e22a79371a3a66c8d73680d0dc2e7b9b52ab78424534c2f4991519221973f32326a8d8e5c3e57a1841aa8525c7b2d369541ac0b34ea7403bbf3d89db6e32ce4020512ec86201688d5289eaa38182157b49f8478346e0e36375e4ee7f279b6e611be11fc0b702ab57dcc299382581f688a06d9030a41accbe7741a158e6e9434ea971f732a77e71ddda05c1b7458298e6b3432bfb9833aaf7d9cc9d98259aae3da11ab411edd34c8a31b173ab361a2e665800c0ec03007c89094b2fc3cf2a72d649dbb6df24a34aa6fbff4773b0ee9c722bda2809a18d328a6420a321b27bb0d12884674673950a8f421b332ee4a34d89c7d89aa069b776e04b1e53871e78f762e96a5c1e61d25e8999b526a32fd32d68fc7bc18a98baccc0731b22c465721bbe93fe9fc4e45e5199affeddf46957753f9936ef68dd4ddb22fad896acc62f9a15177919d7491ffa151990e52f7298d3a48b7b9ce39b1e06bd9e71bc5576ef1d2635d582e8b4ba35845cb6c48e34acb381b15b89f9333da9e1d6577f76c19e5118e7f39c618555a3857dc9861fc468554c6fc9879e88845129888b90ab89c04266a2e079224db4396b194313236aa46d07f2a5ec69c9addedb2c894784a6bcd9a45ae441a9a2c8f96b6a70b2144e6296a4fad5921f4f4c69cba5da6a2092f48b186a61d0888744bd3cb291ad7362469dd97a48b591a5b0de2e5789e115f05bb90e80e79e788d65a7b820b938f383911e73f62e50dc732421953262c14a38dbc9136582808cfc05ed8a367c383856cc4e11958b422a741ecd1469c06310c0d58cc89387225a6b07bb9528f3dea740ab063a0636f15a60306b17320d161525d77d0717420fb42248a5ee416b2314983d8eb37535c77dd270ffaba7e765e0d62f2f545c8575b445f45a6600f7dda658f8899aa36ee803e5fab640a76ef639e1182b7fba40e18c58c1deb1430881ddbb07bacb46910c322768c5a6c0b4b6e86829a92ac08133bd20c0baee7c03262c3a4ba234c2afb6447aed1d1884422b75023119dabd1902bd5f4cdf350a5a52aeb980635d0b1771f76cefb4ea2cf475f5f4428f46a7d10c1413aa77c7c1e7a11de49d607bdf710bd771fa17fbcef247a3d4ceaf3511a7ab52ffd903d895eeae945a7de43f685defb4be89f2e143aa5d42e7144c8b2c814adbf93e82af53b892c0f1cf52490084ef549f6e5a55e3b4c8af450856459a674b5eda9ad9d80ee43c89438845e8f7d5ce8834955d1e947451f57bf38531fb22f2f512553b4232153b457ab69df4104a7e889e054a83e8c3355a5d9c41a9b15b509630d7dfdfa62a307350cb9645cf68400c0fdd8906b47bcf4a21f8da226f4ddf99cc9e7bdfb422f1b72c5b8c917865cb525f6a171c90de7dd80c02eeddab38172d043aa904e6dd50d7d21158cafee6c6ea8a1877527f4baa4c136d430140a8566ac47a64109d4eadda821ef46adb59444bc252bfaa1a4d2875d4b755f5c63f4edc535d8503d310f45e7364f02a31ba5531b3d214a0f2569100026ff42a52f89784dace84783ed5135d81d13a4d7b5d6102ea1ba610f7a4387718fca13037a74c1813efae86db66b10043aca4bec5119aaa3864a737b74ab6b718df620b9a487584d77c4895abf3df45c71854706f4956ef2c5db2274479e3bfac735e847a3475ee1d4e82dbc9691e604cf68199ea153abcd415fbfd9907e7be90bbb0b3a47bfad5a50cb6659e4617cf3665fd837dc3c4a6e7fb4bdba181f0fec862157c4094751d0ff5cd6c1f8a68eeeca7871960eb94248443f76548de2ae359a01afd9d0643259db895ca328ba47417a34a4898c8ad4ae758b9073c32ec9d6a5a1869da7fda0ef5a946e569369b0673a01fdd074066d46472a99e9ecd71df9ba56c7ac997ea26b6932dc1de914ae9e8b5a140a555a2ba5f4b6d6cff3d0a7a36fbbd60d849c4e4f3686bc96b8da4ebf01b9223a3d1272e5f41845a34a9701c0a597c1354e42944bbb5ee91979e923fb506f220f7d93d3d346914ecf5c6374badd136bb687b1c623e3baa0d54df4a1ee441e506c5825c8cedc0ed9b035194d06f45310f4a1876c8e794493695468c80d75a3d148d491bc169393bc16d2499e8dbea373a4ae3d1ba01bb25d2b8826b3922b7227fac01279e8d71836ac30ecea36d7b5a48a25fac0ccc3e7b57a52f561d617b15228068c3b5b21988bf29e11b2b3657a8162e7911cd41d40f0f4162d1e532d4e2d5c5c746af14eb58b1a12b5b0cc06a830b7f43e0925a1be4d8f926fd7aa3664294a368441c2ada741434505047f93a9653a87955a8d3a31d910a6f431cf38b1b3d560b5f3c8170abd1a1cd9900b07359c2d08843a250af5431ff38c6a67ab87166ae7914fc8158692dc7ed7b578cc1b6a32b1a6519e37fdf6b81d5940837d1a5d4ed7ea701aecb06b75477450c3d96add7964d4225b22c2542d2e61051c2ba032ab083b97594458728bf0e3725c254665304b19bbce23e3623132772c0d6a9aa6fd870534a85966ea12638c2ef13fb8709ded6f87065db487524aa979ba047503ef5d1ad5f173613966492ef1d2b2b8b8fce082861a326bb2fce032df8f80118da24751424ad2dde5c6614bb5f0e5320bc9b04fc8b43f744a93a086f4a2a20ae3867061e8d85986908f88e7149dbf1ef3924ea6ecb2d0410f3121da392c742cf41c58e81de98ca7ee7c397ef41ec618637cc54f7435f87a45fb62666ca2a62bbea22b22119dbff812a9c22ebee67c74c5970becf89db8e489c9ab51fc3af94ef3f3ce9b7c42b624a46ff4b5151dfaa2cc17633e99a7342eaae4cacf50c3a892b913ff78df31272e593523a32a6583419d99dc56545254759ce9c9368c3451d55ab47745978caee7dcb8904425913932a3e8b85e9c04c96f9b649850a8261201a53934b7df1971014e2287b07cd123efc9b0b3b4b4d94e7945bb94431a5c79ac1c7269135756da58b95a491b3944dac8d59c2142cd647846674e642aca32675a998a73e46ace304e7f081c516aaa28f92c9d73e53720573ac76a988d4cc9321cac087683d96434f34e8bd5501bfac26aa8aa26c88683b58c02bbb958ab75a49264304b1bc673bf62bcfd6a97ab91f05fd1f6abdbd557a8f15c2379b978c6495ecb54990c4c8acb3eecd339c96bd8ce95d97160cf4e445a1cd9356bb19757ceed21b0964ce98d08956f832f2605cfe879962d9982dd60ac68c3a9c26e6ad8aead0c95761a0b3650e33ae20aafdbd74012669d86b8f3d25ed958d3608c354b6a8dfcaa511293524a1b57b1a6c1200d76ac89c7e4ac611b65e24c4d7ce22deb6479844947055ca0311e61bab3b339ccc971cc31d2bf5133e467a6b999fea198a63df62ccbdee781dd1ef3c6a952a95435a9ec5da6d96aa914b1a966b3d86116982a1c69cac64083d222b7df8198993b6bba89aec848551933e3d1124d6d026b0c918e4fbb063b9e3d9da595d6063b7a9e471bfc2aed988b5e4b77b7af459efb5ad89ee4e30db11beff14caf029cc2e2e631d188343a7be6b508c12c4aa7b4a9a565516a02100e4b6b3c43d97fe33d6793090999c2d91909b6b5415327a06bb3326d8a90743d671bc66bdf4c50b58e5e7ce44cfe0a4f480c639e93336c46d93899d4dec065671921c91533693a01bd71a1869366469f07cfe8ef98359baa92988666d6442bed8c823fad8a6d14185f4e9a06bb463e9c34cf216d9c349e1999e6c79a0669bc2066140dca1492ad61fea4e9cb511a4a328995d25a4d266dc67a4e6cf86373d26ce02d42c5153a5a0ab415d41d4f1635f486dc0ec48f26fad04c78ab1db9121ad2297d7e48c37ad2ceed8786f48aca0ea08cdb10c5146d484f489809eb202157ae003b1daf76e12707650365642a3b8c70704638239c11ce0807675453e3393906ca4f4ea8822e693faecf0ba42259cc62241b24b806dbace4cae934c476be44c0a4b20ed9c81598102bd4baa7b86dcf1e9f65e7eccba95f4ed1f2208253a6972a53284cea2ad1f2c0d1ddbb675f38ac280f55b014a740ef1b4ffc21644ab3e58123fb762238e5625f58644ac3a49ee19c7058221c10720ac29e62aa592a55ea146dd451a96eb354aabb5995f7ce02dbb3e3e0fe792112ed4b4c6de75814e094674f4574cf9ed9d33b3b6b644a4f282a1fe5fbe4749d8b16a6330a8a15d51393936866762f484d837dcf7a333285642357482a99d2a7b456928a644352916c48aadb27d99054db76726143f0261b9ae2a764c32ab2a11645b59d36c464d2b490d8c13e642ad63ac03592a8373ebe8fc47c410b78d250a1ced35391ea865672654469ad26d343ab70840393c2b41b2d08c6c5b84da18693664641d3a8b0c3612f88783e0d315dd74855a2c3f1641a1cd5d05a43a72236eedb39c59aab49e30304dbbbbf74f6d4bd6cefec66bb1d9942e474045f0dac78d2308f747474582c9668869e5413130913cda06166d6ccd56471889ed89056131b56932934e3bae045430d3f39ab908b7b5f7b62645b644330546d149f20de87746091db37a27d535524767007683a9c50e88349856e4238260eadaa1a3a1d99d2f5f5551d9ea1d9d05bbde8159386268a59137a5c3309f514756c60659a3471d2f43b9bce2676ae0d47ae64973b72e5332f6d48addcf9e4c47ac38c0cb7cf9f1cd7a409b599b96a54e871795c565872fb1e2493268a39c49304bb9951cc9a4993c5210df63155f6cac8c02bd12653c3ed0c0eb735263e391dcea4c93e397747a6cc743898b539531bed098d469bd176640a5b39d320ce0d3d2e6d66dbb2504339e3715d6963cb197b8a4348ae6e892c638014d2c6e6dab84c283b806288c422184aa3e8c31d2e4f1bf24313dbc7f94675186f6ab0a345f9c2c9c518b96d8b5126f2c091049107964a20891186dab6f96c1a2c62c26cdf34181f4ddc46e0196dedf943895f1bf98c93bb260669b065106a68aa8935d22648b70b79136d6c58fd29622b3ef171545d29985064186d82f4ca2cd2293d8d2cb961b491360db614ea8c35364bae2cd2603f08cff94132494d92115d4839694417efae51266f93ce6024b63395489d4e126f94b111498312498b7f9e8525dba36f44024434c1f877e69fac0a89f4175779615f3ca3cc29269b9dca953e9b4c1f9d44b77f564777492d3eb2e1bc9f7f3f7d9d1b2a8aed212fa9c5b78f8d1cdae725d91c2dbe873aba5bfa675d743af554fac986f1c795d2647394da0b82f47961b3976c0eedd8959e10d8d56cfcdce4d97762b27152924ce73876279e0d5faef7ec9397f67e30483ccf3bf94867cfbb4cf4e1e4e4d9354dd34eb8abd9134d7b946191da277ff2b1b424ddfb4c4e1e65488f243839e9d26b21d958fb897be279f345fc71c31e329e5e702d3ed33f1fdf169fe73a7cf6a5efc359fa795efa3e254a840eb73a7c9e8fca9496e74a1f6db0c56d8b16a6b367c3f41667e9cfeda7c377748b6fbb7411ea3839b1b1462497cb3eac85497edee51792b22c96ae699a6d61927c62431d9f0f16c25c0c7bf6c50bca6c0f0db68be61693d36814e97d8e639417ffe8bb74f118973684f191778df33e4dfbf782cb3af682285dbbf7e9b89f9377f916a66b270fe9fd9cd850c73d79d6856f0b6bd22eff094f1e3a9775f2cb4a972797d9bd2462dc0ec0dc937ba4fbf97c4eac7779efd2fb3e2f7de1c9b7635e045cbc74cc7389d7c5b52ff4feb19d1baaf7ecf59c16bd09c4fb29b928591da4fb614f0817ffd81c2e5eb239be6b3a48a1677590ae0b3bbf20b01b9fe5db1e52b3610c3b61d81ef2bef8e9d193c08b934e7a91659284794184daa5772e2369cf2e5fd8d04796d9e9d9f02451507e3a4b933e948fbe138a0de325995ccad339d2e9f48d7a68b04db09f9c8bdae567f230decfa78b16a7de4de73e975f462addfba2f7c54be50abdf4cea6bb30bd850dabc974930d7590aec9b74babd91c263fb1279f8f35934f9e3d797269b221e97e9e796ff171839ef72c73e1c286f47a362c7d7b8b941636fc7c3b8b2c7da18e5bfae733699acd2183c07e72a265972737c9a1fd24ebb0a854c61b6af71e962ebaf7e538791b71c3ed25ab83744f1eea205df9ed218c76f2999c459a7cd8491fdfd137afe80b7fb8db435fa8e36e57912b33c551d0bc202b849ebd254829224960df3e158ebbc7952ff1722a5fa8f2a14a0f16c6fb781ff6b4ef37fbfa3216af4a0ff49be78b5493510641274f694d4b344c36019083253397a9b82c05164cb81c08e4ea1822d9411e4fe3306b077d22788ac866431f36773bc7752afcf8cc82fc68a3cc7768b055dcc3a8e23eeddbe7798c013b012a9d00eefd1d5438edabac02825668ddfe0eaa981e22c7a0d795f54cde572ba9f68c0a67a3aa6752180395a58889b9e065294260e42a892aaec14410da6d10b8e0f3a1360477c0d107ee1b90b1c606dd39f6361b1ac1a3eb112fc71dbb7793bbf0bc8f1b3479022a76efec71666a9427c4a7224b2196d8f450ef1ce66198f72b596240c8bb435ecf32cf98e7c229fa42d3ed7480d7db4eef42f4905eb3747bb40d46295416627b0e36f93ca7719dc6d9309a7c3ac0af933aa8a4b325912c5fee479df3dc73f0ba322e579183296e0e8a709fcfba11f7a3b60ae8a3af2ff783bbcb2f806bd04b06b006fa26fa8478ce659de8eb6fdf3dec3de2edbe5dfb72749fe738eedbbb8fce73f31c476783d18a0afa703d78f1f401cd0d4db2aaf4c075e57b6099b9f228bd125352e5926e689a5c092a183912d46bf22995466d0bb892a7b8f2288d0ab1779737710dae91033bf790cef9eed817c63b314f08ee939bdc59dac3ba6f92b46fda8e366ace19affc2c11613259b5103972e478a6cc4ed49059f12e2e587e90974c2b96592c53e9c74b2870ac52752073f9f2cecd2edb26beae496ce7b6ce8c3a32ea50934ecb1885d88a4e608e54b81d5bad231849c8edcf39fff14ad7cc3b6705bb8b3dbe381928a43b674ba64c250db604c27b6ca4b6759ba7376bc02b5149a7b40e6ed491a961ecc9fd0961301de0958f494057daf89a37864b5c6eb06da88b6315e6152c74331d6e1679900fbf9b5df461dff6ac3e7c8b9b853c28d24319370be3499f47c657d0c7b3221bb2d1769745d62f8c01a2f57ef2ddf6f8f190e75ac6fc6ebcd4e1c66bf6ca9961678fa57b65a6989b4a3896119b49b17bb033b14c02f159d75e1093669c7941c4e63a4e1f441fe2e5739eed597f3bd745aeb123de24e8edf3d432ec7e1c68e397de386d486d67c1065b40377e932a0b70c171840e256266a25815611dc9f992a835646f76517b12901192c0daa0fc959eb67248ed1b665c07e1e36607bf4d2ba3c124e20da310f53e5e93546691c5e5ba2efad04c741eafc573a32f37a784c165cf468c3bed8e18d36b99d73ef046dfd0c7d5be699fbcf34369d308ea94f371b2a671c697729de78b1a273b0d08ec8b9e674b3071b373a19cc3cdde60a3bc207ada6810501bce478d7a42f467f6b5112ee6d970c09d76870364ecf9e940df24b23bdf12a50e28885c71027b1319965da650b046935c7182be09ed54b34ed0541319cb140c7b1689846a835386ba06a7ed2a43d3b20b8d91fea469171a23b3270ac49004e5321562c0b9a1504b2f64e756b72d140a85425ffdf6559391c918948c2149cdd5e172126292d08415f7bb9c84266c2e2b0b99fbcb2c392cb1a20e1181aa899d2488e0c80d45ae46852123b7a711a9821b86928c5ca1d5b6854e87dc7e901ad4707bd13cd128d4f9baf05a5077a149c0f9b6f05a1270179a1eced7e4b5f470171a049c6fc96b41c05d801ce07c4fbc9603dc058801ced7c46b31c05d80a89c2fc96b51b90b1017d7e0cbc3f98ebc161eee0224876bf02dc0f98abc9602dc05080ed7e0bbc377b80b9016d7e02be37cabd722e32e40585c832f78be20af05bc0b909fefc76bf95d80d8700dbe333ee32e400870be9dd74280bb00a9e11a7c0170be9cd70280bb00a1e11a7c0770be9bd73280bb0049395f8fd792721720325c83af00ce977a2d02b80b1015d7e01b8007e02e50ec700dbed7050a1daec1575ede050aecd8a7086a385b4a3eaf063f49688ae870f65a74d0e1f4fc69e9d7350a040aeb29f4d039257a88724fa3f32dfd443a8790887428257d3c655cfea82472e9d4ba895c7d0a21f9422e912b14da5ced44fd15e984429b0d453bdb452e3beb89da90d23a24043514b942ae4a236972402b1b3db0bb9dda2a81ed352442126285acc8257a750240ab57a38c346ab3424e6f910b0444e84fdf98a8218ed2ed9486a80e52dda1b45693e90741159516509146519b63f41212b754b2a10e1d77749a8411c4dc50e46a142741044b6e5f8444a4331a6da552a9542a954a4aecd8acc9a90ed2a5070dc9411f32791c86d8d86ca8dbea4dad37f5a6ded06a03343b1a2a72bbae6ebfd2c815110e8d0847e4e29d1b865c53d0ac685634456886d01469a26e34369fd7e58a8271a159354d0d4d0d8d8de845b3ea15918b26481456d42158fc88c3901f52b0a146d3348dc686a608cd9006f96a5e8b0b4d109a9a46c1d0d4d04421720111af0bcda4a979515aabc9f483a00a0d1a17abd9b66ddb3e391e299959e34fcec7f54162f2c8787e786454d81594d66a32bd06ab51a11153c3ae55830a13ce8d52ac0675481ca87821b94cc56b8a8bd5c815ed0719acb8a1264305198eacc4edb58582c4683a2f250e58dd68467a2586e288a104b743ae2766421bad378d0a432e238d9229b87d6da6bb1872c99553284948a73b7da15aadd566b41ff2a68a5c8dd26914a5ef8b908c548d3ad1f30d5da4043444b4531b3c854e210b44df9046c54bc9ed1bda68b65dfbd1a8ed03818a504aa9e845a91521d164341a4d0b420da5ea36ead5a8782ffdd194be144027b544017452a7d3635e0b35c21123afabc9684e700dfa3e2704bda1d3f704b59e262382facb2c1a5c7143acc6c5f610ab910141ad093519abfdd83e9768321ba6aad9b61a89846a85ab51b747dfd05da0c8097d2e50b84060c3058a2bba46857587292d43cdbca285da584928182b5ca038d2a8f072d1058a23564081130323b7007504495cb0c4054a503aae285e0b3d8ad7b2591728ae7809e7a5db665986b68da29cbc0eb940d1d2645c784268596491c54ea3ea9246851e99504cf461c88b6b308e5ce157b7f399a25113a7d3f1549fd6c7c887e525b95e8e87a4dfb5ba23328dea3c9fc17edc95d0922b8ee07c3e1f8a028b3129b94d73bb2792db54bc8adc1997a978c5dc52e9a673d2f33ce412b9a8c631a124c6ce925b1a59fa8515895bcf2694766ea8db4d3801782d27313c17be279b0ddd84458e3e2d005e4b6763adaf064b7fe1b9f0adf6856743fb0ed6a68e4706abc182f40aa7bad2971e6235d4ba5a4aa57fbed2bb96915b7a5b714b8f71e4960e234e714b47b9877e3b0700af657bb1955e3ac720b754d36029c667923afd271a25672e5fd4e742f304cd09cd8f4649145cbe09f85c687ecc98ccd0c4344a9ee0f2ede173a189a19121d1c82c699434c1e58b80cf05c8121ad5c873a151296994fc71f91ee07301a26447e4b900d949d2285982cbd7009f0b90243a21cf05880e924649125cbe2a9f0b1024affabaa251d289cb9787cf05c8152e90cb8a464999cbb7009f0b102b723e9e0b901c20471a254770f9eef0b9003982e3792e4070a6689414c1e52be373013245ab6b1969946ce2f2053f172046581cab48a364cce5fbcf0548919bed6648a364082edf199f0b9021361e9b208d9220b87c09f0b90009b2a2ab281a2599b87c01f0b90089a246f35c80d43cd128a9ba7c07f0b900798226a301f2a3519dc5e59bf2b900f93183792e406680c434aae770f90ae0730112034466029159d2a896c3e51b80cf058a254054d27301a252d2a85e7295ecf44e9246351697affc5ca048a2e302850ecfe0eb02059246751c2e5fec7381e2c535a20b142f9ec1f7c5b500f04ec5e9985c3507000f399cdb2a99b2a236f546c535c12ba591c9498d3a797f5bc2a938261805fabc8190db41220f36587130e015c7025e9980562b43963ec451fb179f2a3983441fb657e4a13f835cccb4aab91d8e60703b468cdbbda20f9f9cc843df6343938d26335a8d6470c3ae0c37b72f8203833b9f488948479444f412217135289203a7e44416984c80d5345189f0f978dd39f636fe80315eb2e16fe97a37a1d4844dc08b7638e88270c0a89316173da4a710ebf30ab15e2116ebf699b93e6cd52834da425b44a2b9e5872e61e42e6173e9b9413a79227169cf38e767899a1b46d785f1ca4c774e4e62f55a4e46a34bcf79ba9369a38d4e3e6db8d7e7f5798d4c2d4c2773c6e78e38e32380fc42af5092eff3f911600601241680cbcfb17972f2b07e9e9327d8e91780cfcfeb8749ece4e4dcc91780cf4f349b6933577335874c9bd107f4198d48a451c8bb3112793746a1d1c9e8c4a3f2c4bcdf792dd4823ece1b7d3444005a66da5eb9ec292010c86b81715007fa46d74e4e4e4e4e4e0ec36b39899b4eddb6d77a837eab1b57b7d1177640a0bc7eddb76f00ec496ad3a850587768770ed47d03f8a85c71f1ae2e2c734ae92d282d7da7f4d0047ee3149ac52497f4f1881c66d2b53e1f0facbbcd3363ea4db5744e554be764077ef16a19d75cf4eabb3278cef34df09b2acfc3a98a69b0bb968989c949d6e423fb4b2add7af6247052ebe9b9cf677af799dcfbb4cf8ff4e8c1588d46a3d16834aa377d9f9b90be798e93a85cc510d5d5fe7a93c967baf69d04e098d71280639e005adc1abad5736b7d8b6b3f3929e4ea1a3479e819c1b8896bb0c9e85d2bc60960351bd201d8b0de183fb1614db1a1e9c6989e8d5f8d14e326e75c782d2622af029c3add641443fbe8303e8e5ca35101783d7dbd89bd9618ff3a3754d361bc9e2b99ce9e00ec8dbe3b90b887f1e849a03b8c0fc687ad6e985e6df48480f1612b6c483d4bc3886177c4abd50fab31612bef0600aa0d276df02ccd305a50724daf5948f9a1f944f109f2597d867c7e7c66e487e613c5a7a6c16d0ef547a342ed30def7cc342a8776d3fb1e19ae11e37d8f135ca37e07e830ae7d31be78a72784e9d5f47aaebb5acfde8d7ad3593ac6c7577b77c4f475385d4e7745a7f44dbe0e4983af2e89663b2b3a6a3c3f21cc75a2728394742b08fe2613f7b69d7e9a8bbe7e1a95432d3dd46466c7959edbac8c06a98c52ce0ff38c5f4fbca12fa41b5683d99625ab22b7f405dc520f3bdc928c1085744be70ebb5bea975a4a3656665d4da69aea4de0c886570165d752b9b485450db7178aab58d5dcfe1601be5d83f4310e72a5720feb8d5c8929efd548afb468d4e86dc53d3dac476e9d42aeb4b0a0954cb1ab936599e27926e71846e8c57d3aae3de8a5ff782d30fef15aa8ad1cb561ab2ead1b85038c87be50e87543ae06bb445f3f062337ec5a8d622ac650642552318699d0652ac4b0240741b680e4dacb556c8175eb394e55ae820b4f5cfad2398ef35a366b776e6f70a8a136faba230d9a7c7c47485857dc7456705cec606ec8f343a745e852cfa52b5dab9e2af124502dd5a1962ed9766a0ead47bcda4c833b35477d8f784d1e86c2ee737602787796fe7cce09e00bc0ec62bcfb02208000f0fcbcfb7cde678c7fb419ed096af2b0be3bb7bda1c66b63be9ea54dbe1d51e7fb9cd6180faec2a8b4ecf3a64d903a85666404010000f313002028140c888482e17848a2e921123f14000d99b4527a541887410e29640c21060000080000000020080200a4a2ec761fbd76f04c60e78dc1a2593f6e64c2d5ce2aca8313368838663336109de4c3af91fc5d135954b7294119b881397df3b8361b3a50e0e18d146351acea78e7fe998465e6dc30b4955c50a18bee3f1e0f57b404002d75040782927fba2491757794eac3a6b393dd5363a1a2ab729ce9895edaf57818ac17f6cc687095cbad764fa16940ba7b6791ceca9004b8e9c85d6461773e3964629dca7942bc06ccc4460b8a25093fe4382fb518671136a8686b6d10b01604fb291b30b7ea1c203a7ed61ad48705fba83460619e3448213c5b873d863fe942b3a365256a4d10232733e62ad6e843df8cd89ef871da74584960b43b6a2e1f4105313ac41a262be7789d4bb1500a84b372a55dddd88f9c25a3ab4661a2edf07be1e907f8622e9984bb184dae99847597df5a6408ee5933bc9e63cd9145c2e67607474aa8d920d158ef00cbc273f211c3c0c89a0ef4e1b5ac01a3c809d5d4552496a9ae8e40d46b92320dc584f47dd75028c0cbd813536f4edf9708a5d31128c1b8e09637640602d1b903ca8e6a1aceadc7ac3ec917d3858e875bf16808b3d79c6cfc9503cdbfc0f1d83a62f3c5efaee99dceb8525868015fc9d9d1613047ef6b52d375655e55f602a38fe69837551b3659893708753f8680d8325960c873f3ec25cdad1dbd7949995d5b1ccc1f9088f5328a5785e818835edab9d451fafe54d7934dba2a36f38d06ac3a67f3f4150f7d931de666aabb59654614a8bb5920cee1ad812b1ec034eaba1b0671184ce48d48d810d576c019d7df56dd0bc8db0992a8e7f9facd2846ec43bb9ed77417ba25a271c9593c035c80777f1cdf8f2c89205219e97ed0f21a5d1eb8333365a535aecfc4a49c3afe381ee4a212f90d5cf030c2652d1ce925bf297844a77011a0f5f6bd37a9b46a1465b4d49d43d5c7a32e5895e31a3800b013917c07288465c930d153e4bc3649c9797f45788ad9b47b956810d8fe80cb8dabe1a28cd7b347de5bb273bf471da1099c1d5bfa0ab05027f557f464523e084541c62b22877f9a8f573591ae3bf526d538634a4d81ad81f95ecbb8a4c827fa247add3a1095e0041e8aca3c485312bd7de32fb865c77300b7340034dbddd341fa2ecc91def376b27ab0bd07ca6cbb4004a48bb8e195a2af342ca30a2a32e5339227f45f22fedbac3909b79161bedfbf6ec8f1989a73173b4c8a3f54e429693a6e62b2525c28fb0677583209f6d828bce79655ac66dbc5d59b9e59eb135606007f3002c95d107d81ca8aa0f1bb9145d22a9e34e27106fa842333cfb7c02fcaff116fd0c9e0d7ebbe3e707ec976c240eebe83573dcbc8125e064fed777e9d9b298a627aedc7e41f3ab8bb06649e977eab08c3a9a7dba0cc8f66bfa42b760d618a1cc1fc5a952ce76bd3cf5c6eac6ec0e4d69a23e545643cb23086c183be682e7a2c4f1b55167c2d2681db182c2380e1c9a9a4a1a8c8dd2c2ade69b72527c1cf923072433974707faf410e8dfa19f698b82111d08291e8379767615e9cf995c182559df8ce34ed8e89e041850b6ce25b13d39c20fb22d1463170ce33399066be16e6e1eb736fd7333621ed4b3ed6e7325b75bc56a196feeb717274256e5fa531e15289f3acb9a95d230414efb0fd17d8f5ceb217218e34356cd2b7f12d376098899cb143bf7fdf9da381f8c38247e3f5255616448735247e8fe386a04f451f766e209ee647c6e31241009ceda45599b56ae76641ea882c48f3d02384651f21f01a3fee33a9caf6765b37f1f886100496e942826d1f4477e646fbce9383851bdcf5c845f2d6b06e7ef014544dbeb9eb34b6c9bde71decf4bed5056970e0c48ec413db72ffd87700e9eb34f408d088b62cf26e2dc51c68314f086c55c4aedcb47a88ad263273340f67f2cd814de119b3609ee02ab1df38020fc53af7934a24422b79c26a4f004640cc12b52207d159d4ebe5340b89e6336d4788459b16d9e0788b4f72922c01e047f7f5b8b9d6da8f787e42b50a642ba80ce91b9f2185339e289db3c0e35d1c9fddb316986334fe20e4245912a651e13e5decee22f65fc3b3c043ee36bc8e4957ed4ae6f1e7ead07823b7701f3eafe7e25db0e27de551e08f538b489425decd121165a74a736793d5561d19935bba1ade8ef6b6f230eda93d47cd2d01e7f79fed24ffed8a689418e6141ce81d64d4b8784ac2985a49ba245bf3ddfe07813e767801f7458cb0a16dab6600f1da1a2733069a679a11bae90a366c2e1725b0f3ebc5c86bf8af6be5fc0df2e6d1110cd2cfbecb3fc7c56a48a09b3b73c7a62d330ba2a093281185045c6a9f474b21c4b69674953b837440c45e3ff53360903801ba233907b0db6e6e5e6987c8d60f15e0f40f0acff27a4fbd225760a50df266208adbd6518714d81704d9ff9f80b6aeb63a44b0054c64e8b632884a876e488813cf2eb31ccfd9c8f2e3af90ec9aebb09ca5beae9ce1de34d5b3da3e333a5ad1f933bde7df48b86293a6258289c5c7e74dd7ef2fc59a8d215a95841a636dd506e46d1689c329446b6044379f1f062e7aaed3c6b00e4def8d2dfd45ce70d473bab41c24b1f852aa3935f6bddeb884236629c1eb04dc67b4d6e6c9970d80d594bf64bb2712594d1d7ebf62d4a05a9263844a03d5f8d32b54ca6ecdb0e1e82cdef6009ddb94b190cb1ed62f9616ae60324378f9f7a4335068b4ebb0f737c20f3f9a396e532fd730477e516edf223dcd03161b297086688fa8624c1d2e1557f511a0590d794b5ace2b168ed54b87969d27201a0493d62f9ac2e45bceaa05c1c4d91b27ec6ade913d739ffaf70c2d17710c45e061a79692fbd33faee512c15d09d7d869017856be6d45c87687c070f7180f00ef1ed1825a75f54a86601840b3a95854b61168327612356a405d4c644408c86566ee6f331d7c0651016015e0a3d7f4d6d5a597c0934c239367b3cb1daee972549b5f76e9598b42ce369d597acaff9e1c39f2a7730aff47b1a1b54537f9ce4c35d1cac1197a0ff7d598fed80ef3586bdebaa614d64828170fb34d8337f465ff737b14869e407d903d7617c0f099e287e8a31700be8fda5cf543ed67da8bff61ebe50191b4033936f934e00f5650652f0f7213d30cdd434d28b15e28b64c3b2c6a6a89c5de50b5174064ec75442e4c7ff3d02702eaa51565eb8b421b93f299d1f9f38870a2f7f6ed46c6cc338a5e0515e48ecca29c514404823300bba87260bd108d0bf1820401b5fe199f6e8bebeb96944e4632e5d4d63e8d3c1ece2005b8965816d9cea026de67924df1db0202863bb4e923f2bcea7abb2f9087cda418f4b0f44138a608de0591934648e9ede1904a10826b84331a2c526d9da365d85f154fe7d098ce2e1092fe7004990c79b9158756f21d685ca3428a2419ab3c1c9efdfa32866e5d75c152172f2199e77b8e62a8e49ef91bd058d6a0a583f32c63b18282312565bcac182c1f458052d2170a5338c2a0e592d1b329ef378f03999d0387b01bf7b24b2e643d5397ce2e09a2e9922a37716ca5e09ea4848c4c681ea22cbff457a7b105953d6053c7adaaa832c5c6c0d550aa4363c3ba3af514a5650f5e87a93fdcb322fb2988ce9a2ad5fdd64a0e9caa98678ca3bf9692511583f56ae7d3251d21b8b41444454145093ffc9b5a81b5ce1dbae06c147b4fecda7ac21b674ad58f21744fa4e0134697eec25dda8826a3528c04ad0a21ee35bcf4609434b9fde65aee28a67062d118c3c424649b66b263442fbfae67a5a74fa4bc4922d2040e82ad3fb9393c5b73d04061d8c1a6c6f577b12b23151f1f7af00e6dd5895bc6e00ea9b275dc64d368f64aab74a5554aa5ca6cbd558ac2390744af32da66be687cb546d933ada7947246fdaa516ebd4a9bf2e577553729ed170db8391875385038d22645cb6f97dedbfe5c292e1fe9cd12d5fab9fb07ff7144e2825453d1ea80379fd17fbacf20aebf4982a7a04f0b6a00a41c956985a795ffe6ab019f17e0e8a69660f4091eb23fbc6eebd2c11d067ad82c8fa6696b284f4c9e67a95fc5cb84eb4408d6f8fe4a2116aa964ebee91d727510de285ee416ba40bea342e93e343ba04bc49a10faead080e3ed75496a1ec8737cbd57ebcdf9226e7dd4105f491a46ee15e9891a619f0cb309b9dfc80ad36ae37f3101f69b5491afdc36262fc9331f5973da2ff23c93ea008890095d49f4282c1b8916195d0575a95bad364d28952150e01fbc45f442b301e421e11a72e2352b50996db803875fc0de9694b6251c753e9ab34f3b9365572a5dcfa8e5f4615f007d02306be1a5b23e6cb7984c9d9a7e16c05ebf4ade78dcfc632803626f2cd4ab63403604295702f746bdd68dfb2ff0bc0aeae75bca86ee79061caf6046ca5b22985628e44a879bb01cfc27bab42933e90b3c700a900fe3cc079798df5dece8735654a9929bba1362e48040522af83cd88ab50f8e4eeea8dad7eb9c69618eb4ac60117e47d955ce9b8d3f6fc9954bb5f5a00984bc9f9b810dac82352e8bf96e64dd72445f3cc66cf3fccc98015c809386224961c146a766d122bb7f9883ccc2810f554a12bd4898d7044e443af40b3d884ec5c68830f4ea40dc5422ff35dab2a8f00a0c115ebc4bbaac22849d7c71cd25367932173d3e07853587a189c9a3bc7b662f90f976cd6436e129ce5185292d64ec80c4b6f82236881d2a71dc1ca746ab71e86adb1705fb5494b8753087ec07e7fc0dfab1e7cb8be6e280d54e041233b0cb89d06f9582eb56cda960d6f537de08c3e8bd5a3549c64838e2e2a5b30fde6044e579af9ef1cf88ccb90dc69d0e149e6ffabe612b63b8cb8222b0dbd5d5fffd878f4c2f7b6a2df3e1f6e1c6a21db42331f5edee4751024ed10cca826528d7eb83eadd1dbe990e111047d599ee6bc71051738508a18c8c64ce8f41555e0d4557ec64d2d39a0be5a80cbb627bcfc1c5d751d11c16186cea78cb5c465063dd2db892701b33fe27bdeae2460d3248600679fcdab86c9520545a7da8852224286a4859c667e68c8f7d199a8766a2edc065411fa3b116a8e7b0bee218faf938d9a88816cdfe8b76b78c2fa3f9980dbb096cc45892b03028e8b651ac69e1c81807fcc0bc4021ff2e409d53654f1c00d4915022e74089c8ddd922b79b7fe07cdba2667c8759cbf58d152a25fe2478c96c49ee044aa77bb53403204bc48c33d9a5032e8856c5053d689380d478f038983c7523873955758e862cef5db00e1c687856408b48a437c6c7d8eae0518bb622e80fef082cfa4383b121bfc0d00de478079c03d801b6bc34df3129489d0bfc1ff91214a260ce88aa4cb024fc5885ce8aad0a4c61af04c220f5118e117d73fb871c6c2181bb7533c1ee86ff04cc6cf28a49d08e0a9505a3d11b9cea7f75039c8d2732c2847b020396e2d72c071216c04fc488f9e365c2c0eacae40171ed7a9ff2c755098d6503e0581d0004dc1ae8d8c2a3771e9999327809686b38179647c0767d5aaedd54469c1958294ec0cb982e3d14f5443c0fcb3744635cacfe4377bc216629be29f3b182ab8908f734ef91f6939176d27a9040874005dd900dcb59b2caf21c1d3f4fa906fe65c88bb7820c5056f738b22620be7288c066d1553196f702f2798b0804af34d9230b5f8ab06a535016023a8a9d6c59361d7c43319862e04fb00b51974413e5ae5411150be7cc89ce44bcb833c37147d04be4408628699f86c439b592355a458fa6110ad90a86d1a930e0c644cbae2cb003f0670aed66bbfe47a3d6a7ecc748e80d6212fe0a40d13ac5fe8ea97277d41e958431779324a19bdf99fa5cdb5468e91356cc181fffed5d640240b2a964c3e0b290b8c8ae16d628c70c03d89913836231f1b2b6d88bf48616f3a77aa46911bfe9959dd50a3c51b5dbff0132cff2de9c32a40d2e9fab74d28780341921539912e1118ee18a3b440eed855986fa448c21900a04fa6a7f3ebe888e9006b7e6a6d7d4d1250e2ddcc595c83a2ec0e0ae291e03f123ec46aae68c2527a0ea686388fece56954fb32e70ba9ab8a9d04c6c0472789636860691359e9d8994ff02680b6a4a1015e2fd7af115bfa1f8528a7d43495e902805634c116a207492369234491b491ac94a1b088aa4086d20aaa2361455945255544a45d54c1a5d15dbb00bc5140af04fc33a825dfb7063ff4bd63b4828d85c1fe3029bf62f838bbef7f4df176a9f3870b8490171044a5509314e4f8a12166b33183e7556f759577cc2d2e154871b2050facac104eed32b6b5fb4854329d8c32ab63701cb066225754b5aa9bfc78c9084c2421831e53c741b6f6405a475ad353f35e10a161ae4ccf2a3a7313b080757a6ec36bbae7a7fc117939db3497c7aabd16a1b917bbc190f78f1cc2f66b335387fba19273c459c2727bd0f521cb424e8d481a6fccf65724546ebde2123042f6802840faebaa2a90f613b3802d5742aac398fae1ab2ac1d96c08cbf2c5d4506f7912721860f30480c359a34e1cf3a05e197456e7ba18cea7b42152db428343961c94a3559664e5e99d202ce8d6a94754e7dc2d4c38dc207b7a4293489f8922c4ab80b2920d387ff003b91140369443682eec9a4216d9bd68b556661ce79105201641e83550da2a484abd164060f7a64083c1b9b6711faf705663bd221b070f65fae1103e1a1f813354e4776b74cf6183d60190c6bf9cec58381664c84be79541492674aa2479f50a002e202833fc7309cfc28cc73200b89ec491fb41020d70eca185fb78913d7d3080a2ea6daed992a3539fa191e25e6d3c8bdcf78445210ba2e3cd29bec9601c5e625ede584e962575f96497c20e27ae015121de650178895bb83f1e522c82cf64449cb95106c80fc014e9e8ce88c9a1269c26ceb9fe8f39380a84346b98a42048199b4ca3f289b9a7fdf58512bad2c369437af33e526e28d345feab5a1c1793de18e6d3b8a3778200662f716b83d308979172e5d0101391dee7397ba66876dca3fb75f1bf99210a294815ed66b473cd21e11b7ab517024410e51ce8c3d8123b4d1f3e083a867f3ca1abb060285ab53bd8ba0ee7ee3153ef7b513479e640cd1b86c897051005ac06addc0509a295c7e4539e0b8ffe03c4055612659e968a188f35c62cdf279ec68bcfc88080d0bee6a8422ebe9be614409ad2049986d3cef03f2381342abfe2e5de33d471ed026e58de66170841bc0abeec15a59fc4796a4fc0bdfb8adde0b6a3676f9b40e40f16787ad873cfc25ae3e544043e4251ccb0d59348ffbf041df1884f2d5cc9cd4dbf19a25add477524af87f9286dea20e98cad8bb0b1d81b704b2cfbb5a320a8f2e8312412e002dee214b3a9d9849b1f36923dad107878baef41a6c2a9bf1d9c25da0d794833214c4f55d89c78e4fc1f552169126e7e4f57e52b29b3d78966da7e15634b1514d3f0400deb2d083211fe5468b2f0a46c6f5c231ed31d9df45f89ce2d1eca2cb71813c51366a65c491e0e71a90c5b2752275b3310344f86affec73dde5e532efe951a2e92b679dd3c42e45e9247f5ca930d1bc4d82b42ac0b33e7e263ce2aa27b706e8f089e437839e2ebaa8bc8315fd5225a305db72f94d4fa5cb32f0372ea12b6150b07c22a68956f515d07a9025e22c011143f341ff5e4b2b065632b7e2780a3daa733482049ae738937bd65c3159cf87158d8ab0f36933727136882a83b1dbcc72287ac4ad36c0d6f2d1bc7804bf285fd337417a404d935580c2f52f903d911222b5f57ebfb960bac60d8c3101a7f73755e18fff5e3059dac16b8af3b1b35fad4bc6af5a140a3a7c11361063fcf7ff4ed8f45af3bf36da2cbe1f7633be06041a547eff6743782ce1f8dc81799da6bc8e03414fbbeb04fcf35c342284f499544b8fe8a32d2e3cb91e566990e5c37108de44b9991f5039423bc65aeadce83be77a10cd5f6faa63a750cb5dde18b3bec0405779d68fb736fbfc20b587c11acd7dc9b4596cda354e124246149eaab829bb6da751734a7963b8f70be21a27f69e5a49e641453dd304d95cd4898697b1853a550adbd42aece747aa2bf739536663396f720fc0cc951331f015b25e1906979853c21ae579701f5066ab4851225086e85d123ba6a2a926231d0e1cd5358f743c8b02c8eba47cd08cd84198e75020cb3bc704f09314aae9887bb5d213b027bd776e12af9980bdccf43a1c5909d4052ebb0d898a15cfef743dfb6e5712ca71eed94ea773a6d4a80750c0f21dc92a4b1ec37be21505fecf85d2b4e21fb03942ffa742f726f9cafbbd945a6d43ee55df58bc36f781becedf4af4739437354dd85896913eca496865acea4df3cbb1f4e69b346c765fccda1f50993bacb6f0e67b36dde127ebff1b417f4d5d104e0fb020c715799140516077bafe19f646e98f70431ade9f79d97adc723d14cea153515d5eb20f8ce036154ad92a2772d536261c8c9f85d3d4967c348aa5cef4fc8ca9a4ba95e3aa06d688cadef8044b922aa72a06c376d7656afab0952d64098d93d4638ad6aa82a214213d7c1106c353ed8bfa5f6737579d38f4b8e1719e5beb47959edcbac82d2e50437c4563fd628dcf28d9c0517ded28ccfc1807a7e3974e4ae182497e79c4a763853c9572edaead50041b6bf945e16a0758c8321f30402d8892f5d07cc0cb6309a350f86123ec822071b57ef57e2f7f2b1dee4a9d36b638f17b6a63b0c75b31023c91b62ed330213d45206bba883e2e3863c227b56b36b10063df3650fc0c9cc97d80a61fe202b88d88970e2db163228ea8d0eac60db145076374e8ed881c383c440c00e342c70bcae2aadee77c82d15d6395a403ff666cf4daf9dc8bc65b4d88a60c8a3f81bd63ff376d7ade5ba74cde37635c25f8a849695d93ce7247710792cb5fd3d1ded664810ac2013272d35a78246adae883ad3c1083379f4b8b3dc7a4703f11e2c11088511dc1d3a75699750dcede81bb3370a8daeca66d97758c6f6df06a2d7bf62d3c1cdce24bf4abebd9a5711d4c78468b537fcd08161366731f2cbd0d09b20943309cee9ebc4b9a14332c0f349ac1f4bcadde38de82db1141c2d1868fb7f2c421bbb6651b9d6393b11fc321ba2fc5c19166c7720698016c8e3dc882380106a4f72d40c6501acbf333b04bc6bdd227ba3e1f0b60c609afef7c635d212c817765391a6024d89ceca24e81881bd1159841ba21930c6a3a8d2b39e7a30a8ae215cf529f734ee25c3138cb65ae392b5398affaae2aad58f69ffe7adfee9a07940327e9bb92540c80b346e9e7c8ee99ad562e328b98b85e029201d694f519b1366947bb58792711df41d79b7533468cbc1880cff5a0fbd89c4dd24a65489f284fec4cc0ea0a257a3e87bb9ef98a014a21345b49174bd95c814cab4e788faeab1348a40496db57a86c4f6b128b0d11c52d71d3c01a29ab8c22707fe3a5a9da93f3cb0ca74022e8a19982b03093b83eba707ea05a224088a4b720f8387ce72a6771bcc1bc5cb27098c6ce554524db99f9a8625e750b8d8b44606950d0a4d1bec1c001e94ee66a517efba3522d03862e0a278302659acdfdd7b9c0b78656194282aa84feb64ba8fed48a6c2424407a78f5d6fb6e9e6b49609e428063cc545512e29055398c01ea105672dee97fae015f22f70829788e15159685b4c1c66378257413b1c197fbef8e846a011ef9940ea18ed3556949164f6545c721ca6e41d98935547b88a33d366cb52b68bb3b269083462de1b8986aabccc8bb569819370f4fba0139d76804c40cd1220d7a884fbb80076cc6f542d80948ca30277bea3cea9460d75068dc39b6e50b4725a9860c47e65584b05a43dbd28bb1c0f747c9e1bc8d8459de9210be4fb9793ef78c55f67963f882810f047f44933150813853b54bcb2ba60aac1147060426a05b5c21423649d68d7aebb9c915c58225fca39fe57fb29e62999c951049dd4d8d41c26b32788310778554df0d23636ad76dd6308d2aafcd8e7f8448ea02b6dd07504bae1ae56692197e6cf56c6718f529fc9f46600e02c785ce41a86dcd80902c871926de315462f864f2ffc72e5574031215cbbb6080063800efbe029c342a704456ed999949c10356ab0c4062d23bcdd2dc01791aa24500332b496ca4e0aaa9f47f54c60efa50c6981bf090ba3b8c243bd9dca630f63f05cad1bbc4303370238750c8de5ed5a9c5c6de70a3987aedbf70b6fb237c4da0f49a9f8848ae1ffd0ee9155151346792b24a669bcd1870f0f38603f4281cb707f03097b7f3d096401cd2cde57aa8e5be9f6190e2cb17bac04440ca284f257fe06768b03eb2713eccbb2515e3a3b3c069935a97fb4d6b6cdbdffbfcf33573b5275842a0ccf589ad0da7f53492bf39062815a62df0b1a60ecd6774b3fb4b842639944a7ebea20ae6982e10856ca10da2988ff5124b487cc87b75f0f6adc1fdb46fc3d3b1ba78329588a00bcfc466c77d57943d4c0516cc11e64627f3e1b2b85464f57bd1b983f905f8cda8bcabb608479f81f9968bc9fae6e2e2ef00623620f39e9bc3097defd28c1473c799ca17c40c2b92f0a2621960f71623bedcf02aa0f9ca4856225111c96a4457c01637bbae1c30c0087cf0c749f61fca2fb7969d0cddd1a3a50663c501c9acedba3ed335a82935fea283cdd5f454fbc2f33dd4fdb422620ebe6ae632bbc64698d781992cdc5a2beab6604bcc3e0ece2fb5e4ff863f0296c8e44defb8d9202ea2d52813600b6bcb1a71f84dda73f7bee2fa3e5f309c7f0f6209d5a6dd19629531a1d1e72d1eaab1c1f3118770b50bcce588db35dc73a35c19296aa61d628abb4ce24a89825c843b3743588850e19ba0b8ff18166ad4e6a30448174f27a98755fa11010e8475455a4e3723e01b0c5ddea4566fd5e9e05b982b11d3911e0c5b8865dfed03685d241b65880c39dbf19006f08d487e7b4102c82e6ddc08fb1ac01bf318df836f17df0c40e1c0bef028195d80c10bd0ae603ff50effcf0564a0b4190ce4d2d1ac7e2bf7d6a11a7c5a4d45d0a91309bfe94de2df1a4113509108c403f4c04137228d04820967043a1a631c8aa56cec346946ea56543866d65bc78805cfe82f0cfcea15797b6578306446d954650e21bb9bbe6ee2bd7937f38085ed3db23b6f42ecf327e46dc3a699862f08a2e93d020d36e0f0acc44c3f5afa9df6c46629109098678336679afda79a1a9a83f1781dea3632a018144f0f1a61d806c238219ec593656d616359b3c22c94d90d5ee83eb1a3cac481d700c861db09edd6c1cd846e836f39a2066d38652bca88f816bc9a1885c2e9475d1eb71946a5c919ff22f18bb65fe791cb6f24601d1d62a586582cec339e48177d3e9add93048491093360a274539c59852b9df44e573e69e64b7977c2d37f8fa5c2e47aa6ea332f35b9644083ee71a99bd9cee9576b2b70009a4823361ea4c7888479599acb0ee249ae9992c26f169bbd15d786c8f08ed61e99192194edc55f511ed081a6bc32e312c4cecdb097f2d7e2975b84901f215be6fd703ce31f4cab36890a0c6d06109a7340724da9df56b898b9c7d7d90f191a60dab7b3932f6f86011674c7c220113129d25c3cd425c89392c21bae3bf6583dd99066f433ba1493f9e0dd7f7289df22846021314e53a5bf960b7d71d044aeac3f9ddbba47c4275cb3274a4692d3860b2b91e8300dffd893bfbfd818023c82cdfda33fdaa78674daf6a4d4cd907091e967f3875374cbed2c21da2b0a288d65d5e5455591affadf00d9819798326338fd49aae063d6366e695d1bb6e64a82770bce859d14b63a74d439af562f63e69eddfb36dede38aab038d54819b2adcdab7482e38c012ca866f5e0f97e7283dd347744c23f97077eca7d6a68c0e716cb25ca65f27ae030cb85aef18d4639f42bd92ee1a0d66c0706c61d3c49021f9194d3f0b477409244bdca9ab8fce39550da3cea183854fed490f32b093c1045e35f7fdc9228653db110ddf036698f3fa9d128628641a0d120e5335a7dae06d8fd3c3c75b80e02da0715097c37c9cb72e96ae6870019e3be990055b66473c6f842261f3004294525bedef31b8c7bd5fcf0b6998d7bcf584c2e232f992694eed96ce3f255956d3f1815ab1c3cddb5993132dbb2988f2f674611039e807466144028a51d16243104192529c9888196c94518a3aa6a3468240f83d74b928f2c14735b0ca8fea5825f18803c776bd124dcff12b37fdb9d7af8438b989f1d98f4a342e0ccfa08fb7b9beb61563e652a659ffc501872bbcaf8008f8a86276203177fb0fedfd2d91f800a139c6ea9ca6be99c05c2c689b49ddd1de6dd9050b35132268a4c2f832008bfeed49eccbeb1e025f14f52c1f70c51506254d3bdadbebed6a7ff044dbf106c638091f34621a0fc45d1011579ac9d49e38d50a3ddbf7b62e029a42c35e9f4cef267337e3edd89504b58f4046de235c00976b294c5f6fadc2d641f4a43b5130d7ff49c53569d5ec8cdb58d3cd3b0eb6d40a2d0fe9a4712e1d232ba3a1b95b28e590ef7128f71969fa6ea59e9e3f857fc8962e9a64cf58efc839675bcd49526a2f8bdbff69db810f7decc8760a509439722823d3c03a653f6325ab3d84191ae75cbdae10f9bd02b5e4221e7d5ca2c9d325ba584061a11b6f62e45f5a26a9ca431baa62330849c35b534a94f63c4317dd016ae71e67b92217e7e71c2f4ee32ac26985e28e47a184ae0fc162fe30cdfbb94d3dbdabb8ebb3c0546dac5c0c819196f1aacfda1e6a05aa36992d01967cc0caedd9840a935d86cb5ea6e200d935177b90596f6eec0d940b27c39e9080fcdd538fdd48019fc4be8258f6e2d624de102fd398f84cd3bf2c37c2c7e00b71b33132a28e22e1ec68af1db0869727780810f3284a5f655bf20d50f82b022e4510bf3da8c43ec8482f55c303f890336f5655cbc3c406bc6b34201f97f4cebfab13de9f0e37c64ad3656973eaa52d71bf8e44297527585b138be240d7b621f58ff8f5fea0acb3fa28e3f1a478373b6e57311311d823c71f9fc3efabc8493bdf4f2796a0fc6b487c8c010ef5a3f36a4cad246e8e1f9363a589d6fe96773afa99461c9289242b8bc4a10716f63a017be8f90566976d126ad9ca4e7f59503e1ce67cbe8cbbd5e81cbfa1f3ed60d81e174933b52fbfef4b7441825b661b568b43f717a46f02143bbfc0fcd6716e367783b2745ab6cc931b839cba18446151b43f745955c6c95c49e789d2ba6f0346b1b6ef1c4784ee188116f5c4799bb614151661b51d86a72eae087c6dd544bc7d1690bc9314f703ce6ce1127c8d8ab3bc3f04cfc77f188169b5c1ad7df564b1b1ef01e95176eed85104cdf45bd7b406eec1e55a0bbc541324cbd204f3e938ab640b114598f1f00548e978ac33771cec57800ef248917761433e66f8782ad5e7d35114fe1c3b7ca27c2286c976558108ebc048d7c2a6cabaac75a3e92d18a61bbd1611c724ef20eb62a04e5d9b6222b220d069189d0af6d3d6ac4f03ade2d4536ab2a569f0c41f79f124ab11408b10f052609175ae7a3e6f9a39ae199d361f65be399576465715b7edd56bdf4701059f6f944758ef0e994e1122d95921f17c24be5b07c88084fa94667f3839f5c5e0b2d8bb80444680e329f9234650b4f2ba775770d45c7a08e1967613bf3601629ab053f386f1a11506c32b4ae8849ca7ac1817cf2ec19c3347bcf0013fb742ae1415559473fad6079c92bc1a3159e4506678364674a1cda705eb116bb3b6de88b5e0bb92071ca702ccc70896ee67b105e440facb1b150d0c9775a9be47b2c3e66fe46d6e328d25949508235c4ce3e22a550a8764945fbf304d3051a7667402fac93962d45ac99174bc3bde0f460d962bb5dab097ab93dfb150acb3ca73486d380a1684a481b446bdadd7aa48711f15b086b5ba176779404240a0b3e0f862f4f178c7a6b6a2d90066e8c463a93c411671092ba05d9d9d4a2805014ca53347eca9c3e898769fd382d6864f6dad46e746c420ba8021bab84f43eae34c02bc562d0bc8a54a2722d4c82b98233d8138e61646892e722f50fc0edfde95cf6978c0a50907a6d6b966c2e3fb0325e5c85d2231f98a3fb86ce37af2646a4968daaae7ba4fa266d4240e0891feb9814e964920310aa515242b1e6cb6b7cd36f1f6b821092da60098a13183accadc4365b578107c32b605836483a4b5fa23349a99278fd2ae6fe3cf3ec3b75097a40c924243b4a348c3bb0c05c8d168088b20aa75aa3c2facc119bc9e00c0963a44aa938bc35eb019ac31df403f7a1caa55b0bb3dd185b59fd93f1e7c3fdb4cb346e86ea9b14c3b0288c71706249ca7e2065b00ddd20732ff972198d4105b83d42aae3e6edef063464a682c4419b73edf5cf5c38b1c9c1d3c08784e23b7aa805f80d9745b68245d097613f8ae9d9c8f7b872f2565e7edce2f93bf86affde06564f4fd41c5ce2037b0fd86324fbc74f05dc076ad34c54b888b17c6cd9448c25041431d29fa4fb3a4402e48f8df081d09ecd1b8da82d7e9aea8ce8b08b1af0e273ed7f096c441798cbee7f5f5a805b725ab61825747dcfc29a5d395726915a4b203e50c189c8454ee701d9d9a9dddbf3eb02748a3db3e2f0be2366c6298e8ea678a1312fa552cbf3098329a3b8218e85892d72ccba4949c38de28bcc6e6042c868c5442055112267f17bc8a4c8ed64458c5c7b77c5ae244ad5b794eab48873ed9c7ec109b0956035d851b6563d4b51bd943e1c4524434e42de11ba6105f69f7b8c1750071ecb8b5a3608e856d90e382cefc1513b5bf22383893299694d35d069b9681f9c06e8e8c70e3022c1dee6adda7acd01bf3deb70c24b0f6cc28de17ad0775380e2ccadb255362a40e33970600488eeee73719b0444015243cc7a1cd07d2b55c2f2259f50f320e3718fce0479dbcf74b3580bc33bbdce530e399eb3e62cdf079909cf260f0a22bdfc36098c12a8220f4c7f716d37fdaa4f7d1a0e39776cb0c8bbcdc4d81a34b702e178d7be8754365860609b21a4b00d16d8fb5273334229b6d85a3d6621fa999148df74b898dd082d42414ec8ea23b3ead9e9ffdcff4dc7d043ab49f9cc133938143c548a71bf76a88fcaf1d56e0fb11da50ab4956bd8bad64d733ecaeb359ca3a5ec350ba62417189ac548d8b989bf942b2f801eacb04716177fed353df619606c5b323218d1cbc2f815d4a1e31a6a9e3c58fbe158134bc52ac48cb7653ed07ab3f72f25c36771ef99b5a4fca069e4e44d8a9e473e241d1ae16b3255f51af1217528085f09a696a55ef715e8b3db7370910037838f7769ba029ad505303bebfb37ca1bebafc979e0cc8108c72662762b8677f8bdbb9945e07610bf83e27775ef40e8c6087210839902f9517431a191af7925c1aafac56f1a4445306b46ce9e2e556a1353321cc2907d28284843c26c191601a702354135542a7a619729cb1a017c11bfd2de3fb9ab99f7652be9918bded1677f93e6675a7f183f50e472580afbb08a54a43ed4b8e6ae58bc00e135085562b74c9643a5a487cc6db082e9b6d2436e4c36339046848987b67c00a6978ee56fa03ea67339184bad83d8fbe5ad62e919e66c24152154ba4e70e39cdd207606e0e628554fe86f2c545e32993382b4f6dca0d2a5f9fa197f4e5a2542f7eebaf64beeae66a20cd45762d8361174c8a26fc5ddaceb5c74cf3f06ba9118d1fad2ad101afa587dff33e25705ead00610c8ab9e24b2bace69409bcc4e3a120ba477114bba1eff5ed72e9c6eb5f8e20291724cdb92e572e6606a237eec113954110e9098845ab3056be437c1a7b45aadd926c8a0025491bd89fb52a5c24bb8604b3c7ba6d68b2b9281babf06dd20f295d61baf0053c4e4929e75745bb2623d6b774e38d75d56e6caaedc8ad631e9d0817574e4bc4c29081d9cd70d871c9e682d0fda99f33eb963a1aa50a238a61c6dab762bfd47c84057a553db51ad64a84b52e151561ae344599f52c3262f0a949a36a7dfb14e88bc7060b0dc2011c8743e6cea7c62df325ed98ba6c76a7354ac8811f868d62e12eb642cd768803b0d05458d0d6f4bc9ac029710f86ff14adfd55983792031e2829dce5ffd4761bc2c895f8a0549a738de054c7105c44ba8c8e835a04f65a40c3b5051ba4ee55c06764adca988436a1d2340791437a2e5bb76db5f27f9410fc762679ecd6d3733154434d75b93d77a55e824751ba62844345aa280ec50b44f912e7b1eaea55b80aefd1eb9b5173bf9e449081375a466ed72af0a69b477aaa2a18d8deb06f82e73d3dbb3a4036fcf7a906e722196e259d2b1ca480670b4bfd86950ca8c9f3668a056f5c43d35c62c20cbdc2158e52917d9124b3a2065e3ecf48b4ccb48e443ae9c3a3b0bdd69f8380deed92d489be6b98ac31667c5fe0c11f7c524b64d0c46c33c00a6543b2f470fbdf5f383c76e86a4b1729e725af276dcfd2cc38a9a15859d10f7d83e6cca8f2e96e4602ed24e81df1ff21dcd4e309848426dea8a2fece8e929468519b01e5cae7a12a2533e506b5a1c1e0ea4a4022d811a08caa277df48caed24d70ef649704a2f244ae5251eec6af8850b48e3d53bd086d5be6fd687baad157963bc1acc45588c57ace944201ac77a7a76bc9641da02014568a5f550b01dfe60b83c3ea67f3fa705eb4254bb2084e2dcdad1adf6033f75406a5faaca0e72fb2a8440301a76be56e6109bf4f135c566e81c1cc0276814d0881aed6528e4a9528f3e22fd50ee476d6362938eb7b17ec698c06c3cb1cb0be274c3a8424ea2c43ede6d55d46e444929ab34a60c93b18f3aa04a4ed2d4fb83848c27d91778b1c5008a9b5c14db2f8bd538b08ed0758b42af071f3f423ee2bdd87772e03efe1d71f8dbdf715182f39d2a25bd43643c427bfb0fe4d0bb2303471d81158c6c1f68004f032ac1a1f2257ea0647c95230a99f3662bf5dc3ff59cf6d950957dcfe48ce71e3dd9821e9ef59fc2e02e4513787627742f0f1c12109661db51a4afe73fac70bacae2fcfcc0723db067f68f44bece8045e90af53ea8ae3a5091dea7bcf129fb9bba2f641536cab4bc10ea6e4a07cc16a0f4c1f35a96e072f7c3980f667ca5f6a7e7e9666e75e050f6db2d7289f2f19228996e5609f678c33b83940f07e9b14c7a8495c7e2f4f8b47bdc031fb3943f11ddfc85e4947d433f23c4ba411ed97f31f18299e19c1f43f322b57f222fb2716d8dfc9a416d80d470f3cd19749557689c5e89af6e22936908b2dafeba8359cdbf1b802b3e9f9ac5b914b2586e6e881cee254e622fac933ef6fd63e661f21878fe41efaf12c6b929b0735ed2d3305396526a0d185b58fe737ff1fd3526cdbd80b587054d361cab66a3044633a40b8322349e6136399f7a44cb8d85f698bff620b5ce413c5a6ec2e42f08d7cd503a873f7fa8318b930d6014905861050a36f2af444f0c9862767784ba0f92ed45ff78c0d10c6d4293d83b4117efe7642d50332add6721be883c0382e48eda95eb5d22366114d9380f9d0389ce464cc49e07d42eefa4f4ba8d6d4d5780ebe7a20d9918d9ad10355fcc9f2905207da9efbb8cdb2a4e9b7e0033538636b64f2453433e39ae75c790f3ae4fbe3f561554257f4126e2ef01af89f4a57cc712142837a4130d644288d1e483476b256ffa1f8bbe2b3023f7a63d4906e81c0839fdba3fee087e76d2cfd1a7c1dcef7d75c49634c16e7805bfcd57786e34f13750a2271362fbe693593d49eb38933d59b23d8cc40e1b15120e65a305830c47f6c92ac5b7a240a07a57efc9396f340e95978aba032d1801405be595480029b986cf7e9fa6b4254c85d338214d6a1d294e75fc0ec3ce91b4ea26905db2d8dcf47921f63fc294bae062d29b7d50ec2c3a90581defba839f8b3b0a471bf41bfb9b761308ba81d2b21f2173d9188ed808cbcaaa0c9a3cf7d067f7beff7bfd19843649a77fdd46477e2a8efd0a0e1175affc7492db25ebcdb263dd973306d69f70f69b82719ff764e41ee6bb23f113a6621415e49c4ecfa100e7cec337bbde794726a30d2b1110b33f2e93f0094c7247b3068d0f5c78b12941a6f6879e566cdbe65ad57292f876585819463c3c4166364f0853b51eddb2467c917c193134b8419e3b3e42fbda7cd275d5f438281b73e14ed79eee02cd224d7dde9d4d2f80d79040888a2502da8efd5896a393fb656fffbd65649ff45343e1bdd67cb494a97ad2874a1ec9419d4461e442ffc9eba63163846e071ae11b4ad8de0f1922d77e6b395e68d13272d4d02c9e101be79301733b402fe9dfc7cfb25fbc84ba6dadbc6ef4cf58a67fd382f3cf175b762236249f5852ff04fb045ae77526adfe23a190a711e20795f9eacf0020b946423e42fac0d184996da89e7eb142eebe84ddffc9e471cc3bf791150c5ed6e9afac423720db4876a33c6f08a8599f84132f567ec6a8b501611271db0b0588fe0266631851431e632ec2bf324c06e3a34f67ba2e4c4aba2a2248f805abe6449bcd8540b678c155026aaadbbcfccca8a4b5ee4f67702a0e6fb0b4e3f386d9813045e5e52f202b4d9733267c0479a58c72596f122146b1916ca8ebab5716f3162f226f486f3d0e8e95c1792b6d40437906dd3d5d7ad7bd2c9c21408d20d5bc63ff63ccc170d795b5f65bd0a59dde470df9200f69c0520ac15d2f6a505217e92d9d73faaad0182fbf2e24ddda3f96669ff51baf027ad7e81ba583abf0826afbdf1002039a9c825bed9f987c7f765962bfc25583c78bdead22ccdcd5b04228dd5580029f1b0e1c9ac0b3f459818202f0f1922900c9deb5f13b5d7481f93758a4d2770c3ae9505dbb9bf4a4ab1beb035481d046b1cb98ca3bab24f414b6017cf8482409b1c248497f028a420a67ea2d5541979aa5b25e5f1aaa1ad2a5acb7ec250dd50fb161b5c191f9f420a8adedb18907c5232ec27ae32745be1fc0b255a8efb412a4a15c2e7bd75044e694fbe37c592e6316d74e51226c30ee094352da5154ae570de3fd73326ed324a8ceccd886223dc6d31d6c9cd97947c596a02ce177bfbfe88d0eaf5c26a3815f6e424dd34d8325336245e8f151f8ee8ee31c533f05909b4e413af8ee80a0500cffa4b61480991614423271dc80c01f0d13c04d6e0c131be75f38f12859e573bb82d80072de98b0e7d225835632bdc011526c70d16a00c0e3f6f0149a3179de86c58ad74a2bc8c450eabf12934d19df8eac2334c0a4b977cb518463eed79c7156c2324f42aa7892a5a59d67234e5f93e24f1d01a05b51ca4e8a1c37dc0dc040196f4045474d6d965044e85271df9eda6fdc2e155943b0b9ab086b2ad29fea55a48fc2a67c90a948e14500c45a81f35c50c89770a375701586896ef031400960b756c0ad3b3c5e135079eab7601f52cf897cfbf941d423831dbde2872be80feb3d5a6e8e29c7f495da2ef79efb8b49bccc6f11fa116c1c4ddc88d8c91c196d6ce8b6e97191b2ab5a13a9e000d0ebba8acd44ea15aa249878ae7a6bc1265af2a7316c65df8b687766c85a021d0295a12ddc9254a7dcaec8df65b3f237f368d86caecdd445898b01d219f10d06df637098289101548945f0ef60385da5a18c50bbf4087274b3a6f8e83fafd0d6491fc6799745673780399644ddfc249d4de9d61eca7896028d2e28ae6f9280ea43fa6314212b6aeb20010cb0e96e774c3272031d7a1a69e37f7bfb300b033d6c38c63496a81591c86381c7b2ea29a024cfc505232c19420f432aba3f21592896078acb9b09697e2c38d7d23cfb4407cd657ed73ff04cf97e9900d7b6442360e3904a800e2d50ab394ff8b8667aa8d2a8d7b45b7bd80e517ca7a9a66ac2054f93869817df01d18e4e770924bbf4e0543d5182d1ee909a3e20b07b2109830e48ec3ce1b9818081ac76f8e29a800dd5dbf9dae3c87dbfe08303cee0c4f21216dc3a29184e8b3d4352957ef4c9125e85bf17d70a7baa7ded48afff25836ae2571c8a12e0ad32b3ecc02cab9a392920d4613777a2494f708d8b4c20b5c8a5213b369529e516172b39ea327406356a9006cb91782a861fcb3e0bbd8fd0cab716d92d5a8e17478753acc0064b13318177c418591c1de29f828bd86165286901301a3e89300d204dbaa79012ff7051f2497c23a8a287b8435ab612d64359efd96a0fed36ae45880cedcd41fe7d7bc3fd3d48d8b4e6a60877e1974af40783ec68d7d843a0ca46dda036eb264e0e9e6b9c7525ce639a9a174999afc226378d2e3a1ed5824861260df8914aa39f1d876644ee10d85d9dfc090283732d8a11c2bc386bf13add93784608c89fbf514187c345dc3f371b4600879a300f7136071487a417d7d500c5fdc3c86e7f4ecc8d527d3d48e688d4827adca421f53a305fac865329cacd69bc05ab83cb724cc37732266ae39474d14559328c7b48e4ac4aa2613d9a442ab2eae9ac8c54b8d6dfa7accae677f0f0ff49cd9f6b48628fc93dcb95677469a0d1effa55c7e03f97749a959bd46ff42d0f1f1846e9d54a74084792c7877a1f30dd5c23fb0c5bfeffda53e70c7cf73949fd654ec52c9198e102ce2cc809a552bac977ac4d93008480c4aa8d9b49a2cccad9ad493609d4fcdd0681192adbcaf42f3e8cedd03d29f35502836a1031f137e87be7032757fdb9d68c4e9a4c7137a26be2b92312c76b3b824825f1aa7a93e2db71bfe9e5522a63a9a836bf570342f31aaa536e7ed86f72a299ff6d033c153356563fa7f03097bf81632a116420ab3233a3e634e298117175ea88726ebc017f335f583fe4f0aa8687d008a61041fa3f446d32715cddcc2ca071d924d614a2778b2c1c079d8d113dd8d3b462f7a861ca48d3b0ffff3d913cbb0e67cdd4293e569066cf2755417bfa907096943f2b8bfd332c2507dd02d9261d90e6a784c6c48dfe88d2b3181467edbaa9fc8cdc96f21ace9a7ab5878e55d626a39bf67aa2c0ffb867b3c3c7771b121039e56629dcfa3d6fb3ca6a469e89dfa0f8d66316121bb1077b55fe855e748bf37a5b4f664d9f59877db1559888f263ac78f982f894f2aed713c66801ca12770b5b83673c647c12223dcb2753c6e0568b57f39860e0daaa23a3598d670fc35c6cdf9b52f862e24bceaba0dda74c78a5864220dfc556ba8ed3f27e03b4db8f868e63209339cb7ab2542b67a9bbc9832299435344baf635714b27e9d9052448bf01f474dbfb0c718b3744469f0f9a5f6003aea9fd3bfe76983a1cfcf911b5bc0965f515497a1893a98fa150083e49dbf0005004b56f4fb83d62fff14f0bb37f066297134eac458bf3bc64b50f7da435587b3349b6d1a8195a8c8d4e1f4a236dfb2089bc153cc419553166fe745eb7208a8307089d38d8637a786597da803f07604ee4d459a56c17511eeaaf817843ffe2b6d096fb0de4bd5cccd3adfcab60beb6082f4e1e3f1ad9e47c9df665208a42ca5eb001b5a89b129feea2ff2ea40b469626c1b07c60c61bef6107ec3e52d6f5cb32c3c977d5c6878c79258c22f523f957ca7419717bb1d1b694df63603371e356928079d65c6f37c4ff4cb667a749025d4d38544c3bd3b9b7d86844b8cf1eda4113271cde032e3ca6ea34d04c40776275540411726059d545ec1560c5f95ba1824db0cbc5917d48f13d6fb0e2a950c26de6564b87760edb0c9caa926c5d9c9de49e9a7f3fde7a250820aff32aad80e28cf525ab5a67f85732ae4840678fdf700bf410ab436c6d52c90d5afd146bfdb34a94ebed2c16fd7179fd75a09e2d7e896d3b7d0d35e2a67d778671f9a7af0669a8477cfa384cfc0c7a5f63b98661646fdb3e8b077f500c86a0918a350677abb1bda4ef2477728053a5617d360252db21e4767e92f34148daba527caa322dccd45de06347c56c12bc6c1bda8474942e92b9ddc332a1a7be7db79ab578ad23cde9ce48ee4182a7be2c1fa7f9f72e3b9169c2bc4f2175eb20dff7dcc95b5d63d22125b0b7ef5edb04b20b89a84c885f97bc26e88d109706b9b38238f253178942212c84a777d1f439b949d511ed9835a0f85747908ccae3ae638e805ded1535fdf6951006983cd164da91a9eee2b5d4a8c854b2dcc702d756c043fd04afea41c957ec441b26e22912af659622a040ef07e9305945d4365a279552d3003a85ba2f756d93df77202cd70619091d8fcccaaabfc473b04009cfc9be5f73653dc21ed8fa8c5819fed1974f4f59da49840af6a5c1b5251cd7966aa4aa22be811079d8c8cdcc113700102923be93fe540680e3054153e690a9e14fa59a3538fb937a6602138438aa4c5de1b1f517559dd83ceab49b4b59a6ab5aac9cfb46856f624d19fc9110bba0ac92242d946c55f6848e53ff13ab0f04aa3df18d9f86a4528b98d4c1e300a410a852eedd3ccff9f6e61a26c88d482a49b797d152e24f12cca3c702a1ee32420f39576a34b028c9c36d32f211180033ace557e79626dcaeb4b5397955f26935b57a12d9d3d37b0d72ca0c11c32d74edc3477ed9f4805e725ec47c74c4d6051304a6e98b829efc4d4b6375588bebfeac1d1cee0056d7ba9ee3a853c5405a9f1c318a68c1dc99fd9d920106773ef711d0de8442ae8a4a66e29c14cb6afb71fd69a3578effa48bf14dcf36cf72e86233a6943fa85c9c98a4e9c4a40f28d07c14e99f84051c8535c64103fc439b65fb8759c23e2b846284a745857201bcc1547b52396804a86b1a4cb814a74a5d582af73a41de3304ac2f3e4c7cfb40ab90c9fcb9681655741da3ec9c214ae3ed0edfd0e712b706a7414292a1f847073d7b5a1ad414057e2a83f4ea83b813e42ec3d7554165e9c14c5dde86b6152b2d33f68a7d7897944820d319b3bcb0709e90feda3cf107dce0c944f3d349d22eb3c7de0955ec8a19dc93d50bc4a0fb6eecf9f630196cf86eeb90ccd366183461a7a872c1a83a96fde4f52d83b342e628286bc8074954846300b7e5ee1d26f38bcdd58f09229c98f9794a5d8db8c1767bf500e4f51de36303ae9253f118139a2227846f908def1992a5f5b282432840d070708bafd527be7a345aa0804e9586d635472ccd99c2ef8ccf715b541fd539a5a9eddbc37e0f5d3848c4c8f05ba5ccb0115b8fde909c1ba7fc5c91af1949f1fc121dadaa221bb0ef282373497d7823245a80ac0465570144a474bf3389517066f20cc11a9182b6cf1f80556f0c066ce603b368538a9e65ba339e15efb9203fefd56afc09b6607def35297346f75363839014a52581b8df91c4d84b4019fd818773af26a51dcae6b9708a7565b2883487e5f768ed1337d264dc50832812e14d8e751cd70d1c996288bf8699b085abcb098ce72574d18e031862c9a66148c99edd429e6eae10b363c5965fdf8babf7b7053f39118761edfec4e00b3c001664417d8f6682169aa2598d0dfedd91ddc7750aea49fe74ff4e2bb300eaa8b9e404dc32f5a05b878c90be995d54f26389c5e1079caf0551fdaed714b6602b65ba1aecd9ab855982099c0a833f0efde88c9d4f0b8d6eeb3cb85d36e175c5ef72fc4be0d111b3bc84c5ea04d15916c644232739dbbaf95d40138ad3d352f41291e51acfd874e3f0ba69252f8367b444c1d42268c8a7793a056f6025ef05796766f9534acb545e55831ad42c50a301bc02bc29e8f5f4494b2bacd49ca0abf4049d581b5c41b6c87a34f3caf0cef0d1603bf56feee1a58917699b3a8d5c4d1b77c2c0ddf358603ae509e696bc6f799302bdfcc54837378200d1ce92943fe776043b759fcf74970f646b65366a83b949250249821ae18a736f1305431d2e5eedaf5ebc192c99d274ab2ec608713756b297acbe1ec46d98002f5af765865e75676f17ad595c7a93cbc902c538ca59ee3f400ccf2fe6b5c10ba285d4f1c712ac1d6d2c3ed7e88a0bde28a1491dde634402ac80bad1b96eda454f26c534d8eb881c91b7dcaebd5fa07fff5f3a00fdefb96baebb8f977b8a4d51db823e88622d841352aa5295a8a47215bd26d2d8562cbeee849d133e956ac931c6d24d8bdd988fa32939a9c75467ed9cfb95523eac39b9722c74fc60e72cd5d78ec7dfb7d86fb9aee552f9e1688162f13115fe58c5a3f6d1e81ffd47053ba7aa2bc6fd13f62618edea0198789f01947454328f52b85fcc38e0f61b25ba6ccb80a186707efd2e93683ae768ce22199c735205f059efaf1d630a587265093e22e8c66fc8ac4646bffa28e936b938229f174be3c4e27c86ca98591cb72cd3c368c994d79d72d9f283d6fb99bb3479652e3b875914d970dd698d6a6eb6c6d939dde75cb11e7cbc22431e82b4ca99b59ec964998d6f11859346e21279ffb1a1afa89cb7e8999b90d9f691c8ed644aeac379d04d57d0cd55f2cb4ac453ab230f3f5c36240c45ed9c45df4c1281e489a81c4a0d55b567d7eb2b37911edb375417f59d4bb2c8ea08a6465c4f13b11cfb289b6fba8adc158d4c05d455683255bec58636a5ea2f97e8e55d8a6bf9290eaeaab164bc4c03a582379ad1c38ab4d1de922f821ab43d66a8e50bab44231b12069d949467113cc08e3019f9021ed30ee7c3002a8de20648ccd85e2b67d0a8d1f04082c5e05bc2e98981b30a6296d312eeaa9ffdb448cdb329ecc71f4bfa5923528dec4c8f6292d065dddd90a7d46cbf71df1a796f98d950d830219609e1b2a87baa9a30d605a6981dbe143edf3e45492f41dd266c0a86054a995d5c2b8813ee70177f4c217cb2a10ab58f3dba4540dfc368d0de54910b7d0060140cfe410e9d4b326fe761df61075540566d5c4c4f74442359f5bb70e854222d3ba9fc8c4647b81ad9eb69b0a2cbdbd909d353d5ab37df09d98f67c6b7a061b9e8b211de9dcdba40e8135eec3e1b257f0a0c6ddc9b687bc5feb39482bbd873cc2aae90c5cf32692a201973ab8726780238bd7b2edca41d9b280a448c489d7e5296fdf16bd2e070f1a9142060956a678e5e07a0ad1ebac04687581d9f1ac6af858eaae73a55df3ed74889d0822c8b3b86ce517be816abde658003c0e9b7317ec624368489b11513cf0e0a584fae12830aae65ffc52f8bea91221423502a3814408dfc71316c376768c18a9fffa0bae63ab3d7ffd1e915b644a3860f8321c501cbab069b3392fa106a71f0e119505528c3bf62fbde0ced3460ad92d7ed87b3c6e42c088bf0f39e639eb00ec2e4a4a38b84fbdc1ab725c2706d73d7a41f1a3f352150cd37182a47b52813ceb20ce4a93af41b7e525f24f4a54d0b1e0d229bb238c320a3907314f566abbeba3c724e763e041a9bd652c3a55cf9359ea565f01139121bcfdc0dc1921c53edb851168de62d3bbefac81284b96a885d574985fc307e55b2345d61dad43b4307e41944260e9c4121b1571eb01b688c50e5fe5e49d859f25e4374e0f348912248dc056b56cb74a33e534cd583f8af3b659a5f4749c30eaad1883823ba810fe976afb74c2c4b53a108ade0bf1f99174b831558666310f81c8344f0000155d837bf1e60b228418c14c39a710b3b0f31975ba5ace7b2e123424a746eb7e597518be449d22b6de15c7be82d7fd01803a3a8053febea4499bb770bbd054c2e7c270bd4514480ddaca809d1310ff0121410be39a97b41a3871f9794439cf08909411c6ced3290c3cb1d1052608c1f522d9c75288622132bf8bfe14bef0fa20c32e7da24c01628bff4751f7f0a82665b4f43e5b82c96228bd02a24a602513c8178727c307c74d3ccbee4a4af796a2d467038b89b8438ee4d1ab53e68759b169b9e20bd067155434f5c2fb9ac53e3d397bc6d12e73310d309b24615360287551133ab02c465efa2b3b22a70751bd290404899b78dd3b98e7ce9bbb45be4060d12deca540f9e652374e3b8611bdc1c60adf5c6c76cdc4b2148da16243fce69b50a50b2ba83d097ec2888126fadc2fe046a400e9127e2f8007be02ca969d562dc04be4d3fb1c632e591c24f3acf77d9c4f5e99875638a2cf5be2961e72154a22522ecd665ffc19884feb968f6f216ec410d77796cd48e33ebf3d77b7788a3f514540eae82c0a6cd8e0185d18d0907105c86ce1d44b599eb7115d27febfb5310dfd52cc2e02a0cb7e58e318c79e994ad786004eb3b1f523ca33d4465341968af631f1e02c3ac3460be7749fa6c7ce840e1f64e8c5cf596310c117515541f2f570ecc515411c27e28b52db717996fe6544e60ab1ccc9119052a067411dc8e9481d6dce1e5926cdeca9a780518b5fac5412063ac3ccc0be46feabdda6015301f18c91e6db445d20a0330225715301a58483b317551e812679863ab31a55600c734d0aa4e339d129cf97ecfe9fe7f602c271d6112d9f83efa596686e34723a35adfc68f045238d67bd4298ad5cc0137468f2579ccba1b00558d9efb7f257d8563341d1a1da2581510aafcb2dc25260260647444536606bbf07e437a6c476f0103c4ffc056aa2b7857e6619eafd0224ec3feeabe37ce3d8321292c6408b05d2145062bdebf13894afa72c60c76264ec9930e99a26f3d64e787b76bee103dae9763ff55eda634967625f240b788bc632fd9d7575e2f6aba24cda818b5cdaf1bd5744930e0b62c7af400b8d16af5224092020125c82a22889dd982e02fdd0b82422f135e3ef4420b0ec3065fcf045d59f91e86069abadaa689515b806bdc9987fdc7475b2f92c017241c9a3ea0170fa5c6b05098fdf0c8045c9e3113ff226239e43f34f231f2fd11f0373be5b96d43e59c7da20578a8da4869c95a44c90ebda7ac37d581404f25c54de01400d796f2e18c322e3cc9419b4ef5a2bb5ac9bfb0cf2ff67c3d329a551bbe7cc4e578ed0c95e684eab9e17c9ca75172503c91dd432960d6f638dc4ebd6d2360e48d3cc23da15e3e92a9edb9be80b0169780acbdab3a9ffa81ced3318ebb98083f17bc45f0c6594f4ae7eee75dfdc8f8b96b24cd207b29bcb9f954c5521ec6e0962e192c5364cd03ce60de1fa66d0b84b7d9bc069b66f5f79cc0af4aead4b85dc118741bba15fb21ba91bf0ca39e6eb634ac645e0fa02862bae8b4922ca91693495c085e0807d1b811bc053bc6c0e61633a1c89eee79893c79c2128504cc564fe88c4fc8809d7f7a28e494062ca026785dcfb64681901db2a745b389ce0f8503b043bf2e10cbc1fff723d4a22fe19d574b4543b72ae73580795686c74a171636053888d84713c60983bac7a3320dff764f06c948c941fb7456d2be01f29c58346b3361263733f003cb5dbf316074a40aa1ed7c62c5ab20058da06fc0f1ac826214564cf3343ee167b1d53930934421d6fdd703ac4f4e84457fb52946871ae077ed515c65870c1d6b5e6ee4e880ff384bdd9a651408df5104ba332c924c85158baffa6e2ed27bcd5bf5b47ac4baa5c9ecdf7290316f89a923c754e86043defd63355396208fb9239ddc65308a19d8f597ac13903cf3b6df33a8d3f853bc007f45376666ee6b65ad66af002389761bf02240a4b1f515d8cb27a6f03c625ee4cf9dc9909d6e0999f737cac88a8ba48f4becde299dd03bb9a7b761ceb554c76511964788412f0608e151359f6852b6915ce0d49abb018b9e10a4e6d83d3f72a2fff86c5f7cdfd83af78f91af0f46bd8d9dae9d48fd9a90f359bf2e93f57f1505ebbdd54a029e58f6e2ec23e07a603fd68356c11e0eb5f785a7ba23c87e8bc26f963d7caf718bad5f0e3d8d05e0c709f5f9281b0b3ae0107d59f6ecf9898c287e2b8961f6c06f7c3a760e90a50eb7b5ab6e0aec2fc1a4d8e2db89e9261934dadd3f19b85e61c4eae24d7191d2adb27898dc945136071057599976091492dde44dd2b86983e2537445494872e220fc9741a45360191a7f5b320a7b8bde8ba68b6139a4747611eb065c7fb6dadac758c97fd0d2ab1a8ef8604afff0fbc3a87d35462ec8fabd1cef0408096eb1c9631e00f0b1d9e2bf494a8fd85bd92237c445bb228278a7199faa86fe1973d2251693cfa28e7252dc56921a20d41f98c3750914257de52ce6ac24089c8406fea93152b9c79647918897e73130d4a1e172a6227c525a64e46595cfb6188abef9866dd12a2a57fd28081099c7d28f5594092c07fa83343f4307ad2eef66cc89cf1f7ae99b30b644d0da3780991aa9446e7243364d74dae8c320e3f848fe67730ec1ab7173f2e4f911c0eef7f6b48d3ca537885bb73e62f284fef7a480c406a69782f9c1318dabe8e154f51c6ac35a54279e941af408c12a24448d9062d6a3f0d077e482ca4c75cb14b1a8eff3af92636b274a8ec74e34999a4537d159b16610bdd345d4052bd9d3aa7178a0c15a55de2519e390eb729a60dfe9c5d5ed5ea56606c42c752cf0b603693828b9cb3a7bf412d59a046ed6393748d32c2e8d66e09a486cb9c9a81864aa8990495fb7e88b0717b65444c33b104d5d1919e1aa1ec2c14050d9180b9351677f10cdadc104aa90a96dea4ae64b94e5712ced02abd756a1f504c49c8a699a24314420610411df780dc9530171470eed253cfec5ab00b57b43edae673570ba708f20182cd29530dfb4a42c0c8631abf31a379e6043dd6d05859a39f0318b1e18aa047613f8139312abdc810228ca66e2c1ab776a6e4a02dd13cc8c7b3115221224993d406c32287de42160f3dd7cdf7e44cb7b25425b848337b14fa6081011b8c483db0acad2d01fe60533394b5de281b2d8c49682b5eb1420e6e45c7fc2c9150f6c154e97d7c89370ef7dada95fb3e5495d984c1d78899494971cc893003bcfa5834fbea2d2a378c6f17c80641b7302e48618e2a66215a3ecf8c46b26ae4489297cbe890878af1c4c44b8c0a3f689936d9fbe50e28862ed22788fe28086225931aaf6d9efa2b35a4bcd1654d0c866ae44cf32c0ec1f27678fe6e2837f52c6d89bde840f1defa46662c97955e3d79108c2b91c8478c491ac5b480c149da6e28d11a788cdd46cdaf29092480e1faa2107c58acd5e631170707271214a7833eeb814ce3e0d6b878af78106e446af5199291af829a9300c6e398c6b8a8a39238eca0f9533ac7e2fa84fd8843d906d839098a113404c665ae8c8571bcac4490b36a9d06f8aa31b61ef30b986682d3b0b915ec416434e3b8f9f90e63499dc4593b02c1c705e1d9563800f995145008280792e1e608b3dfeed25a587ea4a540314ffb6e0db7bd0560d65b7c9fcf942fe456a6b0b3a94fbc7ca761fe93d07ef53ae1ccf80c642a349df187d30eb749e0dc0bbaab4c98d6e0cf77f35e90ab447d2899ecd1223674f645477197d674c82733fb092fa2977034ec10e0bf7e0eded6c69e80033983d809ea720972f498dde67270abefa2830eea757f3124c5c8e907433664c35c2407c3d115a5164b28468ada6269690776fcbd1bcf905939ec48405569f21690635d97a0e2e1390240515525843a726bc50e77fbf7d3981097b8104e0a870f1fba2b897cfad373010f5699e22b6dbe7b4cc12eefccc85fedf2b7af33dc5abebb4bce4960b946f13f82d0907d703575d470eb035c66c3c54b5e77f486772301442aeeb881420d5fab9fca74e363933f6f0fc439d65fd81e4746e9e97ddbc5ef82f6e25905b703e014b2554e7fb0ce8d1b84a0c38753f89c046b2cb03575d2086a59b11203ecbd704b4abfa064f4c44bec269353a3a252447fc81ab032857da0c0cc040042df053f328104fd4df271f8c3fe226cd2e90296c9c22d6c9effd5e95fa34e5e2bad107dd200ce0852043ceb631ebdca2df1889f63ca59f4c439019517b3ce41a447d530e661748433093309296c723529c21480d8417bf0e07bea5cb48a7848c907a99ef922730042f6512dcf3cff6c889c079ae7fe8ab16b0cf2bfd0d85185cf1e32d1370fc593402b534ded39cee19d17f7ed2838dd9faf8c0d0224f83fbfec9f70598b78ec53955f9b1c9c261b1236897f386041b554a71536b963665e0e7a518c09e077b68d52bb15b8abe90296231519617a983a7cbe66c5a7381bf298342e81a560753a60db0327ea4ddbe7a4e29fa617489749bddd43f613799a1782e12535e8809640d0202fb589278d3606f8a135e2c19106a72a85420171b45b6314d0241bb1e51779c7f929c80cca7001f83b0e659428b59bd355faea16433a27bb22cd0c76d524f3aa9b825c9386b2bd474b29b0afb59ab05426913ef47a9b915d0cd328f130af141e98674dd7e2422e19710d36a371f5aba743f60c51fa92432b90b0848ab2d8f6a27bd20382e75cd0fab6abc7766a691a1138643c4d3bf1497c037d17174f445fe764a02e812f7f22f9c55a1109f40528a0cbf248ba749ba1ecf7f4100b3b74ab9cffc6934eaee6137cb71f142acdc673f33212694df6d142b24c7f94d058aafb560b66811ca3d8814a05c75e926e5cd587d7284c9ca42706704f18f48a579ee7e85d13f7b94aa25fccf876cbd080026f1359063f2e1d889f763d94d75417c0338e98d51e8ab6d1867a60c1c5fceb6c4505f3a926b6c9ac1d686f757347d928c996eca7f8148871da59f440a2fa1610cfa41ff3d128358556df00aedc124a891f4890cc59765a91c6c6477de6f9117d4038788cc9f6950b29673db5c1e530700b9f414356a5523d3aa807e110610579f88bf95a7b64b3f927780ccf078b968a81209eb2a90c7350de29fa30d200c0392cc7e8674e68051b326ffeb6949a0023155f40f33eb478801896304b974b8c3f81138f05e3efe5a1eb1d6538770b021816f8dabd2d0db397d913f68927b412c2caeb067e255c0c8bc3ca74dae9c6db9329702aa6bbb2a5c8ca40e1a83fbaea22c0dcd0816a8a2bcc9ad76fd8a7850df4ee1113f5ac0005562fc3283962ede07e341a725140bd2926b6434b9429f58e9c8d81f0c13578c8f171792502e8da59c1c5b624677633141da622400010053286f19829698a55ff459064d2b2c625d38a87fc39196901a5ca98155fd49cb8fe228ddfdef92143f57dfecb98f70b2073ac83056114115edb943f6687f1924aa0d419ee1f1889ca3100589fc13b4f73a79fdaf1be8b2fe37697c441e0093eec712c3d2b85df82d272d7990c9f95c55135df7e175900e142bd66a2a9da65bcf959bc9f663204e0a53f036bfc9f810bb6299422f461ba20a7a6568653204f85f588941246c785d5a7567a24dcbc98f4a42f196e7cefe23d6a4e21dd01b2a5ef5511077cdb87188737e5c634bb29428923504a2c66a5b20a4d2569e5a5e8d251e981fa208ab92c5f67d1823c131f6c0f95abe781eb62db4889947b55b6262f5fadd86e92efb19d808c4fe55a6d52e3e1917ee5190ac0036ff71b7033e58f0866076e0af5a4f7d1f24b3dec1621dbce87491db32595b91d223671473d26907785f5b3e6fb0c476702015f4d57e71fac60d622c21eb60c38a56b7a838224d197adb6fb9c5ca4314314c996af8a30db266ba4726f657449f559f43e7dfc44412f76d02a70e7c3d1b7de8bea0552c705520d38b511f224aaba4358fbba7b41df956ca370c34a335309ac5d9b58c2ec2d7a4655ac630a01efe44e3d803044465af6adc062433a9908f695b93904cc69b76ba1ecaf9bab1eb35deb656b711dfae940750bb466c598241ef13a3471033b8b136a61d07303e10565d540e4ca440c9d48886bdd5c571524ba0570c78163c066867a68673fa4d63a566bc1adf5375c5de99138c1ff87ac3279b8e1e98000545a61be0c36d44b1661a16a9ed7c7e210f303038d77fc89879d03de5622220c2fc51040ab0b34d844cb0bad9b0702ac66ab45105cd326c34f45a4ac92456cf349322844c078fc3a16f180ed42b53abd388e21edd784f370adf3110f6cb1cbc50fde71e6ae0fe43686cc6cce5373340d68371b1c95b9c7fe9859a8cac1efdc60f2535b019b3d77102a0bb6c6ac6a76919f7da7801678c27d6e3371c214640f6c98122cc21489a06532fe817db33f586381e8ce74e15faf1314b5ea99a45d8945aa6ce69c65444526bdce522b7ae38cd986e609b908ffaa3b25f61ca15a1f0f25f84cc18434cea660f1d0091dd24d18cb9539aee42629d72823e2a55cacdbb347370d6d4baaade16181c35946e3ced44d3891e4f2bcf7c27da3c0809857443d205d1588f8179878c61c153088126a6c76cc6685de2146df049ac66873a7a009b0341869a31cde3467247ccc760887b321ac4e6e92155745162f4e32525476b60a45590ae8bd83c28d3f4a91466f64b090b779f70ce125742fa51045bb311cfc92b6b12c603ee2ea06785a015e18777a4721174bae2de948ef530883abab1cd680c75059836264f8850e7051d0f654824230ca79616597d20ed89d252e4c0bbdd0630df6f00d1f24a90c4093c9ed0fb8f28f3113491c09a165892adb761f4ad8a4c54e6b166a43c95f470bc4f1690656934cf978385f44872fd23117a49ae4a8391f742f68b53d5be4730756fcfc73b6c323a13163a4777522178c3f97fcf0539b8f5eabacbe1a35fd1d18ccd21687eca49afdd9ba0cb246e92a28d955333c3e245d83a48d3fad394cc3b8f09944fc715c395e4b84548c1f3bc72f09033ef8c79248cc0368dba199d7311db1a2fc240909d63898e40c2b1528d46e6a604fc60bba7868576f9719adf92bb9618e848cadcdf862a4fe080683071fb03669adc2a4e93cb6434a52ad954e38c52a0758610669f653ea1827c539598341825aa344da76f8f28fef013227b820e8aafff3b155cdb4da9b866117eab93e08d368cc79211a2b1e57aaf10352765da92529bdbe880de53ad6efe638586227e2e9bcb0c82d720878c5d64f977f4c5947f8646ba2fa4b825c10700a411f8c0943c0a294537c119c5696dc75283a9f15792c40507addf4a32ef763a730e5026139baef8414f186b146f150d94b40e0f9467157e385264ebadc84034f5556e6c1fb5cf4b1dcdb3e5efa51f237e040a75772de7acc6eb5c6074c575e344fa0fac34eb37e5791a90c8000f2b5736296651a05f4c5fd63bcfac7810d8594a2f8b06b359f8827d35590bfb1b5250e0b828968b2a338fdfd33ba7cff478627064cb38f34725fe939e1afda5a7f197de8d5f7a357ed2dbf8498fc62fbd1a3fe9ddf8a477e32b3dddb865e6263ae32fcac35cd3edf149cb5976bb5547c1b9aae9b122c9764c9c4ba3096751b757919f46b5c273bbdbe952d6ca7735f7d32ef8148c944394ba4f9c5c0619b7d440e8ef2a938874305e0818de24bfa7988b77bcbd4cf7cf40f418dca344bccddd73469aaadc600240b6ed9eba6dfded90d011871db0473764efbd6b65ac1ca1aeb5bfa05dfdffd728f46e03e0f1dfc1d52c4cccd11804630b397e886c2fbc8292926325274470aa2789c41040b0127ec7049442e9e52fb00b2978e0f464bca5ee1f0cfa191256515ed62a9f6c834365f6e67e4bd3f7fa1cdd4a62feff89d7b07c0223e0db0662055450c67c2188f8a659457c35603667fb219b3ef1d4a0207a52756a1481d50918bb73fa43959d208f1d3c364a98d6661a2560233f9e637c9c9ca29dd8413ea4281f34e6a89b76de5e929d63b685f10133cf71dac09038e0a925e5693e9c973ed516cee4c714fed62262e56e918ee2b262db877c53ee40b99af6cc84043b9357f0f5736d8b9bec414fce21adde68e0af1a525be1322e01f73d08f4407767c9072ef457af6085856ce4188c5027f3244dca6730a707629f23ea7f0a18f2515bf5d993bdd9387dfec591c85321fe6d8c1c5df0774facecb62f03f0e0475428a17d3ea67db03a725965fa30f01a7c18f1dee468e6cbd79e71edf42ce65abe05f5b781216de429de5d5b197eba808e61aacffed3a469eaaa1c9480ded2630f561fbebf89131fc766bf545dcea9035593782a40760e46399e14a1c0a5fb1efd49d8cd7b32bb226d052a949808bca821e3eec8f71c04d359677a1c81a4813c661a7069891b8d7c0a49d12ec1440b52a742268bd1e9f300c4063053c9807666a13060822c81c7c1201819e13f67c42e7c712612062ab010c503a82c14023e2fd3d795b6e178f9fbf629edeeae0550adb38e178805835d87f4f2bb649ba1255f041b6086bc011626c05cf3f61a2248a667a2ef330153521326a6958a89b55ddc9f1acc0d8d4da8bc746517dbb05ef85ae238f0b163727df9328236427517ddd95d371d7560d183db7c11641175d31970d533a2fdabc8b17c05caf73280c9ad2e9e34bea4b81b7045f8e2d9963c5aaba5d7a99bb87e2a68ca8bf523bcff995466a254f8deaf47bda8c37e89adf9204eeb8223c93ea6a5956c984619aef4065cd2cb06d453a4651596e31812a15c5b8119d880d20217f559e3a77fefd298051ef1929bac062dc240a025400fa2f73e6e6fa9bb879966503cc09a23a1a916738872cea33068d71c3b0d05ad2077e0d59f8c94e7ef9bd6b47046000a2f09420177ac309f75bfe420bac9fc7cdb10d68a89928f06a38e1a4b7f35a84b7d31cab1748ff6cfb99fc07cb63987a29b7b4a6fd4943e7f24f32524462a2cfe6c895114ba705c06db285077cd1e83196c891e932ca059107924156e4e33b96835f8198f165631e335088f5253fdc33bad0f8cbbfcef459203a25744dc4a749cf79e88ee65b90e7de9436441c38646a4087a7a7d409fa8b20c211cce0e4e099610594e2abf19c2af69541da41a555836d066c11729b213f8001bc896a03393a2330e5ea2cda06ce10eecb709b254a3de461ae25f028808d66a6247e261fd2676c27f429eaa3ab91f4e2e67cd1b65961983bca549172bd8cf852e670a889fc2992e6eb160b72e9ba011fd71ca72275d9044a2323d2dbead4eb84e25d16c902d2792e41e5f62c1eec190abfff02b663f366d5af4200c03a519008b1a3ed2bb27551a0728ca56b5f6fe24b99a1f3c44dfe5025f182661a642c1ac1defaa5c521bbbb4694b37bac8aeb4c15642a594e838df0b3f3cad482a24e328b63955d3bfa47446334875e21431e94a724dea1c09396369adca53e656bf99e43af67418e24bb7249d3ae8f3ec59baae491ec67cf5b6f222cab227a626b8f75e89bef67dcff99c93d0c03d245e5be0f4e4a84540df6e52eec8ba59e98ab76779c700611d75a0e77ddc6704d47aa92290a3cf66dba7cf14c82ea66a95d193fc44709e0186826e61ad5fc17c4240becfbf81446b771386e073a59683ec60986aac82f702b4d0329ba0e489894f2bdab40815adb2d4b822742456f5291a4d06cd1367359c7c4c00fa7af15ec3a433962a87b1375ea2a18df9087ac0698c2baf9299e0956205d3d1fa0f808ece93b8223805cfde0a8bd635e74b63a84d12580c8411942dbe11f031ef374003eb7c30323541a81018a7a9ca4910772b6f8825afd5c3ac0d6474a9a09d4581627a27534397b65449013095ffdfeab251cca624df67d8272e957a3f6f5631ef09e8dbc8b75efee9032c57b999425cc81b2eb14d25409fd42dfa0d368a4a27500a9d0053973bf39aec3c6c7e892578136b1f9ca5f789a5037347714910e18a0f091d55616a7095e11e515efb6cb9161bd5e7f586153a996208b69e84753ba88696394522dadb1969f438bbc7218d5759759a0bdfe8525f1adbf5af318ec25474a9574b5ccb76be20111cd846686a4ab6393da5706c1d5d0b3b4b2c41cb66767478c9ed143b68e06667295fd35721913f2305f1f25d73d476e81acab751e1b729b1a4941cb30d0a82246e636a06cb78f3d9a565b754a6ed3e9a29ad73e5320f2a2050259757bd7f94027d6d18ce208a319114ae8b89e2356825c369a3e484a499c4a285feab50fea39d9a1dfbf9cd98df9ae01828b53d908f50a639228474d32808813cd02633cc9d9cf2b4eacff366b07d5782aa3866a28d53a4a5c99c0480c5bc366609d670aab351403e84415ab892367c77dacad0c4e34aea6c644b9e66871a0d181979946212a50de910cfa4a55cc7f3db1cc83154296bb666a42c20b6c3506b42ff48e7e53cfa74188b35ec2df0f33c9f997d9a5a8cc414314b9966590b51c8354ac4aee97436e1eefb36fc1b5c1c0c5412f64ffa861297cc8aa8b243cb2b29d64f84950c98ab5a9531e84792d026b121768a642e53493387262ccd1f464e60558aed7486b241e78670dde278e97391547dbe311128d5c1d457697a185f6eb467f6b4095e3da19dc64276c29ae36169237e2074e4ee53f15ad8171c264278f8fda0197b3ba8a28e4770e6197a18cc89162cafba8a71a1d78db96a9766534db97d4a1c6ddbfcd05949f0de005835404be3006906444392995f06c229c9c86f7f7f40f4888260bcc0c7bfc8de59154b8c1626534245727ada2c3a0bca73107ff3e0990d77affda0f0ee1d39ab8c957d39dbbdfd019c099be7fda2e5497408931e5fdd30ffdcef4999283b518252b0a0c40158fcb0025acb5b4623d33903809ec672911c27eabf14b0daef031fd72e724c8f689b00662f8e281f91be76901d00998a945abc69cb6ea1875399e927f17bea84c9d42054215a7bbee56f72d206f1e08ec44f4edeb55fe1d2ee0001ec9e166a35c6afd57872a35dcb7774c885ddd9142f1fcdf4e6880de54c6795dac32a145a172c29d5e4f0f39f03a3d346c4a40626467589596096c36cd43ae5bab0f1c5a9d1cdecf045de4435019efb62bd96cfbbd05825bb7bab7f3cc12c4321c7fa43c9d3673a29c9de202b5ee553c4274c37b2ffaf564fc37ada49a4c61c4e5121c30df69cfcd98ef1f9bfa82302cf6d919d1b1e1ff3c449440f247c9ddbe6183f172c76a7d024f1e91c09a238be09826a3a9d45d7d2f39937004c70806c31b94f27817a515ffe94e77b01d628827ce09d20a5e0929b1f7a37fcceaa3b44a2018a6b60d7001848116b7005a241be0cf84ac520067385d51527d736060a129489fed463b88dd3721bb7e9582eebb45dd3691c86d33a2d8d39699deed3e91445a10b00be4d10750832a1dd77309dfbd92db174cd63551b6108c33a82a550b788d1c60726540362ad5cadd63975fbddcecb271b89d3e9f53b93d9b11df6df80887cf923d74292af85f56ce20a9d6616e62465169ce3c9bcebfee5e68c06c120d315700e111bba7f4444bd52a87adc0856b87e77f85d8888a19849bb02910b89a3e4580e515533d67cd2a1c5fff4eb4f38da001c1707d8eaaec1944a3d3e2d4d2d38b42b37a13a870a16b3401d8abc4313f428e1c86abc8d02393c85101ec3696161067de3a546553255af5b4ded7a11e68a5c4d0ca8d49e94e184a591c4c22fd4ea855c41ff5e845538bf4f4c4c20458dc0d9f546d7f7fe40c4106906575a3bb87cabf264ce40a82e88119f54b5be148d3037d89eb1cb3f11e0d35434994069328bba49fff454967e221c92c368fef0a35e59346ad312b6fdb2de77fba572b6ebe682e6087235da10fe57e863ea742df03c42235c778b2ed2c7237f49364030af6a8a827468509ca8a7d48d21142008f60e10acee23108b19803582d6d707d4f3312c974322b8ace1b2c329f21140facfad5b26825ddd69da600179ae180dddf22e6afe5331d5ec7d5b21dd862bb947a91dd32ce50ca2949f23dd4f96ff49c16150e6a8023669751a3b6508fb5c85ba160f1ea4862009ca4a42b9daf635e5f6b6385ecdf9a771f7cddb2d541c327a137df088a0676f850c6d69959a4dd1e0a162d30921e3681ba4c08829108b29f8ca1c8760baa9b5acb4e7b41dd8015709da95e098201e9d8bcc27c65e1014c9b23233690f4662d0450eefd08776bcb10a0649f15f594c8b1ba5500c3fb1625750621c64bab86dc7129ef84571e3e804dd7a11f10f4cfa19a1354b8c07995bc390749dfcb16b6c20fa8af41fcd980f529c2e03d43b9c129df4cae835d6e2ad7e8bc843b9a079c06195a2245812d3a51eeb4cf8a3ef3e21c2e98fa3f360d05ba9ae48057a570d5be494ead02a2a56d13d2abc7d9f40ae719d6904b224c3eb6c2495e241d7f89efa479707a7150a746a11cd3c74e8a15020ae356107f9ff0b5dbb3ff394b7ec1412d69283c8a72955258d0baa6a26ebed3e9367fb9de43ca043b24329a9298afa393278f43a4bca22870cd5eba0d9245e6a2a7bad66d83aaec808948b1ded4b30c66a08b0a4506a09d23e0c47ebb0eaf481176ec3a9a67a264798eb7255c7c28428e08d9a39ab1f1d62661252c1d8fdc64b849818fc6b97db7b7b9e810670184bc3721c61ba46bb60fd2a878a1524431628e0362bda3e406e9f8a98d5e18eb83b59012ea7c4c2c22478672738373b4434947e6d3a31b14d58fc8ca045b1d3369aa885be489853eab819d086fbdb7328477267dfb846c08cc2c5a6004f96fbc9c809903830d821cb55f7721b23b5fb576b30ed0ed15cb69ab7a582fe87a828d8e4b5355ec1ec991b29adb8b9cdb0fbdef72d683128e220d59f359897db3ccad708c2f6c59d95b9fee095fe80f66a72e679f77d8861d6a4eb4eed1fc22c7929b851e7c56c35492d4956985b7bb2a396004233a84e9e669605797559345ea64116a1b2617195d1df2aad79950dc328435ba213e7e54ef66c8fb3a13afb02d437608e7348fcf885eb896fdd2589f9ad744f096f529351e078cdaaf902c73cb22c7cf1e61c8634777df8e84cef4960d3b650f45c64efa46a85285a77712a2ba0bc07980c75c0f62cc82019226821c835385500e2617d28574da8c4c4f76a1cd197016d9c270f832045335d497c76916ef53348d9e11733c27c0e0c20fc41539d35a636d1a79ef5a2811d083bd345a09073341bb52f851c07beec9d13c2d1adcae6c45c27e035c7044989ec9cf5314ea9ce5e11fb95e5825288840951ad94b22ba66647abcc9f14c83e681f06bd39c356c9880c6dc32dc06bdd1ca4388216d16548daa10e057b62de814f5cfd1789366c9f3f6bb7ab78f6342f5b592ac0c345fa455b3d42a163667f84899dbcfa6f4fe41fe11b6c8f152b9f23a5b3b2c3105e523e02377716090e0ec642dd8448d7113915a0176f668290475e99bafeb6aeecf22470f70f9880bc2fc8e7198e33f66127b92cdf01816483b541460a7ea48466782b29edb10f814e9017fd9195fe2336c297db76d3f34a7e27f6fd3676af0b6fbdcfaf3da4c9c6442acbfe9baebe79db8f4738bcb0ef904ca1204b8100b5a83cc654b901d8bc21e292ad3c4730561c8e9c6dad5a6e1c05c5426a9a29440f7f52c577f75dab3216b058dd308c6af04b28d58aecc9d5f91f738623f118264972ec41ca1a435607a4dfb6d65b14c01339f2a57727ee754b19f7356755f8c4e96ab842ea55c2d125ef7dc3b7287c56da147dd68a7fd40d30423bf8c54e76b32e0b75d7b8d6dbec1b8c524f4aaa0c67a18d6b0f3725638c6c7cba0af62156b6627fd722951f81ac37c5b667d9ab7a1d10376381087bb2a5ac9fe144137cf54c002d43db153a1ab7e0f28046f8356b50fb34fdbe1212be6a06df3c3405e34a09aa6116076836d6ef7b98d608f0bec3437e3ebc57676348a2f3a90e2e2332ff74616f314a6c23764f549a6a4216f314b191a096fdcd3006f18f73a0e4143d017cbc2b84a1adc2cf4f606c109b3849afdfdc5aa085406904b2ca041dee3b8240dc4fe99a1b549c830d884043caa7ef923d5f08ef42be68fe7e4abe63309a517cc21053b1bba967842434278785b3491b917acaa513c2e7210f6a1eadfd9d5cf3de5375069047b92e857cd32ca7aca5d416535cfffb23413f44a316a58c1db78067e5e84a1df30c61cce7f42c27124c80a1bd60670a5768cce3666252b420aba71a81480e23efe74b1444e53580e913f4eb8072544472e9075bbee8ad34e8d01faf05f7110bde67443d5dce9673db85d8373e8bb48008c87a9148d90fd975652f52bddb5045d9e657c4492c35d60bd347de1eb2d51de012c30d5ebb80397bb14ff0bb8c39ce4197d0813886dea4b3b49e36b0ee58eae9923e2256485ce2954b3109169f5f3d9057dc3f84c58dc78548b969772eea441627046b875c97f9e4c024a0bac05f9a3eeade11ec0961833683b6bba7918ba9a9f9ebfc7bf675f632f33a7f599b88cf8a0cc8b0de1e6562e7a9615b2638abd4ff7e841189b0c114e174210a6ed0c7f15668c2048ff4e285ce4e2c97626b22572725870dff9380b2cd46c66c3b5a050ea393b5fc980f1ea4062c229cb1c80accaf69d5180268d0566e55aab794c8e9beac30e120eba7ec2701c884c3bf75a71c7a1bde77bd6d333dd890f29bface5ee7f772bd45638863d4519367a9d303e0ee6c3ed84197ba06b93aa76d10d9534a791f05a789873fc49cf4436c58e3906998e9a64f20a30daeec5795f0733963f6ee3fc3c0eebe6796483be33b1c0bd797a73feeb58d3ede8f5c1af4175bc147ae8dd1ec4a0352937c4891bb291fad52cd12bfca344cd0b2f571801d2e3af048efe73f28c5a066b19fc71fdafdffd938739c14825f613b6dee232d347082e854227bbf324e240a3085070a2b2cb3861fe873ae7ca72f71d74f65f06f39a4042e0d84c530b93415a5043ebfe2e52b28c16e9ade4df4ae082ba2e05414d363d1eccd44ce5487ab0167f9d292d1ad0d10b0318f5dc494adb4a913d4d0c11405b7505c2916e321f2bade891a51f22cb522cab1156d8483ebdaca96e0cb0b622f6f2eea0a57c3e64a9224ae9286d1f0eebe5525e0085d1c93a49761026ac6d8f004883e9e8714ba3301c074cb7b9317d073125570a1ae946858a98bb14f4f701486e295df7765b4870284a7bec251ad65ca8777abf03f7eff035e11df53116f8f8e2ca1717e68a2a2e317e89a43a0973aabd16ca701f4416cf9e24f71c95b76b1ec07a546ce83e967e1c5883d0b480e3e3ba09323ed9340a8e28deb8b10432e9360440c412b545782bd2b88f62a63c67e0874db38110c8406a3cb3c9c43b4b19c7a77ec98a27387d073b91eecaaa45569108c34368521fee05651e07f13445e7028c9308d1fd4ee80e593c591b6208328286c533ea989709f3ea0270118261292f02be8481c784187ae0b30a7dbcc88d70baea262b96325cfc767cde58c81cd8724726625ec7ba748ff731a198b27093f8a6d9113bfa3c54355a9160e9171d328a16c0b041553bc5cabfe26184ff012257603d563df3647c0150e68aff8cecec54c38ee2206f48a0916e93f5e1aaa07b871c398e024ae856ec00ea45b9b56dae194c779ae229bf54faab09f4123446950a34e71cbcae5c8b456b32e9cd170a58e5450e60edc0e80708d18382d820f889971c7516e6c5122173c871a5ecd05caac1161204870cf9b8d8996ff8f4a1fe992b4ceb436fd40d7a8eea705d23b06de4ac35f87f91824c0ec2cd70c8d939c08032b9e3097dcf8cb8c61476cb5cd2527621969503da51297c8b8041c1fa762676852dc24c0d9568f5f893f2313279ed04cf29992b3f3e9878076effab9beb77def2fe1f11e9d059755186897f80799942c1dee754d6e68b4176f2f2bfa0df721855425aa482a2455c95528c040552dfdb2506e7e1351299b6c27c30347f683f8a37244113f43e6f8995a43a6d4041ec167c91f12560cb219a9ca17e24f9c8ecff827b58199b9fd0b5d182ff2126b944610bc5dae1fd0f1d57d4ed33465684363302217784f266af3b2deecf64cb5e8a73b1e84b614a82f22cc788d8086df3adebaf72d92a74c8d09a61d8d7407af31e258525159f7c1120f7388c83d89012cc2b7aa0324d1d029e07162f5a84aa4f30a2bad35dd9ed60e7fae2750604b31372bc5280f25778e9e850d9d4a724339aea47a72ffe3c1be949d8ebccbd836a4b663f6b4c8d7820c8a6a4a39b613ed6af48f26a4aece81f2a2cadf0f72bc70dd421809272db0689d19625fabdaa143686e9952080778572483e08efe5df8a0d0988333b5bd399d9850355caf0dc75b4c9ef6ed152befff73cf9b0511a41624363b9c2de28caa9265ab40a76b011877ee465e6883f308a58a9125f064b403dbf14384211aa62ee306bbfa243c1e142f67911ad1f8d565d48bf9f87c15ff97e9d306e4c6dfe1e3804c5d6bd40b24668b69cf2cb81fdc44a2301c07039655f7acceac0a4104caf6735f126f06e25725953faf92acc296926adc41a038ed5a4a0395e2973368d03680f2e56d2943180ad5cc21cfcc221643e0e0ea8cd0b852ea4c1aeff398ca5a320fb38db0595a5d8265eaab3344efaddd4c36674ba38b5ca2d3ad3089476ac2cdbf8dd4fb6b8c47730237e497123425fd2ce32343085d55a9ee4ce903b8ee63b050412a37109b8c790e4d7f18628cfaab0c51f5c01f8402db3a793f693ccaf76166e5cd1bbb1c943d521301b5c2a9c84c9c4bbc5acad6270932928cb41735c7d2b6d6c4629ae60b0ff2790c49fc31648a100b45c3ed87c7952031c38e7fe69f2cf68183045d882cc5f3793490017d8b0d36a6ee19034a2e06554eb7834c4e9069ff0da055dea246cce93cd9a19c74634bf41e9599c5d8870929a80193874e7a25fea66804b7095da4d351f7bfc04cfb828f34c3e8e650333ab8bf44b16d09761c5c8f4d2ef0341d86846b3cf64bf0b8bc3ef8384530a04fd3ce7e878539c66f1bd4b8cdda78a9505e068bce52245546292cd7d42f5d25b5725d2deed7e0d25a618acd84ebe9727eb614a2dc5fe775e576304d0f7d83e3e9b147121d6248833af463f8ae5fff2980eabad83a5ead2db194db2b3bc2cf7e8ca43fd0eff714cbba51cc15ee5f2c227d141db036efd425a9b82590de0598a00dd7aa22f2e55a9bb6455f11b3f7e6eca4ba7dcee062b35870f09bdfcba64a353bb8c66c519fa9d8ebf29d1d84480a9744d711a3dd292821b5ab997fb391170941cb6c03295cf90b39f59ad00b43cfe43e1d7b2142f1a02de4882e74ed60c7a51159f42afd7b2513d83814768bf4b2d74a7aead3d0c01d9b60b032a28a5e97e8efaddb1e7814761f4d7f1ceaeb34ee040aeb03bb55309ed5241dbf2d916c810205803a49e2f43b46315206d7c4b72d41226b1b410b2a7045406e060c22daeffee673954a8b3d2b70e8c7c5231889da16563e7501e7477bc163debe8a7e6bad6d4236d9841042f6de52ee780b9f0bb50befed5a5a83a7aacb5bcb017d92dd9c851608aa580221a433a0ef10bea7c00b7e52d0be33417777431b38c8ef02d2b594806e94638c314210c02702085b96703b6c905d1d2869b86ece64973a73a10674a3f73d20084d628c3142182928d2c1d07775375797d6628fa4eea9bb5d5a8bad69ad45789dbb39edd483992ed923d04037ea3a26374a354a9f2e5726e64b97f66266623c05064db246b897a884f69944966050454e8c31c618638c8f31c618638c31c618638c31c6c811c618e319c638030a1f63b48937d21c93044147cb5c8ba4824029eac5dc7037e003e09470c35101b89000aee18bf1628917a3695e40e785d69aeb016cae8b4d6bc04ca2ed045a5b224ee1601ce5186374324a10c6ca06ea9a208692cb871d3972e4c8134a34d078a6715e74b813aeb0b94e8b9c2a2ecc755a0021c93d8cb9fac6a4a4a0d45b896c217c08e87bbb16c861f463ec378db8e37e947392aff7013ac5957eea8a0ff58806c3c6719a1bf188830a9ce6eef6a6eba66b898f05b292cecaeabab94670d95c23b86eae9b7b6171dd5c37f1c5f71e637c2fc618a91a2315e3a9c679efc5cad74d2c7960e24c13cc1b374d307126ce9d3a77e2b4061bc82425acb37bba5da41fe44b3488f052461fef6d5140f907dbdcad66922ce8e600d5a3e626982758c166eea6a8464194588a528c51ea47bb5df0758f009200de3ab3cc489f5e2456efd9836f655966ac57f7615917925dcb569608bcd58564b7b2772f72e104026f59220c845f59227cfb3cde54c3cc051898087bf4c0a0c2a01ce53aed6683714360a7206e2a150bf5217c374aaa8f0dee25be27ee25be572ea67128b743baa83a8713e31be7894494de270f4ab579eedb54de934b32bc9bf3590a7a2418f87888f7f8d706b7230e2e463efeb9c18daec7ec6eef89f56dc6f49edcf8ab3ea74d97757237a6bfea5c8ee9d68c3bbdcaee74f92e49fa4a6c95fb3c2d9a4b8fa4c3dca93ea9c7af75ae255a9ad884a9364807036311695efeebcaf2a3ddad310a75341290be5e73e05dd709a83bc543f0858792dde06599794f0c19ec7901e98627c2bc02e95a5a8231d2f08b5128909703fa7a09d2b574b72c036de2c5b8279ebcf7b408b92b7c130ae0ebec131726e1c840dd83f1e10eed23c329ae11dfd3ee6fd31a29d7cdebbe45e876b8dff79e32f0f140470e51dc7808dd9c81468cdcea5ca9312e14e3c2334f3df8cf4d24e229eb587ef0e3d952175a21d975b7c8c47c041d102c0156086300c6ddae5b13390b244a902841b2e4b5118ec2c47def2b88e8be8ee2ba284fae806271dd5740fb1b5f71dd5dd23777ab996e6cd185efc9234aa6b8ba2f5540ed16a40f9fd5f156d0af3292a702ba399deb9c4e24c22445f81ac2259ce0e68a5a631de980188ddcdd65863782054e6abaafebe12ee48de1587ef4ddfbce081674e1de8eb1a064652b380704c256bc4b0acbce560091d7638560f242b8c1db6c45642b2c869d5e56ab6ed7b5e0b9ba6fbe7faeb3153c049cd80a0f5b711b650aa8f58d32b9f23c1e0673272c3698db57dcc90aced1e7d16cc5153de24f920394afa02c49214514060642d810761018e804291d33b36376ccd6c975adc1d61cbf307c71b9b87dcee2f2a72a2e7fd202177787ebb4d0421577abe1db971225419ece351eb65cc9ba45e3d6886e7c0dbcd2a59ba4ca75cb2a062b755dc79e710ffefc347bf0abbbb36e452ecb0fbed71022f0b2851389e9cc6c1df5379198b6698afb607f72140dbf4fd98d4f5d521365c581f65d1197d6583275ea4d4d561c28fc5403e3a589925c74504876d9bd30ac4530ae4a209d6c07b82cb828dc025cf701b8189884abcdc585ae835170393a0a509404b38d6371709abc26341a792f1a79d1887b79ff9c476bbf4884c1378e7c15be6a2452b4d6f05585544b7131bbbd23535481822c2ec7e03a259c208c2b6575f17cafaa877ae805ba3b33333bee41f40aa76ff4abaaaaaac3ea22114529e8f472ca503769765afb56ef3d8f64eaa19ef7085f3f0cd677b1ba51764be26e585555afaadeabaad9035e082dd723cf555578e9dc8eadba25a757ef564bd13843a26d9cd65aae15072adf47aab4149e5e56b5ef0fecca99eccacbc7ceaa92afc7d257f6555596997737286ee8f2958f47bf4beb465dcf2d0fe8c332f3eefbbbcf6e505cfaea738a9dd27b90a04a30c1cea5d713fa7cb0ecd58df97a2690eaaffa7bf455cdb03943ab948b5678899832f4d99479ef55c72eabec557d5885d5e9b452d9ab2c11d4936534a39688d63865cac05ab4d63c9618746b9c3ed2a3cd73d0fb8da447349e7fdc8ed0fb8d02d03dd704f2f9783ebfd4be35cfb37f2a8de7f4d6fc819dbe9a331e4bdfe58ceb03f7fa46dd238d2302be6fcebcc946233da2efc728a28ddb3167deab4b5a5544f87a0e956434f4d58cf9832f2545174f24b057d59ca1afeea6a39acc5b3d85aa71abf770aba6ae0f113df258cfe9e7f4d394f97cfad094cb941a0281424f0949223e92ca00812e65d4947f6a7c887e522e2385881e51cb07d5d05d8f40a740353e4469a84e0755aab5f78117ce1fd9f55c7eea759570822fae43c3754a3001942b572e0b0addf8b25c927a9fea7935bdaad45ff5fce3b18ee559ac3ebb9ba64c7c565f75d3b14a9d65ca5496881abe34a2d6de69d488d8bb92fb35b66de086aaeb99a418aad1ec6a408c52afc6dd1a87bfb88d93c4dd82c0dc9752e195c238b090ae6593bcb8f09a76e263285ae9a07f6a8ce25ea43f6631ca9831d989a37dfdc20edf212af9e23a2a5ca785121c971e5e2e07448ecbb9dbc3874b373417eea1a50795f7705d140e1b73e672699933574b6b94d61af5e8725d8f972e631592ddeb95af8df132882b461bf136461b31c61cb14a986863b4b1b5c4ebd7751e789832d7755dd715af6b8a3156e75e6a4c206f3a0fb3c7f419973057db882e1249a24b25352694a426528e94b4e084c6599af4888b1e39a1317fbc4f5751b11bdfad87ab5ccaa2471bf51a972e31912ee9c820e60fbe2b52888b27123b7c629933d4276daaaf2ee7c5f04e767af73ccf2611445c9ffee92a53e657f924e3776e070fdfa6d74b1f2b9f56525eaba835ae55c65fab4f9587af54446cbf8d4b87487a44f3db4b87386e47bd748802b763ba90ccc65f6be53bd94f933d8faed55d47846f8b6511c2379e08bcd38564342e8d4f13c8fb6489300a6876ab5b62d00de2481c2a6d2c3efc36ae229a406c0bcb0f1fdec37bb80faee5f636cea3b9874f9f719712f2d0f89e33f1f64d217c5b1e2bec115f1a8fd3470f8f97b1fef01f78b8ae7a1bbfaeebfdcf04625f2d11be2df74c20ef9725c2f7768b9f7eb02c3f7ab80ff7a1074bd352c3d75a9affb251b7bfc6b1eb73cefc1aede8612f49d7894022f00a1192dd68cfc361269077b644f85e76933e3dc704f247bb49af34f5357c7f6b692679023a55fbd6a89f07bbc5d7f89c3f76b8f46bce442b6a8dbad48f9d15b1506b54d7a8546b34ec769dc5f29c5979fc7cbb620f37d6b831e5c69d1704e6ae1cd6cb0474e5f36efa5891be5da3eb2a5554b758871a4ea9d2250b64379155f2a9512ebc94f362621ddc0df8155c788fdd4425b8f0d46ef403173e93722edc5ac9062f4e6bf0486bf0b204145e826f1b282d183bd60e84cc51a27159b2b435ae9280b991a29c24c5d8c23e90413a1823b40fddd5a1a6d12dedd2426c445cf7eb03ef54c730d137fa8fa2313c36b7f3de5b7676fac993cbe3c53417b70ffb8bdb9fc0d8dc4a3fe9304a40b7188d7ceb272fc647922dfa86bb9dc44814bf3c5ab2d676111b15ba2ee6484ae4f6ca325d5a119e80b9b88eb3b8ceb563e76820a3b8fc7e17c210c24feed6ef374f992277e9d1bb0bb7fdc61da5f3f9d2f4af5ba125c2fdb62eadb9c8fd44caccf548fab710c5fd755a68e18b33bc64a40c461ff01d9f6bb90eb27d3ff79e752db748e42e03a4a89e96dc1dd769d1c5912be1159d832ec617238462c0f749921effea7469ba244d522572b9b8b81d43dc9d7b912ed9adc8dda64b6f92d83dde961617f7c2cef514b1c905d021f11c740c39cb28e6010d31a486baee5be8d3dffc411d861eba74950875853c318cdc343bdd9a58b9ca7ba356aaeb78236e356fab12e12ba5a5a1cfdef307e859263f2f25f541abf49a5d541d8d7c463f4f7f55ec5d63dd9ab0deb7dec7acfbac3456cb7bb6ea33eea934593ff6a3bdaccf2b5b036ff64fc657241255d0a719754be27e2e03da1ce2f4c885ae9c46b81bb235d3473708642392d6e03fd00627cb0e3d877715ccb9b0edb3b9d0a635d839ef063c843b17b675f86ed5ae9f36d6b93a9d03e1b35ac377de5359e2ddbd2ebb0e61ec5d310b6ddc0ba476c33edd3aebf0931ed1c34dbb8886716194ee8ea2fba6fbc8851ebb1d2ac9eca65d99786bca50f8ecd3e3a7cb4c74452f06dabc1bf0146503854037d185b4a1cd7bd0d9fc526b551aadc180529eaa4fafeabf780f7d7cbcf422b7ebc652feba3ee731ec59765a37ab5fb55cacba287756ed5ed5258a6b5578ab5a61e151ed5e92d0be14e31228ba48ca33c01664946490d6a29ca4f4579970a3ebce39283c6c33ae9b5ccc6322ff983c239c23b60d8ea04347cb0cda399c233ad935781d28421d32dd67f3a2784674e0c0a1e33874e8689941270c6be75ed421c43565463ef810f318211e848d0f0047cb0f2d42c408711c1f40103a8488a141dc46109452d09419511f7c38f5c1071f46948e748c46a3d171e0188d70e8188d70fca0638e260e1c7c47d55d973afaa8eab806efc4f11f70c8b458a6335a2abc3c83759c9a332957877d36adc5e3a8cf8815e806775cc79b1ebdefb0482b2d410e5bd4800ad7393c447cdbc08dae4e82eb21b40f6e7c47d1232f2eb3d3362786cb7f4cdee6ca70790997833fc6651786cb4e70921e49d7ce4ab80ac682b3e02d54e2cd34fd717659dd6da2474e4c17dc917f9689dac40da88c4db4163b07eebc1827ae2ad00deebc9d2494876f0e8a179f6ae7c09d6b6297b59f91ad889c262927293b109f78c08d240f119f84a80b3d28382dfe08f2080f0b2334c39df8f88487784c38477c4c3936efae275c59045a03af8b5cf924df55de5386e53543ec90a5c2305a8b7f35e2b4162f1181c21d08c615f45d4a13cc57ea0613c38059b94bdd9ab82e97d3e529b9bdc35049b2b2af79c4a5bfc3acbce5f2bda7729ae9d255a64b9f241b365caabb302db7617f384f991e2e1df5e16eca4030e2753957454b8cf617edf252064710d72adfc7976bdfa83bfa4808203e80eb7897fe602e552ecf1388107a89b0dc0b14b92a6751b12c2ba761b9ca5758ae72161539bdc3d44de5369e0020cea200be403cfbc3ab39725c929665e552aa2c2b57b904f38dba2c776d5956accb6960be721798af1c6645e5ae3595abfc9de52a4fe5371e10397eb89b4080f8b334409cc5d2c4fc5da5d640202c6c6df429e636aea36ef00a7169fe68798c75ad8de47df813e203b0b03521ec7d389c48bc5c7b4f245eae5dbed40d8aab4d93d42ee3252f692f76db0075655306c7354db29b0f9a0c42b341dc87205e83387cd2a320ecc657c371a972a9dd874badc22715eeb0806a60b416afe170b964954b15c781a85b131788c3298323c7a79800c8152b5dd60906e62c563e07bd520588afd497bb0e40a5fa86fcca69de59be6259fe72581cb7a1626970dc058775398f0784c3a182c3e5126de20ae02b01b864b900aaeb1b2cd30360e3b26e40fcc69f8a8aa591eee2e2a2f295aba848d2cb25bc54aacb7154776954ee227de5d2592acc657d57e553dd9a907f978761f94aa5919bca731c8803e0392a8dcb3b8dfc746959ec1277b371206c0dbc2e77adc997dbc051dd5579b15b91eb62711c476d3900ea96c4b5f11b756be2da38dc814faabb129b323f58a63f54787da8f05e3dc85fd3879476cea4dc161b6dd4f86408748b4f6e3cdc01033e815060941ead3c3e46152317ee5841b5c80192bbbd2b209317f38c30a9dfe8153d2c9e4e8f243c0f3b77da3a27e71979d66e54b5ef3752c397e52a95e5dd4970c7bd5419974a280f76632f2ecce9263de2a27376b09ba846e79c86a5284a677cc6e30d4b95799f520874a54e6f923ea9482955a4a4d37437a547923e555c708ee952bea9c202e7982e5dd22dde456be5e4f5ab9c48292f3aacaeb5ee6208a7d421d3dd4275c8140faadb14ffa9db7537b8435f068b886f6267a32e9a76a376a336222e025a46679b5a76735d5cbbbd85824ec2e9223e40c14562aca1820c026566c3e525dc0ebe6cdf45d26e226a6510687fd3a28e1e31ffdd881e59971a6b53f5376d6d7389444e3c26290681ba17687bc991897a992e7b40a54fa1ea38741f7d43a7a11075ea3252422921dadae7a12a6aed13b2576b9feb32ea050719f7a43c242352140c3523c36ed7a56ce8a0ba15b9201932a80c19744e0a4b994f79e8548752dc0dd549519f53c6a59c53c874a9f368caddf9948a3df4d055b7d0fd50ad7da0fc4c6c33a739518fcef7a4a6359df608fbf490a847f3d369683dca3ed1693a0692a0504a4aca7db89b92f299f2f9143b2fe3d88bdc50fd7c4ed5ed4aa93d4207519f8c522bb38ed56bda8b9aa869b2a696252a8a9aca2029e95415c297722fd2650fac6359bcebdd50f9ea42b0fbe88b7d306cfa744f8665d8a701ad59c7aa12ad59983da2356bde533ff71c941df378e8b3efae358fddae3b65c7eef14c93c73379268a1e9b68463d3bf609c39e9da2280f869da2302b64bad356847a56298fd6accf7a5996d3a622b79242ad49b435c9b2a6e9d534594a4eb5255fef3c71215d0ba468a0d1808628d536e802d323be0f77b3ee5ec2dde853dde4caa1ae0962e8b8f4c8513a26d0230a9ea2aee3c540c0dda04eb1a195702fd4a512fa4e511975ea99dbc16c64c2827440d02cde0dad3e5dc8e73efa7e30e99f4f7d24a0d2a587bed55c32202cbb04d5506bf49f2a6a4dba1f7bb516aa992ee81f0c4a982449760b72c18442582814daa0b892bdfef9e7979407fd7349929fcf41f22e523da0d0f1a7ca83eaf50594efcd9949ca4b55c8149240dcee614fb26a0d5f19f959b7d0a5f754167977a9d6de09a874291989d4f026a048428fa7a1b55c18f6aca74c76e9a920d07db80bb22ca1d3802e1f025d1e7459e452ea36ea7eee398f875daa1bbc2d173b8f974de75a93b72e494f3aa74945ee24446b3021a0bec1ccb6712f2d930da824d92744a86b82185274b579545abe1818188ac22705d5fe24b4ef80a07c294d199e2a75394dd694996e4dd3344d5385f4d1075f18181976f7333f9fcf47baf749495d59120d5022024b4ca047d8e3a5946152a50e9a4638aba2aa4a9d528c7329ca6e35b7ced6944dd3adba1511325d6b83e25613e8924f7daa7c6a9a1ed7693ae87350c50e9ae0949940557eaa1da70c8fe75a0756b3da83ef1445e820781121cb83c99a6a75991f4424c3a798628a2917facae7cc974c553187a80859bee91b9ff394c1a60a52e74a514e4762d5faacd59b60b72a77c15ef0175c39a15ebd7f058d5df015f1d26e947d52499c9f4b29b159558e82416cf1a7626fd08388ae753865408753c6ba04558a416cf1c7b258a7a12e6f5197a7301013150d79feaa2b6495599955896888d835569d6d2a577c8f682d72147c330fad43b8a70c16e3379e77ee881eb9a9b5165da66f1a4f936b2d1e545b5a8b0e0cbec2d50d2682ac0a646178bccd81e19a0c81473011050c3b1171c0fa105839f9f494f17c62f7c575a783aa65f1e16e655940a7a94e1d549d7a65dd8bfcf34fadb0c03968cba5485a632984682d4a98e93039a0123bb94288c9c98b0980bb11efc4493ce564b230ee255eb210a68d64cd431db0d0a2064ab20e72ddc852ed4b1bcef166aec83ee0dfbb800f77a1f5e1eeb3fd94649211ca2ead494f82104218a4359e3efab665c206545252c7d81dbb3b486b4cb817e956147a98f7f876402598b8c168ad49efead29a748e428b5ca7c1682ed7db6e2dc46597cb2dd7d2de0d8bf93d7e4fa3e865374a740d469bb42bb99d4dc7dd34265a931ea435497425118d1ebd3b0f6ded9d0969734f2a75f5c849bca4e280742d6f56283c30abbfaaa262be6bd628e641f022a6e541f595294a9574ef4144b7fbbdf76065296a560f22aa2acbe3dd80bfbaa7da46a493557d55e03827970cf5578f48a236a0b51cb838af4b6caabaeab8ae5a3171b77e1011c5d659163ecd9b2e5f5d5ac70301ad41c8b7a7aba21ebca3d11a8422a903ba9d03343135fea6a851e192ebef3a5c72ad6cd93fdfaacb29aea787c7d264f79cb234afce53e73953fd320ea340a70d55dcf90c5eb37e5ea35253e6f327b39e3eb267f75cc677df610edc48fec10b93f09b144e8f86f424717888217ca91f6e8c312ac681497a342f2a9b326f8ad6266537cf69b2579770f6c858f6953cbbba64dd6012be3089dbf1ded307dfec55e53be374aebccc2acb0c3462245e7879ceb01123334e67f295fc39bb1c9f37d1c1719d1639615c98a44754d4f83b54d284284d82f06406e85ad001ca75553c9f972ad78c09e45d79592f4fdde63d5fc9bed521507a5ecebce740268de733498fb2ec32ab2f49ceb46f8ad656e65984bc21f37316966b56227de7658d8bc6b4ecb48f7c8df9e3dd79c9b0f961d933fbd98adcf678b2eaae6b2410e298320e7e644c198fc7e324ac904b40dd413dac7fec753df032a68cbb840ebac7c02240aecef94b0680e5b254d478757978014c1918041535be32e114cd7310174f190b85a8081eb8f7ece10edd67cc1f4e8264bc3073067407720ec66e3cef2aec11a90ba168cab88ba60ce8ae52f082f5cd1ef0cef69c91aae710f4cfe5003cff611ae1aec7e37ab238fb23822c4fd061752cee7cdd3d359e552a6a581667a11208933890cb6e4d195026c473aab5f94fbd5a9b87cfea46dd393d95a23cd281ceb2f2fc7309b2350da1c4c1a97e7d3cb5560c93789678388543d3878ca7dca5d0333dbc81993210269951313373559d2bae2a11572a22d02d0e4e56fdaa2ecb10f47244c798597e6319329e327dcc08cdf88844a00f4c22c2ec0cc6e2ca0adeecb2f095e4f1de25b1eb7aac0c58a3867d39ec9cdcb01f99e511700e064998e4b22cb1cff4013acd6565dc33815c177498e4ba360a24c306c192afebaa30bb411e01e790574db1aed2cb773948559c63cadcc09abb791ee482d4e6b8901fd03f20e891e149f1bc1c38caec16e402d98dadab9a3ee888f2b8eb3902ae115c372f5306822a8f29e37939ef5d15eb07a5ccb22cbb74a12c9312e76ea02ce4c90e121d6e7d2f509681322923a8c8131fcfe7e301559aeb505ce8c930cf41d63d58b1bfbbf1cd2c8dfc0402ba47fef2bca69190a0eb109b71d1a1fd6c35d3062d46237f1d7efb5c32f643fefae7bdc3cb6361cdb087a36237ea793c9e43d02f1b1e021e643fe7f11cf6edbab99fd36bfa50b92e55eccb69242b67b1f098878687c59a3e3ca701a9bcf2d0c0de481ecb8af5c0ab6002c0e24a59dd85504a7978590baff378a29af21955c643f5735add0591a4bc1c240f844d108665735ab9723d81f77ceeb1d373bb315f33d921851ecf792291813ead07b31bbc20cb92fdf30bcaa59ee757cd74e7439faf5c70f816e492a68f19a70c58335dcf4376639b7b9d71de1dfd46bd5f23e021a6e798fd7c0e33653e12c69b5527417821bcd98cbc1995d725f47c2e3f9fcfe7ee73f78f75075dbec8f5d48dafc7c89d871594dd4d1f9e67f764f51a01e7b82eacf2688d823cd8a6635c11f0d4e1af11bc5c37d7cd8b7a5787a753064ab6a94ea74cd556911be192ab24496b0f26817c1b421857da882cbce0853080a1657b4f280d1550b82645f0a0ba93937395ddaa739932eefd78972f42153c814cb744500105df14c10309236fe06db9cf8813ad71122531d7e6cc20c35d09a785f7c4133622114f1b9ed317add1d034d99af86739c90f697f6ce00ea92e3f6b0ddf29cf495ae3255236907afb8fc95bd223e7629ac9bbd1dd8c9d474bcc0a7957fe81f1983071cdc463379a629974ce6382b97e9265ef063f7ba79ceff670fa9e8fd85379c763b90bf8ca0ae131aa27a57e3ae5fde4224a3d61e7deef7aead672dfbbeffddd19aa1b83617a4c36a8b3e46defec832577baf481ce959777973a7ae41e8cac3aa417541e0aa1e30ae262dac6268c2811704edc3b0f20dc109ebfc308e146a0bfeb70a3d028e5cfd5e1f2ab8b71e265e1de77ccc53c264fb88f09e7a0dc68f60eec5fa01bcbbb36eec66f22a247428a5cd7dad3808bd9816ff039c7b6c3dd280fb894fb68dce776f4df2ff7a68bb99e6d406beec6f4ea34bb9b83c2449eed96dd8949651f1369370ee26e3c5194fb1ec67d337d9a67fba2dea9d9a3af3c279978c9272fe11dd0c84a2c2fb9a1b0e56f2833715b70f19adc7705799af91ace5e3da5d2647f975356b1f7b2771e8d557767fd95b4f64d6bdc744a99e8b34f925ea124a5ef153daab0d0e9d164279596f2292e4bd15714ecc4867798b44ddf486ef2b4fcf38dfffae1f488b78773f9fcc7648be7a447477a24f1df14fc729e18985c76127a3befc9fb498f641850643db2350afac6a64dc0314abc1bdc25703bb0c6c1a52d83cb82eec192aee2554ec25db49267fbc6be5e72b96ddc0b7f04747b4cde163d4a999f1e0ddc0e799e7f07f2de9c27f22b536adb74965287f4ddda46043d028e7929e81770d740c813c3c8cb7931cf09ee069f0a2f4966b7b7e481c18242fb6ef2b4b49672f9ecdbcb19c25da0b20bfaeeeed64c94b4d6555c96d20a7937c4a4b798ffc20983e13277d11a6f6da3b524a1cca173caf9ec058e51829d9ccf5d703bb08be040d5e0840c9e6f2cc66517392f56c2495ee5db386d133d2e2f079be7bf295e121ea2abe01c9cd53ed21acf5a3da526d19a3b568f68cdfdb0fd70ab7f2a76f2e6f78ddb819d99a480ec4685ec4645ffd84d349d7cbe693c854f8dc29d57a94db8f3a202dcf919037899d7d963e753665419f5aa4596dcf9ac5e76c4b23bf184dbe1b417e39c0e251ceb704ea689399debbab89a4ca94438ed3d547538ed1d548570dafba7c238eddd53817039de6975eee57d56ca69ef5d2ff7f28ed5e95e3077e3dd07d10ef77da332eeb35b10beb9ef307722f12e6d4d4fdff8caa94a2ed08c46088d6b2db31b11d75d4ed23395702f517a8bcb7571a0635ca8c49d5b12f2d5e9e6025e9d7602991a70a7dd82b8269786c8bb546480aa1eb8fe449122ae0f4c1a30c280cbf278d3dfa9ea8a78072ebfb2f1c0078a14e1de0d6a9362bdaee5baf7a4828227e9005ee06e89ade428f7224520469224e92e02ad491f03dda88be3244e11cf31e220a1c142900ab8211ac084db415d621b2ad2a1a3f29d744892c3c295a82aa46bd958e762126a42a3454790d6d80b1909899871f67897ad0ef7021fa4358a456c1bd0da9f634374e2dd8057c209c9369437d96737eac27f41371d179ee19fd0400b06dc102d4eb81dd22185e45d18a932e5c585722e5cfee6c38557c2bdf03907053c9c78e2563ab640a9533a8868ad8a314a31c618695c23fa1445699f881e8df836459d9aa8e9af3a2bc48d31c33012c3574a0b74a3b7bb9b5e2e480743b9c94960706e0bc74517d7394d740aff6e4077978583f0c143a6bf6f0d1e6a35608b926ed398a620a1aa9ada89d6d8480f80ef0eeb134ee874275e8c91d7b428b6c6d39b6c53572502ef645f57ea68d5045ff16ef02bbbf5a720adf19960c1f4c932129699e9d564798af7aad2c122c815ad6d7c450d5d271e532d12fdcc301a13419ab03dbd217548bd678d609979a779b6013689225742b6798f8d3c9105379d680d0b74029a0e238e8840c7389dc8456c8e0b51d31039eaa2af86f9d6ad2faf4079bcb641729b4c6f4241ba962bda80eef4cebbf14440b76713ff6cde4d8ffae15c70a0dc4f7aa7354851321d04bac1b67931222a96810057a60f3778820b2fa2a865379a236b00fb10dabc88939304d868701a9447c0b22c3e2c8cd06cf3627a0dee060e0fd13b2f043963741c2efc19dc0bfc165370e1b12cc3b22cd24b7959b49754d11aa4b781375750eb4d2df659372c1ec1e6b3ba3571b33ea424bdb4893b8f00656d59963c4d3c7da4762b3231d03f13044a09c19b785dce5141a036d4b3793637ad3d1bcbfa0e528bdef41a3b9ca53a8df3609dde7acb37bd256f3dc62b5ed2b2ccd35c979fd7e52fd951fef30454bfcea31560d90b0e291ecfe98ca795655e9e5ed366a7c13e9f35717b93976155a7f7d80b0e94da1a9872378154b72c4df5cbd2ec70eb35b0b2b0b51a8f3bfc731eea062fcba5f90334b38375add5b05bcdb35858ac848454634f4d27ebf12d4da744a776a3a67e937da7deb35024df76ab7910e746945db248e4b915a3d2f45d2386fdb29ed8b2faac2a959aa7b17e7ddaeb96c78afeb9b434a26722bb15e1f12a274595decd3737f06f3a02611c42b646845e66a626123a5ac38938388fa21ea52937269150684c81db41240e747a754b7a54818ba1dc0de930b081ab712598842524121209c995be728525f3b697138fcc8883021aff601249ba249de744a92b51546555525a9514b391b426e55c4942722569caa9a81c09478a48ae24c524579a138e7483742ddb64e4c6e9fde98a37d44555a9c3c1f0e33f1d6cc37c3716776d5cb61373d72135b037495daaba2d4289505e849272b708254742a1710e5078883850ea15921b1fe9e0629ce4811b2512dc78e7e28acd7b4b20f5b81f0671726ee08c362ca0efd3a3cd8d8f50a42f7af41e87c0ebe26594fa88341be7c2a1db4302e5469c9c48833bd938814cef87448a1e359c3f260b1fa1bcca886423bd5a6976397a9aa86f2c274ab2ac4967922623330ae49be61b99b95007e3e84c0fcd4440d88510efd92ea8b351076d86d021815d7e816e2e2c3dc9f67270a939d37feff71e4fcea5b57a446d02635e8ebb019fa4f26c2a2d71a034d6bfbdca485ab3b068ad0a5a9dbfe8c6ce487e58ef4bf3c7062e76ecb20e79a71e6b0ddff86f7c8aa2aa09a45239db2f051251d49f13f2ee8c97456bf0336ce7c08f15cdb8f302150de1d75037e5321e027de0e54533aaec824a676dcee0257246652c5a831755d6690d8a2c5731a3522de535130782d4e55fbea7ab3f598730e748b70eef2e13d03e5f104207af59398945499fdfac5b16c99455f8593768b1859691b4c6392cc50e28c6526076ea6f2f272a713ba8c3c7830b3fd1bcd7300ddfbab4ecc68d436dfcc63937923ef2c95e3018380c1cf3725e9233b481e7c060702ff072e0c085ef27820bffecf6963c145cd150dc0b0e0ee44f6cd90bf7028fd3233e8284b1204215ec85172f660977b1648b2c3aa747fc640a5ec255c0ab0494a5c7a3e2facb793197a5284a45a26f2fa7a1fcc08bb704bea1c00b09dd9a09930ba7785bd04745ef9180bebbf79b896bd2ae9da5e2fa171d73d9be69f602761856fd42f29ba2ed6372e1cb712f90975ce9301e3af88ed2a3ed1d8adb2107b7830fa14ccc4c84efbb8cf5e5bc295a8394920b3fa4e5a381db51038e6928ac830beff801e1c257840b1bca8be11f3c9b0b9d70e119de824229fe10869760433942b24e7641e11de497c585cc554e4fd1a34e02c6856f335cd896bf98a2635ce5f2969743c1f317f01dbabc4544a3b18b737a248524badaa3e2ce2e86dd8d7ec4a677dd2e08e13529f702bbdbf661a68944ff713f96bef193224584641f7c37ce00ff32c7e739f32e330729e6f3e8b77579cc3b19ff41283d6992a214a9ae34f1961814dec1b3db511d5aafaccaba4dba9b913e397e6f900e086a831d1b14e16e7db8bd3765dc7b5b9ad8130968a18f1abefd7709a9be3dde4cbf4f9b8ad7fddebb337d3e23a1bbbefaba2173c36ef81ef39d422241f9110b2637c3e28a4b2f16bfd1699299cec730abad87859ccebd2cad98a4dfaabbeaa7a9e6a77373da6dce4b3967143aa735e97c65a74da23568c4114ee8e698cc6f4142972681bde7cc3c6637fa795d806fcae3755197ddb06318365d5722856276ce21351902301e93884b8714c282a95c286d6a911e6940d10bd5f4f5e1ee101feed6f0f5e16e768e428b5cca32837dc667d84d32333376961e7d67dc877377c67bf6e83bc362d9bcae6b66f741ed463fe37c0dbc57a5a1bfeee4baeb2ebddef792f1ac6242f853dd8d7de3e7f3398fbecfb2cbacf6953e9e4bd55d2a49b012a1ae641de78897518950b7b28e736467a247d36ef3d53f879780db811d9e026e073dbc1028ae07bacc6eee8bebdc4b25846f4aa50e0a6d3cfaa65436c0bd3ea488110318e07a5e240957f615fafd54167a7769e6af8358a8fd814dcb3283ddcb7a3cc7aee73c5c8aa25cd3db4abc1bb095c02cb5d4547d5897978d529dc92e36a9dd825c7aa70f213cc6c5eedccb965d5eb4d25cf1f7cd1ffc280509b144dbc3baa41042a843d35bffb02eaff7dd8eec3c794efdfa35ada4ee7abe3b1f4db273f932f5dc9a32944844e99dbbacbbfe261cc1d7b7a62f35c6183d44d30c80be9a3e40758e4237bed8af6fecc36175f3e1e27db82b84eb506d4418abe8b1fa6e5687b07ba1af8177569aebf3b22c337de7fb4e6af118d7aa1b141c98c9aaf4aa6655573cb3ea58085f7edcd806c5c58e6d941028eef57929d53ebddce1ce6fdfe1ceef70af1fe0baca22ed0f03dc8959961903dc7903dceb6e8cfb59afcbd2f4af5fbf14453d77ee3a75d1ebf3b1d475d7dabbbc7c5c97a7dff3475f1e63f9218f1dbbbcc4e4bc68ddae57bf8e9dc7bb8e55961ff3d62f1b2d0ba9d0652321b630681c2c9c5cbe7c29eaefd1e27747f37e549608eab5f4a8e59af56265293b49372f0b94dfdd850dde4b9224e94931fec53e7cdf700e13700e3e3cc3ea58c8f4dc3377dd646864890b68d3e8de5ae0833647bbcdda83cf6e35939b8205947396c0ba51498ad544ddba0e0f1e52131627516b5a43c0651527cb4251353dda9ca849a2a2a669aaa6c9ba2468dc245e0c45512a1235710830c2b22c0b72915b2bcb0cdf02a24b035fe47265da14cb7477b7ebf2c4d0f229a6b2274992a418a518a1d402a5e2fd596a31c13a3fe1303ac6fa3b47e951f677d679ee4dd9e5a7795d4a37656a9a5080bbd23e712fcbbcc4f526ab736f6475bacc5c4bb401bd9ab8d364ad3b0f587fa2489d6e51d603d4b94ed68a987d6bd3a9ea01ea4f1429825ae2bdeb4d4160a8bfcb0f1c08b56dc0c86d8ba9c3bac18daa345dbd1bd3f9895e84d61aa8bde0408db01429218844adf55d74503a4d816eda6dcd458711f1ee3611b775e49b2d7d37fa92a22a2b45b6e98b845e2e2ba0fc4d7b614807437530f16ef4a1ddde6160605a6bb8043711c4e93021ba3c5e0cc5940e8c103aec4649ccac19c116012ca05cd08da2288abad20a5aba8509393446aa2cf56eb43b455193952cebbc1b2ea011b2ce8b716deb75e6268e091fa937173e0bdf43175acb4ef808e51644d9e241518c45205b40ba8e814550309a3046179e2140317273b3eb9a200617976a8d3f841d4e7293c9eade11eaae2fa4e024f19a668fe7e09cc7b0f3780fab959329e7b41910ec1705a70c465172564ea4b48ea4569585b2eef28c6729964435c083f1240c282ecadb7151dc1c712c85eb254dce84eab081a1284a35a723626eeb554585f919ed63cbb22c2bde9a735ac6b961b661d1ed9d17f376627765c58aabea55e56458d62d86d7aaee3233b3757e647e2ba0dbdb694239638a52d914a817d347d8a74396cf3d77d84e1d8eecf4c835a10e3717bec1806f282dd73a65deac77bd5a83941428cb0cb4b1e68cb69fc8586fe77a3bafe5be9d17c3bcc33bbc436dbf27d832de138a962278f018bec87df05a8f91d9b2601ca11bdbf44e6b51a01b3feb45b67afe45418d5cf88651d0f9ada34cdb61f4936a1b8cd66018fc3a6bfaacf3fb546bf87eac8cfc7b0175d77acf781cc62a0fab36181de38ae83078e878a8b6590226d3b0cbabb2e26cb659e2c5b017ef067c8add1eb220fbb14e5ac7b2179f2c8539afe5d0e47d734c0e3387237788eb9a20872cdcded17937a0dd609c684dce44e474b69753d9c0d8ecbc1bfb2ccbb22ccbb22ccbb2a265cdc0861d3970ef549675c86251f03bd79c879ca4472cf3a13bd9460a24394bb897d7362fc609cc122617c1ebe8409d4fdbc082154faed322e78bbbb509aed3a20a2f9e5ca7d306255ca70307254eaed322878bbb7513aed3620838433092448f44ad5d0d703bb801ee250e46aed3690317776b27edc5e530180bb78379092f619d1e3d6ef2f8f5a5ee1fd1da11b7839d7ba16e0b47d14243445bd8c804e549d27b316e41a24430de73cf3de75e7cb2c24da090e75301edc755159021843008ce4589a23b8a1bd0fec6516e33f311645f8a30a25c38dc5ca7d3862ceea6e30d595ce9a6cc3b42ddbd5a40dddd780aaa47f11c82e9d18b489c6531e453015d82b908b300a81e51c1a1bed265f98ae9537cbc7457514149d39d976c7c85cc55040fa6f7ec31ddcd1fd37bea6992a64b557a8dc57d9697dc9702e6e9dc67c7524c4fbaa47ca17bfcbbabf1d2735bc40b33bde90a0f5a075af2f9fb1c2e6998842fbd93f97a6811cf73966e867a9e51af7e05abe1a8640d35c5512d999a1900008020008313000030140e888462d1803424da164b3e14800d9eb2507a5658b32086904184000000000200000000000041000056a0af94cfb75891281301c23968a8a649c4c9b7a5d087f346e23be843cd3fb16b24be160c10b9613abae2130e4a2c12cf6e616f9e1ec674553aab398c19bf71a3fa7de78ade632a0caded87558d5b9d2e0a8e02e837481498cc5eec962d4a216cccf0d2e534484aad9b10483171bc1eb398973adba695afcca54518c65ad6a2c83ee6549ba7320e56f47b6f70283cd4260e8d158020ea0957e545a3253b164d3dfc298656e7c088c42d1e569623d9db0c2e9f51393e8ad61d19a6d1ee67ad28244eaaebee562cf8d967b2b7525fa870a70666744cc22c1b5f25bdcddff003e9fe299e1b5b5ec82f4f273b6bbedd5497876ff325cecd52a06626199701277f05e2023b29d459e0b3fe0dfd4ab27fd13fdfd50be092339b4e52d02645d0d026c8bf4bb97d45a208dc2f2f706d299f0d558b39914ae184b4885452fc7b9abf93e9a043283890483464dd1d316e11e2de2a43a23a279dc33df1672811996849e0db11bf0dfb76a8b4a901ebfc43c46cff11851348f6f492c63dbbd9b0e6efb9254c83b81cdfe48f152e0603e917b51257e9eac1f7dcfe4f604e695615056b6834b001c0816495b026f46e4992b4846f8a58de5eca1c5c53c35947551dcb677cb2d32e48907e251a8c67a8c5996e7da7e3c6b50b5fee4cd0c833b63b0e82944b2dd5b9d463862aff772906236d93a7e4380bd16cf4fd049f42d020f799cf4b36e088576937bce8f3fcaa601c95f7647c4dbb245576ca8ef123a6db6f4026d75dd4e0bcd6c3cf4e9d819350c1028022641f8128237dbd091012416b8d30a6b35026cf5788caa098ed177da567682863c68b81619b15343504e0d73ecdcc3c0b3baf05ddc3bbffb05757152a6f2697921a0beb0390487550b13931fcb0f9034f187e2841625a714ce067e0bc76d42956aa6f1fd698214a44e4ae34bda9d9bb0c5b91aca093def579ba85dd6b0e791b611de21409cd3d599b534fd442ae6fbbd445afb32cba2026355f8fec35eeb0d3caab2a16726580f573611d1d3180caa0e3d4a69e9f1c8736200c7c645ffb9ce86e6d7ccc99cc0723d8572a086964d08d2a6cbfd2d048b0e3fcdf4aa6ec683772f775a1a5bda31396dde2bbd434404f84292e8351d94d3fae823e1e077f6d733dea9f1936becdcb19d28a394633ac8bbdb54ab8a22cb018555f8e1eb0f2d3faafc22abd1671051f166c29737a43871cacbccc4b1dafcf03abe47b46ed3e34ead3bed21ac8232bf2469de9532de2e702298d21cdf445491bba0f7508f671d621af68eaacd5471a88d0ac0ea74f54ce7a790e6a15b1ce42a6d15f9a6e2ef99aa23010523ecb33314a4f893eb3a52b52a98fd4bd3a5227c0b95ece4c8a3227343caf3f92b1b017483c823993416fc2b6ed2b2578728d6e1cc1c70e7c895bfb546d5512e1358d68aa7ba5fd823cbda5647009b7548f83c5e7f4893b4e479c947c9daae77773b8b7315a8039d35122c8a632d3b001ea2a1e59abc1f2a8d183b874c2007e6f733a0c7603f4d6522de4d5967dabcfd7a89083af0859efbe8435c3178c7cc18323902f2573f93f1602851aabaefad27f461bfef6870c939c02b79f03b224dfccb7e2b67a0bc45ee90d32068c013cdf0f0d76945e7e26c3a681e29f51026ba3abfe36293dea9984b18ac62c49fcd559511b04afceac047b4424a968616ce5f765d60185c64110b2a6c0732e187c54dacca602aed198a2bce9b65e999d41b7f112ee681acf33b4eb0de37bee4fe4d3d711c8d9a294315290d742892a7cf17ea6c3b464bb787d813cfb5075ee4ea6855645509d01f4fba52b062bcbf6ac69ef0be08f3dc6c86f21b577d7a78eb61681660b85068177a33365b40678b73398db25313d4f678838c4579ecea6956b36578f09b9d8a274ea9c5aac02e9b1ccf05f84fde76dd7fd81f097ace2188128705cf1c4552504d6ab030c7ea938aef75679fd25ae55fd58c465318c8d68a017d0118d864e8ac80619aced830f0d641d2397a0930d9967583495d4e3bfb238062d61b0911f1b2c9a79d0cf4685e873144de05ee9f50c11a65ab3d2a2635156f756a9ffe152aef27b046c39ca6ce8866602d7dc29a629d562ca253546e43f95626354ca9b5f86192f8f121988e1cee79959adc80ae2e791d55fe4c7710404e83eaeefc768b45d7b09ba64cdec304ab87309b2c74cda7e1227ff37dd6826575b7c5e4a5d8ca5768512db502ebb1989696a3de8688873f93cc95a6ce43f48b474eec745e5f8ce1908f43eb19db83cd1ce2fd7eb8d60c46c856880afee9b2cf4f6797241909a0ee4ca76942b9241faef16701636db59db52d6afc75543c4ee7fed08e9b60338a3448c1c33b3d1d2089891ccaa108c6f0724f2d1d672e2edbc9e06534635dc856beca84dbd7bdbc099024a37870a7ba410a3ac45a931ec536ab4bae33e4d365392419338ab92059fa80eee7ca7b7605c55622a3d9484fbc9dfbeb43e8cf270e5f40013d702fa8c091f4cb389fcfa135e2ed74ab30069f1c2aeef3fb6763df93904c05cfa4f063722653670de056383e9909dc7436c9fb012b11f2bec9ebbb723da0cb938a4114e4358b27823b1a11e4b66e0354a1bb2b5c90ef619b8591cfb721080739a942b8d58c0546ab8c73caeba851fc2e155c5e4389a53ae2b112156a764825f374d2fb8610c07b3bcd0c086820a5b71b15325e24cf2795281133d163c6e3128591bac2d03febc8da5a538e1154e2b25138d35831737817da8b3cb0b475cb40a49ea16f7328348d609932e6491491d64f5d0138a4e045fa118ddc5b8b666994ca2dbfb4e5155d8531819beb20a764666c32b513c219641c02217607df05b7c85ab743405a031f98cb8831ec0cf1d9c287912f12c2f4fcb0d584decbda9a251fd6bd4c38828547c2727b124405c3b2ec1fea8155dd8aa98451c3441b849972425f6003757b3eeb867627f32a64cd13e5c6a056c54640c32d082fe87c6b5745c153295a27c950310871e9a7d4881ea1abba1b1aee397a3cc4924be5e11ccb7268b9099f04270610c7b41ec8a11da2eb3826f0cb4ad3e0bd02e73400efd1bfc481714192a1b40c13735a35c0338ad8e5cea060c4907a672a2032dcf4edae6e1c874687a09514fcaaa13369fd19eba74b28beab1fd048fecd3ce1c82b891337fc381dca593810fd32c8047a54897c1375c4fafd6a6b8d0f8d0a44fd38b4a1261ec675a1531f83c9f9f23cc0681c2a9333fccec730c88d2ad2d4a77b6ae372160948bc1571c089583952f2ac4ed8f08912085e12dcc6dbc708bae8f02ae30c206581e1be1fb1c62a50d9256e647d238c2ed0ed6d622eb6b07a13850f6e17044aac2a55dd2eda95ea841d324479224153dd87c409d41d20137ba7733c7e82211a8f5dfddc0bef0580308a22afdb579086f3771de0e163471a137d6a0c7793bc28574191c3d2f68b10e0866fc182a3fa63483c5ff886688226663ff162d080c8ee72b1e5d0db1a023d06f96a90ca3954f255b6f71b7dd5021803473970b5afc39383f0c7aab0c581bf05bdfc19efb99a2868d49580b268b82789c5910e4e141cd8376cf92b3d86eb873edcd71bee2904ade70b35b4a1c0e29f21b9569019aa71ce347ef61c060e8375ba1ab0dcb0ceedeb3f36a385a66912f9341e1290c5941e23895471db53526ad3f42ab0179ed9c653fd7e75e06fb06cdb0be60a82d3dab3336055f040eb4f4974cb4a352cc1cdc24943d0acb41e68ec099e138ab22aa840df4d16179519a10a5e801933be4b1f4a3b6dc7cccdea37076402c1bb35f6ffdd52ef6c4346faab723c8953a5215ccc42e9a54e512882a950b0d7d5386ffd480a615909f4a3ef2eeab4ca3744e50240c0e90ee25eeb431d37b72bf4337ba8f3dc76f14a6b68be0689dd45cc76a4b98a4b43fd2b00ebf8b9ae25a37ea7182efb1101d4e56eb38250c27ad997066609e767e2af7272c53ef69d611c40e987de00d0dc25db8c82303a9facbf32d00fc433e9c80cda501852f63c0596cdbad83b9c4443fe3a59c73a9b179d5dade73bd154b087e8eb6701dfd590f134f8dcd0f63032b8b6a6261af9e283d1350419f89a3566b802c69df28e86a3a5d59d94c8b279b2eaa1ade8e4dda0e12ab3de1ea199ae90d4357aade6f17c9fb901e06ddd7ae7406440151c5309ceab18aed0d94b9a4bce25638e8f54b43c8b17dbc626fcde7fff21d7ae056edf1b04b5d148ae5f151568db80c326b161045c4ccf21bf508482829726715dde036b38c6db144d99efb129106db1d5c3d76efe30699b01206426a983935b684746d9e80b81b061dbfc3b661d8a1a25639828994fe73d80e639a52ca1f5f8a1c5e4e4a979a1504bd15190d8952c2d8d73ad95cda1f139085c301d8cb2f277de812c4876eed12d906970012f6e252c10d403f4f531b750e15f8a72f33255435f13c2a20afe71a195dd44be76df0ccc6f4200540033e104a3e9cbe3eff0dde39651c7388ffef3c14915fb6ae3178cdc57c1858d1c28a9bc7366bc686cc2201193b025bcf162ce538adbaed1ac9122ca5388dbad515c9922d9bcaee1cbef846f6e29d3164d56a402fcb1086c1780ea1362422aa6f2c4ada80872bae2d88f1cb0f6af4e940cd1925b0e9dff11e2189ffcbf38b65322b10c9d766919c0383381e17e6cd42ef0f78d9a3a0f4cafe61de2dd9ed54ff1f7ba3f1bf328b48053c31bdf53d3f0620a42cacbdcc484b7aa9f055fadaf7446f3472a06e75151d981cc6e542cab9a63abb6f27f02d16e1120555125748a1db279cf90edb6783ad8da4787b65a4d7fd4d60679a2ddb267404fbe2e1c4a406eff4843e481e04b542d7e35fc7c8d28c2b25b79b4d787198da4532fea8b7ac78dce8f1be8f7e93b8c478313248dacb1906f1d245cda29d8fa41d2e124487f0eb52949dc76c6edf9bbac13639ae156d514846635840ed6e11bce08776e62d92b15b9c6efa70d265e14fb1d57ecccdc59a0c27c7753a222764d59a8f6ea9795fdb07022e69352b47f1200e1e7ee20a7b4268ad3d97b4ed7b5c00511e6a3026f57f0eba421b4e92141f9c9566d5cdd4d6f19cace9908a30403c8377477153aa552c8b268405dd35ccb549d9410b103d45de5090df11793351ab43a47a106c45f0cc5ea0d2ae49d961340c686c20d398c409d1387ae2747088d5a04077a18e5df45c57c8a793b1b241f50b8b3db64294453bc5c85ca1fe4305704c09894319954739647c5fbc862a523f7c3b79941e1a5db7f08f6bea9a9a0d71b8b76038a21aee75c06c7604948a90265da42fc2f8351e0b6041734f4226577c39b114cdedade711c3290bead861b841adcfc37c2ced87f9c657b8c10880e7cf1481fcd51ca7272755fc4ef06b48f2c1c18ce2243c0812a9facd61c11294205a93f1773275b432f8b939e5b9ad51927656dcba8e526555d738967eb2d438082f1e5dea312f5f1c28e71674c7865868f9d3566ebe77bf1643d79a011598e98852ef4d15dd007eaaecc076c83c727f2c3d15d40a51ccb941396a0475b17879f176efe593719c4ec4e4285d23dc7c63039b53f0b737882e330e83d0a756345163581dbcde13506084d95659e2dd9af5ecc2d7503ce576bdef8ee8417082ec4fc49c7f6c8fd910875c1cffc76e705eb3d98b0b4de7b4dcc390680660a018cbf20beec1aec893aac3f9a6d2b50b7785a28e6550606526b746d47688d97bc9c9fbce77f4b4bed08c8f4ea3a8aff51859da70d8fcef9ebda8f4ab5a6a30e4d1088d20f6be67f5345b7661e56f501e29f12aac01c8a566c88d45974831e286c740a50b2fc49f4baa8db5567da3185aa608b92756d37ade747e4e4654caeceb3e3c63070e8e56c5d607888cfada671ccaaff8a3e960f19a14f8eec7997f56cb052f3981cc9c7fe42b57f629f2517255d577731fb277283808a0577a853e1c6310595f7655fb0f8bd2120cfdc75873fe2092f4c97d5c912eac6190c9573c101dc759b74184fe0873f886ee484cdd8452287322f20ea793215b78b52d94571286f897fe5acba68828f6a3fe4b9a370d5270a1985b500638346e169b81219b3a63450899dc3f53ac6700e50867d0d1c08c9e0be6789504c644acdc740896a7bd869c86141206c5e7b485fb793c28e5967c3012ef38a5c09c2b9fdac9c050d2d92a89d61a5a5553f8acc3d9fcd47e11e4fcf328b3d681925fac7e91099bd7d80eb708a91128530c354057b0d844991f0150f547739f0b4c6048808484492976a7d0a2c15a836a8f5a2002e8ec7a50fa50b20de26c6e1d41b98036aa88b5e476a100572daaee1c1439bc3af482b1b0d7d7d5c5a3e0b9abc7f39d96b95d1936e189a675765eb50ca829f88b10b8438c52cfe52a531bc23342a3801e6108de6c02c13f4d527786e515d01b43fe94a2891a41f7f43ef8b982266f97f880d5228ccd6b3388b71a32ff4f088fcafcd0ec077de53e54458b88406f75ea3c82df25ed4ee934752881b23832daa0d5b3bda2605c1c5598cc2d14c299fdb88afd6e2b728fa6189f5fee1547edeb924062c1846a7c31018f68657043a9c6fd04904aa6957283d464edf43588186c768a2967f4ef9dc4f24857fa0d949f4b306d3d658a0adba303c427e08d96b5e9f1866bbaafcb6137b41991f61d5c46e2931a662e55b135cb4cb2a8dc57f3b1a73b390dd1b34bc40d5767283871491f3d3ac51b1ea39d3fa2ed74a2fa7245735154f6d1454dccd728914810cd5e54a4a629a0d010b90af256b78fa6482c45b08ab04500d061b43f4fba66627def7a9494d2e61c470589b0974da362e5df87ca88dc3947a57bc6576381197fc0cd14d8f608858dbcd4d02dace8cd6cc4aa5ecd297a212413f32c505e2382c7c63c8b0c92cc84aee834b628cd6b36e77faea1c41bb4c5d964d1888bfaa183638d512bd760b395439e077283e9fea4f3434e7f5912e32a87e0593a44a1ba63df8f34b606576f1fba21ba4ed6044e0639a08e22c8dbed1b868bd480e2e1fa726cea358efafd12c09aa2769b44463d2c10e0660d278609b52228b29aa10cc1a01c1749186c5b08e772a812c13b55fe6c615e73d405c9e7641e8746619c55a520268e6cdd7c72ea1be716f1b2135b58fa80f1cbba5c7da652c0429ae2961914da860eb95ce8dabeb430128e416c1051e8480043ea9be31aa2ef404e430801042d986507327bbd485ab61360e20eee7dd160558a02c7078ac62cd640ffd05855de161bd4c3f650e43d97b5299ecf45478ad2e2d9e6c060ca2f7c8c41caf804a205209e27dd42fe2de0dd4f4019d47e4acd344723fbe477b62eb5084cbb4d150ef42a0cc2a281b59a4d23a7084ae609caf7142bca782526df078a8075547ce1e547d43b01f6f934dd58fdbd0110f266e2dad79927be8edaacf7183c444ceb908c7c753c9f55adb591a389723f63e27f01848e7d402dcd0ea4f6ffe0d0d611a3800ef7bb712e340680a988dbae1e887faa63d5309b106041db18bedc27800c4b6eec7b653810a3d95f77ba28b6ff170ef472d8260c7cf865a8f524ce1e96d0a6371989b2ec3c1c70bbc3ef385421340d4fe163b62d19658e93709b5176d7e3fa2bbc89e771131b9afd6c124ac7b8364788230e98a5498d666e425cc72b046b881bcc94f1c9265254a60da15554c992095c42233d40d985981c00ec306fe8305ca5cf46949659eb6ad591a0a93392d341cf261783fe434df2d5abb485e2a55c798e94779f45ceab448331dd4eff99e52e80d6462ab8ec579e029350fa0d31c6ad39027c1b32d93e28cb33946669522a83f3ac93c4c837ef00716636c05cbc34f9859ee4f765f284d9c25524f328e2e93a03c8ae882a31566f2f7004e460185f50fba1284281d4f1d2849075a1b2a9564779d83bc70ba84f6b58cde8575ff3fc533649e4c05bac946248c81697625992d06a0f75d2aa07bc94c946a28fb8504c2155efae6b58ffbfd957bd8a92f6ca065763810320af759db16b7a1e41e52ac25fbaddf3e25364103b351087f36822ae0089af80fd9230c680c63a92b78849351afbda33ad7c34cd04b1a89db6c532e1cb9daa6849f482fc715f59cc9233f2282743fb832cd1a9aa3973ecc5d82835a176a136bc02afc9b856edbd8d140bc0e756a0babb24fea0409103a1e13a0f443f9cf1a4c40d5967a900e8879aea84832446a350e1c92546b02dcaf044044514f5505b673c65ccc09c1b1a7fe418f84fd0b4f93f40429fe030e4b4e0bed8458d2ff0e5393e915107c7d4a02066ddbe1c08d92a2f923d360242d471517cb22938f51e22f1004928dd965ab6c2d2aeb84c7dda59002db38d13045763ff6135481516b5257e9a131c9eb36e1955a1d89393b44f3799954996c2d86d2f79aa4fe4cff7217a5b3515328e7f44c7ad590e2b2411c92c60b7da191a88de441feef6145811820ce3c9ecde8afb94fc57f2a48b5bc76f4ad127c5411a25e885370e40e9c5c11a6d99335b12c75ce530e69fd834f58e8a46a9b118478c79de8846c07858191254bd1c71f0037d29ffc90484b5b26e71a3617a84ad27c01e3c09f8a243ce96d5757164dc52f2d9b780ef24971e9e0d08cc36f8833e42f11e7906bd0680eba730429b9bb8f935f4d62d273727013056a99f37485fdc81ab1609155f1d536d92ba158129e06f3502508b40d8d8decc98487b5c90c7f8cc7d5b5cd76963aebe5b1c566ffca0e351e5b974c686b135d27b6f1fd55d8188b3a6f57e40aadf58b61946e1882861a28b76c5e01f9147c9593b2c093ac21ec4f5663607f72d9191dd644bdd4979323e14a810c083f9f41966f33113c5c2a0c8d2ec10eb46ccd9793314ffd0f49fb8c99afed859621a80e43ece33dba4fc34dce84110807eeb781bdd047f221f3b94168a910bf81a0387a8fa05f6cfdfb1ba57816dae4cf47c163cbf75354eaca8d49fc72f0132c08e60063043ca8834af2dc3819b095233f758e7ad753f2c9495e00eefe02f756edc35010b3b30481d6158cb1c3838108ae4d0c5cded8dde042b29094fb091680683209d6e7f841ba5073c4088abc07f37e1ac9c34e4eb6ac459a5a39e839366814358a8ee92543955e4fec529161dfb6f7ea209b74241fda4276ea77b857d1199b6ff11fb1519ccee76c0070246a0350b39dbdf63bf068389e876ae12f114dc517cd22cecff683490199e032da0277eb5e1215d1a4d4970146d1265fc0ce11f2835cd6857cc6a890fd3fce38b1526520982e54b0973de99cc09ceb99f1555b8b99b9d4c7252015820cfabee31baccd58a56b32472a29c56fb4ae0384048bef62f9b4b36aeb9dbb2b52281ccd67ca91155884e955825ccd41a106d24b44935249a192b5eca8a10d3818874fff05f715b608f8d90ac97da496b7a57030c65612b17a5fde936917847600609209ad167c3ba62124e3b8f48f7f82cd8518e6206900bcf8a69a70462622aea99b83791a2605b0d3e93ecafdcbd0f28b76f6cf386e893ca27757aec6599c90ec61147a6049d78e519affb5b83beaf0facf7bfa7b0d820434d3c176f97497f093f8a3c71d6e403778fbea3cb6f4b5ef2f160cc3c904956cf4eb71ef56f6d0ad10148553164e051cd36a3dc22e7ecebeea6441ed61054f9f136dfacb3c6f4fa727b7bc03462b8a4422fb8f4e372a8ad1836d9d5415f004bb48378b075ce3c3e43abd9ffa13b058a81061eff5a699270805810c034aa80af3e1cc783c26d25718f3476954cb071311005b3cad930ee047d06abc80eee8585917a588cb1ec9a526ae8b6b90c9334ee929a62201db225ff4205cebc22e4041f86f21d79f193dc6124d844b6ce69bd0638abc234228277bb1cbb9962551c5fbf62309616fdafb2c339da5542c74758ddca22cc92bd8aa26fc45e6be4dbae1838eb63e55b42d18cc30ca20fe505f284eeadf47724fbdd4529f8a28395a482ce7dc7ec8927d524be4aa798e14399f8bb55caa19d71a6f465e9ef149d0e295f96f22f948b7eb3145c964e1f5f7235ba1de964707e30fc3667e33e4dcf0d46892279eae0023f93be278d3355d17277281a0ef0e4ffc451a4981ef3e8733ac73a9f1e1f849ec76eec8d3db12db6269cf944eeb9d44986e99fc037cbae134960c5a24bd3e33f9ebd2356fb40b43886200e93b928c6c4961e2217f5eb15d69d94230ba56878222e026699e52be2aec156e23b580ad48232763f459ef02e1f65585efc8a15db36c9f6878f1ad93135cee8b65eed370ee46affb943895ff78e9f0c7df3aef1092e11e909e9f3b0d551f27866ffdb191ed5fda9123d904c961fca0609cca6dba23f29aa8b88a665a52a50838db8f5637e6d79011a0e2a268d8f62f009c9e4c1b1ef59992fb5967b0251bef2a57b5486e41019e9229d80083ab546a950801f0827417c9ef7de5a21dc4dfe3f761baeee393656e324e20faef6ab9a062c0d29d4bf6ede1e285e2ee975c2b99ae41c68b42a4fa832c3a40cd0df222c782324b6608e36a047c7dfef12f08c003eda8c0c423a0541a9d3b2024690761a09b7f6a082042958738e9b1502901364ae6032692548fe64538621bb0be88eb8a9c6eb6ded998003a1c3455511668b0a36f9029f70903b4b04c1a54621acdae5e496d3482099c5b2f7d11da42a676ea230cc7f33d3290d082a858cbd227ac83469ea7cb6c601c06b010b476ab510efec03e89b50644cc69379832fd0a1fc0a05372e8c79ddc86a685b759e497d09eef6a3163f7ef5b3f6f12360bf1e305f4189774c868f8212a370d57c30859fee54b0419de9770fb133f278566ee4ab580c48e3fbd803abcf01910141ee1cc471a42db2854fc1751195e2228c5c0b202dac370323b0423b89c84109bbceb89a6becf2200d875e586dab2a142ef3ae04c54a048fb6627db94e1960f93c77acdd425cdecbf7474435f9e77f482c1083ac333d8066bf791e287d7aea00fe8a3bc25f404a5c6d63429e9f2837d9c4ed630af057b921559804fda5249dc0aec217c211d4a51f68eaa7ec3e26332c1f5584d6979396efa0c0779534d6e775718d787851e7c7206f9a1fe63dbeff9e3fbcac4952b2a20f745778ba3e8ec00ca6ebfb08d07e1b059226fdb8e3ab83d577be998fa73b587d4ecb416d48024c015e5214d0348deea6c47cf9a6ea5a48a573d8d1a5115e0b2e4bdb91d10a4aafb82858121d3209e9962ea2d6dbdafe365e62a1dc7b60d6621cd8fa59526079e3c818c9b7d0e1461c1362b2895f0c6b98cf07223d8cef40e369a5a0b721928852d95027a8331d337061117f8408916b3f7d63c8a9ef0a04e1ead5c8976776d1fb0d672e81805cf2fc13df8805aa11f8a6882cdd3b8c2ee39d382809061598549ccc6ae493e7bc0b4cb347918a2d806045f4808f729bd0f05539f1af54ab66d6c887581667fc596ce00ff110bcb4fe6b53a3f8b4b3038f7163d34f5d745278d3213b5484be26a9692438cab11f6ff556c1a0bd4cf7607f7148ff5f88cc1e488b2d4ee2cc844601603c1f3b6754b41e570235ac39c67a53b722f6e94ce57ca75a6473b25852bfa5f7c17207b2933dea06d0bafe19c57fe6ce64a0002005cac1c8a53c5a447b2a68e152bd6b21558535a0d619ab843fe77b8b891cace872cc16ea4576352b744d1555a78fb19a0e1f2e1daa5df396b084df0b1464875a309ad417f5a9ad14f36cbd4e634a9c4ffe38d9f0b104a29c1091a1fc572f08e3487074e7a26f5f0ac21e56ac73343b46cd5bff54cb9646f112637045db40e27d7d83a2bb0b3162a7a66f8c88536e9c5a7b7a33afc3fd6c6673e793a6c9bf3606dbcfc2a97831d102aa0f5349ed35983e6010aee96504026b39acdc9cb183f1075ffb7c6caa1d30552d84124e23aa15fbd5e4a1164c94d346cf9baf4838aac8a2948a6204eb1e4326f8ff5b17913c1a9ec4ba8034f990541541ceb74fc752efbdc8c6de343b04f6dd7e2cf6c3ee43843aff51494cfa21a6ecfe9b8f24a4705d91e25c14bf16ead5c6b087f155e2faceb0bd464d9a00459f80d260a315795f00ede4dddeaa48c5b13af85d57df9a6dd0f4bf3f8e6bf657fbdb197f18a1bf4c1a9a9bc20c594a147adbf6afbdb07827febd7af34f71a4468fb80b1ad1066c5088061b510fbb722d7015c4e34f324d46e2041cfd19566c00f0f513f98d42f8a7a777410433b49cc745b0c5ea6e6b56818afcb63029e8ea635a68c841ab6e77e740f48fa65b014df04089d6632f89f8999b4185729ff7a47c4f74a62523701607abf8f4d3bc16ccd1d5f71177ba21b10fd116be74445c852251ff4a2639b9030d0ecd7d93b13a50421c346d52ac4f3853d50fcf204053ba3f81c300d30452612705133fdc85504182d91a7c1308ca1b7f0f17308676615a9eab29b0d09e8ddb84275c7baf7df1260a6b750a68d59a99731a5951f5855e8b2c36b3b0f425e5f18ac813976bcc75969a5d1789723bf5bb42825868ce06070685ba18a304da142ba3819b166de8d2099f64dfd254f5fed5c939d892355a3cb3d6ac94380c9e3c3426044bd780aa27111900bb4903c8c81eb6e6e597059cad5417a8592f9e4604bcf499156d49e39edc17cc86ea22ff5e23714c8605a37115ba9d2300056a5074ca052eb8e428c8c7f6c0fce70b59e56f8e0e4c3f041065917efc23310070a4ebf5ceb9338a250e33109105d808de289f892df552673ef3c150ebf838dcbef8c7ed53783a4686e569ee9b5e6c4be1894e788c0f3fd82a53f707f738ea38057f5c2d89584681c36c18dc93320eef347beab80af5f4e53591a70bc02bfaaa4af6c6db26874a274429dbdcabb829bd76a12a404dc19346b90d3d6ed9c6d8b1300bee8afa3554d194f164bdcaa3c8e118981a411fe4cab65624f476a0525ca40ac9e29a4b26a01de69f0839d28ea154f1d1e6e2f12ff84ba0e02f8dd8467fa4bf6356b09719f04f31c80b8cb53ed5273a14f2b9b3b68c0bf01fd03374c14486d2cb74a388fdfbb97ffbe88257c70c314404b7213e363910a9910d6f6153db494bce0dc4de9a7f5bcfdeac77fdc64bb1588f5a2933823397c3d046cab9107f83b35fe3883eea71a89fcfdf7252cd4dd95a399a108bd967d280aeaf1b701a7fa4e007fe1d41e4861f170caf3d5db03df8de618d281e0d84b77798cd0c9312bb77c5befd00b813cf482e5401d5a96317a0126349b747dc092a22fd8b9f06790a5c17a4c2442a81e2c817982b142cc0fe5800ea7abd5e5beada8fa542d12622fc3e4985060e520451f5107393a9a87189035ad6183e054d7298540236222e7ae313df714dc5aee752bf81179f828c4b4e51138da7d79194beee97fcca890882ac59c3b9b40118db6fd0d0cde8d108ee1094d88c821a33452bee1af6c3c161fab626024ff82055472f92bba49b528fe22f4b432c50012012759a1994e4658b8b17f5018794aa7d0ad8cb96fa3d45bc21b9d9a40874bc84e9e4c67e3f58b734d09e50a8d8b9f93e7f0b1cd47a3b81d20e20fcd523a88188e7840a0d8d2c1136ed50c333e327ed59ba02342bd9f0d5028d33db54c2cb60b1061350d42c692553414a0f55e505461a07d727c6981c6190eef21ea313a61756005123dccb0aae9b18b504007b808b795c34d3f3a54045ba32a7e66f22a6b8c007044cae3c9982331cf2181cd5cc4ce1ae417e17755390813700fa66182d9207c03e2676ff2673003a92d0c0f3ef52dc49baa1b7d177bf576ebdb0e02892c52e11422d8ee7a8c11e3376fc428513c58f7b645f7623b118c34f107ff677ec16d353b3a051682f95f50eef10e3ffd8b2c309fc8eb478d54eb0c00c569e6203579c1227939d1b291984d50b46726c0829a3eb8528a644dbd16d25fc5635338909770660dfac51a3ed0b196102aa3ea5ba2fb1eec0cea6a671c37fa6ea837e0517e4aa23817576d8b7c66a37981e89cdb0612a463533bb4244fad0f62e770e2b33414d8f5744241d12b953c18b8341db757d27faedaa67a5efd0d2de650de692f655bc0072bf577664324d03e0c039c736019be241c04706a464801231497c943b4ac1e1f840ae8b2b65b6e212f941b6681c41a78304e55a1c35e5d5dbbb69577f491d4ca12bc9a870ff5e3152f47a5bc52e0807ecdeb4e36f6c060a715c0e421f0558ff97cb99ed85b0c37d2d7b9a0a8c0ab8cf8ccbebe2a6cc6f76b89febd84d4c3297f7b8572c337841e07ca56f4cd6f4190b9cf68229610997b63f775abb7ca10402a5b01bd6fbfd86014795b172b2f3c92fbc86c46c76ceece3de0e5089f1c09710ffe0628e0b968cdab1c27d0113b848b2a316c7490288e4ed665c4cf41b003b205eb9d1f968fe99e39d480ed58af36a4d7268b2410300d0816f72271954c4d0e729442229abc68c50b883edd56b3eedf9fd186a83b13fc2906f247f67fbb77d4b98b15dea4f9d08401ee67120e833df0d65de07a0c24eb1eeeba3187fa62372aa556263e9bd979e9c2f4cda01828c37ef02dd6932cca89be9e68d5851b775613d892326703c7632afcb36cd05ce26b9b62ff3c40ee38b22afc54967b4af69b247d43188f04f00c09ed89d93a8b0dbfb95a30368c04ac56120ae648c88383bd8019ee3c500a6cd9947e3b88f70f1a3ec752154566481e64b2ab7acbb3a9b956ee9fe5e59c5627aa05d7e24a9dc7a5034396c4196fe3610d33937276ecbdcba5ee66a1590f35adfa68e76432ccd62b3f80d57ebc2c33786441c1b083bb87c68ad3cc2331c7bafed8d5fd5d473ff9ddf68b2426d46eeadb5b2dcb5f759b7832da82339450d806f2fc0451089bdc47a77cf61d8ac1a586ecebca121201f5761146a6b75e4dfc2f6f8550671b8bb53a6f59872b65bc595cf4c287fc75a8126923a33b4b03cf36202a5663f10d972a11aed3a263ebdccfbade523aae57f37e749138b2142b2458398fc80b20ae567cb450172e6f5c75e25fb3c5de241a4e8b2e0d61487819bcfcc20983621752bbbe454e0d3b38ce8764d3e1003656b0555d956d5fbd5896269010e98e7fa8e1f918e550f487964edf63c4b5ca14395000ab5340d58ad6af503559f81972501d7f1afcf09c6fe470c51bd41e9e157a4aa0cf620b3e8956e3119e6e4433823cea2addd8f9bf9c8b9e0a79f4491690fc9e5197f29f4ff5533a744b04bbe765d75d7555c4ce4de9b2bf0339f0a6d86c0298c0dde3d9507ba22958f8a8347aae8c544726fde61751668dabcdeba9d8e2392f65e3f0162cf51fea1d5c262be4e47e68f483254f0fc00abc3bd04eb41a7cc49aa28391f114f156a8e9c96e607ba1c5bdb88c7edc4a5573c7b035728bb81e65066f39721057d05109f3d02d43ed89993a0d072e889945a51befb65fd26ad54c1ec0bdc5981ca607005aae981ea9dc9b18b3c80ba0466f2558aedf7de4b0fad0260985907e2fa9e5125ed9c71693f9126aed1ca79aea02856123f10be12b9ae9ebf01c8d0c5b199bd97898b8764d8cacb7cc48030a85f36e242dadde52bc3cc8d84f1b0ad5e1b061faf910b9cfb18928ce48b1cb95290288bccaa04d1274a767aee4f8c1ba8ab43fb02ec3320811f8719869fbaa6c9ea5bda5d9eef4dcdf05a46a28067f814acc2a41bc432fd9dcf01064700033335d337c2e23aa6436de5dfcaa7709bc9b4a490928ebb13524269654a790a6b32d4ba3c5f4bc98bfc4c9e38e40e556a80e4aee7abf23d1210d69510b21a39e2ea1922bd9b8f23002c2ea1f111d676a64df7885c9dc8d549d2d8cfa78b19a5ef820b38c304676245e09979a4f743204f742e39c783351644005855e21e7160c730de9ba562b2e8715f5b40184747e000b1490827dd990d3e8da066d6b9f71036a2e59b9f29f41610c79550f95d73335dcbe906d0195f9d9305b05c85d926a1f9d6cbb2cc5ca9d9f0ace2dee0db2f36901cc8461ba1b4369657c081a71421e8379813298feec6db65b6c19ce4174c544cf9b9ff8df6038172d76e3e0ddb3c516008bd65d861fe00b8d4166b7c0f590195c95095d631452e768636adaef73e2435ab1a4698737acd8309fb463801c3947f6950db0957b0c6ecd3e36ec11e12a998cf5b1a255c50e58c5d5ce6fa17e71d260693b5da18f004f68b9a769a0f0f2d1a747dd50f1715172cdd4e01cdcf8871a3f2f69601ce9d32b842bb1a0c2ce46c1e2e8a991309b72cc07283bfe12d659ef8e50f41e157fc4610754651edeb35817da270d22c29eea9548066d4adeadd6a26c761ba0ce07876f6d5d498b7bd955b565f436b44f54c405aef2e5dbd9c1037f30f3040201ab53df9aea1126b78c8b33569a8d478067b2935160fba50b1c1ce4eee39a6ab053d43de5eedebfa163dd4dc9518f4061f42966037d9a8a08dfdbfed9585525669f1c0214475ffb2a39328b78c4be2bc9433307c74ea87bf93917a6d38ceae4f4918a0ac6408842f1dce4b96a07ce21000e1107df9ec1c82cd4c37d77e34e32ae60cc609c79643499769a66c7007d486c53e23c09ca8c757cb525e8117c7a0a16e5456d0bee379837ae7ed02b4b53bb49dcdcad4ae4b2c506f09ffb9b554cbed158833d85e36311e747dae022398203237b53390898897556b9d5bf51bbf65200284de89beedce316a4fda77babe3434bf97e4d07d479302edb9daf09c7fca69b5a583ee3ec9bb75b42ce07e0b5ecf24d9d00430692004f67294d10eb57558f2aa1f6572f5179fa996b2575ad7fe3150eed8ea4621fe869437bc6b6a619c830035a849289ad115218884b9e04615f34fe6aac90e499cea980ef5644364dc1ec4f50d49b6bc0d89c1128c1a928688294802796af667e1ba9df1cfd3bfae0160c925f85f1371919eb3cfef9842b4231fcb788a08074b999f79de0a8ef68412dbd7bfa5afa068df7aaa22354f2820fd5d5c10e58bcf89b9a20604faeb95ad91a8ce9e36a000980f603a5b98f74f5ecbfcfa3f15842c873be8985f1f44d160581662778df4a760171f3dacc287ce91f7d701f429887ad104a8b12a3b8fc3015161e5771d76ba662a98bb27c0b6d5609ba6697bd8cf6400e4906b996d4f18b8a2a35a8100f7df790225157a1cebdd7fc40ac463d621f0c067a079a4339b4bc5e3273c6bb3885148006e2470827a17032b6f13f8c2ae728cbcc862397ff76557416be4ee1c4ea90c5b63e9cd8d00f12ae89b52d7c74bbb49d27937cb96df69e17debbc22bae2fb85ffb913bc4f88e623c98ff7cd6c599da70867e46297ee55d006d8e1e37d019aebf85a801d69693dbfb180ad5f8ca550e17914d38111e3446cd728392f4fd7d5ced9de2eacd6a52d467d747d8ecb8db96aa255133f013aea792659144fc0495ce8971a1735ae1d2837a7c5c138690d36672a38267ff50fe34cd337a5c9b04762ab3decadb652a89da178ac9ceb9151c325c25ad189c6baa43f160f610f7648e16d04baf649a36177893c4f452ee706f72d53ba426ebecfb950db3da24b925ce7e4e234f711afa8d55db7b9968074c407073aee39c38141ef029fac84f0016c5014935011d7facacbbb5d921839794f2365681601d54a1864b7549533eec3f95b5c66350484a7f89c8cc935b895ba0e08468d579c40c00fdeafd786d6e7639713cbfa89c951b02c93cc9c55f3a58a0c770032b419abd13e7d978c695d22357038f63371dc9af39d740bf4cb679754ae6099809e7a54b0b179f35b7890295ba245cdc9934338c857947691ec51793dabef2e9376b6b27d7e502fdd3029f40c2648a24b88090ea2bcfd359b70496036545834ea27bdb81c52c053957f3c1e94c2ad47615acb1cd424e60ee9fb11ade0692e22efa0664dc4df2363c02382edda1955aeead094d7b5eaed54d6625dc846b963b070bf322a703574f75f716f49b15aae1f880ede0d8bf0f1ac17d682ce45e9758500d6947227180a747192042d7f783bfc754ceb44bb073682e8d2dec3db6aa42d7a893de49e6fd2ed0c0200e3ed1f159486529ba32c48c492cd4031e8592732e2506ae679b23ecb0234fca0972b14ddc1d7e434b3af28e93129840abbba14e15319301a70b721db712900c225e57cd91c6eb5d5bc4253501a5956e441fb73237481360459baf5cd823326792d6272539c11e9104f8a3f038a83fe733c1ee832b076739bf5b7e01a2ae26bcce5f4b23fe1a344b6beda3de00f0678a08f925fc0469e9688f89f5cd34986e68c8fc85b4ec25c0721c8ff3d760c7717f700ce2b5f1041bd2200e3a1a5e38fcd8e804ae263cb7ea8bbb620b2234605f01ea89d9da820165b7c4cddb81f2f73b4918dd9363c3e70d6d62a4eed685c04beaf79798811754a4e771eb82fad3c3548097a647f491e8538645b96f675c0798e58e873ab3b78c36f3030e2f9bcefbd35d471b6e7b7d588d6d1735cf779ac57e1cae4013ec3f9d4e4dcf157a3dc16a57daeb8cfc0a6787e40c87b7596a43604c137cef586ebfcdb7cb9069570f620992cfee716b5ce8ef62cbc77faa669882257288a32d6b036cd20d62a43ba00f2dae7542e34f6c552a16e9d36882e1a49460e48f6596d1d090cbd24cf13893feafd4e42cfcd8b7d133f462b1711b28eef5d65f34b4eaa8834249d173482a35ec46d448875046a665becdcc2d207d5864cfbb811643d8d0c09e23d09ca681f48a35f566a678f0435f387bce473e122ffcfed738e5488fcd204a5f08f9c14f348d5e2e9ba784cc035068126e5a10faf704de30d6ccc22210d0240c5e3e8c3cef3932c6471165e731b8f848b0ee4cb1c9d8c5ae770e08d82ea94f1421b89bc1615cf51c39a7a8483e44a1394211c90293e234af6ee0184a73ba0a62a25554fde0e667a0beb33c0902eb9d3a75a7fbc89c053f89839dad08769388ee0188dc854bc74d493356154d823765d2375473f4a5a764b795780ffe87c06e2f59c0ba54e911e4f9bc0776d70b98336cd9e18f1d1d7871cc8f34c55e6e7fe6f2629254f50f0044fd046647ded32d27c82803df3d9961e1e8400c9c511710acbf1518b235b58c74d7eef7a8506afde067284b6aeda4d1dbb5dc4d5231425bce3f51ccb78fa439d0e5d566e8834116930bcac8ac801b8f2344f9f71a38a70917792f26ca984b6ccf3442a4da838488187250d557d4920f1149bd1b3e502fc55f607f173e16515e60908bb560afafdb71a15476159f0e86bfc55702f24e0b35f45a85313cb9df1d7b0cad2a7af531d087927bacfd220e00938a60e20eb9c66942f5a16da2566031115e0fc54d0012221cf4e23f1915411993fd6bb5830d1dd16fe9d6847da1213ec1f11411628cbaf7c35aeceebc1c09264abe427861f666b10d4d14c741a39813fef5da43c38e68b7df6b2e94cf411710c89028503f6b7b2c596d61042a00eb8f16dc9a05814847061488af822eb583d57671d58fd3f26cc9032391def119afe26aee4b7b1c5e62af9b305cee07cb96721c5239a493ca3502682fc1e300eb5c9a3fccfaf421f9b578a7022cfc0be01563663f24a3b70cb82bc786bbf26372044454a75edd6a7ea4d821660ecafcc051f4f5c726ffca5e3c795881ebcf268b17ba709c03b516284690adde47518046c86c49472f04ae599be144e4c696ffb96be633c49942d4a5cc23330ca5ccf220b74aa3982911d7dcbd920df95a80736489d77836bde5a86a4862ef1922d4c4edb5e134378866111e238b66282db3e8141e9f0871aed63f9e60ef5ae2d1204622def9c10a562492c9059a9dd5de9f77fbe9fb8fefbc7f68459b07f578f9a13c96f9d107cd33e5d1e03d89c359191a3cfe05603a399421a83529284129eaeec3411c33c3045153ef1ed6c4d6c2cbbe59d6da882adb635e531a179633987fe6a978a09dd2ae34427b3e69fc7e05df0a40a70e10ca207d3d04fd28012854858c82f4481fbdbef4813205010acc4568e4c0977ad09806deea899888a7a5cacf90ffdc2309b1e07e93c24e5aa515086adbe31ca18aa3411494b61a8c3d198713db1e7cd23d6b3c055b94aeeeb6600308e7a2c63f2a5192934d0c0d41d4785c0029b1f22095a39f77b9c5b960f0db847e05bd0ed8736dde05fe0800ed4d251e23bd74a5d02eb117d5b31547371e88f482852d1a84556c356f2bf51d73b6e888428c0c97a4c84189909e684722f39976e255f82c7bd4d02197555836741460429acbc17ca4a955f40ea13b28569bd1c9558f0eca3f390e5706f2a66af8338af9008cf1221cd260acea9c094a8653df2a9e617cdd13f81b72e9b8caa542e020ce54e41fbaad21aa583169dc0f9b33621e89567c06b44135f01107432c7b34ab78f23401530cf71ed8a63a997ca4562a5e6d49fd23ba14b6712495361b7c7438b180031eefc0e93f9164490fda703f5aaa7cbf877bc9a20b1568de266c2cb0be7cab659cc845289a7ea87c7b4c164578103305d4e93ba016b03fe3b421b6017d1f045440a274d8ed667e1ec24b437eb59cc1782a4774536292f6cf040a3b332567ff422ffcb9b8078e5da81de8fcaa4b666ab9c3c63bd7f022c75568ddf80d3dfed8bfbcf2ef275352319a8b3c94958eaf4cbd08962368ff97b3aec6d6ded9c2e03ba2b6d508fb9777a8e4f23d281ddd648fc8959a2d6cb1677ab88e572ccb55db463cf9326311f61c089baeac7d6803a74d2a57bef055f335af728f954f3445d6c8d00608a8e6a2212f5a9a003175005067b462fbe46082ba01f36b5752928888c0eef237d7058157a7d3b848938029b5af0954443a23e5e5ceb274bde4b0000ae5f654ef62b61e580c4c180ec9df9a110d083d16aefd58ebefcd8defc861e8d9850ed5fff0d78b71ee94059477c87999edee07396698b982e9d60853fa92050e50ea238b48c2534be405edd47793c6560895b8dbedc7d7266f9e2f7b818f72b7dde937b09f0250d04d49190a5976e1777fc18da0bb70ba61830d756250a98125ab919b909d7626b696a025f489c2687fe246775499153525b74827bb51de2cd89e3a01c3fcf6ad552794cc3e5ad402fbfa47b828bf1e6b1390830f7dcd01b6b3aa37a1930d38097a34314f458432e6f192663ccf5f2d4a715461ff78e058b6afd8bf2bb8c9f383adc2a3614a49fed666cc718ffb60c321c22dfcdd33795515c639fc417b6544b4b4a66b97ba93ea2e1e2563fb81c5aeb2c835adbee1bc7ce8539506d78f9c490cbadbd2dfb4e46faf47a113eb4b6f4ccd85d92de965f58f48f08bff9afaeac7094a130228a206a123b0f011fb2dcbe595fcf704b31b6dfad69fb7a0216b5ad97552df1815e7f1740f47282e5db3215a7e05919cdf3557bfa709b9176e7740f4a3ad7a58ab357ff13c9551d35d2183deb960872fcebe50fbe9c99df94208c09d68bf27a99e021f0b7bc2519e94b4d3d33cd928035af5e1690f659fac93d94b7da8d42e5ea7f207541934268ffaa977964108fb65cec7c4d9a49f7c9a2c0ab8bd0a46a157fedd101491c1da5848c41e7088ee350ae9719c7b17f5624242c09cf78258353f4b23c07d7d68b29837f10d2156d4f319dfde1069a770526aa9e1ce84eeeec4902efd38c780e8b1464ba94d207a96e57dedf67452f17330c7170e9ce00bdbda1a908bc7666b89b75db65a8419296aa4e2faffc243977bd4677fa1ae9590410ff1181a37a39416b3b1aca0babe9e5ced897849a1276e824655ba17ec33c93a197b983afc5c57beac33bcfbc6562fbb24609565ddd4cb8852241b92ebdcace5ea1cb5494181acc19a1d722cebbd1795fadf832aff0e4e7cbae0742dff825cf75b61b75a349904bfcbc31b4db1976aad811cfaf92bcfab2571f1abf1b0971199354a3bdf03a11d09cfc77c6564d0dc1a9d8c31d83d436db9491216b9d89515f3ed5128107250ab7933a62fa533480a821fbc9628c6f6165c0b2e589195e0a2e4e9759cf7bbc294ae810af40509677b8ecefb38cca1424050231ee8cf65d7b5a35aa586fe99bb634d7b5632b8f06b5f8a4711bb2c33955d1e4863390fe1e0c59578e59f25e7132d5ca5f0ebadbe1b70284fa601a6fe124e0bf85a2c8d1e445b0d589eb8cac257f8f96fb7525a49073308ce98f59d7c8459cada895b4206a767a7a69f9b3f24ac19f2c8317e6f7b1cd18a1d6301325cc13e016c3bc8755b9405bc6886c317238451bb360c762f93b5bf6d9614c02bd9f1ac66d3d2b3c5b8e713e3d294ec90b4c6361690a92b3009291e9460efabb5dbd9a28ff6dd69e1178b44268493cb2cc9da083dfdf208ac37ad52119183afa5312351df1feb16f510be98eec4c5ccb3b31becaebcded75ff6d3fe38c99a1f7c3c6060bf02eb47047dcf0189a4dcb42855ffe4af2c7bacd43f689e17339086becc8cec510108b8716bcf02604bc37bc510545177ce34354178e0175ac7ac333408759e29732f394ebbd7f2fd866566571a9a4e7ad41f0639d54f0d1703ce86772bca180a7ac033b8cca15e61cbb69d12b1533e9bfd0aea416faf328c7d0d7e8506053cdc8e5347525da1b197c55021df4150a3788cc1a23b0023a3b9d7da7f5c420a95645bc4f0150afde3cfe9183324fce563134473f4f1359c2f874c7b6fe1183430c40ea00152adefd8c81040551a939f02f9cf81c2d1186e587f463b6491401e326403d4f7fd08bc31e9c345bc5e6a6b8e899a84118f754fa7ceb5e0f9aef31c852aacfa5d72351bb911ca615f8d2f25f678fdf985e6c8f26e94dbec49ab04ac2d6532454f896bb94ec99a41484c79233258f9a75ebb326fed21028d26e39f5573e444e7acaa93d6b4863da48331c2ffd8f75bb5df682b6bed79a7819b88bb6d133e11f176c6f15f8aa6d63106b67245fc207890b24d85f2d32d87e7a46ca1fcf40fd44325cb562382714a7852813357a013af3ad9573e65a7b38277f3080441e133c14b3456e06e943591178cd5ade112db1b40edacad8fd0068c8dbbe8bea894e195cfe1770b372a6fd711b44bad0681e458c7cbe947300cbacb7b1a6b72c471178aa2aea1a2c714c42a595832576eca52af7ae8cf92fa3b129c1423601234d3ac9f6b10e49fa62c1dc2059267d5f5efb9cc9554a8fce5d1b937ec23edb51d7bfb851a49f09ecc8fda49f832d9d82d7d865fb379ca9b0ec0a36e0c35c1ed808e87ffaf282c2c91f7f0d7ab88ea92dd6f4c5d56422610356fc6c4e1c9f48fca5ab94b2843b87ebe8aa6451f781855d03d6b1fd734e72573becb870048b6937ee4708da8288ef58bc4ff6180ccb2e6d28e778caa1acd2241b7142520a6bafd698008d4df17e8bbcd3605e99ef0e020d59975b66f60c4842d63708ff29696050f95db5690d513a48c0039101b1da5c8792f75ef15b30d89e20888284a08943f853319320df5d936197c429f124011baed1e9a5f3bf7a5501d08634f8074e4fb6a7eefd5bc5a24bb38b073a4109251f344f51cbefc638fea9796c0def062c787eca06ddbce292e1b69c952222e3b4390ef42d396fbbba6c68ab0be90ea03939b5d9022315aa493e850db85603bfb66a7baec3f7c7c2177f9e32e7f69038868d4b58d0ef14ed7622619d03a7aa1357419823a2951a36de2a3395d726e172bca386dff70760acc37148be8a41f13e6c35a8a29f428c3055a5400c25b64736a613a8e419e4ed5f6e0f4bc39fde90209a07107f83b0686830b57542a879da0b81f637dcdb8a6ce0f45f6b1661140b82cea4bc8a65a5f16c6a5e552132662437fe820744ac00dc2e8a577d70c3f00504832e94508ab3dc45cc1d802fe0b8bfd2e73db987401b62a4496728d05a03f6d8809f4bd5c367c026fa5153231fa19f5e62ad7577c8b7837dcaee23b6c2c5e8ffe5d381a50a5d763d27e84cd199f16c63356e02a27047121c0426e6b8d2120de7ebc30f2e8f9563c97d4ada176e62b60275df25665ea8c7e4d7f81df730e100755b1ef050d272f9c4f2bdf1faff9560c56f23caa0028a3aa86ab1c667daed3a6907fcfa34de267a8bb28f5a145dfbaf13361da1a747efd1b75fbca982481eabbf61d00d61fb4fcf84bb463a508a04d5093c43190e038b381c020c24bdab749d2dea83434ae8804ac92de3ebd5cc2aa1e31b543c87fa882de70470e4e918758234c2a1a183b0c04933a3421a4040c41df4fb51c4039ef202b8e28643d8a10eae4b2758333a9c0481dbe277b00d29db92a707d78fd2b28ca7793385b0a702737c3b59c9801c2e42488ab9772285d947ac849d345295cf7f79dee1928eac4109d48d880dc71ee898439de2ec5b528b85b1c5b5e9216c57000b11d1b7158588a642b823d7ada0d6e2da614cf619e5061fac49f6915d7f0244a7ed0d6ad688c6eff280bde82b8efc1db10a7fa416cf3dd70410737edc39843cb2fffd6be52df28ed8d69fe83903b3eb41f3deb4350500857a3882449555f7760e30dbde964cbd2336e09b6784dc6ab84ade40e0c905978c609218368f91f2990c8164324c496cd605b3a469ea419c5de8a549909235b928b95ad47f0c3ce7c89fa3d0bca8836d22c7161139a86927e1d8c99d1bfa4dc07fc4a9816b48916403750a42af8111217d26df27f2b800d416a8258e9a98b359c86391a57f9c3637aba4fdf851a2dae9bedc8c78a5c91dd64a40a27345bcdc1c5910bcc2be74cb07f08f0ed65a48038594f623a60f48bb1a7e98f0409b2af98e9c327bb03e5d0e3172d31e17b39d51b265d70aa3a54cdc9cd74f999cd187f3e847e8347c2dead73480ad43e4652862e56673753367a294f28930bcff790aae6f75ae94eb2a768bfef70ea6620cf4fbd252676873259ae091a6a85ebab05635329b0cf9f22f8a779a4475d45c0a0013ff015541cd663c848060c163ac432c1e609e8613a17f530bdd666b1f999ac1bec27d0075b034b6c083c42952247c45ef5b1ccdff2cca4740f4ecf17fda60524152f4ba5b7707004360647edd4811afe44c958ef66f02632e05a8c29968cb2bb15fd92adcce8765019f5b07bc07444e0dde208be5824d6c3917af7f9b6d5c04d12c829ed3806321985895ee3531128dc381b1db117c671533bcada25fe064e66e06c600bd8526768e72f5cd659fcf28e16017971e035e3775bf6e10fab8b4a559e4c4841e5810a250189183d0cf183d9a3000ce4c12aaa570e08129c77ef51b6b845c83d20c7cddc18b045268152ed2267250f81fa128fbe51c7c7b070a99a17c27e688a42e43a0715ae952dd0931363cc52835168e1b506d626960d16e283902459598fd25b4520749486938d21818e280420d641e42d24a4382566bab255319f779ba465a46d6e5c8cf6cbe7e1bd883929712f0fac23e4201bb2e9235f663c2c45eab0cd517c3d06349a8c3e991e441e59f5ad2987bc6c5798974a3171c887e84d5ce755cccbac6463f5b5ed11181876726d2eacf0fd3657bdf2342f270a91a17da2327dfc89d04e6be254f1082685316cbeac1674161eb362d7423892a99b7ba075d986c618b1e40febfa2cfc1f1c06c99b3a7d26fa508e823d379fddecab31c19df74e4cf35eb93f8273ca41118ef0b92d5a32d6ad513261bdb9ef2a8fb97c14439123ea3c201a0cb69a07f105c77bcc7db4557f0cca926ea74c475905ef056bbbd68c485d8df780b07f9d6e098c37d9bbb6d1a7b123b6fc20445a7855602c494f2b648741936e89e3fb48d1494449a5a563e3d767e88299b0930c4bfca0d8aa21c280a26d326758039ac820f983c0add8d2cb7c7445dcfeb4b8ab1a69aa4e02e136d4347622ea1d82f7f5d3ff0c58c599fe8196ef2944af5b71e20cc7cf3c1836aca2b55baddc39f934f9c31d1734822c4237e63e48757af5b751345fc8c4c0a4a725c17ab65a4bca602570f1fb05e56a2744cf472cf59c4689310a17c68c0bd073d7e1b06a1a6397fd1ad5c2d7282ed57b4211cdab0cd7343109a1cef3ba61555cca9bcf365daaa8f6892e6db3776a8e187cb120bf2d79fdf9efe74d7ec592371a4da0bf37097fd9d51cec33da38d545edf892846aae68ae8e1b8f5b56b453d4cfe2ca8f1da872f70c5e2ee077c9f37ccb3daebc70c610797b211cbdfeee4e68edfa4fed791963bcaf74d074f178446daa7d59bb64188cfe09b89b9a1af3426e8fc233d0f0d6d2b6a468c7986745a2d33ffe53c6e1d98481b7ad482fa16632fca470db12dfd29a6afeceacb7892adf5c386f7c41797103e576cf82a6a5226d3016e07e7dd449947642a34f4f1f6970087689f2fab3441556f2ff2974dbe0cafd978c7e1263121f872eb829be740cf1fe75d44d663923cd2bece850bd343cf4a70bd81566243a07407c9707f304046baf607c752f577c3ab9a55f16bff8d586b705b9329956d56c3495f5fc2e75574ee5f44bbdb5e2143a77640c972d02db38d872adad16aca8745ba713895585fa3fe40228d5d6fdd040db2e7a900fa91faefbea85236117c4f6ed55f9abe030445a7da58fc727c0c81c0ee5f8eab19a0cae434a7d53178b6d904298989ecb8103d944df5776f97e1b4165795366e46a9234b956ab86069c6420e1ecc78e74e49e8dcfa46de72e38d16940a9f6c1f8e1f6446413563bd7d479b14a55fb057540e875308c4015bb797e7fcb8513a5db4581a7e7bab7a8935617324e155c7b67139daa0f30c29814ff1a23c6ba601c0c1e08dc9d594a4ca1f1782befa51577d51babfb4f8ff45c146209366034f2f5092a8bccc854d5136d35b81232bcea3408c63248b239bb90be310c7596271378285c4840a437a459e2505cc870e86e196b393f7a27f65016850bdc2f882f7d0c44c30458063780faa332b7cf735d6a764c256ea3d6bf82a29833dfc5dc4c309412f69acba53ca5f4cd38d5aaad7eeb16ea96e968d1e8eb461a7db530c945f5e61a8d284efe75924a19b88380c6843222a0601cc4fbd608e6e2595312b7c9bfc1e89f833ac74e2e5d820800ae0dbf2276aac8587bf130e3573889bce254139f465134a2ee94937cb2198135882b6a333e7d46b53296da5f27c5c2a1c4e3e0b7d18f82b70a6da659af512b9ad75083573699664319e3c0fb0d56f86ddc6ff6fad6970dd0401286da083532dfe16928c3dffe832c94ed2987d5d2a5374e6bf39b934f2f8c56f34463aecf74bb9af5dbbc086d961704e3ab2f37568bf818dfc0d80e0c9d5414c851660c6041e443b9480bbd88c5f4beafb09846dc1018bc14027e4be8e328837b51310a6749104f1f7bb5a8705ce5aa7849271f33d44fdfb5cb0701c685742f01ae2d0b3c8de50c040b9f4c6c8130d6f7728ebfc018571f46e8dace268cc4b22286d13d28e655b361b0766116b6af3d62a0ce3fd813e2dc1aa41fb18ae5a73ca7de1c2062ecb3c473c93089d9f74b158e56f5617f625989837fa05dcc11635167375cb0c0ea1ec2269a55ef87fdedcea611c4e10ba1438831033148e3efd41b19914e2c601db6207223633f335b21533102c886481fdec0724b4da0d35c2429bf503f7e975b9bd50f4a2f7a0519f828b8e7dc72edc15643432cd205a4416d8557c435260f3832a2fd6dbedce355674360d403e104f7b811e05f5a518cf1b8fa53a8d5185b7db6660058e17a5aa8c74bbfc454253b4d46fe5af833071d60f34a4ed993edd50c060e1669db6fa6e65a392aacfe2e4baedb702b5506facd7e238a9ad55e0775d0efd8bd17a3d99b1c8bfa6aa04ecc8982a355cdd823244005c2ccd358c82230c50a073fe3b67ba24e6f41706d27608eb47da8cbb3c4a6fca74d87e6e18ad7018aa96fdda5cbbffab77a296a829ca2593843e31cdc51ccd8b0730156aa50f2e168044f6009c62b43d685492c7e583c07787672351c3475e10b08aa32dd7085fb2d1234cb041625eef14d492c615abfa6dacc82437a9a0584ce4e8805622957bdcf39124be2ddf27b73020f48e45e91d924fd56f2eb33e67d6cf57c2eb12b2a185c59432552e6054467ba930154a9f3f88ac90c64c839310c28ef9a1cc70c533b6384225109348498841cd99c0274b74c4c0f02f3a14071ea24f68171485bf3969647e873853ad843374e37f99087fb9c2af26cfbdfb1a3c7613573f88b710a01d98a62d87fa9caf35bf7a01636c82e36af5fdbe981ae43f55c0e48249d588469917b9bd5520468798d44d400de21ae6388fa398428378fc85ef83c03234f5fe1c48afbb753f6c7588407719e556dbfbd6e37e3584f3ca056e3ac7a1de7a0fdd8f48f93d0a50182468ccd239f2c4f416b99bb3eca9111f5795a4e71bd70af9be0ff0330b262c3411f3017ff5fe858b44e05f42b289014f4b0a9bb8251b81321d75a86cd65c0c05b7e2cca1debad4c8a62edc1eab6003922803ee427f55034b78b31a558feccc4b11d1222163c69c703a77f1ce3d3d6655d5132f60dc7494cd34396a987821ed500da06f10cc654df571925dcda7e08a29aa50b594af2316de7c93c5d3a91153c1be3a126322deae592d734004713d7e94cab88626d995bee3634b1b99a3d75184c96b844e9ce65f0fc9dd6c6367408b60544bdf1caffa4ddd0a763b26c82f463a52d5d7e72e81f84d167fd9fa8050aea168acf9d58aef26eea9a92b1285c4ca632574044e5f8d2ca60ab680bf8bf3b66065cc4ca9a421828c6c1e464881a1fc30017e5feeddac4e3aec14238b572c55ee10e08830410a53efde90f3d228e466721ab9a346aceb63a74c8f1b78ce27cce27d706c34867a9c096659d0e9c8821abe2c80ec09ea3e6f3029a02f65392ed9a81b5701c377dc0de32504a082512d707e7b9d58186dbf952d5ad49c2e3fd83f6fe46d6df9db4a5f632b640fa467242a4044d4b0af9f96ba52df2dc8e272ef938a9be14dcd52998b4acdedcecc678c3c96a1a98f10513381ac0dce7ff9b88bc095b6c771371ad70e5f371a4d1c314cd67a3a0ca531a80603067d9ac14f8d0ef80c80631a9f9a06d0b20856fe7ca68bac442baeb3cb51e79ede3cba8dc0326bca50ceac84fe636386d510c35d9f291a82b4480bd449c408d410b4c8298859fb0cff6aa0407dd6e64aaaa6d06231ebdb175432bdabf2b47c662e90fe1da88ad1a0be172debfc8501e6cc91d6815c40c25f4b9465cf04da84494746a39d8b404baed726d51389c6a88868c85714a9e5d93b0ba0ebec380394ca38844dae47ccf65b835062ee0d76993946b90f23597bdbbfd36354c796200169c538c3ddcaaf2403c2b29d1bbe4beaee090c675af8c9985d6762914ae7ad11d0cc2ef94f51c0d7b7b3fd0828681fd65ff51e31acb12ea4ade6014969fdef286d494b79511469d59deff72285009723491e1d9d1b8fbd9c8e81f1dc13dc008ca1e31a913983456dba3020eab5a40f0f31981b44e6e5e7443f5b604c1fdb31d7893e49b3612ad02d78705c577e5b3490aeb379ee0d2a05285b12004243e7fa7512de186c1c7780f616fb14ead71b68aeacc6e23f0cd6349757264e7bdb0ed27efd59ed77bf1a782b5d5fc3ec052edaef88d92e8ae59f8948ff1addd400bbb1c43d71635b053814439fbb41a97244b5a63d31a4f02cd7a0befd52b4d15ab45405cf65ceae2d7a9b4ad93c5b1f432e6e1981de37f70c37a84bb7c85bf2e3a34b7fe2e6764b6b7921254d3b04dc6b6a4e5e9ec074c4633be261db9b72a1c5ad81e89a7b915fe48085d35ce284280f9562fb9fe95b5118645a988ef27d66f43616a7b7aaa992ed49c4fec27b020374d154732f00fc5a5e9a142df2de4c2c8895bec1e81e37d1da04a4ee6b6a7484b336b24971e1eca7e6c9b8ae711a48fe6c87e9034263203d8cc5854bf7d0a4e3db5a87ebcb0f3e1025a520c9fd075d9922105192f54750f9d0dd2ef6d8679bfcd3569249f07dcba3c6f9399896b59e779b35782091887e3f5ec0be9b96e6bc0a363732dc1bd361c944f6ec7e39eca37410b156d6bbbd6e6ed0817bc3e0c1a753d93ff14017e9e473f43ab8e831cb8ea6eb13844fc48d9d37e1a45f28a9c49031dc752e1ed9fc46856ac17c51a1b4972af2b295ffd92dd401428a7fdb232b54a9fd90f405d406c7d13ad3d37705e1f402c9af54d4391144e5b4b2db6de593d39d1db3f7564f29a47a32bb7c910c30ee0cfe90b0a7ba13cf046cef8a29318fb8e7dfc443f5400807ede71af3c132e857f3328ae8889da40e865fe0304a370517978b9e74e6726d00ab54af0fde8271c13e736e27a6cb1ae84445e693ab528828bc270941d6d4f6c3a4040ab394850a4eeae34d9eca379c37550f4920aec52ed0cfdf6aeba16b3c6a8b7efa42a3300d13594d7e3d485f95fc73f0cb325c757a22d4edeec270abde7958ce3d65ab9993677a347b8b3d916dc4ac00aadc4375e2620a965900360007db432c68b4fe1390524ffcc4b802efe31f06152252f512e92751142a2e4e551f0266f52c4bd614cae21e4f82dd831568e97fc441a0f0184cd8a45e81d18157b4523efa522091388c11fe5fc5c32bd1eb3efc611b8751b44f012487d37748a9baef918d4b3df5454b38397e4f2bae863467e9aec6f84e3972dbd06f0551a701b1f1976789747db976359baf872d8b9ae50bc79dcd2c585222574c08d9833a48cc7cdbcebb1a7fd119aca6c720b4dc7adeae523031590abe6bc02c733781b1c44a7860305cf9c012e9286fae9c2b63380b9ea95c3cc316a0086048c153afca80e2e8027eb1604d0b6a8116834348101abfcd22c4c296c4d2bace83a43cc46d51e29b4556c851634e405c299f38ca526ed43efd5a3715c07f38d577032933dc37ff0e4e13ba5006e957d884bc7ff839b05ae0547540d234884b10c761170b7d9e45ac591c11662e28a119294132f04e275712a3a3814c7c2513de855d920d903daa0512869b592641bbd1a61b479734647b61b778811c119a0597dd018d9268bade5512e66568b2a9752d102ee7f91a5d350c3fe4afb54f2ccc6193cc4ef434ab892aa1b571850d854e9430bb40da21c82e6469ccc450cec4bc81965320b8d0eb66e8a98ef1149b50ff61ab670abfbfd3b0dd2a6abbf50108466e97b5343733bb64d2ce740d1d15b163f064455dbdde0c2a13a43916a2aa75afef38b29d25f62bd01573f676d8fc158df0a8ee7a910a307a421284d1d0729d90e7977f40d78433fa900c7c158ed4cefbd682898b3a8daa0929a164d902eca6baef63c2fff01a31fb4f7b5d13d2cd1ba95f087f105da79590c1fdf849f4eaefb96e837d83da27f393ea9513a665e4d20377d6fd787904dbea435bf854486fa041ce3aa5c63b8f7c208a465a114ebe2eb69f74a34a3004f6cfd197b009a76cd89d2f4e2b5104f28c09a47295586c63cb6d7c70f546cfed3cea19368e88b7bf937a9353c8389618e4b0c393e5f46afb1b52e1de6d08a3885410c65b26a56cbd471ffc936a7a6b6546a160200f2382acf6f687eac205e1394059269e760924da7782402e8d0daa8d0b114a9d4070c11bf06e5f66838e620b963d5c11e73d1bd45c2a41116e982b7cee30e05db45d5f257ad8a50757209afe5d99b7934864fb4e15af9bfeefb2dd50769589f98c8e857031ab77b9aa50c9d9822cb06edd4e6b5354b8a0610660039bccb2f6e4593bea7862623b8ea6032bd18d6e8c7f2cc8cc0abb181a22138a92562f817c91952e89bff8de6634d98023265c181e4f2e6b25698d70b3531656e39edb43d77d56253bf41ff6019747c9346b72abe56527e88784c350c06c4745ef73241477087ff62f1987c8239953e0a0291df469eb60c5d830ac53eb33a458d2effdce6f918e069a17acc3ecac9c5a26e27ae3635b430884ef4d6cee7f0201d05dac3c73632ff4e5f23ae6327b9fec3b4b1aa404c7b4f72bb26aeb6970d57fe977ecbde2881fffc6acfcd48a43af89c4e89ecabc6a3403b17c88401054d003eb1e88a16783b614dd31ca9945128873af26ab207ce7bca8c0b8833dd3d300ee68eb0ee5ac489e65821ea566989ecc81b8f98f9febeaf673a7367f361f2bec85c44827dfff9fdb2c443161533f4ac4028314b716e6adab5a3961858d9bd67e004f2fa68627e5666d8c6095f6f754ad594bf629e9d238182c2b8b6d64af97f4819810b333f619ece79634e27f42a2f5c303cf88a5f31750482c1ad240e2ae3f4fff683739b53d19d79193538bf6cbffae8e052952e0844a8d46a1b073a9018a4ae0fd79471ab04d91cd3655608d890a9c657455bc0daf9609517c9c309c8cd039a81f42110940927b6b4401a596a0ce93ecde7043fcc976b3c381b35ea95a0b6b1a410f2198049caff3b844300088071ab41e849299878e94a18213b4aef24c1d436ecba65114be8bc0729bdb6e67190459adfa3f2d19865f30e58e16535d3fe97a48caa82e66238d370834eaa86fc704da1cae04c78f65fc6f7127d76183f149a39a8f9e4cb3335f3c57109d27ad38c752566d3b696db6ceb529eec17856e685d2bcf069a0a9437a637713287f23133f2f4dd833c1100c7795bfd5e683dcc49f9b753d71c37332f1c9d40e924c1a6fa5219959c8adac5c971993c35d4ddcb9dbd4cb8b08b4d9812061da6a43ac44560deef852e1609d3b4bf2bce97b787d7839021ef83515c8ac59979b5598d8cffb3beb666b677c40f80d7b49aeff1df3fe6a29ace8e2aede03079d7eac73670d1233d5f3f8db40072932945561155621bb41f647d3546a695bb9a2488e55b5145b83cb1d026682a1b966145b3430a33e41a359cd677154cfdcb96f58b6d69354177b7304ca70d8a81bf0e309f193dc5c37f235232f4ef5a08be1a9cd2ea85f8713d041ebda4b0fc7ca6ed8f0085b9f574139888de6ca11f131a80aad445bdd5aac0e22bf41389cb26d9714a326743bb399c9020ba2acfc27ff2ef68c1cb6e92e1c13afb9457e68ecb48eb371541749761d884476afda68abd1303660cfa27b2b355a0da68c6a04c2540cf9609b6de8c693b523aa15278d729cdc4d03a5a04a2d92fe3191770f7a38d44664156de0f81bec4dadf7df78ac5e75fc8bed327bcac2d59c7c771da838c09994e69e1ec4c8030bad5e8a10300290f5e5886116014b5fe388d2ac7a58275add4fa6bf7a744a9ef769a3b9e304a0706161221aaabde8b3293440f1fccf85e1a8f99a058304482bccc5c6db9d4cfccb304b11b5f0a4e76668563ade7125f7177405bab18d6d423ee2a6f9c733303728ffe94eca5673a24d42b2f07b83c10f7c01533afa160eb4cf163f62b54e5ea7e3d7faeacb467444fda3ca7faa4e002e0e15cf03760e78ed7d20ca8460cb91d2044b856edb1d12a2ead6fd83c11fe00a5f242675df0d2e1e5980fd66dfef528a12bd537780575e2778af0ae018a37dd610eee958025bf1cd0183712cded5ce9cf6abfd99ab484c021b51ca7f4645922221148cc1bd018d0798106c66cd0cc24d886e0686e2bb64d2d38c48d97099e8d71ca5f1b9025cfb3e83c7addb2645760f7a8e8b28b06b869dcc50ffd01b86b8687efe0dbfa8d6928a635c8f4f63a9db50ab0aaeba36de4263c149c9e860ec22c5a9f94448c5f553c31a08bc8b1e7613450a91f75ddeb0d94829743efc5cfc06d0b1ddc3b3a868f14abe96904dfdb6b470dcacec669bb518ebf4e51dca5d0b067b667f5112b34782207636911ba89bac8d8109af3e38b8146c26dc96f7b3c83bf6decb9f72835fc929ce70e5eb52a7943d671d207a419539b576ece63b8da85678f8a39c2a655628ac41caf1be3a83c1bee33851014feb85286495595300c93ea195f630907b1dfc546fd8beee11a887f83f51a039078d87083d66511f87903a7fefd52d0adf57941787adbd5de0791159146a12789daf04119cf1424c91e5842d32bad0c4c00631eb3e9f99d3a11d148aa5399c8da6b37b83193028037aed56672c245893395ab521d2e3d78c893d22424d7280490e34cb2742c3b653e833ab7f94e1de82d8922bf858ac2581e2da27da61b922145fbe4179d586c5d12a986039e2273693502d2344730160f1f9cc60ba7cb7ccbacebbc7ec710ffe0f86342cfa50ea126a6d3d3e50e03965424be44127a6c4caee84e905156e9516165b98a6bd9f1828c27cc95c8195022270cf490c511eb29b9b51b6ae4e9d92010a3678bda8301375fb1363531ade050757594c4a61bae43083b049702c428afa64e91dc880ef741f1f8d26e61f42de72bceb774ca7daf6aca7375f5ea95c39d4a38d5e4d539e4fce39aae3a66f09cbd9525555910ad400eea25d73fd632676d1a080dd0b1cdb9e3077e4e4738aedf0163b089f35c77de76a0c8bdf0ffa1f1742dae0bc7253b416c43dee2f43a2d2fd0d0c63026cb918d17eb87becfae4c9f1ec80dc5c84eaaa1e11013bc9e8c471a1977a81c83839b4239b9db0223641fb8beb800e6b3114ce2a62f57d9d4b147876a4288af9cf6181c66b62334c6ccd26696571221c01cd24d40064da7cc56d5b8027b3fb8e3ca9b3606462f7fedd2ffb6f7f634f1726213fbf34482c0d08a5cb70082c7989f2d984246a7c46677d43395689291df089d6b3ec737bce8d84bb8bcd0ce4019e4e918c46aaa3f2e1089a20ab5d56c0b12ae60ddd9fa72abc24258e72bad070d939d9003033e3009eae1e2fe4b17993180bef50b2274c12b48281cf33d896988103a486468675d7d473981ccf3ac539fca7356454dabdc30ac14a2fb87865e5a91976d6d50d15d6157c5ac0900ce639b9b2948d32688b78b58156f5738e07aec36143e90550469c284ed1ac0796f1b1abb3890fd359774004424ed4a47a9303d2970f8855a6e3898bf76c7a99baa5d8eae31a27b1ed010eabcee1ab45c9492cbf5f42a3b569a34029acc7561ab091c681a19b150fcfd229811ce809eb541db2ee22a67762f79d7b5857ce051d7c47742b91ce7e65697a64a1e7c2d69f541896b7f37f064967b1b0ec343a6b1fa1b526353dac4eb7b25601075062165b39c6f7b7dc6e24be85743a295ba03d8435ac39ff63d7a793932e135ee8fad9bed919356c5398b6e559818811cefea6368cb06ba728c054fa13adb42da7e745bd8358ff3cb6405db2d76d0ff1e13eaff998db06ed0102a6dfa62272fe2810fa99326f35cdb46655131adb04bb8ee84d61cc688d5d2a646ac83e49b50031e17cfaef4f73ee051a048d02465de0c05e2cc7d5a764016287b0a55515dfbed699e32eedcbebf5a221f9c04ed7661f1a0702d0d23c80c3a399e130d77f1f0d25050d2aef83fff01760606c6da8fbf51a9001df3f97fc71e909da9ce4490de79a75c1b2ec1cfc78e0a02b9dfaa056cef492b4644906cdeda84404d2053df45431d21d5ae12c648f4bfef28f1a76cbb27eafdc13f5137dcb0a17ec48c955c1678dd15284cbef6b18df6966c524ed2011b9cdc92133dcc151a2056ab3a4381915f79be5bde68bf57a005d65a5644d0a6cc2f054ddba783323a69e9d388ba02bc472c80901f98eddd52bf6f34c0c49253c427067dee2dbbed1f60be61aa8b2ca31cbb6260c4985a10c3ca33b917d2ee321118a1570b8246cc10a12ef030120fe14b1470f7733aab80df6cdede15825f5dc362430a9c7f695e57f38f007144f96b3be36dabf48979e198fdd88c8fe851bcdd0147d910df27f645593e78fa1ee9202bbb63ff93214456bfddf036f84cfc3bff30c7893662367ac27f2ba03bafa2205693d8c6ee40286e4cb76a1463e1cd28b98e05a8e32f2c40e5aac316b0238c9ad70ff3dffe7f504d78ec07478b13403d68b134c6eda2a6e75055d1156c157c61c0a1d9d30c57e9ff0a2db6d5bc162d0cd80e73c8ecc5bebb838fa43df921614b1c0e9e1019e4850c78d8d541c376d434856404013939eb0a0c67b0d1ac673f13f9380635a1a897b528c75e0113262a314b9b7496bb54310ce33bd123b20f46806b3acb1c9fcda8bc4a9586c5ee47e7e7e86729a45db59e98e772af49bd9240a94a94a372c1f590c09c00ecaace39d1af3f3e4616fd03ef9ea94693a40307a8cf5462f630311ae9537bae816b8a33ca4e01049a53c05294f3c965d2017dce2a96c8474beddef1946dba389eccd00e2359cb061633ec499d0a78c1094a8e590bdacbf8a98702c36e8144ba314778d30f8dfceda0aa1de1444e8bba6b982cd323f5e1c43acaa4ddd158c8f5d279354e58db540ce58fbb1ff2266c0fd2f25470018fd08189f846af23c3c40d18738c4def160d0a34da706ec11246332032896d6d396ffae1052b2ef9adcfeabf7f7f00b46992a31603ae82d681eb712e55d7e3ed5c7186060e24374f869e5d7563c7380c548dfca8dc174bb254ad62814d843f8f2ec4cf0cb075c06a19600c93ddbc87a78c8cb17131fa1dcb2ff615e001398a0776795922531a2a79ce7fe84a1dc1db0aa8ea6866aa40c9eeb8558060d01d3cfa22c77ef6a4bad18d2c6f4a8b3f6e7aa4f890534492850421eb50d2afa7925d06e23947f2b85730b30d1731a42ca9083b7c5905597c58ab3785fd2ef35a7f3692d9bc2c3a0a5690680e3fc1bb4b6f985b078cefe3be7c237f7ca607e210cc52cd0e751bad5068a881a79894cd0dcb620544c0903fb22c4ab14e64e070bbf9e4d5e3d3a510e49a30f047563c074c6a2e64d4c65f6ef749e477313e2228e143f914aebaff12da2b2c8f60338d0e588542865fec3d0e22b1d73208870a0340c6911f7e1c92ca30d888c0bfcd4217179c98f749446c91712c8dacd289d59c37972db995a322b22f5187944e139d443d0d30ac47c2d4a1f036427e4c3c0c440647cf866462daeb4eeeb55a1c3f8b282e85b0c543f2a0ec50f44c50c8339cfd014ea5b232dcc31556946f66dff94a197dcfe50510cd5f9010a2087ca24d4a5ae8347424ebf3fc5066151817e594902d3d5685658f45d2017104fccd85e32775692220b627fb7472694a4161165894521eb43bdd0cca8a00fbadee72825d1aeaa01c7f5e47e5df61296669e667e3d0e8b45726883ca3b96483111a905391e1ee3d0010092dcc867eb55fcfbbfa9b2baf6889ee62b43bce98f00846bdc8eff428312e24eba033488fb8c9d1fc2712e96af5ad880c24433bad80d40acc9e90b420ced9ce500c4b9acfe91a3475e2d879ed71f5fe7b49cf0ffebbbd49c8658e128de16424c07edf684b2b12cc3c35ea02737a6df753494efb6760dffd55635d6fdc926afa1f6c54138d6029b9d7c168f3c10e233332505b0ed33a314e25924ff1fa528b720b5f738438e263fcccca0218e082ebff147f4fe7d5398782ca0829c7420c8bba85f71447dacd3771a09bf9a683d2767989a0946f9e879490bf84ee8d64d2c0901eb3d0b8211d31e299861b963abf7ceabeb7fd9732512e0fa7f5c46956e7036045ce45d7bd8bb23666b623738c451bba4ccdbb73b932c2a9d5965e83e8c26acbf13c8d7797269906d3c4f0805aa095fdc284db2599f3c3b5f17ac9c0054f06f06600b31c20d670d6430fff525fc5b00e9ef98cfe42581f5ef6d5afc5501d155624ed00a957eee5c7407c1fbf599d0dd3c5ca39da97aa237220d8bce23a0b2bd2ec93763f0e5bc8f8847f20850152cf10afc8abe4f0e01daebb0d92dbf07b91e9ae7bf496d229c69cf247a7baa8cf572e07ca256821ef97a5e628749478b392786a0de0eb884b03e1842e1ce1728a0d2046e409b3805e99bc607553fafc7bd66ee7c1b5680efe754d126eef5c2bbe0a8dcead1c1c9db5dc2b6a1e70429e261828fbd54b28fdcdb42e3709b5bb5fdf54121506347d3a06dfd11a0e674c6cd16227aa29d7b15200c6048d96e843a15817c217d4911e45ccc8da5605a1871584596fdaf1f613c2610caf695805bd54e3eea0156698152db16629321990f6fc9d62830624f1c08f4f9e9a10fdc8d5eb3e284a3e2c4dd547eb7d2149e06a7cf2745a96f3f0aefadc0a11cf7756c8f80a902a11e27b8c48786f3964c76e910c08194bc7c2a38b6b1693eb7f183e66c96d4b6d4eaf68b68f5a6dafd8554b14d241b1bb19b08d815eae9ff1e3cd61b534576be0ddc599ad846ac762741008a42501a20dcb8f3c60cf5ee6adf5da72f63af6c3fe049f8d89c7a41d7d55b15dc1f3f20e338c9f1ea5e37dfd2d7000939ee5b08e875ba2a82154800d015e7a574489a6f583b59dd2ddd96b0a6e387862802e112c30c93c67fac8e8b07f75286348ed63304969822457796851f1a8309e52fd2e3866c7c0e567ef1135223266261bd59c070191d7abb9cc229388d17374873f06702fc5cdd71627624afc294378d00c91707c4770a489313f74e2d534fcc4ee0d4016d037c101bb82ee19441c2805b651bdb801ae17b2aa26a9c8d54d962fee4d00d5df993884ee40f6c4139ab3416053b308e10bb1aa802e88c1f8ba04e1e3d6deaa7704186b79ba20c7e80ab7788011a75b01c7b9bba80d366bf2486f8ab9be28005f00a7e2d6c576b5fe35e68d3acb4fa7dd4e14999ea5d8b009e40780e7854a2ca6217da56407445045d23f152af4adf317df15d08499aa241df72ea2c0cbdb742ae4120bcfb1a30c018e5428f22388f9dc66db3fc9102b60688712c4a5d48c2d9fcfdcd3cfacc90398d600f017b2d2640613438e036323b2309731aa2acf4c3a15b5c5dfaeb02b0d12cd7aa6894e20efa2eab177074cfeee8a872b8c5ad488067cbb055fc31400378968b457688304a058fa6796d24f97aa29d52379f1354297867f07fd71019172715c3d0168abe684dc9f9c9328918030a6ccafe5eb1765264e3e4389a8a1c9dbdaa5a66ce3097ab42e28bdc71c936c2bb17961e1932e274ae039161d37842b4fafadeeb89fbd72f906834badbe0725bb44f8bc01155f21df6c49bfe608a461251f79b37e5e390a0a5899b90d11dd5501fba17e88b857642d7f1d7ba8964559614027227d0de53828d44dbf7fc228be95bfb578dba19e9358b2ae8120d0655fd34e139a2be45b8a0e903d2301f57dc20d97db9f99c313d1c9c593f8f7ee879e75730a36f4a61cba81ba635049c7c4acb4733fd45102068c67a3e028333ed6be287d1b9bf897c115b666320e7e8e8914bfe0f3d35f8493f15b03f45280c4612dbc623950619957efe522496fd831ead0ddc792edb6d00a9fcc50f6a1c7f9cfa4b16bb0d315998d1d464d1ae969385a5ad270b2fa150169656ef24ec34b0caa0db88114c8ce0caaae142fc2964a858226c1452ecc1e5f4bda38058c6d4c9f801ec9bc4362212381b5aad8e228f8ad7073ecdaa9d331c55f433307fadc1fdb92bc42c1e34323b8147294a6b2927578a3effae53ac8da3968810d87016854377780130e1541c15c1d1eee335abac90423c38de2610982641e6d7e688d316fab6bad83088defc2a416e143cf3f6a088349a1546683c86e6854b6897d118c8238336384ea197311d45d6784b071c9387667758e26e78cedc6653a34bb2af97c3efd86e43ecb389dde64352638c1f740ffbcb1e3493fe736b944be0c97c9289b523fb0a09178bdce39265b1ccf12f31a875d5d079ea9ca31cb13158efc4ee38ece752b220a98559c7403838b1f89a067aafe34e6f4f54c4e8a5499f440c4aca56142f5ddb2db9ec00dae8d1ddc7e5674ae1e9b85fb33d8a228051079a6e2eaea80a88028e017472c0d8600958c0f4d044f2a929bf80069a5e58358ef06ce04749e1b3440ce0b37800bc277010992fd869ae1c0174da01ee9bc96039616d8baae70fcd1148b9cd932022604ed0859323ecf5693e696411ba34b007426768e4bc979bba3ba9c3eb87cb215fa4a2a1a10115258f3d095f79e8804713b9047a76369dbc7b6d7f17e92fc795515185f1c8b92434f5b44742180326f8f4311166f4bf30442507344394cbe5edabf65217f1f6bfeaf8da4c6c9e103b8af30ca73e9c6ab8d66e794a9c404f62e89c2dc40452c7878b97e5c1ad5c60bcb0d38e45374ef5259cb7ebd5bfbcd696846d2251d310bbd08146b686dacfa953f4ec7c5c6a8008b88f4e879d574f09e48cf8ad8c9afe0f5d223b672c311bf84706abe2165c2ea01ac114def0f3050b664733e38fdda26ad71bb3d6ec886451fb6ea694c9e895eb648a9d1281a2a61149312d7f82bac4be4aa7bb9185b6aa496ddf79492564c73fa239047cf3807ee008c9177e4f3673a8f07426b1ccb9ba0c6aa533cfd6da2acf56b5311086ca30d973de86852cb1d9e02532c2c721a097bc253c84b794ae29391b5291233aeecbd86b11f3667306402df3f7811b2603621f315f925eba864a5a0d14fa31de9ebca46a5013a51510232816df194b2ae08db569756b21f05b0c93087178056879bca9d973e53f1c29036a6772765c601619271db53d7b578ccc69441dd23e1fa1c87688f323ba7f099c44eb6ffe00f44e0f78fd415a4d3f41a8a92fff668e30f13665f8076ad027afa60301cc0aa0ad90162bf5a59c9b261bfc2c10f8618d6c23d208d984ec4df6de72ef51073b074007dddddddd2f6de1ec5d1683f3f668882e86f9924118a92912c486668814129f61adf5b64ec12a61eb7892c1a86d755b249cc0ee0462b66a8b9178d348a85a0892cea5dc46580fe951d7c408e8d872e46adef8240d49754904f6ea3288264554af549f2c225797953c42c4484c15e96cb621b96a29245787db1b0018dc2e2343748e36dd0059e174e4aaa55b5aac6a596badb5d65a6badb5966559d65a6badb5d65a6badb5562883615990b51600308b656e9116ca8995bdb0dddddd171bb9014990f4e28dedb677a3b7408bc177662b10eed72d2aa250d5d65aabe5ec61b4cc711e8dd822de48efe6e6c64a1a19046491419040903450b6589aae815b75968c861259023daa22845e056134c2827118661c387618018e1c3870e0c041c466adad52d2481a49432369baa66bbaa66b502e2236d8239b02bb58be62996b74e52eadb576947a4d1764a351d1a3968fbab7a4e9955aab0d65306cb5aa0cd63f4963720359aa5b1845bc8215608aea2d379bacde355db37d5dd37d5df3d1b6dddc2e6c9d77b85fde6783c8731a33830ea365d0e5af8ac871dc3fdc755dd765e851cb479d6d5244a96897fbebbab89b6430b80bbbae962c822b160057e0e851138fc8006922374e42e4105307c9446510ce0e929e4bc4f651af0583dfb778b37934d5e8efba1bd43fbf91a6026531ecfb1f54bb4820edd234a0ec857d7f1d59757777d7403cb1fc0164a9fec1b2073045f50b774d8faa21bd52d58c8edc4857a4fae5eacf4dc085ccd5933490a57ac40159aab3680ec33c22f25457b3bda657aa7f98fd6ca14ef4a12062d3ce79f6af6beaab7f33df78739d2069ba26d2d0080149b106aea8bf8949a75345d9ea26c962d857ef6b1ab077e7585fe36032342f023075c1284800c7e6a12ccd16a4ab89402a55fd7024bf9021103f04c93373a1651aa7df255ee72418fe0a7023c6f1628e1e551d654233a253f55bb1ab3a87674cedd56dd6bf47b62fded4440ba65a6bb7adebfe6f54bdf1e5c276b7b0d91ecdea56e6a2f3ed56e6a2b1c7f3b92ed0332ecb62700ef268c4fcf1bebe762c8b617fa1bcd8ea7188d97a1187d898833dc398177344140cb92f8305b205d109391c82ea5797f76da14e7414f39421890cd01c3c8d8192753ba90a6bed2ffbd9514cc75284a41b44d0a5eab69f190cdb56f70d17defcc6265f8fde8071f0a1fe6a61bbbcaf25471f623e434dddc0deeccafc9d31c6185becec847a44e70db201b127112e6cc166777f5ae0d2156cf0b05ec2f919334b09718ca7c085a2cfc2912b935f2aa44755909b7843836ce1c6c81029275d3da9fcab3f5e4ff85f0592abc72162f7d022680fc4222217fe98bda43c662db64b7a494b1eb31793939357272727b74e6e4f3e5d876541fe4a2c665d7798bd74cfdd53fec19fe89f93e08fe421a9a2422f7ae8267e3b9dec85c43bd98be8d7838570cca24d444264e20332412a711109cfc4af044990e498889fdbe2f37b0e4a6844ca49c7dcc0f1c23dd9cbca3dd9cb0bbf1c76b190087f319ff885db0b2b2f883e7b246fe407b64fa67275298518430064aa5da64dbb5c4444af4e85b40b897bffec0bffe890957f1bb5c9d5ab8f7aaa3d8cb00501885c7d3507d8bf6a835c1d7eb506b9caa25f4922492447f4ce291e0a4ccca1d398591e46cbd2c33c1a3187bceff3138f598b13efe4c989ad271eca8b13efde9d903bdac5c4ab12d79e72d22eddabc7eaaff0abbf8065901e555fc152c808cb1aeeca5a882e1fc2a25f29253e8d995554ae72182dab789fafb8ca62d0ab88ae721591c7a2e507dbee21316142f479c2c461b46cc2c4514eb318f422ef93ff7c66314237e1d188f984f7c98f380bd9c95e364fe662f3647c7e2f63c4718839f40bc2e02f09263f97879e0fae318893ca9bc0d287fcd12bd545d5496049d3a3ea1e9641f4a8ba8ebc55c7f8b85570e3a87e523d05778d1e551f81bbd4a3ea211c8ff4a83a0a8e43f4281ad161eb7ed2e1eef9276fea09b254bf6eb6ee272ce4092eb909ae3d7a54bdc3d5478faa83f0b53e1359dd05cca0c3acc4aba71e55376a2106bd9437ed328d0c01574012921300b6c4184603802b5e802cd5b7ec2c243ce5ea1e1a64c6dcaa6bf8ebaa1cb97ad622210e11a61661abbf00578ce42b59b2556be15091273dbadf937fa36c15914d7e238659f8b3a1254f20874cafc1549f800cecdd65601c9c3d8712485b0149ba81ce9ac305b29d55463b650f1db6eff99f10c38ace0681fd859b755d619b8796c698820b616c5a7dc52e6086de67c6ac53d86a3df568a86f1b6df544d203b37bb6c45c62945145c6009831efdac226a50c59760eece1fcfc14363885cd9bf69657d94b193febcdd78087dc85a25bbb6d5d07e161a628f2fca85d64c48f0e53ff55c07a344caaaaaaaaca83b1afde7b746fb6f9183d8ae2831e4cfd172f5fc321b6597a1cf060ace783a4deb15e811f7dec8454870b2529a210853e5b27800c5732b438c3cf64fb54873564ac368cfc7779f5f2fece393d1bf6b7deba321067e0002c6286189319aa570ce343e5e9306f83521b36a677812b052a90410978c8c10f6466a0b76103c24daec4dbe8bc1c62acd405370b170b1de8c0c5421370d663215934c5d5315cab4b6fddc8234ffa0b5b32d48b32d58b71470d73521c9b7a416270337cc951244201596067ed257321b12b210b7cc73884fba1580145a3d8724a39e573e818774063833ae8004dfefc19956b6ba17f2a504640225d6aabe95ab6511566e44a3d7907c6208bc414339c54167d745d27e188fb085ce188fb075f38e21ec23362ee149c0657b8d7c7209a1467e48c905cb9731f813f0f61983fe78e82423f9d6cc810426ebe6c03b9fedec6959411e513080e5de2ea91562194932bb1108e3f467cf02dc514f528ef8ae4992cfaf838a9e8a3c3bd72529c54f4117f4096fa2a02b9a51843bc014c516f7923bcaf4bf1be2844522f0790a5a27c76354f42a738a2525ee1799912c25f0482e27d94662f24a715ac24c7a45d3c1b668d48e13ea1d8587639acb1cc2798630359ea25ae384e8029ea3950802c5929abd1a4eef593354dd33e354dd3b44b4dd3346dbba6695a27354dd3b44b4dd3346dc4354dd3b4946b9aa669dc354dd3b4cf354dd3b4d0354dd3344dd3344dd3344dd3344deb5c9bd7344dd3344d7472946bda61bb94642fda9569579913dab8ca65338e86796c70ae47bb9b0dcef5681766c3b3619a65d9f06c986647d8c0ac115a4db1815923b48ab3312245e3e8c7c688148d9b211b1af709491b1af709b50dee13eae0e63ea149a3c7334334e5155a6825a724aa742639f3524f6552378b5927577523d619474339d980f44aadd783dd93941bb95ece601fcb496d5a8d198e0d9638d370563ab192a65444875c3f936b26936b2d6520a842aec76a6cdf95699792d7df1df6837160d34e3f49d3ce843e75b48bca4397479a346d8d2d943d7459d3a469531b911cba14d22e9c872e7b3469da1f1b901cba0f5de26812b5a6d0e58d76f13c44ad9190c9436f9a26511b64abc9a1ed216a79e4548f1f39843df42e75bd8d093d1e699793871e8734a9b2365b911c7aac6997eaa1471f4daa2c2af450158a3b78e4d063e83734a95a38c456caa137a049d50ad942b7a15d501efa02da6586f54e05aaa50b6d9f1c0a7dd4a48a12b5cb8c0ff7d067936ae87ae829d94b68ca485256922b95c4c45306254957460625839241e5fa9992a45b9aa999baa5992a49d2954a9552a5544946922e144a062583924149d22523839241c9a0723d4d49d2552ad1144dd1544992ac54aa942aa54a329264a150322819940c4a922c1919144a0695ebab94ad5256a94a9524c9a652a554a95a144a0625932b4a92acb5db26535392644bb3d475db96caffecb7bdbea3a265254424bcccc35e567ac8db32cebdcacd6ee86a9cec5ec52b712e96ca38a99b4ae5facc735119077551a85c8f995c97ccf55c322697cc665da5ebb94a2657e92ae5fa0bb329932d85a542271565b2a130540895eb6d55c9c8c8d4d748ad92dcaca79572adaf1a736c36b0cdfcc91b9bb25b0a57437a488f6a678b3a4155a846591dda1d44464646e6c3cd9a75fe6098adce2827d565a324c58ec96bdf644f87dbb04b53ae4fc1f523eaef078b998b92245d19b9521ff23e6b4b797a40a4c7b1e951fd95b15aa9e3a47a548f6960b33daab7d42e356e29d7672569edb6c90e05cb7a79a45d3e7b823b4b238db15c6b901fed02a45d3ac738db6f87857e3bacaae451aaaa3b4191a110ca090aca2f4a25e589a4bf2858e3f9d8a3886104922b0a3ec13368f6d1a35af9f87153b0d92e6dd299b2630ae5f44d707d876be4fa921bb99e04d78386449b5cdff51fdc75f0c7c7c436ced4471f3e6c7dd461936f4e2ad7eccae47a1258cc1a739600596a0ab2d47352138aaa2763cb40cca1237198c195da97c3295b87d9fe307d98791f8a2c23fb88bbfe59e7388ee3380fa67a7bc74a1984c92c9b595eb51e4c3fbbbd8533fc59af67212dead54849aaec6573009c81e4db3924bfdb065934098761fa9fc7e33effbcd4403d0ed05f208719e86f858945e4ec9d6b27f976ed97243b8824037987e97fdce9610dd4a3d4b371ffe15e3ad937fc95c832c38090e5efe5c598cc404fd9560c53793e504f077a1b10902b927aed15b17d100292642320495b0789d80c74cd5c70a1e86b61c9f028e08aeaf6defa9dbf167ff13af68bed1bcf53eb4189e119f4c3bcef97b5f7ca5f4cdf12cbf39a41a5a5bf3037507ada8283132402c44221db10152db0a505ee20c318a094945e0ec3c8711cc771d77a638bbbaecf256e9bcafa657dbd84af8980bc0fc330b8653494c8d9411c77db15748bbb6e8f9d93d5be3907752a355d03fad0c8cb98248e4fd2a868acc6e3ee6dde7589d84c6e6bba663bcd54f193d790d7437aa546aede1e4adbd813cffb7cb4c36859fb154120d039208ee3b8abe0388ee3388ee3380ef4930c0688cb388ef3d1b29770d7755dd7755dd7755dd7755d308bb11d0505e5a6807e53b08aaddb2b056b6c03f2be26922bee15f712726561e760ae7eafaac41561160632c3aa5e491db93a6a078f1eb20430457502538e5cddb6481cb98af9a8eb9a2c6c34dedcc85cb5e7032957aa3fc2ea557b5f35f52c64681792d71872bd0160adb556157045e7b5567bd9cad57a7d3193489ad86d9d3f49d3dddddd01f1e6a50b5b8c4147bb602d03c3e5e295bdf0603183c19df3600cb2d00cae50144094c8f43ea4e7f697bb6706e7f576d64f6b45b9c230374c6ccfbdfa7551cfddde7ad16f9eed6355cfaf4c8639870c8352166508c40b6ee43babadb073f8de7eb857b556f67adf3df6ce62787e6fafe5601c66e63c520192e44c11206ea0da860f22323d6121d35bd90bcf84d172865fa6071369c43cbdcfd4237a1ca27df976e4ec65522feaa0d93c87edec91d4228d0c365448b7451ad213e866a110600f0c00493d6af9a87bd72b14766f95f478d3fb4e5c75b334250fd0434c8a008100790083a845f4e3f92743a61e222c96b99039c3e48c9c913396853916ce2c8c59f85af8b2b065616be16ae1cab22c1b2c7b0340ab83ad079d102e44865c86b5731d6e5ad6e27a300fae3c5ee5792539873f98c4037303f7c954e26ab9cf31b802621d8e25b4075cd199ce7ffe79287b31fff91d81c50cc6fce73023c120fcc132b4e31033ca0b51b66e1dbb2dd14f1cf3b46b3abdcf06114ae642e6aefbe18913d154994ee4eadf89f9cd5b9becf13e51b64194b7dcc15a8e530764b1d772077386e0e40ece8464b983b113963bf8ca1b3777f045e4ca1d6c01b17207db96b1b983eb919a3bb8aae960daa383a7ed60690364b167d10b909b27822cb683638ed3829025c310b25cf8cb0c90fb91084d8c218329fab41b6d926a34995a2a58579f9ec01350994292a3641b27db669cfc368c23a8f70f1629f10f1251f9076d3e140818a9906185e81f44fd1f0482ff411aea62e2dfe7843549d9810c31057de88af076159c1d6b278163be30843bc79938d32e5d3cc115b04b35f043f5623a6cb06227385e159cbd04c6e48bbc55d9aae456c9af46025f14f2ac8be62fc92dc1527e4bb0100d9b45f70415673ace7c30e4afe1f6394a4643899c729961640f5142123a43868836255e7269026f0a267908bf9498747033f9851be7017d380fc9597487b010c9630a4adf88363527f2c37d8420a995f374ea27052381650ee1988265be136b1cb10645ba41ca928e33a25049e7dd705d48787146863ce943def3be880222d39212cf2b31b9278b619590c0138544280ee1b058136bbe58136b6a6a9aa669e89b66947a4d1764a381288b7d2a3a998b92ac6b6c84a027f1aff359d64537c95f34e1c376c11e5c29392df9bd9293f0be582a79c813795f1441a625259d5772182d9778efded14a4497042bb9756995dcd451214240a69759ace95108c37cc3cd9026b1902b74246bfc48d746302c66fb565e72ab46d25b13efb39bc8fbb6ee7a5ff758d342e6ed222cf335c14e70cc5e09151f99febee4762653da3cc014f424701cd23d64fad117bf58438f216439f131314a398d4e8029e8298d50c834d678606686f612e0cc264768136ab4c0806d47b6145cd1fdeb25e44dcb5e589735edd29da6b6ec855552f28804216a861829128f74a96b449b7b2c0593dc0406fd04feaccc1cc2314b114602cfce62ac5cfe76d662f495c3ccc5ca4b94b84844e25d482452f946e25a16035f142ae1a1bc187de52bf8238c6bc0b0070a70015c4163cb2c8031ccc015dba9765ad1ff108d50705cbcb050000aa25010d5a2e4d735c18eb563ccf90af67c84b99fc09f9bc0a08bf066abd3d3cb10b7cd6e1b9521d393685142e557e5d1f34222cff38e6f43358bf17bde276ff2a2e2a1bcf05ee2253c0f471f187f310691479c8930883f441e31489c9989d704bf84c49c9d37e7bccaab2c8645c2fb648c7f7a3462f63c92ec0597642eb027a3e4d765988470cc57057ffee394abd014af87744dbb989cbe95900448df43e00a92537a234b99a2909462f437d432c210e58cf0ba338a4909c907733064790da762c8f2068029e4fcac4f89b88016f03032fffc00a088135738a297f8c2117d48832828d64d298adc734e095be48ca4d7ebeb75ddc2b647f3c26f7a2dbda0f51a7f61eb73be5614093fd4c89bc462470ceb515b59c3842b3adb203b36132e147dfd42fd741fcdd23e368e3962094715ae58fbaab2d68eacb5a9cd4341a7cc2460449b69f4587434e1c05a90a52e555deafa6e8ab12cf4efacb56bb5554584cbf99ddb27fbe773da3d23c9483e399c32077f304856d2e1129c1d66502943c842e27d9947af51ed5f0ea716277dce077f945e9607f3f17cd0e1ba0d2b57e4e5dd2236f93ecc9ae7f29b24752e2f0f218aafcfb1723b5d7adff53c1faecbcbcb000c6283b97d26c7c69d8fbf1a94a40b607afdf9f6201440add77708572a842b5f0536eb36e4e76df4ed6f010af05d207f9000f516432880ea1e8402a89fc162384365f105ecadf743f5394251e23d92b7b1f50a3c6c782957e6b43db850d45563f6b4851e764b0f066c66838979bea55d602cfa0f0a01d27c4231e8124fbf5515d699c5681a2a1684d1d769812bf49f652786b905bb446cf204802ef3f424e8d2a79f55f612adea4557301f4cd12ca0b828345dc45a5d6cab0a570b5bec7a35dff5b2dd17d75a5531aabdb6ca1649858e1d3b768c74f41247f42c3a0eb1cdc3206e18e5d992a78a3c218d8d296ab8419262d705f9bbcea317b3bf7126f2c88eab2893f1a8de57613df4b0841e7a58420f4be8a1871d76c048b0030f3cf0c0030f3cf0c0030f3cf0c0c30e3bec9023478e1c3972e4c89123478e1c3becb0c30e3b943afbeeec72fe41203457d5a094526a14c30ccb98bfc230acbf617943e290397a5445100298a23ae7ee98c1ee8e194c870ae2fb2c1aeb1cbb7de775e5263dc74cde2693c9c4f91ca55e233f1993c5a868d983c70e1d316dba27ce74f2984e98e9c4319de009be2926e6c68f989898989818d3e9b4e3c4e3d4e3542f87e3228661f760a3d46bba209006a2f2bd8abe3137e6c6dc981b73efbdf7621eec76eef57038dc7997c5f0fc72b8f8792814e260f9f9ab82597cddbb2ccb9e636dbf2a58e3eb17ee736ccfe4aa55a0e3da8ebd75c8e0ad8a3326f7ea643af5f091655996657dd57abb6c01b0448d9b520b0153341272c51992abdfac85e4ea8dfd4d73d34dbf091bc129c6743ac5dc8831993e608a0171a02ccbb2cd6432994c1bc8946559b66d2693c964328150ae298bd9325366ca4c5bcc47765e92c5f0bc3d1a22ac71cb982b6fc01cbfa67befebadb06630aead7d8209c46caf8da7d309aa2e0109283365a6cc94993e3a4c3137374384c820b21889bac176a349b1b4fd933988913f667ac8f028ed28e928e5287db01a213d7c08a9393596d9ffffd5b2d65a6b2fcb5a6badb5f7d6a264302c3badbd3cf7ca5e6ecac55d92644ccc631ef398c7bc648ad1a146e9c4a45423e6c4643a9d648e5c5d56f6727971939783d5e01c2b959810632ac5c494e032994ca6ebe278ea759d4ea7d369a2c0e0561dc503b2991d356276cc947aa0c0340c2f2e95b0ca01c8523d6a00a6a8feee5bc932995aa64d9cd71a4d3218b6de5aaddb1c0e873359b00cd34b7c5dc392c6744f6fadb53131313112878c91a15d14d02ed7897669bd44de0b3a48ca8be5bd87d1f23dbd1e3feabe7576bbaeebd8258390a1472d1f75dfbaecf27a4906e3929b9418a594524a29a594524a29c59d7f2411dba7c593c4d725299e467f579d7e79639243d87f520b466e3e5cf6a2dafe642feafb1f485abb6d5d37b2f1743ac5d306b598522cc918ad5dacc5581638bf58f6c2f138b6479d7d3e9fcfe76332994c2653e75f9b7a5ccf4e2726c4984e31312530994c26d3e565a00df46dbbdb41076d9ed227ab214890204182c8cc05f7925f9971b20bc210b2dc02dc883de0625e455d80fe79cd5c7c348d83bd73b12c8687e37d57f3505e7c0e3ae8e3c9e0bc1a6e076f426cde034a9905b205d10979f51a8204091224009826db44c366ec97a4d6d1407ea07aa8e0b1e3d8bd8f727684250a600123c104e41190fb52a6a4a424204fcec6e1a85004e46e04e42ea2001ba455b476fc80caf0db0f3e327c08c24f08a3fb9be1caf19e1c4f72ec15314216495a910690f2f375040199c1b06a780004a66559f39ad6e5a1e891e5c11e35a0a228e66c989aa9be94d6abea4dd86ea5dcaafa6feb645b355675f7dbf25034a047b2cab0c7215a0b575c9fb730191b76893fccb35e59b7d6ab340737c608e7fb744e5ae78cc1116e32ccb094b51b4f7f2f8b626ceb11ac6f6c1fa78cbe842b66cc1ed17f62d9d3b63725fea0978315650d186184304219b33fe79cf331460e1c0092a2e501843e929061cc810a1960637026f2e811b5f910156da2a9692367382b7f7246f298a92fda64da39fd4cd9066222d23de8db3ae68315c41069620a6a92332f38c186304e4e9b7cc8d3a86968aafbd736b99d704172469e648f1e51ee933372067fb2c775394e662dae6ba6c7c57246ce707206669349a248d98ce28d58e3889122cf6890f9cb8075b8597aa23d3e24a922239bce8e467fb7590c041bb56931d5aea44d9002d827802ea04f1cd434031c30f0217b3c37b20704e264c54992cf7feef9ed30ccd407fd31ffd1538bcef399ca009250e6e945234efe81be0c63d6244928de0928fb6c9f6ccfc033a3f32a5fc94a96549fb8bab2aaeec1f7b53b872b5975f7922fb8c1b020c05022c311209bc11618e0c8293204e205a87c218c4dc334ed5e256cf3d4e344b1219d105a0242b750d3a3a862b00f6c16b3279a4a9d52a7d429754a9d46a9d77441522aeca9c53eb07df4447bb40b47ff4d1acc1e3da2d464ed101b5c918d24bd8534923453f42457e8bb2e95b276db3a8f37e9b4f778a4e5e3c7c9f2f1e33a9d7a447fd0ac8594f2f4439e4e99d2d3e9d483a66a658fd4b816465394082d72698a16c9f4d683adb5b216d6a7853feed62b9ca2453e9a12659ab23c9aea11e5fed1944d8ad25bb4446f638b6c921e992749923c7a85be87fdb101e9664e49b7dbd675ff6882207373ce7320e0386e72af321873da39b96892326edd479f25913d1387bc30b69ce911c521493465edb6753425496d822bb44d6db2c147478fe84d2c0259e83cb5e9519f20f3786e3dd656ebba6cb516b589194dcdf09094fed2a08b766a1353d09ff854320d4241903d56d3eed13c1e5b2dcb633d757218655e0fa579a278fec5dca23d8f45e68954173067bf70b33da26d6a1d8d821f40c800f503a5a696e91db54d3bbcaf56cfa9750ed75bd3d33b2a539b7a440f57702a0c4b43fdf4b0f96b4d2bf36062f6d48fbb35c11525802b3ca7dce7af87c3f39e798fe7d1643156010cf4777aeee1eeb9cc5e380ff7fa8af3541606c802139ef1a8846c99c97a16aa990100000000531500003814080604a3d1781447c2a8dd0114800c7a924a785ca149a42807421074c610628001000010000000080c6d020033f0be6cec7e8d5e593e3e6de333a017d089ff4eaf7c8abfbdf11328de37f5d5e801a197e93abe34816e7ac547f8aafc5d017ab71b1edd8d8e1b6b7593a75bd1f1b12e6e38f4686eb8552fcdc667c9de15d4b3bae1d2dde8b8b1b69b1cba051d17ebe686a747eb86617b01b297357b7920f1096348001ae61ad016230e08760965687a4aa6bb3ac42bfc7ba9a10670d993891b0e715f216fbcb74d1d3227eca63e5dc14779addc8e79a310d40d0e7c420844e97068272340b2830657c8d6ed3b5082e08b600022d093e0fb430e6164e590dfa5c4dfebd74693afcdea981009cbe083e2e6d7401e42398b65696328767478acfa7adcb63e6ea41722a5937bad2f9084e3003a66256c08efd591f1e0eccc80729d3f4bf1b7f9bd8c47851d404cc96b80ba26e56295bc4e2a3f28f5ad091bed06223607294b8a5098d9ab0c9fc051b7051318cc9a0c2cd9660ea2b98568839b08a0429e2b224a91654db3e8fdca3f961e204f668360514da3fad6e0f3d2fd88acffc679a87b5d6d369638cb06c4368338f4ca3f0ad39c671c565fc7fc527adfb310386368d0179710f62f1377ed07749767dd41f73f80084249816749dc5b43ac915796749f08f9558e46365854c639930b9a2c3ddc37e76420239447531685ca00e2767c25797d5e855bad4dfc471d2a8ba68a3d0097194b225f3738f52abac7ed47d800cfcd89e562d57c66d53b2958d6692a43d88005d71d4c1e6da775c7163807fd174e7b0b92f5fc2f5ecd3d266cc8aa5124b040e7f108563f668e91df3575e1ff2461d8050a4780c2a088a8bd8d89982e7488fe077c130cf50f12e3521df8ca674214b94ea1cc4d5cb245cb33ac2d1209e73270d241b161d444cfe3586c8c1ba07f5059015ecbe95da2d54f73a6d85027f00d6fe2952c186c2b0144884483d3e0794527827f809287d0855e25b15b0cd4bc5ba930706d7ccd11d20a67d54e6bf61550fa92f954203c123bd2ab51570cd1125713f8c0ea3926d272eb42e06ea53db262436ac0b751c62c1f050065c180310e606758f967a75be41a655f3ae128808aefbdd1d102bf95d9419d42b89efcadd3f392b554eaa1f4146cf81f3e32a82078e3537190e451c7f4a72127b8808496000285fcb260fbc97eb20d06b5f55e845cbb8da7b8fbf235b59f16b7c93d4ae8421bf9e9e71f8b6ac0f72e0bd2dcd8aa2afaa1180043340309be26d0d4850f3b21cff8b92e209f00567dc4d94a3f349b966ed60539c23e3997ee18a8273264b25c0a241732d5dcb5a20a04e66a2c5331723497aedcac7a70e1d8de1f51c9fa7ce2c931830cd52c33343109e642b0b20031087eb5f2a2e57061da2b4dbb08c24d9fe84fad651af23e68dac588c4d7159d9752b4622dbeab96d762a9104d270d060ccf58a82506a8dfd976eeae25647eb44179e1aa414067b0824203df9290a8cae0f7617b10c5ecc985dc50583631084557fab6a599a1bb4f7383841526ae3735befe2606c7341a6f8b704eb13407243b52a38fc4e1e62cc47246d0307863fe5f86ae4bb5df2f76f89a339bc6c929695ab3f0d524b299e7ff2a16ff8f4f7efc162e157caa6cc4156ab41422661aea118f4cb7590f98d0ca7605acd26632e63531c846f68ecac60ca526a208a5efab4f6ba060f9516521ca2afe1bbfd65d94cf740e65286046d3f5919a6a97cbed9499b7fe055a08799918e05053acb1872a55e36ef785f690b63e30291e24022ee1ec025a87501085968901183b30dbeb039bd1654c7264212219cd9e32a06f0e7dcc741895971e6a47344c2881064b931742d5ba2c2c317ce2404846830c2f341540d16c833960be7836d4008287834c79c54c84f4290dc860797c9243bb0d80ed143c2009aa57d08453e186e466b0a3ec13718b757a7922f762cdb580794c3599f1c5101878069b474689f953ec9efdd3cb6ebe1eb470a53a913a5cfc2b29ae9919756e28858bae29f1c89c04339042fb54717ccab52d43015f19b62092b450289b824cc28f718fad0c79de08da0f713c50563ecd76684c65c0204e39e41b35fb3b0f1ddb17207d920481adb9bd10c1ed7c83e897755bcec04aace44bea07921cbb2040f8075fd45417477474a4624a5c552cbd46045be0a5a1fe469ed6c45fa897ec82363b4621129d760367afdd6312b5888dd5db7cc2eb36c49485e2cdbb5c7f8365545a66f0d7eebef34b73a6bf8986904dae8c893dba59eee019657640032c2af6e470b5cd29f47db08fe1f9a368db2b0d86bd292609df0af6e7aaf2b799444e6b0d0c0823f9ba46d7795a18110a507c0e081a9aa4e0b5ceb3a272f9dd2f52cee2153f7836133a7ccc5d65618991a143217ea16b2df1dd4112746a66f6a5e6809d8a48f3152edce755c0fea4fb6ad5c3387c3d9abb1f4bd253f0e36b70e511c64ddeacc4a1504393861c3ccf031189afff7a6d88505100f03c54dee6be8d7496f8525567dbacf076e31fe275b446d45f8ae097aca2247c8625ce3fb41ed5b33c0250279d7a3e9ca6eb8ed3b74330082b10ba3b5c3810bb61fe638a52d980bb49a4740d503bd082f62f982691511c69b703faa3b3db8b3bf517f0b569cb6de9153904b15720305c32bbf20b5f46c18b08cdb4d2cf87104e75a964834aea32087414a306cf7099bae65466b173ab9932049dc04866a3fd78b296dbe6773a07a7ec948e57d021c38e016901a6155d091fafd0a3fc0d541025188eff750931d82dbc4721a1dc98355ad14354bcfec2357d44899658b1939c99684f9f76a1a0d9917e00b8dd22a1b74bf995015d4497c08c7e97c0ee6ba4683b8a6a4cf047e48a65056237aa2bb173f41fc521a48252a4d583a6e0f388ca7b1487fca2a54ff04b58e65840ae2bccf0502ad5795b9d4910d5a54144bb2cba500096bfa3b9fce905e5ed4214675e9f1c89ae2e289d16373f5a344873a564dbdf04f6c7b650b0bfb62c165a77449a6b4ce36bcc19c4a923bc92d5da8fc9cf004874ace3b8b4e7c700c2b575d70db2aa3fe7f309207522e116bf08b55b816cde23e0a23041d64ef4f7d68f3a2bf0945acd868a1c1b637e2b12a7785d731d01a2ae884a1393011120b2701029ebdb20780284d51328393d71364c43836a6c732be7b42d3a2dcbd616befd06a92840a8daafddff0508612d38faf1c09ed30f2e38b54230f360236e2ba9c019f599525cd53b82c50d1e1bb045d0181c02287104c431cef315d9bb3656f3e855863d1ce2db9ed1f1ef306b1881314afe83621ef532da884e5e1330e210e530a926df6e4928c27f377ce2ac71140be6b10ac1545cc932884aa581c665780df3a150df314ca07cf5d2ddaf9d6649d56a0330449222b2827ea85610beb2878da6dd7fe747d8a5164bebb8b8261db75522c61ee52f5d07fc08e36f73c2867976eee54a0ce306c4e6f04819a4f0f873fc1fee9d35df94decfebedf164f5827ddafe66af5e6cf2bbdda946a6ab32e01654e98bf55b99f2422ba067c998572d257e6522fc98c2e16b8cd17bd1584aa619fef82dc62d0ef8cdd9e4c84f090cd4e9bca6c891d2ae606e0d18d739b0863480ec22edbc7b3399fc544a4723326db855b261f2638ad5b7edf62290367768155f1b684b4c5a472b0019ef8e7ab783d9792c4341fc7604d1117d82124f77b2447ab4cb16688685c045a3118c523f995e0a1eb934600b9f6683a7bf1677e473d9e56e97b2c3682262cd3f8c915a47505c4f080c6c33ac8d12ce5393f6750a4576beab25ade2b1335481f58c06d2806eda4cac078dd054fd6595178ca4b3e9ecffd185fd6b9cc573b9dd2f5fbae34ce5a9af44fcbebd55fcdbfdad680c78caeac8a4604a213d14dc57e97a30c1b233397bc465099152bab8f26b12a62efdc4e911e4e3256c6a1f4e4bc6a98eb3993c85e2778febc5aec3d3da04452bafc81633850c99d8e0b819ec140cf90f51b8160869007a5a0791885e8694c455c4c98ee57614cb12a1aa04a2dbdc23182ab29eb139a33fabd60bdcac068785a9c9078d42ce495d06b4332e98982af9179300691cdc4413d311f240a4849a6fd52b16e486ac402a48305711c0d3d3ba8a8ec6095ab3b8c1084ae3eae948b2512988035d1a26d9e04b9c2c96267257e891abf5b9e54035acaca7b91250df5a0447ada4c57826f808b7ed8fa0cb1886da952cd1e4420ce279355db0560f712b29bc9378c82f4de1e4370d1b82f5aa5b6c3f3879ab36fe33554bc38ab22bc32a129e8720ead7f107a08a072a4d676635d862a014a5fcd1f2008828b34de8814b910050df757803f6247f010281e798328d8d30c00f5ed634abe3f24e82fe153eb6fa16bd9e2cf842d58704780bfed16018a883f10af589dcb290eb8e84f90af608c9e04a278ca43440efa0c7c73c33c6de6e2f30826e6d3adab4e49ac14fe988202fd410c6c0bceba0bf0da97a68468ac773da1af195c56aebde6ee4782cb6667dd297bb4fef19f138fc9c21dc8f826bd02133d70f908e3f98c7c3d48e2ea5a7fb7d50be27bee36549b3c33bca52a1ffa272949f95ae3cf6f5e9d5048c070a086c60690f086df5ab35211d81372676d306ad0ed4b1790bf04ae06f797207bb372bf8365775e244e67d142846f72db85bc1736584cd37747887ae7ac4864af60101dd81e3f211d56b101db365aecb9b16eaeba6eec906068dc732f2d6b979e9efe9a94a6bab9fe4b2d0b5d882c8cb882b276d226cc5a8cbd0c97d7d3d3abe70acf2b26e038db66f17643b0bd78e287b8df40521bdffbf1cf5e41067a858a39b6c3c5168da91168714c2bc94f62bd469699703711d968340ac4089807223299127115e74b8adb9e201a649469edb60fb9ee59201d2f509f84b2c04c0118083b6c577788e22229f748dec885bbf87584f78bc040561e00299f48a8c6b5e45976a9bb46bb3f6a2cdb94d329c2b5691c80455509e5814e8c13ff98ec36207f7d174271a2afec2e17675a1fc9dda0a56411cc8bc0929576e33e948b123bf9ea48afbf1eb33b595ed2fe959414a8bc1b26bb6a7b9810ddf60d97a034a95d13bdfbe0f864af5d0f04778cbbd1654ee34e4042684c562d925e56071608e33a77b7e203eb6900ea59c48b4ed88abd8e7c8b9a5afaf0dfc3ef6b1bf2a0ad7f76fe7a9418bb0b8e7d1286bc034328a245f47d0938d0f4aa025e9c9cc8406eb4e343b216d7ed7575a4271b123800ed2e67a1c08f74bac87736c0f2fe849a5c995a7fc6cc9d5220ec1a45504d80d81795a3870f083ea0daf51622b0293547265430665fd9e42c7a2ba115a7a858ffda26851f6f0050da7c8708f881575f1adaf7d08c835ef6a5b3562cb36d2680ae6a1721bd276548fe662d065858661786571801d1845b7882758cee4c6836d05eab3531891d00c9ecaf29aad0e543ee7ad34f80b0fc5e47029cd79e9788622fd9e1423735be1f011b49ff25fda355b314b455249259d3a12607db5b884ad79c15f91f5abfca66710f7556ecffa2cbcb7f70a9f792d5f9900cd66c7faf8776de8a017a275951a6bd05ae997b9605869c01afcd56d6e4e096e735ab5004b1225a1a739e610b2b3b2ca438e83fc1863e33fcca2c5e59398d17acf7d6a6f7ad8da0a0dc66f9b619c038616c28bf80b8603dfe05feff90e30293f96f3f6f6b40fef5df1dd93e25483ceb44fddddd553cd74d5f2604f0063fffdf992ad1a408c7d6febaad60f82ca650d6ff880506d0b0f178cb615fe25d6b168a39007b6953a68b52cdf45acdfb6ba0ef93e95897c643fbb3306fbdf56aa9f0a53e23123b8af56324ba2cd4407d6059ebd579ebf17c151183d57b7de57898ab81fd448776168b9e485528fa7319659a2e3e2f57ec507ae8605a1c85ac0d994f54d6e820856f5ded0c56fcf04b922ee4fdcb88aaaf364e574a278460b225327805f94ba17903698938846a5315be3b49359a004c0b151592d1cae564cc597e2e82e21a12a05da0def32cfaa624fe104759eae514f9e75a00ff5aad4ed1128eff6401013b119d72bfa700690575e5a327ad149b3b442ace4d30680e7b1fc2b29d3228a0146866bfe46d77677d2bbfca65748ae07b0e87fc382ef7f5b82130d1177e3a1cde1448a92d4103c3508347779fb2db36b9a4a16567327b6d8ac3fbafb166803b5926b0f040b71d2054965782254453c078480c0ad050f8e84e131b361c88ae5684b0c3a508cf097b05285641e57240b2ed0527be5eaf501935602e14aa60724d840e45b974549b7945ad8c1f017a8a2e160aa4651c41dc98ae13f1255cc52397ed4f606ac5fb5f4fdd8cec8b4900cbc092973a8e789154cdbbd9a01239ac8791ef6fcf8ed4ec44a94c686e6347911389db3417610bc1a00390ca30595b5adcce1a7d429a4a7a4164b1094d29c5a194266e3ef577887ea4a4193b100238128abd3e5d85276c24af466b52d954346d7e130013f4786bfe652d00bc0f75b53017892dd7f64a160d03ef28d8d58fe10f76f83b70fc4018e1fc5e84f3bbfd57fa803c04b334582f9ffcdd424a63885acb839086f64267d793e5746b0ea4fc538d11eff0daf8eb67db716c9c243d31b805555ee3ae3701b7e562726dc2b8f53bd8ae71d727e4e3a12f4b1ae0e85d66c172ec7d288ddc6444a02a1912c7f8f48f55958977f77fd2705edbf8a11c68f19d7f2a44bb94041a837092c30c9271b3f84f38dea81b5af45a32f0899bf1e0bd8b57121aad3cb656cd6f4ff8b65c82a35333e03fe77b1ca722d84db082eb845c327094700b2c4b4ddc6d7bc3d8eabc0918ba4c2762b9e108ae24363b76b55d02526472e683e5993a895ee637479df601ebb4c5f0bcf6ce2bbeedb81803123f9005958ab67f3b3ecb5d38202dbc4851eb92a5cdff4b4f1ed314962d4fd74d953b14ab0d3b22d7a153a005d1e9bc7729c90e251012020bdfc33536230c18e7a3eaeb727b61c562a466180551b2bad6be3eb5e29e06f3d66b9eacc2e28ab8d535319456d0ffe4ce5e82e8718d7496900d88826ad4f4c7b879ac5a0445f4917cb97fc396ca6aef355bf834945945af9d9b83cee0182672b467678213537d820fae768f0f24976f2235b100f1b52dc6ab73d60f665aac7c924395f4b177066ad4dc907a92a327ca1ee3a77bef86e68b88eb662b4617e0cc024a5435cbe689dec5204d1bfd030566f7ff903aa50cd4c649004c0b4820d964d594994d79f693f297362be7ab712c1e72576d2103d0440e808eb3e1fec8e62a427d5fb91216992447df6b6e29d230b57f897b5e86c24fb7a86f059a1a1a964d043446246f55585788e12b9ce90e94eff00a9333e52f4e83a2e7fc0aafe8dba203125bd456e48b796a4f9ab40f5679ae3884a512d1f94945a2e6a40151230abb2342d62cdc90b019c89b425a5d7c31218498e7cc97c46259e01635e5d04f7bdd248492b59bca7256bc9c0e2118e5f9ab521d636d569042097eef06b001d21117b3615313338f6ece3ec4b98f5f25d77fc9eff9dd12e078dee53d201708d092f1e5fb32e24f45856cc7a93475e3e54ad5c053a01fd326a3c18972dd7133537349105bb24652355b378e851a13a25d98b9a0251e377d6be5622569a3cb0fae855175d28951c72d5928cd1aa56dd80e9e83dc7500b6c424d2674522696881267f7253a3341408acb6515a1146bb30f4c86f16552464af0416b7f029515af4318877a0c081a5db43f5d5b408bae263d36857ca5ef1b6ef8a81847bd52ede651a232c19f630f39074d88897e4146698126e054144507a05286ce569b476dbca8d9fa9b62cb55301acdf46a31422f6fee3f77f0360063e84a8ce1549ae17024f419308977234444404380934d6edd7df6dc7ab25f7988a91d88de4c9d787f0f73a149dcf9422dde6823e2548d9ece5ac591eab29f5876299eb382cb3b0c4fbb3093246ab3bcb78c381a55c09d64fccbd37b7ef157c8a5ed44fc4e1de1c7511e84869ffc92b322838844757c7058bedb401b957bfeac8cc8c3d61e4daaaf8ad5b2f6257bec42bcb17340808600732c2972949642b407a926ece431d3c0ac3a916f534a54e03805d3420eb90e4dd242bec3408a84460215cd27249c76e4214203d1accec66762ba5e01d34f9d18c5fa0c6848b4fcb4112ba1fee436d53777376046fed9696fd8c6a513faecb49f1611dd1810d390e293df6dc7f3c6780818f9b9716e9ed1d9f50dcb5143cf41d327942a549fc4125680ce341062124b643d65fefeaf6b634fa9cc88d650cfac4c51d90e436799a1dbe48e78e3f1a0ce23d5450d2918e86919991649ca198e047347fa7e8aa3e2cfb611731450633fcd50b3acce0c242560c8c3cf16aec704f3f51486e54522a0ea05bc6583c1939f701c4bf7a4682a941210dc45d4efd3ca7c16dcd1fcb813d2f7e6b822a01a32d717b49ddf1f7d48c8bae865b51f7c5182cf907f8a8609edac45160d6f470664aa6729eeba0705ba60c3c41afdae4f43f3724f4370cfa96404830a22510208ce86981b529eb8ea34c4c6cbe37a8037aa3ea41ebebc0d90fcd71a10e08799ac01e2f827a28fddc140b4f19bb89d9c1862f32bd5481966e6c7a1df482b323164a49ad852f4a8a6b75436aba928d9f7542b0e8caa949f4ed5494b551589a6ae4ae4515975d2525b45a2a9ae3ad97ffc2afdd28fc87c765868cc8d858151f76a533b6b262d28b8d344d45b5d548d97f5f4329ac0b26e68def560b471f4b52187e433174a3802866f686cc8bb7ccbdca7ce329905968815c0850f007fc15a1b9fa78a5ee696023f128b637b6a278738cdab79de66fde0c3c0a6259fa5a2ae173c9dc9a4a89b3b656e22e600337d698ee372ed1296495883b3ab0f38d41585aea59301fd5433010346cfdcd69f6cf28d380b6b34db1d3df3e22be303742f100353d56f7cebd4771766e8b30c04f75655f739890310fc116e938b47f5871d326587600762c5f169f7c0c2c82184afd3bf43ed3ba22caca3af654cd31be1f11741a77232ca51e89ecd9fa0708ba084c01d091856977eb8c70104c56ae522fd082420b2ac0d16aa402034a68458b968abf8f60dfe2adfd5da791c1de7bd9f6665b53fbd1f8ce25c8a915b9c1c66bd8fd90ff52ad4402638a73dbd51b72006c295e3ded84d365bf7599be55b382fcb7c6f30fa4547de3bead78dc07020782866e6464e20e9a85b7c2f907cbc642a4ab431f69923bcea1d060eacc8a9c8089df8009186d5de07351c3eebe85813d0e04500ba1cf8b75f50beb858f4be567dce60072247996162fc4febe3083edc226b28c49bbbe53ecaa80260e83d5b3daecaf9679770d12992c0d3965db1aa9b2a5fa100c1d122fbd1be570d51824ae80c9be8ec0e1c967d1b84fdbefe2e2e213bfbc239fdda31c69ca597839c6a749660e584abee80762b91427dfe6d352a17deba37d16c882161b3fff27c6d3ede2cbb8fd7bea77b7d3bd7091988b7d2aa306ea51de0e59707230dfc9014d8df9d801361c0f875d1e82653a3ccb758679a7e4b8459775b100398262a329dadbb2333d89cfdfafd1ce51c7cf82ce2a3e402434fc41cf2430dc74ce4a3aa21c2d570a04283e897325c6aad6d5ce43aa7ea3700139ec22eaaf396eee37d3a0badf1ed18a020a018f9932dc6b787c3c9d247e6f81ee768ff4c98ecc9053e8224b1179f166871c404dc89702756f9836bf35251dbc7480264241517f41b744cef0fc7be9bf7c11ce782579ff344c4b148080118bfab156055d83e427b460d70bd2987c4b8d29e8efd8559494a6e02e0a0f30808fb0d8d9008ee406d656e6e9edcea5e67fb5fca831e0e0ff52cad946e842aa4a8fe7d1df8ab567eb5f73fe04ed7d7064ffa024b356123352ee96f481cf7b1069ff66e3b1c338f1c5c05b713852daeb2188d30e392375bd830321f186fc3b8b3cb28564751cdc3f0f7749cad65fc800faa8bf6198006e931a47c7aa7d007fd79f8ce21271fabb2651c2beea307373194ee25d4a4b21eec5eb993cb38308b667d7c12c4a7f9655ef4f4374bf4dba35f9e983a605e31cb42dc8e954d4e910d37c89337284302655cc2774e3d713f8d1b11cc6ba38498fa7c7865f1a965c35e16a45572876c3fe4936532f805828e3e248703ae10b6fc7986d14e4ad668f642a3d8602ae6e2a800788e3252b71ba38ea4a7f6856e10e956dfa385885c06eb77bfc7e58783bfaf9ea3abb3529189698d905b0e19bff64579943e4a942eff54ffbfb7163910bd90d10fdde124ab5d034a280599d3c9c38f523ede4c59e5da40efdc7c4c8f6e860396fc089435ca8d8d2b9d56e4e30c8173b90fd23f4a6c7a8f1ec3b7564192345c2adacdb4d9cc2f4705dc52cdf76aa073b41c25e876a66a2c2fb7db44cdb7f32ba81ae9056695aad551b07ec6fca3cec074d37f6dd6c67a8a74afb3b31dc8fe373a2f6b4fff97c5e840d73fd1a3c13ad44d28b5242077683c32e532c392851a86cb216f5710ecc3cb6df11731e6cfe1e26e40c33a1f1ed953353ddfc299f760fc8e9dd91e6ca781f382271989c4bf818d610a23b0e6aad42197ec6fea9e0a9dde6044c228cff885d3e25a0d6388ee7a67a3fd361334c240a2817f63ca7a57d039c194b8639ff10b726dee24466100f883b9231434cb63d0e0e5f16bd65fdbe92d7d5a4ba06dae49e84f779096059a8b1dd804dbe66961109a41886d9d0456bcc2cb8ec466b066288e26576ea95751389480d2ff58709dd940e401684d44e00d702c03f07869f47d684727803fb07e007bcd0f1468a3017940f1ca0c15d58fc194a1280c1f635933f67bc12b3156e5a917bcd902804d95f094a4bf2271483f3a3d61861b30f57c8ff8b9016ab9b8955244102e0cfe25d965fb938c15c113fc268a5e03d8f2d5428b2a77b96b3b8507813a25ec06803826f5f57b4b2185bb2a47fbfb418f5565b273ef6bfeb86a91cd98cc908e5d30966fab18a3146c0589477d957f42a80a5aab531ced7807362f53b8ffab79e6e7344b88c3bee6d1355233804fb55fe84ce7a1354b133b079bc44741a23fbe5a0bcc6cf7d2680cf84f7cf298cf1c86b705ffb1c5745374e61cad0c291a0c39956f20d8a06587385c9fcd754e9f6082d290a2f3f917dcb0df53bd79811980f06d729d807217ca7b8c3fc4f4e92ced99568630b8402d1c30fe8b59e0a856d476fd14eb5bcc531f9e5dfa8c1f25840c8ef387e953e096c033705e2bac6dafd17284537bcc67966e1437811d78e3ef4343a11ae576d87d5f104445dee6edeade8ab56b282cf0a1b83bb213ba06c379ebf50b8e6aa7eec556e2744ce680cb9ce705f3b16bb70e23bdca274371bc19fa65097d99dbaccf7467844b26b4291f1c589f330fee388446cd0f90c113873a08b185b4b230da97ab39788a4fa50e1839bfeaaeafd58d1d9732364b170196128dc114111247438450715a7627f27e72fbd3105348a76772ed7e906ce4bd101655eb3f272c83b8395782a88fc582e0a3141b03a78e7bf208beb79e4700f1fe2dfd2b7ac4b0d33b95d25a006ce7981e50a850625b762886cdf68842eceb1338dcfdd617d9706abe7555f3d88cccb46a72bc32a7bd4f3c310a81fa5c2c0a2d47a9ecd78073a46ef4fbca1068e27f08085bb59b427a8ca48c56c1f2f4eaecd2bc9f3a07100404e14e3824cd8292f9c93353d515ed728e3d4eff24bf454bd7a10669d93db1963a4f089c1fb59f3ff890480c6dc9a7b910526d01e410268a7ca8a61822c63a18d5d6bcffdf793b0e2206f26771565a993a3d4242883675e17390de857868e74162db0b7f1543e76f4c60fe061668368ee0d67fb8f0bd091f9bf0e91718cb7d40e3046060f778263cf061d5ba43cfd467d7ba18c0c67805614316b9b1db186712f3c2632fdc480e4d2aabf7a252ca34425c8c0902e2ff6d57abe4193a06493b69a735841b9fe05643c8c0263e3ba4112d11309396434872d289c860a069f9459a5765e193dc130eaf78108ff922cb9d2967720680caa4e5b1d5cf8ceb87d0d34f49460c33a06b80df159049ba903a13ecfe10a785c85cc935fedb5d0beea858a5c458bf7d7007c75a681e746e127dad0b976fcb46c3b2e7864a2a0e2b8d01230231633c3b59a447934cfbf0243b95d216e877ac97bc27bb6db8e3b8f61d1bf962d9c278d20d7e1bebe79a1c142e55f770c1178f3623a7a38bac9a679c62b5d305a04f688e9d87723a555349d98a053b37f7043a553c3eade9f7575d03a3e385f8755de143693f60db6c877d220c8d2205c9720b76ec88ce0459d5afa88be62e6bffaf4a0d1c2f00c197bd3dd2b97b8ab89ac145ec83455f0acf2d39809796e653da72814c51d10bf573a56b926142d5b7adbda9ca8c1345ea298398b9347f98910060450915df74b4349e2c22ecb144b18cf063f3ccff585ecfeebbbc6f60f973d5133458436a68afe2b69fd3e1c1abd71d4d997e9a124dba122be1bbbd38bf8324393d7070cee198f81bdd7653cd739b081ea436c30e92ccdf2b15776290357f1d245ca7c2be1e79b424296fa2661b5f83fc03c41fcad867ec49e10e0804941abc68586db9de05ee2fb4eef34be960548cf156e99a37ac920bbe553bda137d25ca1a9c2826c903851f115fd25c424123f1aff03fa494f949513072516e053a6005d8968aa382252c4667940b040257f3975fe714d3aa48042766f61ec13136a3340cccd68e805ca1beb8e40afd96c392f7e4b6722f6f88f048aaed2ccfca82f6b4fe0635a92c8676a5a15cb84490cbfb3305eab5db4c20d8c18515b08ce3ac34cc44de70a7e7f1a8c16153e6b225b8aeaf162a3bc57875a7e03a030e88bc8f8a24cf0028adb7e23131af694e91767d207ed6fb475e8944c69035955ede094f7eb0e3a387b10026c645b72fbb2da3bcadb9ac95f7a68ffc6b28544186d20dec6764407421fa11d75ed43e1ab1e26adfe47af946c1a1041cb8e67513e56fb01957da65b6cd300bd21a5658f9a4cb68412e48daeca9ba5c0bfcd5015c585526341e3df1701cf2b064267924c9ce624c4d95a89862b650a73c31c5ad6f7c7639bdf94fd459a21e90206f500cfc938d1fec6a25d644973223e2178bf4c9fbc5e91b7910ad659e3648c5fc964f5eaeb3c484a9d91c85b11e285529de0faf222af02ba8975f9f1cac0a6ef76c122b0c2c8cc1149a6e3ba734831eb318d47823c08673bf3b8a0474bcaf2bafcb01f1446d103d0df818665e2bd4f207da68467f011146a4d52f1f2c7df9cf3396b7fc9e1262d4babc07202de5acd297ebfaaef74da97914a3c932e2664494afb4eaac33e577d50adac2866adb0584793203b32c35be1419dfa6080d23e2c8869543b702a23c044ce4c12df156d8d688a1dba2c66b709ca18b54af11418045469d83f42da8b7d4d62a630000755ae695008746d7ffacd5069bd0cf83dc7e641a3f24f786abdcbd99dc70a4fcbf7ab38803290f2e55a241b1613775d92c5923f86e6586a2bf776c5be2321483995c1244191b11cce885b6c0dfca60d26ec1d306b3f07164ebdb11a94b110e3794307a53f9b33db115a5a502ac9dc0092b298487a4338167474f39a16338b92683cd5eafc559260273750a6b21a79f56d57ae109e956c2cf2e3729632ba71bc2cf894c6aabd729f084cd78d566ada79298b31ad23fe440577b59ba6880660574a9d990281de97a11ede0ae09024757529b22eaf873e05c444d68cb45447acbb9467507e6cf70322d7991dbbc84ea9e4b1e43bdb9d3cc4773d409e20c7f15bcbfd9f28087727bce4260f08a022f9684d73a728a5d3e771aa93a402e0fe0f4689d529eb889d1c1b687cdb745576639e5d22f6527c69d2f0549cf137b56306d7c0aa3947ec8a5aa0f332d25761a3d44a56916beeb49c7ad89b0b47e71721aed6ac89ca26bb8dd4b2f43b940e3aa7bb8ef158614216afe855b12bcfadee25146f03ca6785d7071bd191ffef7a7b8ffb41252968f900be3cd78601cf48d4c24a22352f287e733aa82074ed8852cd2e9a83883c4b31577dcbe354fa6321160e12a443aab05730f7d9e7e6820f20985fbea98c05150d61d12a46164ab9a18299db69b84771fbde0aff68bcca7c0234dbb6a4ca4c5134741362eee0115d2883161ed8ff2d9a0a7c1c16c74b3eaf6f027976d742331922f373bc6f81671ca7be58ccc8d311664de0d9b47e511a02af9b1101a0ef7582c0bc8b823f6de626afe63ac94aa49797df92cb921c50b0b9261aa4cc9111e86f1131fe71f53aec84145422298153e8da3bcfab02cb9a2f5980705e2856de0ddf78afa7ed2dc7bef7dbbdcb5bae8b04f15a6d19094d341f20f651041301790f913c30d8a063ab9d30902dc7b9e516c6e40f9123c7e3da4359214f82033b5a337b991ace889a2b1e4ca67899d0f855f878240db93bbf48845b97899185c8ba67ac6dd3edc3d312285e6fa9c349b8733b204ff14558408abe3f23ed0c7791e4521f3ffc0944c048b1216058c183a1d35692769366928540f0cc505ec022e8a7d4cb1dac7aeb95e9fa049d32c6531426b2ae36f42b461f91b55901942177a02b8c3627db32024d4819214feb7b39687354b0e0b6043082ef46655f99fe92e9e4429c2db862748da2b3acdf97f95e024eb921b125054a0290d2a004ed074cb1c70b8f8a87a4fd822586f860edb01021287782a2a8f5b80d43079eac041d55a0cd20a674be0c894558a0ecaee08bc6faa69ee30f1b6a3abbb80760538e5911b77ac808d7e5685de897c07ce9723a44e9be789242d68b7e8d5dff75b57fabf72299a8c3e679dd63ada6afd0e2ef5c7f7d266db488dc7622f0404db50e80360ea13b39f85a266c331b70041773f9d14dd2c58339822e5d00b831f3c8453f5652f92dcd09bede777e643459608ea5accf681b07e21064a92db9c44e37fb1780884b4b772dd01e43900bcb810501c6dd8e07e6cb6f0cf0474795b645a256fdac1e0fad066de1a11f9f0b052a151c0834dbe526692595b2f4c5670ba4e9b5d055a94e0958da7349d063a26c2cc6090571fdeabe754c90fa9eb6376f97bfdcfe3953a2d4cad04d203f09ab5df465c48e7185d5d3734da0a79788b157488904d0382ed8c17b95ec837ee8a335dfe3d5d137185023d9d9c04e6821e726b2abc09307b2ecdd9e03beeece7a1d9fd82aa52d5475b2daa29dd72831ee9a77ab2cdfb19f207fc82b0d52f6fb4058cc7d1c57d95c4f44406123f502ab8f359511d4abdc6ba510e571ddc7caf3dffbd9fc7219223232dcc1eec238db4b0113c76e7c2a2d78186afacec6b50dbcbca60fa3dc894bdd89ba29ec7ab99b681d39502523c11cdd77a73f29a917a10260ec5cf1e02aa12036c9e05e4bb75f16c78bd30bc7fddc370ca684dd9e7d6ccd9cfd39d524311a89cbe500309eff2669b69342087fa142c18f809e232c979ce5f09ca469d6a4c9c5e45882c4e348d65bfba1a3185c42ebdaca9dab7efeeb4001d0aca7d3de20eefe0f2ba660a83ff6d5bfe798505b7d1fa0a0be82207249fa81dfa53e7d46b8b08168b029fd6fa84640059aebb4b561d9e450ec972bad59f0323e6359af5e8283e4be69e4648e7ed2db5c6538a9b451b0498a5b14879b1c4c0ed7f76a05926f34781f2274ed503cdd6e4bb4a27445c6b0ef441122e9a69587ccc3d7584fb513ba3c170d1fad1cc33f5803e225cd6afec23c049cda33e229c6b3eec23c4b9c6831e229c6b3df622c4b9e69e47c01eee4a597c96b2fa63b2cbc60d0a340391a9e7563ee866bb8ca76ab5c0ab1ecd2ca939c5003aa05842a8b5e4c38bf0b80934339bf4787de0001233256d212948d5a9924ed2cc1ce72472d9c2c12c17883f535069075ad1ca2018dd65281fc8f853a8448758c1c22c8ed2679823cc3c53a2040758cd72288ff2c89c13c83952a03407adc87a181cfd649807c0e1774a3a90d5166714789e2dc56b668f525ba9cbc7f216cd768f92565bf71d5637ec94cd93cda65cfa0a8c5d41699e4a505436b201493ef0715f7dffca6d06b9e4dfa93373f2cc503fa36ad0f61bb6fcbaf79194e1d4ee6056b33297145eaade9bd3a1bfa1b3108011baca66e2ffc3963df427278bfb2b8bc7b3d7c1658542ee90ecddbb142b1b12c30ec2b2df3b4d87d074a645269553292c16b22dea391891993908f3b18c05b1d277036e859a6f1ab9799ef02850b92189ec8ee44a4e0976969d22b28af476448a08d369ad211508df59c6a9fd85f4e6c881c16a8b42e8612d586826f0c6e18a084d9d42f452563a751edddeee95004416917db1cf07734f58ef65f89f21e5a4b22db39b0aa173055d6a7f2a06f2ffb840da0fc3e8b0b3c5ea532432e6fec469d0a406cb63ceda7103a05ee13fd11e3af9629998b33b4e9c4666e8e24ffdc9189c8d98d8c144595dca9cde71920f840c4107e54fa6787688d10ee2ccc05716199ee8b334d6b71718819e6abffc1fe00a18e578c65997484ec20dcf94ade2e68c2f6d2fc16f467109e4195341232d22ba572f40945c9658054f2fd66c1916719ea0b5400b70517e517f5a5c8fd1a567552e33ea1d71c1173037e2cb83783ab6257652cf3d93df2e418e796317e58714bf030f9156e0c54ac440026776f62c0d40e7afbe498859d7c06485a51f2ef8f8549c8bffa839804a1ebfea3fe1e62090c352fd033e8eeee901d7ca5f007ea6be821f1320140dee7082655693ce901c9d5550c7c2f83498738d17688acff3d8b81fd13719fa996f729a0fcba9508e20669264305cba0bd2d1c22507497ad525568d3a63bca0b4f474a4a846286321c0450911498663903ab1f8de1a7630ee3ba9416de88267ebdcd64861a902ebf37aa3adcd0b5a274ad36fa8bfc42aff1b75e10a8d981a9624aa647ef3c7a048dfc8d528934edb524cc0da3294b62b4c8a0bcc7349f21d62a52eafb752b08a9fbd6e4b799bab5f92b32f4bc952ccdc6eb6550d97296cb56fd4f992b53e8f733422647c064238fa28d83574d1c818bd659f188a8ca022b086f40ccecb645b5800ac1dbd5c8996f4afd56bfc9312d4ad6334414f84097094a06839156317003df33e4da28f33a938389c12a948969a23aed8572f1efec02805973234c2eaa8c9cea4349eaacf1316caa76a748924a7ad67653aa844564c8a27838f3258b199f7ec66ab0a372d0969af59d35d3895cc3b0e7edcfbffe00dd4b9c6341f871acbd504d705a89bd2a002ca012a3457bd7a7b857745f7078e5b8c8dbc954f0c2304c41c489b1bf657e8bb376d107193c3d493596433b5862230279d06918b1bc0b037f47c0e9ad351702aa08256afaebac18cfbd350e837c466f493437238907cad05aace5d6c4f0b2c2b677c82e9f80e58a11606980ebbdd101d28dce11227b788c709dbb941f09fb8da9484b32d28f55ad738b1b54c07341cc8b8a1000e007d30c93b9c6db0df5ca4bdf4b44897c275d3c96abaebf8ae45c97f01af2914ef441afd2b5a0f80891553ec3ddcd02e72ce6cc78952eb1268713ca6b098749273c44981dae083352e4181170cf08174552b7c433159d5b6a7cebb51cc8523fddd194d5b1e334f8c6c115271a6709f7f6eb523999e6bb853348c22649ebc754c0376399186ccf0dce03e94fb55c929ca73d0f7ba4f1760f18551df08ab28b965f2eb9c0ad7bd292273d328f39c48c50d1f8f8c957817c58d2deb36077fde524b3481b31435f42c55316b89b4e74adcc99cf853eed20d972af35073b7175e5927de06f20595424367e7d1d53c9937dd7bc4e48583cf6fb9be003efe376b7b4465e6b2ef232a1c687eb8b1bc7b92c744ee6198d9477139db5e2dda0db80569bc7b31eb0d0da654f6bee7af34ba88581387fc57f5a541660705ecffa5ba1ec5d444f47ca8ea1cffe769409301491f9a3a025dc688233f28aea45e03e3c6958acef4e5190cc0a335ac4770f359c08d89aa2193bf3c04bae68eb2869a7e20b1b56ca4bb0616cd2c46479a5e2d4738298a325e5181e63f7612148229f4f97ab391ace5f90a5af6eb9bb61c0416b4676740ca119df39896599dd0d1d585f7883e5485f6817b2375773943694dc66a1c4349de93062bc82cabf5f99b9af566caaa8599af0c35fcb5257a94880f37161f8c8c26fda36d62940f01cb12402df59c2501cd26b0c1c8a8b42d96b476d408485475734dc880618a25ad7434c0344bdaf601d7d753a67e9425a50018e590b99e847151a53884040e9420e04c4380b0701cb03783709140e27bd06eb0f4726362e16a15a503ec23d0f007957523c8b8276d208ce684cf8e0c21f9e6de88b2feb346ebadbd637e9c48636fb5c092780cd58da3225ea22b2198061516d39bb5986a8ddf01a5277314f2ea291770d8a0cb9c90c8e24ccdb04794360853e1ba27649a625c73e6eff8b5b7516013390a5ca109237023e748c09b90997edd2d32329ae6d06cd3da161aa999dac4fd2ccf064566cce81b8168a9c17a44b557a8e5dc493f7a0d2721ace46c87060cf02b3169103e16b5d92a61d37e5ddf80982863ade32f475bdac1ebfc0148a814b4b4cba6281bac5a29847d80574469e833b5709761c4e495b4794bb9f7e8437b2549a49c85842e20624e59000b9432f3a75251282ea73596c2df2c08a9198a45153465de1951f4d1683e9bbec5d4995fe752b17422a1faab4919c45ea03c1cca03df09293568fa4d8bde842621d0eaac4c7548e1956afd6371903cc92e91a91569b21eb2ef17c258a32496234f069be447c0c83af662d5dcdbc6fe42e8cd8bfeb9a9460be4a73a50eb772d12b05ffad6c3a2b4218b671e76dc8b3db40bc0bd4b64821fb4a149da9e401253bdd37ea747f4a4d1bc58d8d0caeade44e9a7386b58aaeba58bae28bf57119f7febd5ddb74eee7fc76540c39bcee7aea6d854b0258daf8fb54058c2a04c8f06cb013f42f5b3fcee6ab62c553c72c8118d4bcd3eaf6d2e24091ea4bf16b4c534ff94eff2563250ca4cfa80ab54044b84307e1a8018d3523e4a47a69d1229bae30b572164e473943c10f12097d74f59fd55af6f3af180e9c4761ebde5f0a9e0523a91e3b1af69e207695c5f2ec42793d37cc97a533cc2df64af60593dbf46d24add9c2802c549289f5a97a44f2a5013749ad43f38b32606dc26ef1877e42d92ba972d7e0a11c6e7c4e3f034f4f1313df1c9f70776a30a49f758c9dbcf56ea4afb1fd17de417dab4313d6588c52ea75ab610f16ceb86418d67c81bc97bada18d3f646bd5281cb9b0e465ab84643e69ab095c946ca59b7c674a207faafe47f1e95369be9a61139b292e50931131c5587c3e72b5d32f32f1a13977885a9bbaa6f934c9a3ee35a786ae5e276b8d7bbf64c3263f807b05c6afb77bca8d96a483409d549fe92fbb4326921920fe32ec05ab376985b16019c771703d349862848ca7d2e57eefdde8c26fb21094adbf52ea115ea1abbc77cad08dd7236fdfddb9a57dee314e6acc459ffe56c387ecce4bb18171276a6ff5f1a891b2de7fb00dcb8013bab2dbc7e02bb7ca0c260570629d68e06aad9505a2926da9d882922d3846587d2da52b4392b8acf6f2ef2c64ed8d7d270eb82e8e7c13a3c300d5a2aba8f3b9b99c47861787377d5e3fe5cad3107e92796e1229a71af3f9b3876de9c9c705b13c3abbedfd514d620e4cb0b81c0218043700c2a745296d408510ea5ac0cd9bdf2d5da1f445111d938d6134cb13d11c43f326338cf91ca105eae67ab35d4716656e4f2afbe65608a148c2e650fbd40f9ddccc6926913d27fc1d8fd28a28c90f34608843b87a08468744e781ca3f34076051a3cd9abbb124f676229407e00ff3b373f2af8412757345ea8fe49e0f3d87e7701aee521d14b10048274ca74448b7f8038f2eeee90acfe2d52ba2b651d98ffcec9595a0f87453239b3bd36690885538f1d30e335663cfd79572ee9b9514371dc7cbd0dc1db0d98aec59efe7d3732e22395c143ef60ca74574f3d3bbaceb8914067a396e3323f3996b0ee3d89e5a2b5c05155f01f9ba0450ec83f308eff7647ef06c7382e149a595240d2555508f2da00ef19ea56ca2d332455b66da2c1a11b8b6e0ec15d785b78ebee75faf12f04a537a5e88e3214dc22bbc70ae9abc3854ec3027ad6a9c39c4e030458c5a48cc6ffb9d07ea6219c98ddc85ca57232450cff7c10231416b26a5e8c738195f6df2662256329855632b0a4802b50daf248809ef410332cc8de304ad30a113c6b110e30e34b3c6beaa6533bd5d8823f4ee023dd04d76e5480d9a5a8b421d66c95447dc8018a6bca55fb30e1165166dd12223be2feb263fc707bc3d1ad713a02f2f668bc600574e72b4344bacb323e58390e9a4fe0bac95525f14026be1ee566f9dca9fb28e13b397fac030f716512be2808cc320ab6abb3c849f4cfaca91276faf8c402328ce9d310d50d835ad1a14acbe05f709afa71eae54c289d98b8ef1e39c66181a81b41311464847d795138f959079ff9ef4e8d711b5f34bb16f6a97974f3b7ec62436103db81e721ea9ec775ca6803abecabb27e9d886965d9c7e6cea529038875986fb94bfd8d25395a49d9ec52412eceff955267f2e9ca96976ed05dc2e4b0db29231ea62446c7133c4c22c6ff7b48e54facc11c22530a1d7e933d22532317a3d843b14a8793a031ab8522a5ab61da36bd55aeca3f13fd33c142f641c744e50bacdc230d1a02b423703a62324173f279f76b6bb9183a9ec10407c649204be013986ae3ee69984649c52f11bce683664f7ad10f759db9985100b9d6c7bf9c2dc19c19cb7407b090dff8bc585f0072a3d7ce9342d404e3e7844830619daf3a9d153f50759c8f689552b084dbb0e0dcf81f027c80acd63ed5e1c0b7946a4ba6e529b8a497b4ec24446c1fdcc32141a39c464bec071800094e4063aa1ebec9c718a798628d0eb11abe88f0621fad6ae73a9b5ad8c62aa9273c9c53a750ada403485de5df12443c17037ff4b5dbc59eb3f90339a59a27243603d021d1cbd983bc6437afbaf3b6206d8f15967ed8e533a7bf9ed1fc2a12710327371fdc395e6d0fac7779249a232b9aafc70f4ee74c5eda3e1f5a8977d6f67b221bd3c043d622f4c78d23f4a9009f82b9828499cdadfc0dcef59a4d9390f350f257b3934f2d3a4e8062bfc638acba19ba60304f754c3c714ceee3bd011d1639dc5ab5a08d4527b1744d33b759689cd5d62e93fcb6959ef427234afbc83e3c683348d17d942fd753c117527964d735ffc609b4130b433c45019c5eb8c5e7b4a12056599d200d0863ccd889f0d29848938f584bf6e0c7fd9d04fb49a54e188227023633e8c7af0f0d76837f4d0cc5e42a043428d14dcaaa6df14fbc52736a5bd645f5f197d263df8071d37045e78c79a6c33df17e39848dc17d429812b6b6e8f468a5a4ac8eea1574c587b4eed1e437587cce43b356f670ed917e8172a56c040ded24e89c22402a544bd0e766646e2e4ac52133676b7260d2a08599b76d3016c810eae406235246f9e913363819d15f47193939a3e56efc57747334901c0b7cb24a2f47480e093c8c77520fdbd81613bc04027db8711c0d5c44f23c77919fccd6483a0179804ea36e41b9380440d52181a6e3cff4836d7c763a2226a2562eab41ccf0a7e5faa9047a63ab408269e154c600adda7d16148d03c2d02813ecf59e9b58e50cd9c1f11eae578e3931bf42892ddaa09bacd440571af18d671f6ab3e132f525992fa807651fb65e6bc6f1ff317e8207d31e1895bf5fbd92248b684963c16d3b3c8b471f936a1892ba2c7333b3e4703e572cfa610787f9c470d739aa7ce1d30fbe354f982da0f6477094a1788f9282a2eeb240b0776c9112bea7917cd313a9d64f9403e08ba575420a297aa6677cb22ebf4a0141878b70082a045266d800213d867d0b31d86c10824087607cccbf94ae42d0ba146a9f1f056c710b5f1b67839fe0aecf3f7da2aa1b37904c3300a87133366915bec0f65eff902b62b9d3d5c20542f07e78acc41248b1447dd6bca849b1992d585e7710439167b61883071a9926b6d45cbefc784541afb7383f378b4690a13035ee4286307e9b8d4bf819adf0513439148092ef0141a366107c7bb8c612a0eab184ff84c0f8108d0ca631e74439e314f437067c0d7d13d64772c369cfe028acf00ae1f1ee30993d0be710de9d05ff2b87a439844a357dcf113222fee68f0dc9ecdec4299f91567341d6ed6daab96994c7e64acd5107b018809303bcb120202ad6b400b08f33d712e7b580035041ec5e8979a21109dbb434fd7915842001b7058fa58a4255b6e4b65522cd64f4acc665945c7293c8320629e58a5f06af22a7d244f7cc453fd10c5fe2b35d2c03d0d2a8e5761f76b13b237b9b4c10255010bc577e112ef81a2ed634f234d9d1f5f0a4f8821c5b70016971b11a6c43d7636e8278a62e97b7f66170b2a08fee1ff93bc6a82edcbaca16cc92e5e4b44c67c27db725f71784e467aba283b627ce46798f2cdd4dec7ca458880aae990390454963c5db2cd6b791c8b94c33ebf26019c2e95b390e2c9067c72a1bdcf2463624c54bf3a44b041827aa583a9620248726cbcbe08068f3213bb54a0367088bfaa4ec4e01cac0ed090781fd1878b1281f35b2f3e0dc1409324acad577a6e6b70e08a393a4b07a8d2c3826a8ef17f75f681f799d7bdc8b3c8d19048a2b9f831808f0c6a158495548130221bb064e0355beccaa2f046e6e12a73ba6ad021a9ad0649949e2cdb5691c63d4ede4c44bb46221efa2a2d5aef0828a442ef88cbf8e681f68e6d8bcf1902720129157d78ec25978fc24273fa5cb365b2034cd889adc889b53a1c4e087ea9bbdf2cd864f96cc503aed38122f1b699be1e9b48b5c4c804e3f3428587a004130e820e0042c65dca5447fd2d3a812b9f5acc3a223e58edf0e1b4125abfe26e4ead6756a359622b4fff4a40f47f54b04b5caecf8fedd74fe4b9a1704b1c1c24b20577fa08bd3f9e0981a59b84c8386e4677fdd00675c00c32e007e4b61f747a32773047f59a1d06ca099c234f0c8aa768a5daedaaddcbe64ca0d347549e8d19555ba9b22b7a42d80187f1d75f22670b142c1fbf6f5dc68aa84f8129af58534f6185e7291be9280c8688c1b4ec3a1638211c93c40692059fa797fe1871e48e574033a539190dc400778bd4d85840f39053c2abbdca5edc86f390ad587e9a2e65ed9022832d04821432ac22308359b7ecaae2d4a2fb243b457be5e9eaaa8c5e94fabb9c875ef2580b858d28d00bfb92345e659f257339e5a2ab022a15e9d4ab30dc4045c63ea347814c1d6d81cd3da22ff294b3949f8c01e525bdf702ab67a1206bec293a19cfdf09e6ce2e05cf4060e9f44b5a7fc84b47688f775d61d92e5658f94c00049f50a395198bc8da5753f872fc925ea66b6a9a5cbd4c4ebf8596892121ab09b76f3fbd772a0c78b57d183bb569cb264fc7a1754a68191220d2e219272d37f91c4af2d8a7400023ac6526bb2af5115583ec862c187333083fc208a3ee655ed80379b77adb65dbcf1097569781ac461b383a76b147d289f8eb94060e6afc9698c8212833fa87037d865e1eb7568c3e707d5becfb6876c232bbc8f5571d2179e9950bb1a4ac80b15ac724186cc6ee4fec496dacf3c8a4ec6dd5349fe695463ac0dffc6b19df3c09c46b400981a1b06bc4efb7d1a288887dd001712b746b315169155b788a5970ac919dd6ac439c1110c24e9d3af9a704ad260228a522f9bd7b753f09f4ad506afcf615c5dc6a8f2ccd5ddf47aa92192538702350d93de51b081ad89b951328718b841d65989899d242254bd962ed417fa0e3dbef07e712b3000f8e182e35024c798f0064a8f93a0195182b057f093a3e64594643f53b4036201406f8d3bd8dbcd207b682c809c01b4192c2a268c025fd2f38ce07c0c8ea8f0f742d2f762e59de2a6e5b3e6f2420ebf448960f5028a185b8d823b62acbb03628158d8444f460e64363f226b2480449e1276779fbc657103f38e9e0b7270c986961912f80ad6c6b9ba3d8bf2ed741d850023a4569afde6a8119ded86f0e40745867290992456d200cef1030fe5795df1c9463e4f97b64eea6e83b23abe2eb2bc5974994e2b064864986ffa81712eb5f85223ce3c3cc1385652d36cabd5e4d437773de3a8694dab6cede4af29178291dce9d65832a2a4d3852b797ef273d5c74ddf382c32c884bb021c42cd52978275e6d7b8bf2989f30fa2bce0bd988d368563faacbef18cda9664e9a3276f439f8691a3b22590ba100d77cf7d1bc811231538db97dd0b8b9d72e8af1e75866a1cd64b05f60993d561d24d37b9283832920e921ada60486d5e5dfd85cc0a1e3c0fc4c675f893b8201b22b420263a2bfd106a8237193c44eb6fe1f3670021dc9f805d8c8a2fba8193038db6f0b692c99a986e0cde3b41dc4d4d0b5ad0f29fe0c62a3d9dafabfa751bc25bc4471743f2a5e33f84071690b9d4bb58de1e30af57dfa46189405dd4e67c4c38ee450220972536639146b11222e2ea8370c545b6619b59b0cda6e016375699676685bcb1a11a7181e55f595b2ef6c77e5ede7dc40d0d9a6fb7f3268bb3a465d939d90b9bc41dbcd1c7e80978bcbf0fc533d79ffeb9dc7a467d0f67bb7c5898b6227d72268fba21f49bce87a1b64c8a50aead7a9d537d6a0bead98e9ad7f73f8511dcd8c016d5f9fb598f7d36700a63aad6b41123cd1f2e0f5cd784804f14c5c720894ee1a6f25c70fca2a51cd8e0891795433a3affbcebac8cce06ef47c0d7d0db2c290ff84b70c2f97c8dfd5669172e0ce3d046e7c2239d0982e0d6d12eab0af946f38c682ced598b86930b6286eb2805acf7fc21b209d630eba13946b1729b254b546c9adad49d16bbc17480c80c7d1e18294be331a17811a4da18ca8917b10484fa37ff7935ce95b96392122e48b670262220058080b7f8ad28a70724b79a4a95b407101aa3a0ce22ce855d574d157deb7e0b37e927222a49a9a6155b9016a2b23bc0319903b455aa9e30efb9a12a4af853e02034410369d8f2d1e3c4b7b6099631c8cdc7949a90b56f2188c753757d2a043d1d91fb9af07b92220ba9ffd0d08c21db876fb7d76d17c28bacabc0f801b7b00a2f076205b5f3c3f1cab950028d8d1329502373110f689edf763838ca6f38bd06a8d0edf04599571d6b92138e2be192d94f6ad4adff2dfa1b611d57a10d5ad766b95c773c7cef565952c6b08e6ae936faf07d49323cae8afc7b4209935366e6115d3b606c48e302b7bc7d7ad47b793c39bb463cdb15bf0e487fabe8392ec8f350a3331dc9fd523eb7e385572e8d247df2cb663d0e209dba69f23f698cc30f15bc62631929d15f71f54efa655ba9a3fc828878a02751acc010865cdc66bdc3439b97774c6e9c7f87e85d7cb3655a80705bdd0cdcfd014c5f0798f6fa53fb54c0cbfc987efa36131371cd83a8f8476beb2d9c1e284fa2ed34281122e6e7ce1650cf046e47f984d39dd89753ce6081d5d0760bdc77ed7fbe89589d6384c6510c196148967f87701ca0181afa7f9be5197ef69278851c71687fbb0efc8340f84b77477d3cf062ff9245861be2660b1ea797a0c3f552b599d177bd3b442828adbec39e38e4a23a1098f51993af8f7c22eee7b3cc8a9d4dbcfa522bf37ddbe62825ab64d1b9daaba8172a3a395f6ec4e0364c3dcae51ed5624561fc3f6a5af3213a762e3bcc7c79a532e4f65161a15e63d5ae305a48b7e8f2fcf01a4f56c4247f9c5a00e1f56a8eb22365dbc39c83d347ada579abad3ae50daf3013d084f3871c30e5f6f75caab73dd714b2c23a3e4e205bfd13e7b9524f8f3d890e27a7d160ff62a4df846019f5d45c41f049e27c40e0e581048c98a73a311830064ef84608cc864400e0c94080181181820130a5941656ea8e6c0a4abd5a24b05fd45cb4d32c3b6ed655ba5fe7baf3564c777983abc35c4a3289a06792214e769ebfded6acde336b36e224242b64c01840eb50e4a0d6efd772cf9eddc6bbcd4a8b10309eb5ee3a5468d1d505c14772ced581245b126bef8a02adc777cf03e6a15f31e4b0b898a8959d550e30af5be90918941a554a8d515c1aff952f385663c5db10918ff113c0a8234a96adf17f37d4cb772e291354b8662087a27d32a15131363fa189b521da1de49934cd7a552a6188741824a7d2d057eefc1c4ac6aa8d4c3a852abda3689d7c51a50a4b8aa7d2bd002a38f9f5dcd7ccafeb57f53e15ffbb709d5510d7cf183206d0a7c9ba599b7813213feee48f17eef30462c09534bad64523f93fa9999d4cfd8571dc5bc93a96b63a676c9d4db2cdd97b1332b279e8d3b23634d24f85f387e38b3aac5ac6456b56dba6f13c5268a4d149b287749c6826688ef797ebb54cd92a2f716b4d73af148bbaa3d21c3276bbeaa914f7e084289ec2cd9fd0c5ea7aad934e1aa9ae7398cbddddf95f75f97b176c9dae9fd3d750255a190a36e55b326f14fab6d224dabda13f15130d944b13cc2d5d1db44a15902d1d0427a7f97ac0ded2ad402a54aa1ca186b978a15d1caa5225ab954c610adbc15f10af10a169d0f2866216ad1f9a0b264e1c206cac966c9268acd928800918a5845a4d2f9dcffaa743ee15bd42756d1e25671c5b572e5742263bc54aeb072658cd192b54be522e056b9c2ca159b282295cea776a988583a9f9a48e552b1222240b4225e71a988566ca29c5636504c364b546ca26c93b5abda365d2a3651b4a0b42c91de7b5c3a9feb95415a8bba318ee106621ea60b8c2a6625a64095e883b1e675094571ec92e241f805cc7fb1a5f309a3f301c3323a9f2e9d0f8c172f6a8830b6c64bcd971a2f1deb5b855c74ac2ca196304bc845e7f359982fd4d2f9a4defb7003305fcd178b03b302533d18c3300b0f46ebe3058a27854c91354bd66abe581cbb8242825b7cc1c2eb1266f1ba78687477290cbf0867e0855fd47cb138a06955a386c5f96e8d978f44c1eb52f3c5f2b0ab4f4c9db290dfaaa69f58ebadaee705d13d09bdd401b204a04a960024d10394bff790495521bbb00c32ec42762117bfe950afc668b3e436b5fbf94de7537bb25e5275a728a5de460a0a89d4dd2632f5f76b6295540af52655cd66898a38a563ddee8715110f65130595425d31c69a4c15b2abd2f954d1f9842f13da48219f78b52764ea51aada5d22519f5285558ca8b796349d3efc6b13c506ca13941521c0ca42d6f625bf1aea7db163a9468d1a2f355f762c5181721db5b1a683747ff18a524817eadee3d27d62e895d1b1baefc2254908c5e885617435dd97c1058d2ea11a50d4a0d244ed4ed131a6d4e84871cad75d0e5c6b7f84a2c405c3073434341f8617672421e589226220e451b1336319244d8e94bf2cd9fde82f572d7103355020c505a0c22b686081860478b085026f02433424f07d16042f288249f80b7280c5032dc882012ea27082bcf78e37c61be08d7befbdf7821f0d0fb6101143d6c61f01cafd06c887e067c3f1fadcf1860ce95ba05185ac8d4f05d501007801e34ab9523ab100f60c2b51b820d5595bc6156778c05adb75de1926f06270061a677421eda7ced8728607503a6e18862ee801014c805ac1146714403c230a11683c03cb570595a2807717144f296bad756fca01acb55df7c5bdf7fbaa28200c4351e422c5e97442a1ec152a6060606262bc2c6026358ee33833e35a9056dc488d0033a40549d3b146f8114680117203c6bedf702068113bd2b7e841034a48b90a085b6e98814aa1408803a10a109c20ed0d803085ec3ee579420c218237fc401004c1300cc3300cc3300cc310fcc2300cffde0b865f78c3300cc11b86611886f703bff086611886e0f785611886e177c12fbc61188621f87d611886e1772f188661188a61f805fc2e18f3856118862018866118a6f15d30fcc2300c43100cc3300cc3100441300cc3300cc1cf047ea319524ce0c048d6683ca313f899cc782204c1d5fd3e1104c328c2af8af04a89c2831a70c105111d0880030c70c600ccc802f4ee1951cc6801381a71041158e080cb116430a0013198b14618fe008a235e470f0850016b836e0b2740f1e47e9fb0d6765e18c5bdf703af30a38a300c459308b2389d4e2754ca8c1998d102120606062626260b71fc01148f0ac1180730dd1b8aa11886578a0f1d2c69e00515e880144a1400cb184c745154c8810f96f080174af080034d90600c2e8e10c93b9ac6f0e2148ea6ef036d00de21a484201931df37ea18a28c28e037c6105257bca277efbd5f3e32aec478f7de343e323a80ea9ca6bbf7de1b1e2166a1e28c2b43f8600935849820a3082e4220630626327210850c3268487012c3d1067943931862cc783768b8f888208e5f18dff77d9f270618630c11d2dc206b37c87b04176310a08831981063a8c801efbdf7def04615017ce303fe5e31b020ef1142ffacd7f1e20defbdf7c57b6f4b0c2e42f0b36318de7befbd21f8f7de0b45e8defb7fff5f871824206b9f039ea008bf0b86e0dfefae6e98b8d0e0b32810043f235820c11fc1900604412284c0bfd1f9dcf15bddd8428c252e420009f043951fa890d6e342a2570ad9fd9572a578e7a3f3baafdda0791f9ee7a3fbdad8e5d474f008bfd6d1f4b85f7b8f94714ff5c40be2763701a8fbaec3f3ac47a63a56978211f25d196b6304c69ae82d20d7fb04ca763238887c0fe3ad7010b96f5fc87debb6f3fc8778ef6fabf82e2787c5b24a68bc711445215d2a8df10659b3a80b63d7201de648f742fcc62fd9bdf8e11781ff892bf76a8a007108b17f947a92da40d7fd6985e3fed12a95c6388a42ee777f822172572bbb0689f2dc7631b527a4e7adba5510f789d78569a0ec1a244aa64b97fbe40ae9c4f1d62c197e3886f891bffd6f954a63b4a1e9c10f04c9efc16f05e2b0a17bef8bc4ce13bbff5656dcf7bef0ac1027bff75638c23f5aa5d218412be4759ee729f184eebd57e8537ddff729f984401004410fc3300c4325a19097d2c0962d9d952e5db06059f22c4e521a186ba309468928e43dea6485b772cfc27c2b21a01618f03f70e528194b3acc501221944dad41aebc2fbc1aef0baf46e889f56e0a0db00b2e5e745de7791f1734481a3763051552c881038513684c288184100323d8981965626052a8932904bfeb7576f5ee1a37e8ec08442a1faa8a180f08c5c0e2defb7d6270404c8561188a22171a583140107e0940d9b7d1859d11a313230c510c30c8eeaf1844f066f01d31c610244dca7e0408c5b8a038461624e95b8c8185b437c6b0d2fd1de300637041d2745de7795cc218c38beffb40308b9a98b28129258aa2082344e54eec1ade8d4146158ff42dc84000cd184388b9011796c65e32ae0871d28973417ad6230309328a20bbb7351da4e7a148df828c0ec8a46262626264646e3003326640d2742c9799c077e5e3c2daf25f64c1b224659c4243c54a8e175697e742b365fc42d422d2b87b5e48770f0814ba5d599232858a15d515b25bb4589232854a152b54c4d45575429d964e8b96ae13c5986f65c5b51e500bb4f4f89ac8e36be3eb6b34415f7ba0afb1c89fafe1901fcae76b62cfd7469e27419defaaf82b25e27c6d6c7d8da6f6365f63592efe8269e16b382e7c8df5c2d79ef5359a9a15be86439a582b1674d82b4afe92f913be86c3ca714ae1a4c209879c61cd783337666ccc7cf133f86b7cfbf6457f8d3085841e3c5e41403fab1a8e4f0fcf8e4b6755c3c9c169ddd8c0b0aae1eca861bde0420bab1a8e0e1656aac75121851c3850386155c3c1f9a719bbf7a6d8b031c5c6141b536c4cb131c5860d55cd53e2cb92e5fb1ace0dfba8b7a1faee52d7817709bc4be05d02bf86d3fd0d55ea6da8c00f432c2196104b8825c4126221bbf76ca8c2db453489b78b78bb88b78b78bb88b78b78bb90312693c9643299be86e3273ff9c94f7ebaa192791b2ad3b7858a37838373ea4eddf83654a79f79511c471a9a7f8fc5c22167be8643d6402aa6188f049589bca11a6125fa8d7d1baa99d5180393aa42da0f0c610262480103201c31c206889e17cff362619cc6f3ae07e32bd6d0d50133f45df082a0d75950b433f04221f7a854f1ae60f1b4d8c2a58b97252953ac5cc1a245162dd6cb92942954aa689145cb175bb8e45c6159b154b2885ac62f68b63c172d5e8072589ee77ddee77ddee7e5784418bb9f42854a952a56ac5c21ddba757777776f4a152b56ae5cc182450b2dba2c9dbbbb7755b068a145962c5ab47cf1c5962d5cb0b897a525299e7577ffab128580b6885cc62e340f447a523ca050e8e6fd5cef020a59fb5dc4718946ca4fb1e2d9ffac7c4276cb1612b45bae5047c5f3c2d4a75279429d96f7a4d8ef92c385b5e5bfa0d1328e22cdf834acb7561463c29515e0aae64921853c2d3e9d244c642d07eabb9ffdae48fa871766c8fb3cf0bbd71361863cd3bd9e773def345ef15ecffa093639f6dd43e5dc95e914736d680114681272f2447fd4c97e88a386f0a8fb6d9f80d662400bb2fb5a1269a76c59daa285b45d6cb085ec3ebcb2a50ad21deac44ee5a66e5f5289acd9ff503046beefbeffc4148c914f89b4ffa96a4924087e47a2bc2b83727fed6bafaa6632127ef8ddcaef77ee37208c1150652241125c81300ffea74ac118813162bf5b8d1dcbb3aa6e753dab3291fe9da7aa5ddb89362400ca5af7dcf35e0a0a4506caf350653bbbc668ad68bb21a6909ee7799ee7994ea4f57c3c2bfef5ac2551e2bd591824de6dfd48d48ad6b13abbb2b78ed5d13a5607d6ee08761d970e8dcecb0c3a2e5d193775fa32d6bc250f4af79e14d477ef2df90be6bbf78408454f14451101160bf1745a63ac89d713bb1b537b425a2a478ce20d2a64f734d63f0dcd38aa6230df83aad4b71267f0545cbc9435fd0075ad15c91bf78a37ecb3867835df1360fcfebb514b42a239a477a3f31972b378904b86ab9b73a3fbfe921f9aba19e237f7bdef525fdcd892838b8e2e363c3d86a88aa4314e09d1f81ed57d03e8c0f0debfa8a55188edaef5c42e28fb9ee78c3043a8a5b1e65c48ef08d01bc0e8bd68b1dcb71f86442ef45d317c305cb95bf1ad625e8dd7840915a3f733788e763f341e4d4b15599a0042a2b350480fe59dd218694691667c1ad6e7b09c8b4743eb589ef7a929c6dbb1eccabb21a6c6cec74bdd7baf779ea7c5e404687d65ed526705ca75e8b841a0ecdfb7d755de2ba12c0e0443e0a2064e740128c69927d269a6274c09db322ee39cc06e3613b6338ae21b4ce3509c0d57e28d81cc4e59aafe70b70c80a5b313c5b0ecc3a9374ecde122de6529e6a12df41b83f5d0bf191bba8cfd4ab0315674dd1ff79ab82a849d287ed7b3d64de85adeb9b5e1ca603de4f179e7d65aaf1b626d683b6b3dd087ce7636ec4a50622d6843ef2c4ccbeb4090757a7bbbee4eb1d7daee6481d059937ff6765eb6b6d659db893774383adb81b7b36474d6829db5c19a60add78921f8bc30c696602d09a267ab58b0b3b6f360b6bb27134f97b23e44fbe9f062b061d75d1defd475b646c6c702e0eaa09ee8fc7ab7007b3dd6fd3aebf957007b03eb9d8fe3e8d6edb59ded8115bb1dd6765fd779d6ee581c2bda54d7751df8c3bed075b7b3395e0b7582e88285b18142e784fdba13ecb59ef52e49f7277bbd3b41ff981d80e7aa10589f81049d67417b430b633d2a5d27be3c0be4d9aebbdfa54c2cfb591be65c9d15726c7702c5ce5a6b436b5fb6eb64e081d6d45d0fc9ae3a9cb5de8d35a13a2b86b69ba153a153a14bc173cfad8c05bbcec2dcd1bbdd095dd759d05e9935e9b0a8afb39f8df9b1d65a8ba3a30144993a6b24a6c2ceda60456bbdce5e3bc4a6d00575393a5417769ff56c673b54175eeb7d9eb53fd6b32c6bb2296b2d0fab4277f2422b5edb59fbb2162ca1bb616f673f94f53a15ace775ddedae0dea3a8b4277b2262bdece5afbb22974a7d0b357bcd6da9fb7343bc41e1e0c9ff5acc95e1a6b32bd503be050c1b2706dd7815d98ed48420e6a88b59dedacb5371efacd97ac61bb2c49fd7100838b161ca4b841046ec060e41081b1c595a862e03648a1826c03eec2934891451449542a122460d4ba1451a97086103072e4044941831384631ef003068c8e1fd5c9fa80618be0135b23013effc55bb13454b88959e96cb63040b5f99c1d3054b1f1c10ab14fadf026d8f02a23f0e0b14f09ff4b84bbe7eeeec3dd95b82f71afc1dd593ea64a803736612094530b27583285a2089e4ee087f2523085dee791902a12e2c84a64812711e8a664ec4d8539a4b607e38ddf174440b104c674a1e9dac0a4001481a5130e29f3dac408d1f1e0f86eb816ec0182a5188a009921a2bba75ba446084b5ba0d8ef35b3c20c42741705efc68b2518c0585a2109141264848af0840861c4d209a625a91b502c0521e126ea5310967a6c9390d8126368f260bea37b0412428877c6bbd9116207539876b8008ae8c589980ef5cd301306dd1af20e578618e1639d829c5c009bdc1d61d010199042c8102a4802070a4c592400225842e164072002c6256331b074828f10a730083c8931de0f11215e0aa720a110446088c4213886829c4c435244668f0c2c99706d7c4ee06b0418f0841a5af5c080a59338440523012c7ddef859d006f0f4f100779032a070a617c421e0293c01068849c73d6232e1460e1750286187c83aa2c405214e622bdc81d9f92192244cdd1085efe5f99852f7859f213485a78bf3d5708166b01f0e4ff5959063124b2f6888078d782ac1f423c48f23281e9175755c1da0039676c45c201f0c9f0a261d37878c8e97c2104b2d1cebc9bc9beb7d0058f5c0849a4a20025ab4b8220107541180274028e923592e633d34d181090e3710252942c39017d00ecb851658f84b8211ace183327620838f1656289c10564101175630c08621195e299090428122c8420310b0624515544851258a1b582fe0b40e00c51a6aa061a4830f7ae00198ba4412a7cc078f53684589293f26187cd1002baf201f136ea04e62980307062ed0249b488ed04024c850020870841136b6f47040021170c0932538fcf8d0dcb82ad072060e3e62f03185e004a2688002531880090100400109484012488ef8e0f142caa6d111a1f372bb7c0f3a2e77071d18df161b83ee059d0b4c5ea45ad0a9a0eba2cbc2934077746b568798c29703e684ce848e047b636684cf463763c71bd3a1be536712c52e0cbfee5acf5ad061643c1c5e0796ee00966e1170c7db1008428c0c58fabe54e8420c84b852e85c1352553c000cc0d22d622ae19483868825530e57074f05d40653621011083c793c684edf0996442c4b379a0861faf1a230236583a56f8da52f85820b96527bd58125134d4c17f2f870be26a490803ac189212e124b322a199577338323d2ccac31c407830814f6f064bc1e62154b9e111d1cf0045eb1e4a14014ae0d4ac7b337756d4e413e18c21c4014c013584bdd48dd30d1984a0873f08a300488827765882fcb520bb56b7b580b29dc574a069cb9d6bbf17edc243025805db824c4111ef94888b120cafb6ecaf3bcce0b3dd1339d725c2fbc21b42193e4341382a1f5c2cb7371ae154ff07008615ae17bc052cc1542cc8017870864886b832156b0f735beec00065fa8404b09b2e066444a4c19129221861f35f5410f705e1865c470071d901c5923052d58c10a49e450716206286cf0822eb6f000062460054ecb0503e076127a05c20fbaccc08b168cc0024f82e8a1890e4c901c11126405154c28218b0d3c91400482000296420e355d21c6063570625b5ae38b1082d06407134a9879c11624f880073070810924418023603de4b004c911225da4800428e00095213288411729d862041ee80003aa10401144fca0cb0bbcf04007b2a00094a56c12199a81e99283306c5082116c400358344089016413d643931d961019e2f1aa9981e922052588e2004a40c9660f34100932c4e31503733d0761749102139060031ac062020d5882005078a081480c3c5e3f3c3a353666aeaf9183306a6082129060041bd0c0041ab08412041800941bc0786822034e4b8d348ad4201343831c53901000932539530c400039250898d6f0be7445f8d2e888203ee03aa06b40678575753a5e8e6da16e3c18bc2f61852e87c511a2e09d6069ae09b604d308366c78e3958189196150489d80ca719a318522187620f87d9e757714dcbd051f4396bbebb5955123bcd373bde164532dcf14f704f4111cc3dd451fc11bb8bb0b3e8259d4bcce3b67c4facfe6a9d3f3f5f9fb7c1eb915af98563e3edfdd6fdc1d0815ac8da0ccdd637c0499b8c77e969e9996f4351f438f67c5d0e3d373968ddcdde4ee475f19a009ee8ef2114cb97bec65eaebf3f3ce19f1d06ab57620e2e090ef8a74cd7be31bceba61f0f13bdd9d041fbfa2f4dc3a9b4f2b37b6fd56d3d75935bf8695cb15a736193f17bed1cd346ffcfa898c3ede2d669a9dc7dd57f0f15e71bdb6707ce5e30de2a24fdbb334a32f533f9727aa7f55657bc55b7f9ea57875b70b70b755b85b2a6c0edc1d878fde0ff7209df7f1eb8a2b7704050105fd04f904f504f104ed04b98274827282828080807e807c807a80788076805c403a403940413f403f3f3f3e3f3d3f3c3f3b3fae1f9d9f9c9f201f209f1f1f1f9f1e1f1e9f1d1f978f8e4f8e4f500f50cf4f8f4f4f4f0f4fcf4e8fab47a727a727880788e787c787a78787876787c7c5a3c393c313b403b4f3b3e3b3d3b3c3b3b3b3e3dad1d9c9d9097201b97e5c3eae1e178f6bc7e572e9b8725c413a403a3f3a3e3a3d3a3c3a3b3a2e1d1d9d1c9da01ca09c9f1c9f9c9e1c9e9c9d1c578e4e4e4e8e5e5b365c8ab36db2bcaa250f271bd68905c403f100f8b739d99c00f0760a772b85bbade2eed7ed134f6e42553ee06e012adcfd041fbb00fc2b16fbd7c92616fbd79665f4ff14abd9b4d9b9fe6f594659b17f99193db14ce3186270b70ae88adc79dc5f9f1b67f4afcf4cdbffd2668a538d5ea6fec6a9eeeef9d8a9ba7f9b175ef88ddfcc47e599e29bbb4d801563a6084ddc5f1b676455d77528495d5755c8dd3b1fad08dc5bad127cb4a3bbdbf0d152714731926acbabbbc3b87fa47561d4c0e7ee26f8687170f71b3e5a21778f41299be9b9669d9e7a6d99aa0da7cc48af4fd6a719fd1e9f8dde44712a4d7f8d7737b83b8d8fbe03d76b6bdb64abbaaef953fc664e57dcceeba7eab9f14eb32da337dbf9fbc4ebfe597aee8d6dab2a7becee9f7b07ba7b0e1f5d8a5e5b65468225e115a75c354ea9a228c6c9ad78353a51771b85bb5bb74fb85b04b8db03b85b28fcbadb276480e285052c20c464821657d460a0043f24a141078a645df088914287582a1d00691921a945042a651c418fa8c204b4aa51808e96114e0840cbbb69203a64a84929820a9105a201b440b9164b4ba47b22952da81f82e8defb20ecdfff010245e183ff0314292ff41599fefb20c407573f4479a16ff54310e09f56525ec87bd32a087125e5856c10e0ea5b79ef1f04685394eb10c794aa134a011144f7e06aa97bfba0ca8550a8174df74d1d94fba8b72a20c4b79d98523d5952459141c87b930a8a142be47d141984ee3b0c0e1beea7bec843a5526f3abd142b647afba00a0aea4faba50e8a0a08d35b710504048a4c6f1f88d377ef42a6932a85237c19c823efadc875ef5a8c2930a572a1930acae9411514d3dbd46ac983024410de9b564bde9bdeb48222e58552efc1e8e07d4a054410de9f564b1e8c0d3045de776f5249b142a6175552ac90f8271594283208995e8a153a3daa53a5deaa50efc10ce1b0e17eea75f01ef5a00a8ab8e489506a0504048a4e6f1f08d377409cde822a1732a9dcab09df0aa586303af135c870756445ae7b2b72f7efe3b0e17ef7455e92ee41d5fd279d8520be0b5a00950282e82ed4a9a2d828178a14fb5144efa77b17b22a299d940b45ca5d41c0890c5120e04406f2c87b275d0bd2b34b50293452661c7d7f3d4b03cabf77e27da808650821ba95931fc8bbfadc5fd602287ff2e4c87ef8f7defb9d156f68ba5e189ac255cd7b6b125747debdf77a5e0d32dd0f35fba6b7e00f48dd7fdbfb1f48f067f03eeffb41fc56dba3e109198aab5a785547dfea28fceec16f06afd6bd3d0a574e4850e5e407f25e7fd17e57505e13dff4e1a35044bc6fdf0791ba07ff5339a1218fc077f2d4a99cd090e06a7ba4e92dcc104b8aa655edbeb872f20319ae8eee83aada5d39f13e80721df6ddf36abe4fa931deff7aa05267749ee77932e1f7c17c0f9302616060be460d9818181893aac68bcc0e285e4c0a464646e663626460625ee6674619d3c780df7b30a954cd979a2f355fbc2ea60babb8a38c8cccd7a821b303895146261c65762cd57ca9f922338e325fe365fc1a354619556d07123233a34c8d0d99b7b103ca2833dab061ddfb19e1675ef47e6efc8c98850c479955cddaf81b2af76a6cac6afbd658a8f745f8e12853f3a5e64bcd176f8b4c1782115e2163bc25abaa8da2f7be020379c5199debde78df72596218cc4661c20155dccdec8487998d3e871ae18db3d9ce7d7e2ed3539fb2d3546d258fdcbed9f2e735273d8acf75bfecbcbd4cfd9bbaf7a9944d95b6b30d08d779a346a7d6ea2dd3b6b6adf833926aa4ea3733916caa478480e4732d5acbf47cbd8c6cb8f587bbe3b85b27eecec44721a35e5babbaf19af7b9e36ae5dc189937f95c770088d0192d531c6c679d53d7adb3b9d3d396ae38a38c74a21876cbf9089684693bfb90f32a4bc2b47d3b697acd69920ab3e1bc613beb9df58a33aa612886e5725565266ccd325a8953b799e26479ed21061f8798b89ea5a789336ae28cbeba5fef5326c3e937f3969d34ed7689bb631f6530c3dd7d7c04a2867bce4e0fae5c8a5f67db8a354e3d91f29a64673d3bb50e2c23a9ebed86cf8de26c308d61682e535ce215877f30717735fd221070033f677870c36da5d20d8ead547abd6ca5d2cd283484bb933e0a91ee1efa28f472f758ecffcbd7481f8bdda448be559337aecc4af977ec785a79d29258af6d8fe2f4755e315a66f33f092c3ea802c50d32d2b931d2b96613a6318a62238d6161e0800866361a0289c4770efd9b0d6f9d6d6751ce0d6f6d3b772e1fe5f2112ccf56dcadcc3827678af32464c861d338e9a6aee6a7eaa7f908ef9c69e29c12927a2aa9eb4de3545b2e5553bcd36cdb65aee5d5cc658a53d314c3724aea7ad36bcbe844350e8a9e329d67f806bbe14c83edac356ce354da3e9376d63b6ba55396d71b0c45cfa39d66a40ca3ed330976b4625b5ecb8c833e6fa43e6f78969eab4adb388cde6ca70da7b03223c16e3a49fd2153d5f506d33a9b6a0acbe7baddfd867be9332ce0c0ce44b0574a2467e2bca264be21518fa0382ccb408458fac155e0e1843bde3a3d6925b6dd444165969e6bde69164014abf36aa227adb439774ff2991f626676f23c6e79eba35245b3ceb314d3ca97c9d43753fc37b5c8dd81dc6d91d6ce3aaf38978fcc9c4353b54c71327dd28abe65e6ac77aa96aff7f9366646526d2693c9744af1e7559565a1cfe5a3cfedf534b3b9aa655e5f9f9f7128c6c1cc398cae1909c9a7f8d5fd2cb87b1133405471b727104d50027700b8bb0e77570288037a6d9930574ba7b5737393dbe78a6f37a86bd62127a41eb1e16c677a1a4952d12cf46367adc9f406779b650b5a89b3927ddace226bcee122ea111e867420420403320404c98f2343302548942819820d15b9010812233026a491d70b6bb31c221a223a378a33e2d3e352938af21146858a2849a21ed1b9141b514990e623b5c8dd8e8074b72230e263a6a23f328a3355dbcfd2333db12dafff43af369c4ed53225575c59aa2979229d40326a84d11323e17c9a1a67cb46db4ccdbc715ecbcf4624eef5a933cec9a7e717a5d90775957d5e71909db5c639a337b399d3247cd39fe66ca47329b6bdaa16ad3987d1473199d5fd665e4f9c93f4fc1bee4855d14cdbabbab199d3d9a9535cfa234d52d3a3f4869a241535fa127f6bd6caacd739cb3edb54fd397c7b757f6e9fe86984532279c56d9c2c3d51f44cca2b6e636cf4b4bd9e468f3fc5af312dc9a66e8d2b5b9fe24fcf3733ce46186de99c91302d876daf79d85e9f5fa4755e4d13ff2c3dd3d9a9518c7392691a0f51dfc4422170b720f0d1a503afb9a7a7a7a7a7a78787878787878787878767676767676767676767c7e572b95c2e97cbe5d2d1d1d1d1d1d1d1d1d1c971e5b8725c39ae1c578e2bc795e3ca71e5b882828282828282828282808080808080808080807e7e7e7e7e7e7e7e7e7e7c7c7c7c7c7c7c7c7c7c7a7a7a7a7a7a7a7a7a7a78787878787878787878767676767676767676765c2e97cbe572b95c2e1d1d1d1d1d1d1d9d9c9c9c9c9c9c9c9c9c1c9da0a0a0a0a0a0a0a0a020202020202020202020a09f9f9f9f9f9f9f9f9f1f1f1f1f1f1f1f1f1f1f9f9e9e9e9e9e9e9e9e9e1e1e1e1e1e1e1e1e1e1e9e9d9d9d9d9d9d9d9d9d1d97cbe572b95c2e974b474747474747474727472708e8c7a78767c7a56304c57b556d3622ee6ee3ee398cac35d68c4324a7e72c1d32f3c6e6ed8635d336121467a21f6b12f3f52acf35a77966cb9bc8d679760271b71fd0e28a07dc6d07dc2d07ee5e5523f27198a6943fb7aab66c7b77375a62dd7368ce381423592b2fb45cafad9c114c6b7c2bb16ccd3b3d6f768ad3d376aea53ecdb7e1d2acb37922a9ebed6d1a27697588defa541ac21b03c962034166e969aa65069295a078e320eef60a8fc9438fcff300c2ed80b559669348bee58a72b90675df726bf97ae575aba8de2a4a549ea8112e09ec76c3af57904e4f8f6bd5af175e7118a6713acd3a554bd84deb597ad2366ccd372097ce0d66563a83803270f79a8f2d80eeaf17eca65bb8b9aade6066563a65ea4e4f0ce4d2c17d7afe3e65bfd514c5e9bca6ee6ef351870e333b791ee5a798b65feb8cbecee12414bf3ebffc9cd123add94c4f5b5ef5dadaa711904b07a6d77c43334ddbb5664f0b80278c407218998f2cd8ecf4c4cd4ea3f2dcd946dbe78a71b4151a50d7ecc3e78c3ebfba7fdf6c796feccec3dd7bf07165e6ad730a5bf33e61367595f98ccf94c1041292dc3e4b7cc33fdc6d06d0751d2a55142535d12c3db53e8d106161f59c4a04ee3377cfc1471513dac6379cdcd669e9b45c37aa2c3d6f328a4b8db3e3022a7390911914e4f229cbac736353cb96118eb6cf596eddfa9ce535cde6f95be394bcde69b6cdb27edac6b74751f2f572b75844957f54dc55ee1f12ee8ec4c76fc2dd62c0bdf7bad7f996dbb067b92be5ac4952f554e283a6f19099ce61349b69926aa2aa5ac2702b2d6f6c9e668a61365c6aae38e98653c236532d614ad886db5af51f772ff251059b99e6ad946165be699c3223e1f4943b393e3a5966ca82766419fbe4f4f0648c7b7e4a1f574e4f8e69649a3c463d3c3f19a7dc1ab7e21019a9a890994db54c876c251333e3346f5ca6ea8fd7cbdd79dc75f0318504e8b575de30cca67112cecf8f0be7e4c87080b20b679edc63feb864403b393c375b35f111aadef0c6e66fdc2d3d7d49994df5477acece15890f1f40b81e65c6c144919829a9779eadb868a7795d713f727acda7ecdcea916c66a29c677813cd4e23a97aea35e3e0ee4d2e90c38ac6498fa2b814e2630e2698f6f8d3d396f7f9199da5a77ed2dd5d3ee6a07177575313071aee7e838f3814e0de42d19ca4f1dba419e99cfd2c3d5fa6feb772288a937d699ee6ebfc32f53569665bde44ccbc337ab3a93fccbc6fb875cd3b25422b3716da693ecb94d4c161a7d996c33798ce1a67342b71f7177c44810c773fe2230a51b8b7b6ceb3194effa6cd4edbe75b6ee34f3fd3b64da6ed34db70b3157fa6ed6ce634df6e98f61ad35e7f523e92aaa7d69928291fc981e5c05c38e4c072603a3894fa34927310776b01778b85bbad808f2830f1597aae9be8f582ddf42ef1cda6fe78bdca6caaa52a4b896c8d8b9cfb4c89f870a2383d830ce5d0db8df4a1315ac2d67c53c2b6a352458d50bcd50d53c2361f3d94b0ad3c757aae5b29c3b2c6466b4ea27db876703dd69ce4f5b20ea051da655e57b5fcada6fad7979d6fe65de69b527e7d7ea6153d8f186c5561267ae28c6266a6e9333d65bf66133d71427a6de97dda4ed4dd52c0e67dae4926ceeb122320d976ee14a72467194ce7f02db7aa1b9b293682e235df90a0d8b6aa47b4c6e80f9dc349dced04725e8394fab4bd5e3acd47ea7ebdb4c66dbc89729962140be99c837a44af2d1c14bff458020cdcbdd56abdb0336ab3715e67bfd523dfd28f628ce24a14974fdb67d2cfd2334945656b3653dce7157f5ef242335246612fbdb6681ad3707072cfce0fcf8f0e8e8e0be7fcec943ce6ce0e0f504efeb9c91baf5b1be1348ede38f5a8ccb412679f331c75b6e21207c5a58ae2ac1a8743d398f67aed55bddd701a966d789595c072dfab4ad3afaa9ba631ed5f59af1929af9f1271b757681a0f494f4cfbe1c3478f1b3692f35a2484e29daa3e9cab4af3013367785537d1eb95cf75c36e3a6fbccd13c5483bcd6ba6a5a7ce48e73e6de73ad33673c54969920a6463d84eb35e87a0282e887a0476b3954a18856dbd9eb2ad4fa50cd3284e67a78f9a20f9662b99bccd9a8d6cb82347a58a0ae18d4dbcb30d966d1a3df1ce40360e89995322395c6613b6cb73dd3aaf3058b6e1745e6fea6a9aa84ad379a56d9899e69bc6e924b3f4448d4e2299aaae49b2a99619c84eb33622f56964abaa89b392dcbad32114a7eab96f484c9c959838d348554836f13abbdd60e23ca47462c4890d48f6e124cab88cb301480ea359494ae4665b870cdd6ceb10772b8108641f353f6eb675889967e6b91a916f6312c12b4ec2ea51661c349ad314d34a98d6799da5678d6b07f736ae1d1c2bfb706a18addcf8a64fd3c499062b9dd8604e6ca686e58db786e5309ad7d7cb96b7ce69587a625a89577cdb2a4ddf704a9437de44b3f49c61adb39122b8b7ccbcf769b3a9e5c9ddbd1c95d8e8cd8ca2eafad9e8535cfec6b45d629de2757f9a6feaab47dcfdc67dc8672a806aedaccf7da2385df356ca8fa6ea7a22a5433c58c00833f0428629c4c84109acc0a0c70e24804f440b9c662cd08512bf011fbaf48c0be4280207585a9029a2c813aa2930ae02448105163766d0188026055e340048102b280a400c3500dd2d04dced15ee55dced03dcad03dc6d03ac152b768a534bd8a6cdce9cb46624d54cf39a778a537fe4194e62668d83e18d812865332592673849fbcd9a588ca5d773e31a9355c500aa98558164ace244c5172aac508184bbb792fc4deb45fecd2b5d713b87e6326dab465af8a758c11409982288bbfff0710a4f0a2f528c408a03489184143ddcbd55938495752b1bddb4cc14ef122b65a27fc5627fd392a92f43312d1b7daa6214e735f6372fbde69d6d78c5495a3022983e354b492b16d33886a2b88cb98d40b6a944af61b3b396d7e791f33e9e8799691a77fbad713400f9c4681a0f89bd4dac55e3a3c37a33c71ea32aedd3bfc9b6732751c246f0c6ac34a3ad1a566e3d0cefda89c556759738888dc6d18abe7593d7dbe358ec65ead6e989436fefda314d13ff9a6f59632120ad580d4ba6661f4e1df3e1d48f4d137faacf5773f988f5d94433cd26aff835a6e5dfea91ad1ec9a8114e6f0072dad69c443d62a637c8d04ca41ea1c14715ee30180c96bba1a66acb1bcf329acd56bee58a52559681e494d435098ae212a591eaba669ac634f3f52a526529112caf181452a088b93b09c50c4e4241e3ee9e22796208de32f30de7f5354e22cdac0445cf1a92f211f3866caa3f889e90d27a62881b51e192694554444065a9cc376dc32915d66cc5ad3775cd3edca432f8e8c4166f9537a99abec634f32c4f1c91bb0bf9e80411a31343dcbd158b7d6c557fc4505c9e43ad1cc489159c68289b6ae923978f7ce4720d3dca8c038a9e466b4e92cb3518c0010698e21eabd13180e905f05200131420a900b5029ce0ee457c6c02054d60d1caad19e9f55993914e9dc65e2ff584dd74ec358ae292f5b11a221692d8bfd40d4b7119dba7528c2846f4307cab89254d745e98e0c2c4164c54c104144c14b9bb8f1ecfc2b7f499d79d9798696ee9fc4daba6647ddee79aa4f3373235f62396f4b19a1f2c24b1bff1d1e35968c5b2a99631ad9a9f9497b8c1124d2c91c4dd5b79e315579646388d7b75bfaa2a593f2ff91d3b76ec68e97c84a2670de312a27beb8633edf50b46b6ac3569949710298165cb482596f669cbf9081b51a287962def33132501ea21223a7f1f615b3657f5d35335c21a6725df2af34d7f6eaff9a6aeb75f01f568bd2a317acbebf7001111bd995b2fa4e7ce42be958f54a4f4fc1497786353a5693cc4cc296ebdfdd6d94455d6df723eb2bd912fd2d266aab1d1bfb40bff2d5a2cafb4fd7aabe9cbceaf617dd6280ef22d7d7eecf32db763b8b5686b1c8bc5f2aa6ea26f6dada299b667b373ddaa524eb55ac6925e76c66a6c5eaf22568cb6755e65ead6274a2b7796695c7e7adaf499625a996d255e773ed7195e33d28996379b363bd1d7e5b9f589a2648f8c691a0f79bd8a6e7965fde34f734edad9e867e979bb6123dfdafa443fe6a3a847cc3c33ee73e83ecb13b5e5fdad6f6914bfcdb7be158b7dcee87726fa56a9aeb71afd82be611bebf5b774a6694cbb61233375ffc6dd505cf3e9a9d5a26f012182a238d90d67da2bdbf09132df88b2c6792d53226a9136733eb24bbc6ea521b5c8a6fe48d523660e82a2f847f77d3e6836ac1f57aa477c60040c8c308111594623b030c20a23aa8c463861c4008c40c2dd6f2aebfff5385fd3c2dbb4f0af9bfa362d7ccafa7ff1b083fb070220488c456881c468840e46cc50c3da388a1aee9e85fb18e5071367330a0f77c79979fdf4bce15fe74c2df2ca1ad392648d69371f45e57953f74e339212bcb129cb4a34de18882a5bf39a7d80a56aaab4f13a649bbd5e45b94cd594062589bb79e25b7a43928aa2421071f7117c84b202941bee4474518514e0ee311f7d10f2e1c68727a209b7a96b109da4a2283904114d74466f6fa63835883b41c40e22c67ffd018608c3dda7b8abdc0530fe7082ab1ec5599b19768473122c87e6e30f3be4720db395aca115cb272c55632aaa3756822335fe6caabbcb0f01b8e31587613bc35413a7cdecc309db254e33cc1352e3e3132ceefe1b7f2e1fc1b6524edd3d1c82e0c1f8048afbf80489fbbf7ee3afc9b85c3e62c160a592774bdc1d061f01d085d7d213aff8f6b3b3a373ea9c7ebd80d8fe2f130be9b57573b399b97c84a3b4614af906af38bc95320caf387ca3336a84d79ca238a4f4cc1bb6b33653d508962b3586edf48465249cd1543d6138582e4fa4356bbdb6d60cb3954a7acde7ba62a331d783dc96dc16feafb7f9d73ecdbce6235c94940be2bed3d269e9dca0382bed9b9b543d71344d631aecb671379ac643b6aaae304dd378086dcd26ce43922815e5d98acb7c233a2ab352d19acd3413a96bd62197a97a24b7cf25fad439cd428eca4cfb91e372ed2461252611a56ca6f8f522d775e808c990121c6a40f27af9f4b88698446c25131f23d214484620b966e0ce43139b54bde18cd46db362dc12b81ead1c9a35a66d21ec2976116f6d9cfa66b69d7b55dfc67cbccfb75933524e73789ba085a0abb89ac2f211deb1239c33f1a8d3968f7a061e9abcb6d9a1492bc5446bac5b9c8726366b14eb106fa1282ef17acaf1d1490c9c20e1ee3c34b13dfe552dcf8d6deac6e134888f4e5208f2f116c6ad895b0fe7a1c92b61dbdb6cdaecc4ed12bfcd46713acf4cdc9af57933a95aa4a4aad523a997b40ab7b189d5bc8d492486846938f3b3d1f388a128fe117b9ce2728a6d4883488b9c87269f6d6ab9713849a60ed9ceb095613380ed077a065a052d6263a4aeb73423a56b4652678f625c8a8d7c2b97695be3d435cf526cd6a8fb4d9c57d6e38a5afa4c4f6ccb6689d1db0fa1231ce9e0688af3d0e48110b1d9a1492b29a7b37455d735ab2b7e13d3c8a3f4a8873b0f4dde3c7f872638af9f3333d299cbace4a8ab91c14393ff1d9ab4364e22d11307f951a4f3112eca5a493e73265692deb0d34c449e38777793c974cabfc3675a91c9643aed34230d9d4bc6d3dd5da67e0e27bd3eb78dc6493d7ca461f13316a3f19136c5dd93f8489ba155a3755e6fe7678dc3653632e2e38c8bbbb7d47d93d7d9154f4fdb9a7736f50b3a3ece6eeefeab2a9bcde02dd9101f6565b8e7f516fb5c24bb2263e22e93e18c4a7cd32f53ffa8c4e8637dc3b43527f9567a7ecd2c3d374e5d55f3d5ddcaad93f519a7f5a9e635d38a64392d9db7b8bbb7340ee3315bf15636ca659ad72ccb4bee2d9d536e32994ead9d5154a69a4ca6538dbe31537ca371769070d4b3d5d2a56ae2e0bcf46d6f1a8b07bdc30f93c974eaa1a40af9f081a2f8c7ebe543e7885ee32feae1c3470dab87ad64e2c35632d93a9b3e7ce0d04349152a99287918cb23466a784b1bf9c124f637ad9c8d5e9f3275a5ed1467b3a928aa6ea521230fbb002fb9bb9ea567ec6f5a35a791911f4c326db3643813b9fb8e8f3133624ec48688d9b8fb0e3ec25430c2b680ed113683bbb764eaefc83655efe091aaa7ba73686ec756d31dfa447132ad7359e2f493ff1a2a4272a4954d6c5353bc6d38d3f6a9a6674c09db62ea91560e45f1aa7e0e3567da16fb35d376a625fd2c35f5f99f922d1b33dba0f8f3500f26e8e187d6f9eafe1c3e336dab1bff9126dd7d878f3c40e1ee487ce4a1061e5c3cacdc5d898f4db4b4f27aea6cea5595e5d09d93d4fdaaaac4c80f269f4bcd15cff2fa1af7b935cf52157d35c528ae3cf78a6f8f95340172f7231f7740c1b843951d8600f17187db3232f2b972678ca2d8c6cc1a47dbad2277b7c1471d5e87137220410e58725892838f91c90c98441999d0e0e312182c5181bbe3e0e312002c6101872e707080bb13f988c312776f658d69e58abb7dceb237f28389cddfe4addaf27ad3a2ddb472ce260e2dd3f37cddb462ae1d9348ec53fc6b4ef34ca63ef9af586ec56779ca729a8d627fd362e93089fdaabe8dba3f5653d36ab1de66a779c549582e26b1cf46e579cbed47d173c9b7b6527ec5b6ce66ec6f66e969a6f865ea0d9746fe158bfd4deb489feb6f9c8d3e876d1a3db14c4db19973fafa5c559b4cfd186cc77e5565b4194ebde1de2666cbfbccb2d8cbd45fd55d66a48fe95836b1cd3cf5abff39076919f9c1e4df5c71528af1cbd47476e63523a9fa8b6066366da59246f336d3acc71b7cbc95c3256a84d77cfb9de29caaaf7fa028feb1716ab69d7bcda68f1a20dcdb00e158395836ca615b7ace4e552d314c9f59a7ea4de73567e2ac64969e669a93e4d68cb3c1fde208c5a0080977b7954a3033cdba282da2bdcdbfb6ce262c6f355532e4eeff5a55592b97e2979d6f936778ebd72fec7355cff5f658e35e9f6f636633cdfaf16fbce68fb97670b1cfb46d63e6241545f1c6e589de7040be95a4a64747279a93be2553df9669fbcd9c935ea7b9cceb6fadda5ee3b75971eaabfbf5e7156f9bbaca5233e71545c96f6974c5489fa4a6479f8be0deccab5a6a9596f43ad3f6dbc472aa1e89bd8cc8b764aa911f4c5eddffad1a14c5e7cbced7f9ad71b5cfa128c6691cebcd7cbbe175eb93b6ff656aa6ed6fad27be7d4d2cf666b661bd4cf5e971bd2b1f61d428976bf896bee175ffce5aeb7cced2539da56a2bb7669c93ffadf3c628adb4954a38b95b89f39ade90571c7ae220669a89ccbce68d9e1935c2e90d19353af79a9152225b3d0224b76fb6a155a59529ce4a34162ad5222616528f98d9e85c4b6d8423ca3e9cda86b39d4ad8a6eecf463e9cdadd65dc3d0ca13254dad6a53e6d3058115a91581121f77fa9fb6dfe655357d9dbc06af88127e1d5a4ed3309564306dc3d051f6b40c0bf545ad2dbb83b10630de3484319230d5cdcd84aa55585d94aa5f484a5b87cbd66d46882862afc5f1bd392fe65a6385596d1ac6f56756314554b186c678da218b6669dd714a7b52a4b4fd8c69d5abd65339fd4a8e4cdb265494d32c6d0ccc88c20000001a3140030401c148a86e31189a4c628c7f614000879a2607a54180ab4288c41ca2063885184000088012000233233b30100870c9771c4d9b9be941a434f685cf0ca7ac45bc35241f2b7651f01d4257b69c5fe74eb15945d89a1a71d105d63e74f3e8f333436695e9ea6b25b8b3f3cc6c6cbc7a955dde34899139fde3f9854012ad40a07bcacb176192a227440bea0f646564f2802d44525ae7f24c0b449ca238db50d56b3aff93d59c9c926dca13afd790bd040cf3f4be05fb3bdef6bfe474038cd707b8f318ce78e035360ad859a9fae9f318a78297412ebb976efb7100eba64ff94d940571941147c6f108288a8c124925de521644b05b30efd83e90cd757521497dd0052531f7ad94e3497ef22979b59620e2bff8470686f4ba4546c0fed69992bf5e73b0a8c5a80216d69fc56e423a7bd35e851ccf76c7ec4597517bcf39047aec257cf947ef1befbca74b3b1261f5c4a3ed0c37c900865b3843dbc28b62387a4f2fb69b0188bbddcde2f02cd6bde2a1b992ee1a639146036a445ada95236628603d307b7c6155aae4d34874b45b47d904d61528396647e43a8d431df40f058382e3d2efa1a6aa14051122e1e93babab0fb937a9222ff6c7ecd4a0a5e7277f1f3708ccbaf16b5972bd693799884814cd7edec2492749410dc35f1904d41137616efd29495874b0657ef35626548ceda0e118403e4c62d54123dcbd43ed193e101e13a6e57124610d9705f746f2f33a952728fd5c07ee0f388474058211fa7a122fa036d053b5527e18194a825c6d08e5e5b347eda3e0118816001aaf2592651318e86d2d15305238143e1a563e4f65768fb2b23cede819486a9a7f5f1bf49ef399c45ba1b9d8dd6e3b69448901691c606d16705ae32c08a27a7a5126f6f49e296f5a933efc11182fa69614b0a3710821f829d94140ff03f9538c5a88db1bbb107abbfcd08885302ef1bd2f9fc6842f25b5001bbca8eb02ad4c2293aba0b6e52cc8906cef233bd05dfbc27bc9ee4ac3b6993b38b712307e22bc3721e8df32e37da4d485a7236c751ee6a8a7e755ee8625e009596b537710ef140207339a03a80e01cf70fb46a3504a9a862da42610b119a1ab13b85ca3bf91ebfa4ef4b7de539b1fb8c37438e6b205e40f2732caec2d229c82d64e65f6e4c52d244a289633db145be359d12fbb6d7c176b50de461b01b1612d5638cbc45be4ac8c101668de7286fb143724148d9acbede41839e6e613d0a40542adb4c0401ae23daf6b1b94e8f3cd27d3e7cb0dbe352471a50169be57907b34077e865d3796cec183a390db3b1f42182cf865a67ca8fae496833c4564b078ce29a1e87a02209df5cf25ae2879a14b185f32aee7efbc598945be01ded3e1d47fd1777fa19d85ec75c6dd43877370c0ad81764d1401dfa1d3893da7dfbea8fa3c29f0d691230bb9b02128bf300c8ec1e7f2e334cb9e49f2fbd1fb26e06a76eaef710dd94d407623210ca34a286a25b177cbc262678d2e79c7f5131b277401e2d8438cb763f91803fcf446f6759c9292281a188786556e8f00236c6e3db67a1fd081ad957e1d930b16d65db6d93fe034ee5cebc0fb2509dbcd99036565847a6db0aa2e8553c42ada772da1099006e13b11e81a997bedd3f0f56578578b5eb42beab221668cd6b8f2961d258ac0a637aaec5f39ffbfda8cfb2bdc206d41b88a20f92eab14bdaba30d363a9092534b33c1b294deb5079d0ffc4de4ef523a4d46a385e5f4e793fde7cfc09ad4c05f5e0b0b382377bbf37dcfcb19a7c3da1b64e89330fa312b20b0137d7848cd932aa2bd900c1b634f42772d62ad91f61346da84e5e9594492b816ed1c4c1c10be092095f7222912738b0c6233d5bc55b2337acc408ec7d0322ce93a174631d3f213a5d162c6d087ca13ad14c4fcbfbc2ca5bb4711a15fa189b656d122bba2f8589b6082fdc2183538a04f14b46b95b3b5e3d92531c949ec19a84ae6a214d33037aa7bf5ccebf2fcbe542e8e0392817549df2ee242ce6863a58f108a3c90ad386ca7114fa21efc3b2bd683ec9c84933314ee63de971273961efd201797814dc618a741d83a38059a7670d9a99c08b03c6b04d004b42383330424e2bfcbd55150cd950c7beeb822e26f14f88d0d082e0555d8137175edde78d7f073684c4904bc4c8914dbac1fd582bbd6687688c3060fd27a6747229108fdd8017aa7e1fe8c439f8a3c0ea9c5d773ca90fe6cd563a94a6c7b6f216de3e6dad87515f9da7470bdcc46a5b7474e50250781ab802c4c6f2d1236657ac5bad1927e773d83555b345d0821c8beaef31b63ae7dc64b9a3808d2015810a2228f82ce8bca1e0b3e8693422316af800d7a15ed544048000a30405b2d558c4c265a2265949e243ed63a844ed214c7ba192fa4fb45ac40c93a41b1af163f272517a35ecc092a2b54a2defd3604e8e7c32a8c8454b39b0f4803dea7081bdc802482d5bdf17a053abf7b0f654e98f56853045994c6efc284b64affbcdef8bc08a3924ad83d0bf9e409bdd693a69a51d2fd3cd0250cb5e05bdd520c1094d1013d83e6a165306bbc70b0e5f68f636ed76fae616fd7ad23a869457a148cdedbb25934adda015b567ad34501a4c3a66e06e2bf413303be00af48f5fd7525a2b14c09c3b438ae4031c3ea050e29c8aab6f1b28b98e3228805a060d4c1f59f02157396723877da112d28eff03f78aa6115d98a770461ced27288410e107277692af29d9920f70513b5f25cf3670d35b3e04808f5c1dc575a4bf69653ac68b1dc28779a7b8e2d2c6d7a18e1467dd3a55822a5b0043146134c55d2c36fe5d6765c7cb60c3ba4a37dee4f0956d9f8239f68d3b1227c0d05c8bec02a97c9329711de047c4160f3a7e57ca8774850c4c88a17ba89cbfe58ffcf10c046d1898a350e5bc2e6e823ed0c40d34d129ce262dc5e6e51e9d92aeef53d362f1566bd9126c9e2357e5cd2afc33b93c3704aea793a05ba46cbf2692760a3367f0aead1055e3989b6a5e5ecc8e52478dd6e9ed25d652c5a81f4be67f4600f81ea17b372579c2a673f9588ea9f16334d58acd710118e5a91b2e3f1824057a1702e30fcd1b6236cfc635c82fdcb24d02ee9490308968f913a3fad57cfecfc7ff399450396a42a3b286d52211beb912d7239dc55861f200f43d12f23d26a6514bff07988c822a6d9f291ce998ffd42a09e0e55436838826afb147bbc4fbabd6e252f16b5568140d2aac8aec316681dfd6c767c38f1e4879833f3e05f3f8553cafc15008f7b8db5df5f1f7a3bf4f9b5fdab9f2bd06713cb448577bf144fa27c2ec14f0719b3a3c8231641dbecdb1be1c08dc7ed8a597076701c152f20f764f5cf8b3eec023faf428a6713cc00232e6243960377f487c4f808fe3f790c61b24761f36d0ee53d0c0447bd3ac7d2d71febb721f0a6c229db8ba1fcefb4b659b58b8aa03f0f96577991d27ca812474416470e5e384116278231ab28b6cb0133fdfacd1517949cc6d10df53383e701190d6ce99e24521238ed5267973f1bb20fc7eff3ecba9d51c24ddc67376d421cc44759369d3c6a54d98c5bb635b9c0545913245f0f2a63621a0f0d8275704e2bd459a5ec8c45249db54cfd109c5abbc62a0c66a267f82228d2a434cc5511bea614bcf3ad1e9be381970098dfe0586c84977dffc3829e4f6cb98b9a75a38e9996e8e3f0b2f7a4271003155624b40d08da36e29bf5aa9ab1eb954407aba47971a69906309fc6f00b5716299c4326a987d20c5bbaa81596067837b01b94fcd591784b54d83a4502670406c4c5597f37778477a72530263938c24c12f6b5d3d4decffa0820b1b277433450f382cf544a7798fbe1e7a6497749aaa8a257f73bc05f3346cca4466361ff72a12904a9a2fd18eae34e7e0daa20bf7e0aa9930dae7e1886e70d02aaae50b15306e25a451b6f2cdbe097b31fa6ef3311f34dcf7501e97138e7583bca8d3753b1e3654560dde0200a9dc79328605d39947fdc9698e064ea648b7ff9e3c539b2420a667f8d23b7424d0b79c9a02fd02adeb5acf9ae713317224781bc1bcf22be29a52f5f2b28765dc3d5337d94543eaa79e4875a5ac36efdd388824443eb2dec150939d847f80300860b43885123039928988564ea47e4327973899ce013b5d7ac4e06513242a6f093abb2aa2ffb92e2fcad681934674dc80adf80952721709e9f3bf08a4666239126569bd63bda334eff87baa2880b584cbc9851ac57c4c7fb43a1dd584a7ee3a547d8bd4da09e78eafeff1d223e1e54647340edb363998f06c3fb068a21e56ed92f19d5a98025bb01dce85a7c0dd8562e77e6d36e59ce3944121c2c1065dc7284cfd9e8d0b7e3f6293b67bae47165bc78e207e810d19638541c035204896b04e1327bc703f4a97582e14c327c78a7beea57cb78ad9d39ecce6bfe2e8ce0cbc5acb44a93452d290fef6138b89c128e0bf7f8fc6a6caf8bf3cdff6dcdcba1c349f33e1beccffef926fdf79850d4623fe60a3f0812bafb30bdcc3cd0bf8e952987c6c3fa4cc659db9f605901013f754c7fe6c63581a7f9faf8d8ebeb287dccfdbf667b51caceb6ff48b6e91350959a858fe5644492c3d4b06e43b27e6c982f9348694785d20c1adc60fad81300023c3a18e0810640fcff3af0d3e39c10e9b8d7ddd0b3543c9bb678f6794266a092d3e5160648f53129a884e762d0261ce7bef877b6206fbb5662dcb2615ee507f50dee51af4f543b4b7effc0a6cf5031787ca6b88e62865a7647a735b65ef30db6fff12716bf2c2e2005f3f24eb5e8fb852760e73295a5bd4e27fb5ad044746d2c3de0a378730782499e246646e2a49942ea484fea1d32fe8be076982cd1201c25969b71b370b9574f4d01f10962ed54af61358b13e6d13dc53ad832055f42712284521440d740cc26b120933d01d83e00e8ad58eef75489ff6527fde4ef6915f0446df6944414d0b706b8b2290d9f3e0f619ea01073ba0bcda73e86eaf442833a8e510cf95da0e58f6decfc07ed4b88bce4c3df3ae733215d84ba97f67bf97a2c2809e3ea18e5627766406cf3e678ebbb230c1f1b1f66daebc2f18f092e02ff44fa46feee4d3c021d318f1fcf4b470e488ac9887afc0573152e9348e1a77cbe682c6b57ad48f8a86b7cbc3bd85d3f5f841b11f8a50e1af4849ed257f14103ada16fc28755a1d7d18fab5545710b087747b12a796b08a6f7efdcc55a1fd4f9839b8f2b508acc5ad5a94c5a4a4d82b568deb49a11694caff76fa859a146990a83ed0a88c13678d26525dbee8f1da8e75de51fd5c6aeb62dfe329627b62f68205ab1c7db38e90b48aa7f8707172c7139cb0297495b963ac621a291455b0e760f8c2cdaf3c9f51f18aed538c7deb2ab3d2d3c6953e9acc1ccdb535a0d16a982130c8d6d79cce58c0968e55bef1f00bfac3c9754d1025bcc0baa6cd968e19f83e9398d1d8cb6f20f978ba1add50e514d312e6671cc8572dac36fe8ffc9eb764b6cb505671d64cb6cecc016d978c6a0dfef4661847f3c9c87486b84dab9246cd217b31defe82073503b5ef64256fc1a9a5b2b665941705a3b941cb34d6bf4f1ec7974d1a24bae25aa8686813eaffae82ff66659d8b8f934eb7eb35c57afc3d58cb9fa19d8e03d7b7a2037a19b5c2813211b4d300e46264ca4440f95b704bb371dda474cec62c1718d93cb8a7594e695ae1b0604d64113481e00e1e0cc0ec00ec58fc58e2f8514d921edd5983a8874f0c6237966b61cde949ad8d9c2f74792c6021d5f151676f9b087315726412f24d6f3fa678c2cbe7aefaf13e623b44edad16c6b7be0a83cf98a114a99fcd8064764cce17a395699134532362b7bf99cf0cd704f6a483e60f67853c4cdc6ec393d0e3047c6cec9f53852902b8d73ca2c946ecb0e3ac17ee14b63f6f1e3293ef96e13329ddeb2ccb7ab7a61ba99d0cfc124c96494f54bba2e9dce7289d6138ce8561be297fe158c2d134734b91cb0ab1c044fc02876d02afc65d131621fafc413dcea769ef6b2703bec65a875a503116ffa4b83388b85328c353805476f3602fc71ea3c61d533e2ee4ad9ad74f5d3048d47c0862352a7e2aef513d3eda2c7900262aa07022e8590e7b1aa14971fff89b525c981a14c3cd75b38b477c00ff80bec8a516e0fbaa924912d47938d7df98b0d1867d0928896bc6ae6ac66c1a80b5286e1283861beac540f5a55eb720e91c990da269d29fc505d0ead722a6c33edf912ee12566c05420887831d0e5be0c64646fbe15c123c45962fe8cff4fa22fa05e57062c02682745b33e6341736608ee0a109a3ff972cde11604cb477247d9c53123fd7eaf3f6991a02a3c7ee77d6dc4ce579f746bd80c0ab0a94475b9f1d0512ddd9424516e537341220a48de5f1de1cb05cc70f4ca214c8f2058d04fb6d59c81709da7dedfde3183a8fe9426bdd381bfb99aa14a274cfe3d847810b50169651faf425f33cee5c4f5fa2080b8dce31d1472f5a00762f3e601a71ec97b69f0c0934350507de832a9011307b88622014a3140859fe641b517ac20f9d47fa1d29505eca14b5a4e32880584ebfcf215be7cd2ba335895247bb8512ef32a695ad18dc003c11582c80b758d16eb325854ab4bdea551d79078548136a337766297fb5ae5a3ca6985a0c4771cedf68d10ea61311dba06b91ea085e5e3cd004d02d05000f9983c613126080f20a72c97dd479b4b1c101b2c4a235f08d41c5e3a45bd539c43af9233a2ecef28a09439a4267c6ae8216011bdf68ae8b733d97db44655f33d129ebff2bb2c11b858dff1caa0b338732f167a3e665bde25a3b8e09b2f9370578e15b01309d153aae086326c528298cfce88cf5867e8616df6e94ed9980cd5293d5f5b5d879128a1358498a768bb971e3cb48531e7578c1842d8139e8e5deb0f1aea28c2fca5b48a4ad99b51bb3d8d2990fe56d4800af236068235e66b81f3354d136f515d4398b9a53080cea0582ae8a1f93e00e63f73255f8288f586456324fc0e0a8f0b46a75be92b80a65a95d4e38d2e67389e9239d199c290de8571497e4dca9ef1901a1f4a7f89c18fdeb2e85a5012fdb63c57e047b4e429e111a6703072d678c51f4fde4a30c649fc6e4ce532a1c8d827796e513b24c4cd4ffcf6a50723e6b006ade3c1f2c715628b6114df5ec91a203e0480849aeed7c8770bd484050851d80f93e0736ae4532c00a621aff8becb599c3f10dad04c3d993cab5b4f98a561fec7252804c4886e77f3e10ebfdd38fd833011b79125c5ff7c7390df511d13e41381e1662f90b3c718e740a27ae22ef071942604b290abefbd85410142c9388f7d78d597f83f32f6782f50f6ca41e5ae61782086e15314ee7d7b5caaf79d0a15e019dbf4b7d6fc4df856204c60dc90b184fd79f9b3813e6f930bba6dc0d686f175f47932e26437207722d8e10350b93558cf2adcb39b432df4d937c8da12bfb4e1e5e79c32312d1de99775a7f6867c56cbe8ce9db5a68c3a4c670105cf8a29b7448b7ee55c93007647f3e4f4e900b710aba5c287d94e5a699c2c17961a156e6f7baa82174cd1c289e97b5ac92a0df713568efa4a7781c7ffb25aed2329030453485ecc2fecdb5522666a7f110f43d9b8d814cf171693ee4627fd3b74d6f72cb30d5eeacb2dc1917a862eef7f245d159a9fce1b6b42dfd039360e866318e1b9c68d17c9769f549d25ca6fda3abf0ff4f0fb397ce4aa51639723d6c5356adbe3e23446433a8b1500fdcdf4081d8bead9317f2734fa908615df5cf34940baabd7dcbe56413e43d0efdb2ed17b51edea1be6e2e03bc454936df84ad2d2ad0dbb44b03d2df10c4092c2b364ed259920e84c81d69e0f2a4d243ba882f68a5758c62d6938e8a68c24de463ce1cb575c9d322d30fe8501340f5e6d4f223e4069c4fe9f2836fbfbd3b37967eabdfd1e8ffdf57331bc4efd77795c87586fff04e38a48439e492249d33acf3e9b02a910d441545a2d291134c5fda08ce3e2294789702eb5506422c0da60a5f4bedc628f52f099eac63db1f6ceb064766af4eac354871d9585fa21cd5ad818a76d52552c17eb0f395fb3d7e005502b45b5d3c392f42734201c36fe8a4b4514f37f0f4be16b0203a1075340b2f3a2b16db15b25a1479d6cb75f4973fa40ac8799fcd6819217df06ef2e8c49956af6fae01a45aee0c82c5d12a9a5efbd7b2fa694e8d4f942839589e278ece1f922d053de16679c9e20c8e4c7136ec3975129209459459f7d0437bc0bd51ad0bf185a507050b8f873cbaf10724e642f6edcf8a7ca89eb34f4f13f11f0845de4662ad8fe3b5f4ac526e8ea1b07eeedaa4471b7ce1050d4d975c6de083a015cc6a1e4977e05010402683ce5b07ea4cd7332eb74f00f3d26e7532b9340a8ae4af379a8ae10c0e81e3e96fe20d7c5f00365ba1c981a1227a6770d41f91d83ef06cc38d133b0f1be6045f425d0ea6669ad99a1241da3621343c3c4085c6eb7858b51a27fcaa991c6a12332f5d82c2807fcee3f95349e1d2c624910f37742619e7eeadce051e5cda07c99a016b65fc73c7ec9b4fb0b2622e279dd4cd15e3dae50ac25a2a3b30ac2e47ec96d768c135a315a2e6bfd464e57f3b106dd1436c641c9b599d53589f432ea8ed17567ce1eba340a161c092bc94e87a9390522f71c5305aed7fcbe6dce8b5b09836f8b4440fdcc3572b7e4a1f24192e2307c67703e2b3bca87664d5df7bdfa88abeb7cdb622d0929f177238d245521bc1a80eec5c2a68f86a59366eb8e73dbd5061d3adb72fea64c5b6bf048da731811712c38d0e4957507645e113023c84c85b16f556926a7e1a84efc355440b744c31bb91cbc5a6cb66308416fba4f2af3b36a382d974461c59de5a12abd2e871f8ae3c86c8f231c7b0951cbf1661dce415bffe2aab18e528c4bc9259493e234e0a39ae9951f8ab041237f740126c47f26ea96812142c5ca66f0d8d89d9576c3d61ed3df8c9d8b9a575a1e121c07abcb9b299b2f765033482d16f59e03a958cd6ab1cd8d5d6089ad289c5d5b455298359af79c864ae0b01be191c484db308a41bc59e953a3d028b9a8ae9bb0b835a82130ca3bb809847b6731772d07d7634814da96ec0c2f16fa3dda7c67a87faf07e744533161bfcf7b3bd1f676530bdacdc4e027b15fe8ec19f62cc2b7564a61f287db6b1de978ff359c8244cda70c1aae3e0774c49076a09581f3bafa1c4f4296dc56302c0e06a460d1c89806603dfd0fcc829113c2fe9b4b32d3844b1c2bc9b09d8e2de2ae569e0caf6ed820ecf3cf8a8d2be86e3aabb5a410efaa677219997d842b086e0862bdbc88f197c2201efbdd2baef219eb28ac12bcf7fb476fed052ffc769b22f7c4e8cdc29536159b9ec54fd15516947753a567226500f22b30fe10ace41ecae056d40ac614f7f1e63a63f2f26312144e4f775546fb3dfb71b21d2f3a5139e24b062031a046f48d3330d498ae99f0e535b44ce0349a0189b83e795500e533c2c5792be580e57f3320ac444d4ee1e3ed70008b42d8aa323db347780dddf49f301eaefb7a1fb6b5249e0ccb48762ce57ddab5d684d0662315424592c1270e0433140d54866606a1677168ed42e335e3dfc81f59725e5cccb93c7c42226cece8b8c5f91e9b823924e8621ec389b73522eebe6ed20f7e079b5eaf9749414667f84e461ced369ddd9e1affac13977f3ef6d89dd88aea0be00240f8145c5eb95f4128f4bc3689ed1d4d06c339b4ea67d521359d9351f09e2536c73c190c87606b22962db576f0e8217042e93e0fb1f8e97f6cfaac7639c360e8696d32bb332b0c667370d7499766669a8ea3b0b5892daeec3018cca17a27599fa9d13894c2966eb2b8e563793204ae9d6c7b4667c3700ad8ba41dd752e815bf6cc4da06dd8b415cb26041b966b6559135a0d536ae5713273d658752fb1d3b0557a3e8383c87e793904cfe156edf5048ea27beae9143f023bc5b7153808ee95b76b680c6d959f43e43cd4151eeef128b65b3a4e9173b4557a3f8199260d24da23a720703c381c0d1a3a198716d01bb4c5d0e3d9eb1f953c908c7bb3ef3f1e9f8aa5a723369e50ff60b9ecc64e696732d76d0570f08e896a13cb3cfb9418aad423d94c53f9bb6162cd5df61aad3c74dc1d0f6ab1c5ae7bc8d837dcfaca12b5075b7ca6a79d58dbd2d01ce9371d1a88fcfdb4dde80a80e9389df447f1a51a904f86fd3098d380b87a249fc490e3b0a1ddccc4981706fd1c10e04a6f83127866921db22e7c2dfa417a482fe9d45f09e0708f2de24f801d71bc256e739aba36e7f4e019934049b86ecaf296024620a85b77512e62f8e0eaf938fbc3c712e0fe7d90b793f99944b3c784fe7b33e6ad566c91e5e841ecfc6a38326d306ace6e8d93dff62cb5e4568f4fc55a7041523aad274a3e72c2eaa3180023dc047414fdead07cda5e6637addd5545a3e3c98a166b3c0e13d8071513ff0c474ef0c5fe9bbd1f092eec5338b43fee3cad09526ecfd8fcf7965c8341164bfbeaf847b93cd194e4f1cf5a0ef16d2ccf0b663a5a1585e36bb187cbd5fd79c45dce63b43bd35ebb1fd686e63e737d6decf10302c1f4356ea572d87e465812cf52039d27382af4ced5defeecd43efea18a6ea42195ffbcfa74aa059e8695ad11e9faaece6e266dc62b002357509acd446a48c455c68ff19316b276186c897efa36311d8661b83504e09d5dbf37dc894ba0c86149a6816c6e5832c66d77d6847673b1a42301a2c4efc69f1293cfa6cd49d4f9331c1617274d8621d75441d1e56ea17e805ea1726707adc52ff8de8e1a7e3978d112abfaa5a132fdd41dd8ade3e1286a9a886bd6fcc0d7aaa5c6a275169e283c7704213b16844079f56a52f28ec7d88dc55070a9aca96b12d755f53b8aab8413fa4c371c5f1c57a96840538fc94c8cd76a30e296b93cf9d9b9f6e50b9105bec55afe30ec639d335d7c29f1de7bc797ab943de5062df31da463faca27cb6746a867ccc16689c0584bd535657bee7c35636a5962ea044149a5628df1f9f1990ac5708325595c3364d9ff6d30a15a51537b72e3b6ce1cca9689edab3ed0b199cfc72c189f3fc53945545a5ea4bf5a492c1c46f67d8892e64c26a029d9acee2d95bce81b07e563720bd7153c1f541c353536988d9b6910f1bfa456680f6477f812c9dda6bf5f576171fed62fe85103bf3647a7370a12f4d96232bc43cb1955686b290d508ad6344dea9ec2228b7d5770f8369edccdd312a2858afe9e1241e8003b5375dc024af6accc816abfb3dc70fb8706d88cca0206d70d96588b43cc4d24e8db6319290695f9307a5bdc5883f50764382a368f24339ee75b4607ac992c883416eebb46d1a803e23d476ce449ede8d3bddd21eee16074f28f2d560762c34889680a9028f0e085ef4df21d8627ead2ccc19218f5ec56fbe3c3877185fe5eb1d696bbbe58753fa3d73de8f55eb5cd5ce182fed10536ff457bc53037fe11b85299f7fa46d3f506708a297f4e88e05f25b4fca5eafd013abd2fc8bd6c591ffc0ec64bf852203dc84cfd6b0fbc5bd377820f6cc54f7bcf9ac7a0e8411acb7d418db4f73b81c51fb9376fc84faf02dbffb51fb29c6cacf92cd3f514b793cacf4abe34f89950f71658cf6d5af1e3fc809ca3286c079c9297cae782202323fbfbf069a601a4613c0cff12afebe9a8b317324b12972fce892b3bb4db6b6907a31ca8856acbad574a126c9be597e9ded6489d36da07eb366bb4121c4f6905366833749b0049b1cd3d08f8fd2069b471f6927e66b817e87110bd7ac98ddaac01ded1a78df96c07f6c3f2cd12678850e5f239b9214ef09794dfa05fc73ca4fe4621f68f4c8db3d6af65d7b10c7eb4cc767b5fe99d1545b0f2bd45efcfc8eda2fa6c1676c03d85f213779d82d39c866213dcbd9c00aef71411cee71fb1fd8f85bf87cdfd54a5fce97f97acb98f09dce1442d70835805023a6dfcd98dce5f3d12050c8ca0846be3ae8c735cef8c0b98cdbbc07ae03fd26123abeff74bc71a3a5e402a7acda2b7260d8f5c736dc8f8f263daa77ce99e58befac55df570dc56f0dc6cba92c14d2d70052e926e72482a1ffd7f015cc3a5f014ecba2b37b51479834b935d2037d27d0f89f9fa3dec409a19829a1697e175585f1aa3a0883649814133a6febe1809bdb28eb4f53b13543e2197438a8900f18757618a6a072b87282a323c1824db2cf6e1a3434e80dabbf370ab318e583abd6fc6516cc753eaec6d599ef0170824fd88fdfa24a591714fa1c242f1595be193b1dec2fd4ff576d55369c4a8bdb37f847c0d0ef82387cfd7a4f7b8326203a29680ab106e5db8bbb881430b68fbde1d96a7705aeef59541d77166f105e3f70df5d2932e2a1efdcf885002b38abcbdc838cf2028eb5bee381df6424cf3cd4735e85050e2ed6c4bb236a721b870ed70b55ad87b3c9925301e97a16288668d46cb4f7bca0c0318a4d02d877ffb973435b2833c050c4bd1a5b7fd1e030d61ed5a6f9141cc97f6a0e64f816fe4bee54367544e71b0c88750b48cae80f79559a5f4d4dbd8233a1b19e160ab886079e353a5f2bd14a033ea362111ce184499570c15bd230af7e9c98797430f2940cdca23c077e9428aca16aa816e0a7c9bd31d9a8cf5f66366224587ac1ef0906c93cebd96b1aa366d44ecde706e89ead486813f7e77acd0eea56fbb64f1e828f21ad0d1c50f3788ad17a95c6f06006e170706f7835ec1874656ae1fe8653d61997d7cb0d6aca926a318ea96d55811fe1dbae0611774f1319ca2c19db71e19839a4a9899b601b5c18a72c810ca3086758bde69308bb6ffa40a8b9e9efe9d354d0422686528703be0d94982ac29a24af7ad940d68cd6bbb14928cc4032a27f4213e97f984c0e5f6f063158b8804f95aa2578ed2ed85b50711d81eac61d5dd0c81e0ef94ecc3f06146ff1bd11176a604fa6aff46ac2d71ccdf0b0c31184b13002ff4553cba7e9be215366093c089e2e0071fef2c7d20d1a9293f92e85a5226daf40726d1a5f7b0f8646eeef5d2055c212718f38a2eea2dc664054e059135894e7c792fd1a57f2e4f0b0a6264dbc562588babcb7bf87a563687c8e6ca06288660f923baf8a4af44e307fd687499c48c3b9e988c7e4f32edcd0a7f4113fc9a756cbf98c150d7ac7ae6154fa9280d1320713c1c2fc1a6af6a9eaaaf75284a3fcc32f7652b864f0475ca3c92cc6e4cbdc31079b0f2f4926ad72bb6ac140312c06ad0af98a6ca11dca780ef2bfaa12f4b6b3d1266e65417f5ac840a27c4808568662aff68bb1851e6b393831025e9e4966667b66eee1ac3f4b67eedc831a0f9aa08b59313f4d2bfa112d82b71cf252da3bdfe6690780ad9d8238ad111988baabb34c629ac8cea698d87e500d5329dda17167b848cc6bf5aab2fd424c6360ac7c758bd13bdf9b3586011ba232c9aace4508925d4ea9b400a4de1e84a2cf421c67550bb8e58c13b66559707616257c33107402c5a4b7a5f0c4162c9623d6ecbeacf478232c77a2a67ae7a2b29d565051cd0810b3a43a00f87bceeaa2acd4f11ab0b4f8adb100a07abde2e909f0dd21762cdb61831e54aac86079fd33ddec930ec5582a81ed5f050d4dc41b09e72fe707cd16c1a302be98cb4d7c3469f168ee720a8588058de21bb8012a436815fbf47d4ae781755e5f2f11d35aa7a09c79748924c40190ae1f8181afaefacb2b420c0e1e91d146e0b33ee4445fe555cd799e7f88a4c988ff16ee8db97461c4a31cd63f09835eee54bd1e6c0896799b9f2cce3f79ea7d19b10643fbe5d84280baa9a6875304cbdc4ef0298762092f7cd7884d1ee901af21781c59a141542b0149c9243320c66dfd56f4ef55abaaba7838b4e38b73eaf56ca1da7fb6f9cc213163dd24cd86f4e793582a44c6c272fe0128f1584f9bc85789120800e0b0161bf1dac1b23946334621016cc086b789c58c0efc237b14b8037e112d515bd4204ebc1147e379634ef070c719487a47897e50b65afcc8dfde2061e2185312300bab271985452266ee4392544108d869b253e55e86e4489f40a3b3099512c8f1d0547c95a18732f742c9534ae0e2c1cf59d76ae227a245e70d29403a4ff281215c12ea312b0757063f9d28dcf45b5a842dfa4b1d741d24e2a8050392e03e04a305efdff0b3244e840f78dc29274188e0d802c7f933858883a16f2d0486baddd7f17f27193a1a750136ae3db4c95052b1c6ceb0f1a5dc3f1805c8775251ba15442e6b2182da96e04daa9d0b73dff79dc1c6017b91267f05dfcc78922bd7724c78c4d993fa0ffdd85a070b14bdee371d8f0dd840f8617c7f5c1d8b77ef69516ba0b8550eef4835522c750b08b69d6764b2408112f8a31cca335c5b0d333545f64740bbb1d47e150b966c9ac1d4a63452a2c283d34c11ee73067146f1b50e607e03c0a3dc57dd5ec0e87bd6c40e89be3f759e28bc28fe099ad2359a6d1723022d77db5b75d727e193d0b7ad51faaa35343fb6e516237d03642dfb0b9a61ea55c1889ec228ca4ef2d235cbe43f51f91aac8b3f1c3bee5a9534f3a9660beeda5150a78782ff9ebff8e660ca82dc744d7624a0f45b8242f43a55e786671372e9775d6d939de160f2b5128d721578fec0a3c872707ef152fea513f1016608febeb59a39170bbaf406519483342f83044c80be9c7aa88f09dc802d9f05ee4e2d7ee4ea5d166020dab03f76c2237714bc247db9998313d383a3ca257acaeaa9a149af101e5867a7e32765562f2849d81e4da7176d20de8290ff43201ef3cc96e881dbd34b6c7d1af96ec2d8ad7368e62284258582fc37b4278aa5001910eed19b6e035f2a3bf8f0ad65f1326dea6403f91a5e6e83de61e42edef9897bcd65ef9445fbbaf9fc350183d3ffa8fd33e6684f947c226f7d16b51cdb5862420d8d03b00b9e2e2d118eaa333663686d0c386dd5ab5e4f25bad426db909da944e152d7918a099825ef8bb61755c696c7024bbd045ad01c379636dbed3fb17245f9e2050d123fe447fc61131ce6dc19ce52f38364a502981dc38645ffa9e114dbe144ef749746e7442a29fa7fddcaba1466b289dbc5888633a9569d4dca74fc43bbe71026eeb1871ebc99fcb8a252d57632598e58585608454c807707cd873eb79e63c7405a677b49f99f9db3de66ec1dfc825cb3e9ea9302c5483d664842da9a5a226a9777b71c59e75371a146ac1b62cf6ad0504b1a0e4138806df5ed7b325b8b7318ef447b1ce23ab393ac580ecd782ff44df88bdbd849f9eab5d11a8ece8b5e748ce7745405e14082f9eec62bcc6259041f115c68b7b0f34b01bd5fb1c43bdec870cd1b09654fa2eb47444ab8dcba6fe549ffba09b57fa70286e46ec558ca4df855f5e2b20953e05e81a222de5df747ce799c96878788a8cca997c7ce1d596dec9fbff7e4e00064558e4bbfcbeaedd0b40752c4a8a3dd1b7ad36544b97266f11233da94e6a428a98696b28ef6a8f5463c3aa8be553d430a0625ebe40a6f13183fe6d2e9189d6e58e34a91e8d9ace9fa861e80defdc2a785ff94ccc0ca383dd25bbda6abed14dc81dce0b1b8e527351b6511601d62c68a8e78c916936e7c211a3327e51b2c6bb17575913834e69d9751d29816c67ad8d92762a1d817b85e56b2379a708e04d05af318b5090c473bbd81a62b5a9ab87f5bdcbb865b13276c86fa8389fd8a2c0e8bbfb5ad99caf009d02dc5debcd70f45de898c3be1190935024a6aa337e893817607ae6b2d32c628816f28ec06132d78cdbb1c6b67ee08e48a9f1f290732e188e092da01cf176b7165292f131b687208513507ed21418bbc67e066c88f40462fc3ac3e3ffff496e7aa71d4e38bf4bba333839e0628d4281b1341d397ba9b7fb51c2afd08a7a460646a47c2360f5d149c6a92cdcf1b7df4732634aeedede2719ad6cf541638709e033329eee344dc8b668bb085c0e8aed0e17112f40baadb9e7e9ac35e0ba2625862b21d0f2fb13da7303e9582897bbd4546efecbb510d07b6d6ce863a3b1e29e6691e6f51487fb3b1845c6ec80e00452c66180dfd17305682f2c73ac47a81ae4cbf2dba610b5640d1132d305b7c2a0cb2a9f534f23c099a92ccd5a80731c38b0f82b0c1627d96ffaeb31382e6818f29f4ae63faff5cd10eb98f4b7bae0acd7c864ae40a78abdb0c322e83c3695807da1d33bf0776eba931332e56a31839a16388b92587bd4527c8cba63ebd8f665f616976066fef2c70424a623374e639b3dfd662c09ade0615645af1faec35c7fb6d943ac8d4fb222b4d29bc8707f71a50ed12f6d0098ea10f4802b1f736deb1968e5737f61334250d4c09c8885c30a51fa105b08aa1af1198735f8262f8c08dafe63408f2f26b4b37325629d1c83033b0f8e371a03ee900e18d8f37983e30bc82b623a627a05faa13419e3958d7af22f0ef06c44fce716545eb22422f8a5be6b3e149c210a783a9ba7be4a7dd1ccf0c4e12f03cbbed1d9c719299ee03a9e21beb6317e4eb09088e8bc2502ba29af76ec775d45e684013c4468b3b77b95db197944b71791a3ed62ef2822741e36d4ee1045c4d5b0457378149a4dc7597b4705c8b1959d0110e73183c87a101da8d209afd9432ded98342790df39eb45af8a932e9a8c6128371e6ed9d7ef12287c42ee66494ad5e7ca011dff4fdf2a069b9d582c93959f818d83cc3611e248fdf2bb2a9ca653ab7795fcd7647bba0e927886dd7cb3aa4e0436dff438d4c8cbc556cb98baef5e54205ae9b76d4030a1dc917a943f2b0395dd32f2b436fccfba488c63967fc7e807ef95401e912be4a61de00acce0a12e4c97a49947a0295d15c4a31fdbf12105663277cc8c0598b5a66183bd1c0fea918ad239501e0cd03bad634bdce5535ff343e0bc643d97981e7817a253d2e79268f793939208f8a718e3bc3333c2148e9a145732f21f4fc64b441c52795c0657f655313e67496e38d2d9e2b61b9b000bb037538b12a3d09b5b4b33621eb87def115708362c22c910b6e265ac7009ce76bae69361f7df1ac9d4cd798bc22ff7026ede05c1354945bb3abae5577eb03520ab6e36cc139343268ecf04fec64c456466638affa2b75912320068a1d256580893682baa80f6fd53116782d4496cf361aa3796117802c1e1977481e49a981dab689b94c6be5dde3e275e490f7a1e873ab6f84ed0a804acacb6ba15092f7f7a08ccfeee162aac0384bf2db0856ab0e600b6d8ffc075494613e8daab9e53b7f24df1dda4ffc0732ec0b36d71df171e59b8877ab79bb5ec9ff14c02a0d9d4f02dd19efa47e619e6c0f0d3575fef48c99f9efa72345cd243700fd8520d6092e737e249657dfe68d0b1c7ce67ce4d42dec82ca62099246e90295ad98a416c3b96e12b655a31097ecfba812eb0424312b1e0510459a5d90b19d67800615373b4ebb452ddd63397dd5d2ad913bc34d5e988501f8b223a4073e8077d680b7d0d7d971304a3e553d218a99aba9e5cff80ff324ff3d7e4310b1405ba9d0320de1aed41dc29ca87d4566ebaf6d66e8fa88f0b89d28d3a42ce845ceadfaa12281ab34a5ee30eec84eabc4aeb9b985de26e4714463304778afe29a5a5df8e6d248ba745c7496fde1f38700b04ec0c950324e08b7254be0935ed9ddb3d10ddbd5246cccb84a932319d06fb83de80dd9afb278aa999396f21fc041f038cf1b4d5739e3d03b975761cc2947103e0d67aa02fa7240cbcf534d8abc6f5e8ec8b4121911f55fb7f638ea9a7800077767a5791bb3fa8623462f755e70a655f3a39d358206ef413b02721cb5d0397a9777e675db3c721b6f4274d5954fb2a5795307b99de59d4db871e3c86f56d0f5b16e5b9a5d9d395d3e6c1f5f4cc7962b3b6f71a024eb38a35001e305b25c13946e98a48d77a560ffcec587f764e9aab37d6b4137e07ba2769e03827dad453f79172bba1b8d60d34c1f5a08fd5799cd9a97ffc6553e7ec5e9da7cc6c42454b3ea83fd8cb7f8a1bcf7bb7db21c39f51335eba4076f61e6fd596333f98f05665b3a140dfba9f46ea23656d318a1ed555b3fc4eafc3656d2a20514dbfa9ff51b175198cc97f8aa55acd98da96f514f67a4a91af2fc66c84c577a750a2da8f7d95b3896d4c45eb77e9d1cdb2967c4ad4d756dc3753a44d147c6ff4b79398c0a16fb11cee83d5c57e0acf02ca043523f614ba6d66f106234cd9ecc5a36b19e9fef9c8a7f516a5debc36adbb862baf429bf331094fb88223a17504fbd5c41706a7739a668ed1e6d6bd4d1902b6bb827656c38496f5d32f0e393ac9eec00c59dadcd49ac7db427a5d1318fafa62ee7f301ec325b29dd218b758c12a41a7550259c979b846138074f15ca10753ee6762055077995b6179b33961e670eca9f9e8565ff558cb0c9321adaaa558c80e80edfaa5b49d5b6894a29f6772511482af7b021186d7210dc8737b8af502937ee8080e8a0fe8f4b92d9e907f7cbef9936311b44277a057009089138008b5d40385671639023d73d59f90a07c88e37d82b0460486ceb357b26cf5a262b3571c7f7a91b9c61a3a62cd73513d7ac10ceca41a39cd88e3efee71c21237ffc50a1e9f0f9d085823977fee0d6207ad7b9e936ae4b411ebffcc2fe3b65d619141935587cd74a29a21dd93ea1637d3643b18603b19695c2c96cadd5bcbfbf7a1bb0ea7b302bd8928b47d1e43cf5fe23b4e4173286bf660073cea733a3d6eaf595077e484a2878ab611f151241ef980a6ee157a23f782cd33f58274e0c91c8cbb325e42ced53cb36caa7ec567a48327a81da7f3214505d1f39f32fd8863205281527b1eecf51c2623e6ca1bf476434226ceec2d14aa6c77a60806107f2bf71e601458ac719dd0a6ea358f4bed81803cc5accae63fd642bfe64c280c050b658ac240a00b42725145924a7ea7fb2b29cb2395d9eee1a8a697e536791baa914cbe87511919ccc4ae5f536e51e484448125103d21cf29bd5ebb9894621cb7ada6f75e48331a037519badc6d61266d4a909ac07c726c4a24086c6c7c3205a53be3883c8018042d3232e5936997bd37d6d8ba10ee04dc788ba48786d4b6c42f28af377b4c2709a9b17bdcd92add267b02066af2bb077c2649b8ffe6ceee10e32d4fdb521af3b4bfa39e3ab572ad76fa1672f64e53e752b343a7933af6d8b17429265ed811cfe49444819f303ef93016e044344a6f88981af1ea9a71cc6b0b20520e2decfc489a8f5605509359c130081d545ef2341d16fc3132e63bf144fe19cc9f7c64d8920b16040f972c9c5aae9b110a172dc4b60ca90815c70338927b6e381321ba5f2ca90430693819684fd58cc6f0bd84500a5aebf28daac1b5bdfa485d248baf63c62819a7353d0bc4be51f3ce9dd76b52713892b2e3fc0f38fba7072bf80ff0b7c1600bf5d2feb99863b04f672c7ed23b1697fd16358e0d64224a85631ac5cab8e02243d0c092fed89f34709c0fee5e598c0f7cd4430a9db87620c36ebea1d9a901c422a06a89b0acb14de64fea38d130f17d90a5e3e94242fbc0bf2b3e8852a9f427696d5197b18462e13e388b9f8dae7dc0a76e1c1dfa6222cd68524473362089ea60e3c8c936a57e9a829f7a3a5d7cd3d46cbd479f423d64077d190e2cbb6db9d4bdb60fefce801b6687dd747c26df663db879065a71045c1581ad863508d5fbf2b26aff6b26e78d0b3e8fc285930a759653d65b0950f59ce24aa0cb273f8e77a4c6cf0accd5d7dacf98f427099e54f5f31e0c4207422262a7bf039aa9f19f18688ccfb647370b6b7dae23d0a171503f06efe62366c9759cee59c0cf8fb159d2afa65b3747f565383d83a4784b21c0f9b7893f82cceb90d52adef2ccce1b56fc00f15645f4e3e3ecc05196754fa3a043b977549e81a261be2dc2b255ff59737f1ef8cc9d5dae3b2fb959324000dc69e10a8a2fe565ad4049de8c93a5d6c50f25dfac8ea37a2f91e54a9dbab14f39d0cc74f70ca148ba5fa21b387c7053d69b4da642a4450268e79c2182916776c174b5d488fd7f88f60a1db06668b6d4d76feefe4932379b6126a7f9aa02eb348a6f0955be7ab692d8aebb399291fe5788f533037eb95e9ce92d9adbf2a3498f15d50783e53223a082e7e61dbd524bb9f867dd9f98c99ed8be0f450f534e8dc7b3e070f8ca4240b31bb57753e025774a4e9a171bcf6031af877f2714fac8eeeaf6ff0f8971f097cb66213341d9341af67b7dc180b1fc48bc880f4f0520dd723b9502571e8a83827ab88d64b21f5f350e9f4bef21347f2f070da39f7f23081bd85e271e1aea3429b33695cf48a333c3ff9f96895228a901d681bcca3bccd238b8b86a19661d79b999d8cfd44f6870e9bd5eed1e7b1d137d343bac8539470b5021996d679c8cb1c580b92ba627b059aadd3850de173b15e29c6e13f30412082d4e7a17a4a2171b04b758bd11e8a20ac2b60d4b284f9f9a8bf1ba0ce40ee68e0ae70d3582b34713cd28dd37cb20716bef28fbbebd6b5f0630342c0c4fc094e5a108fa80797c06ddce727c67d17b713b8835d8b75f13609e84caa333942e268016e7e1f1f599b86c6e413adff37e83c0817b1df5881d6f2f625f77f7469190b52efeb25c3a2dca776ffe1189898dd5e124d2468e7a3b9124f8579d1f5f202e28ef3f97756fc71568bbd75a2e9d9fe137cc3eab5586dff0e9778f518cfaf71cb4954e3ff20efe74f02df0ab6a86bdbd3e883280ba3e0af5cb4cb71bb00164da441ddf06de29ab7403c8691ac4c9e7508c77af9ba6cdb9e828f7354ef3c8b98de0b572e277f79541c6900bb2caf94829e8eab66ddd18190bb5b99fd4298fe3ad71df74986df161aa7ee88235cef89b684c1eb5e00199a529b0701c4dd8c468983aa4f410085d0cd5b41368bc266d729394d19b87070a4455c915b4263b049c6772c8d7c67fac13f4d2a7c520232dc5a4c4838dece517db9de3bfa28e09b9d1ed8e7339af8ae9a3a9b0955d92e80a1d671a7442e10d5eba6c845641374141df5b52ed72ae50fc8a378f096c0ac7dc6fa2dd186033b282fe163701af17a3f2f5aeafd986c819341bd4c0f928078cb0c42244035330e62eba117333815ca6827070d7eb5961e392ba08316906aa87cdf3b6cc376030668708de70bbe3f5d6b3ce75d6b1de7ad7afded49183dcbaf257484208dc83e01a71cfc13ad6bdde7aeb59f7bad55f671de53bebac6f9deb56374ac7afba6c652f8de1a1a4205d1696b1d52b6098ab946f4757004e8524a2f76f50b98b09a51d3d967cddaee58d057da671149bfa4896baeb883fbc9a074524dc4da88da5754032b7a91ea944723ca17fad62eda009292aae4a9932ca855ceec842165541f4eb44fde0c2fd3083854dc7adbf25a6ab4665e80d11bf6ef5150d455542d77db547a098465e9443f5fadedc57bdf8d0383b1de75a81a10248caa54146aee27fa66d5010b0bd66bdfe8dfb01137be890de3892cf10458c28c481cdceef9312cb7731680ea67afa8f643af95bd239b5a28f14bb7ccdef40c8f972a58d8433611e64aee3a064fefce538b8f1b49124f6a41835387228171d6f4761344d3167fa70bfb0a7bde6e4e86bc4de142beb80c743096baf2f8c64b8aa4dd582f536a07682593f660d44f702821b58f66ef98c4c6a5cc0bb25cff7f1390270021538e3c466c42bb500f8e4487e2e748de388df27036ac6c637cb27ea068e8c301ee38c1f029e259dec7f681ed1cce412d4d465eff1110893196ef28cbb5ee94fd2c9cbc8ffbc2b8283830d3c37938ced91a4d6ed638a26c2848b3d304618ae3daf6ae1e64d579f3d8ca36cd2d02d5b3c949ad621fd1ef88a438de3a99d24f515e6b4dfafeb15c9c49351a46bd30fea491a4a2091a119accf60c2c7ebd99d68d6455dc209b9c99e744edf23d1afcc7eaedb3267752735376dc5bc426708412d8554876e9e2f73c89ce6c43141a348d63a60aa1c4eb3452ee25afd5c8f6867a1ad079810cd91fba455e529cea99be1a8081bb4649a64303e4a386df86716a3f3c87919c87f4c6ed46de2e7f45b03f04e6f607a9af8faf4e400d4c367504f9db87397d80149a53bb9b932501b6229748c52b3b112b2685a05ea34e3bd30cde7be4a53492ea4f9b2d69e996528f4c2e93ef8cd9391c60096300e72ff91828afffe783d94bf6668bf3c46fd96d33bc11bbff3c84b934cfcb57d76182b82858fbc53d6544df675772ee04585eb5590f822d55a3cd2b06846d79214be2e0aaf3b25e226a3de19f4f2aab08f82e70e617048d894672831bdb925964a4ad9497ca82852c3423b5a2622a3b567028880548452d3a29ec82eee28359aa8328c927da1ba715185b0dcb2d89d0eae0af204fa69d1b838e1c495412dd05686382fadccf1dbcfd3aa5cc11c5bcd97a724e890d3f7a056694ba98356b50169fd4d5ff190306dbe18ce51792c10c9ac04d85b09ca01e166fbc0f6d03bae1bf126807a4977781dea7f5218e768f98fb31fdfec90c7f3c424244934b7f28900bc04dde06fac9bf72db68b6f9da963f38c7f98ba692148f32dc44d7dc1f5103e6ea74a770a9ed8809f161567c8807c3ab9da81b1c862e4c832027ed35a98d520d94bd0f530b65eb7261e8961ca1ff75815d2fc6a7839ed0c1c417522a1d86b824e80ac0b1183955aadebee4ffa1c21c62e845424f025a120667a092a7647fd8e36838f09a14e0526a054d3cfb0dc7fdffd4eef3dcfa78abc2e949555963217b9549240cff113775c718a0ea48b4ef78b635c71c50c560e9d7bc42dce71c72a58adb2af34a6d4d8179738c611d426f948783e608263131232ab0b6862ceabcd4c76226a0e76f349232158b7caad745a37535ac5c332a284439a87992e39f7a1d8b3ba8b746df22d1ab79d03cb984d9ed7323041c358e98876226fafc8b22f5d327784f94a6b04b3e504f7bc5023f4184ae9a730277b24ff149912e0a5eb9d5173ded9c29b74ad4e74aa93e2b4f7a2d9c76fc8516f34cbc286ac916f65fc7a6052e99e0c92decb15100a7b31c00b9e84beacdff92550420c1d9a20335aa343b09b2656011e051edc1366739ad3211a4570df2a039970d4cbd9f6a7e8a45bfec981d14b7793df28004b805aaed9cb47405137338d6c3dde60457578471645bd0c96a83108436305cfd23ca4fb20ed679a6fe682aae109e34b70e65d4b00f419113d60622227ccf54f25cc7824288723a48c76ff2125454dbcf38f629285c5c95fc87883a7983a1cc1c356f0c215cecad34b7099cb08f7736a0fa93ea5fcaf77e307976a89a18b139ca10fb9124122e4b6a021f407a47742f2590188ab8a4702b5818159c785bd8dcd25d0ff49601fc5352e412b07b0144eb976062331b426708fdd6797a2c1c4d19cc57c6710fc2bbcd895b6a3c6d7f0f0a1c5f500f34db2251b429456490bffcb68312fba1e4fbeb58692ef2a282d84dbe9a1284f9695b0dfd5431f996260c0c2c04398386c6ed67d07074487e74e08284f7ea1ffe06e74ba55ab1db42d3537d664c72d29625f4a600045b04cab0ad1290451db001872b0fce2b3c19040b4f8cc6b3c4775ee61222fba87abdfef06e87c3aceb1121cecdc0a1bf689a1cd63fd5658c8aa7b83f2cb2dcc53e004e9b2447c2911417ec8972cd29168b9965ad5c94622301456825aaaa0e17ad1ab4e540d5e6ac1b49cde24368db15e3a49613ca9b0c2a206b56ecb57bb2d7327cca9c16d858a70157b308ace2dd81a958c067e02c3b60c538bf571b70c063b02ebf938a450092b514932d71cb313aff604ea3915c1492dfa326a7de2e450107a0a3370dd8a3b179a00ee9562cecb259cd8cbcb45e4cb69adf8e5f183c77675f993d5b89fc84b0205f5eab25ebfad73d6cfa43800c1f2f4e5689e3cf43eb6b243e4e40fd93e49b7b7642d168b707227f9f492c4315a5e8000f8ecba13aedd1a09aa0eb8c8144f3261eb447019b56e2377e1130aeedd05be20e41aabe0fb17bc36a3b010436a57d961e4edf73bda76ff2f56101a0902bb948743939a77dcb00cdd1a6829f12a4c3ccd4cb6b1255467a65d5d4587a0a191e32b8fd14ce6f195c434d34e8f87a5a63e3641c831a43abe31595bb94ca1b75e67efe5b40e7a3747ca9f08a173063c5c51f9aab83bf47592d4cc522b066341c3be6c9397cfd93742775e0d521dac9b9745c23edccd4119da54bcbf0b2cbd4b6fc5aac4e8bdb50b836a6ccc1cb1312ba31b59c96e530fbc41b37b704e6faef9901de29baf666919bf399d421bfdf78b8cd4de3842a53ad61d1a3a78bd2e37be52e6a316bb0e712da2be6db952d748685173502582852af6ee1ae2cdcb14b4f7fe1fbde1c063e202cc8db920a9ba925aa09a43483b9a7ae27934964cf9322b3678e8921bca246e0e8045d5ada02703624c4414e48e2fce239ee2d5423c58ea61c96142652ce051c000bcefd2ee4b450447f1a8338f5132cfe4a2770c2d2e1f4d0b73b8500733c2768e36e3a28c6505c9317c88f87a95ec7a19b7af0d1384410d7055bd1a3693c58344590e22890040b8548db9f68a4febbca7ca4f4c991e7e4f2a9179463c92056212055e590594ab94e85b4593aad7b5328c97fd5562a6929fd70c407b17474e52f6a73f61263328c2da9772516e6878ff752bb1feca67b2c944cd296c07ca20f61a7d9406ec8cca1485b421f8a0ff3202b116af87246d530605d625bd0f58494a2f9721e0d710820f62803999257c16ac60ddcff386f88a0deb3da40c771b74f9eb2ce31fea800fa85ef05179709f170968baab63767bd0e35c77c1a098bafc317d4e41b600c789b4c3ec55afe859e963469d3b81ece8fd59d7fa113f1736fafde58e69c8c3edc8021f68a47441c19e37ad97a4c2e10e4107fdfbb08b81964c6b7ef33eccb70c15bdc8866f183695144dc2b02329d91b0755e3b6b12fad38d1b1926dc738242498e825126e042b8e31c3d462bc34312f5d0ede9cb41e65ab2f49500e9e763cd50221fdd2236b61d0a97448d4726b028f937b0c40ceec5fbff91c81c57ce95c7f1122bea9087001e5a59afee0f22e23ef460392a608a02a6590f7549023a4902453bbab424ac73916f676173bd4be6df0920eb813c147d21eb05558576cb2d93598b605c4453a8f9ee87f499e02a4ec76d00235169e2e97869ae75bc8c54084ee65a9319d0bea218e6ef31baf4303164c19701650ea9ddf3a5e0910d02dd0ae5ac1920b5960236ff0fb25b095391d990a9b3b8b7339868511e8a1c921a9f227226ac05a6ec5729e37c996ae31647f8079fe80506640b4a7ab3bee823794bf98a69b3174f0cd59f1f0b8e2f619bbb409989430aadbb5185ccda568c250d3a90b52317afcd741c3b56fe85c3b9f0bc928ca680b857aa18b459bf399a031a0f41204d8e1b542004481708cbe905d22ebfad7afad1fa7ce8ab3e15f824611dffaff4e8944b588b1f54424ee134f119488edbece0425d5cf092a41926b11375896d95225b473bebd2fcd49d4aaaf4e4038e621ea02ce54f4bce4f165ecbf7a08c361481ad93276ea01b02504f3fc257b01fff0d0f9a0f5a5c8cbfc0ac96cc0f9001aec43d0d281ff3dc08a5f5f4648bcb88b999c97f428d042b42506f43923eed214410ae53f087a31787bbcbb6dcd8ca0869c11ba4b9873cd190f32367ab5593950dd4d60e3c4b65fc2ead2792029fe244755c442bac27a7ad75aa60ef6dc0e7b9e7d574f14ab74cb027eba908958039c8584af18d404ce7259af82c503bd32feb43a73488ae1ca2490d86158d52fc48231b8650c6eaad162a77ba1c1793df8becd8bcf9f36d9f059937c133976e67e9347fc346863d548fa9360192324e07cd91344b90a90f00e1d1fa2c50a2c4841526bd9efc722b717016dc2515dd83183214464a8e971adbe4a83286db70f4112df93a96b7989054980a014d3c3db8c02b38210243def567940e4c189dab50138585a2d13bd37d6d1e2a176e2577d8e010bbc4ec1cd49018f0f821e8896922e00f49cccefa9fa4f8af615239fdcae30c6ac301d021978e8a0a84d377cd5f56747075fbb0c28e35603a21fa9ebf0c2037c881915cdd2f0163b89b05bfc68aa70f013b73247a25ae8673525403d593a8f22db2614252d741245591ece5b444c9e9d848d39af369d9de47ee01a22234d80cd3044bfc51cb42745f4983f3e6835bfb9eaf09a9094e81204ef587967c89151774330c4c0bb0e13b3b4685d9297e63e8ff2ab0410a721f45f4f9a91c238eb9bdf109c6738a3784821138c7bba672ee68bde9419324a9a7bafa4c79658a14c64bae5f68d58b8d72d2b57520472590a48e704ebf0112faa98534365f47e3df040ec76b81f36af1872b463b56f423c9ee632e9e9b66f2549f5602cb95ece6b05723bd16c1a639b8ade8e757d6cb5bb804c6051c8482606ff2b3330a9ce4a48ba4efafba0a7958cf4eb25e5bf47ce7eba5cb40721af6be55eaa3297b880176622492be85ed029f060eb19ae0af5db79574428b93ce442dade1f8d2b4bc5e77a21624f57b0f99218bf135ed764b6a1faac25ef677568c1af3ee730af90ff491e5655eb4790919cefac82f1771cfd20315c5ee5f154e122181d3f958b964097c315939b762f9bfcbe8d2c1cd8003b1c35354daf29925ef4dd84c0d928d2f4b0b7326c72c18e8959193e5b9a4e2067eea66f20b4a530c8544ea31c7087244df3e610aaf27d0bf150f1e60a6fe280191473e8c9b102db9b09157e65e8e5243d9a72467d806a1807f3fdc4584e1482b90f17775e2531308d5f5b1b506e4acc67abce3f6bdd3c773252b8f00fd918396e8e2eb616eb909c6b61dfe84234f4dceb1b32eb3a3cd858d6f9ca71dd6ef8fc2004422ad6fb4371a2740b403cd54e3ac3a5590b7a3e8e56a15b6eddea81d4e5506a1910e6303f0af217b6da2e6d37df1307344eb0de69403ec1fa9f7121e9ff5fa7d8a70c343a479639c1c92be3f3fc6babbb8a095e41485c2fb8bdc989b61a20318c542ae64d62ca9bb811c145fd4ca527546be41e34470a758255fa8f562e9bc9284e07a3273069c8c245f66fa279a52cda802dc3f9ab5bc91c55b53f58863c702955efcdec799fbb44f7f3f1a9991bc895d38bdad836297097b72dee01afbc730b420bf6a9dbfced12c7ac5709783e28f305866633925d597132bb7b20a3660ffabe1b044c08d14794f1ebf01490a60af4c3b8107f57b82aa02f219e2f889e78a0d36fa6322060451d9e78d0b67a20d91a2ad82792c7291ebc416464f1d41a262b5b5385b652c6ce02798e4e335d73928fe405accf2997391a1a343798fa02a9e4dea761510cc8b89e7896cd650620f4b4ce2b4f0803ce8d19c80f838317160e2a10a419fa3e2ba29092c5e72a0edeb0cb3ea3860a3771f04497964a2ccb1676602942a703a8132bc50ff499fb06b1ea803501a8611f27743ae260a45ed9c78612c41f057ecf448e0f5010686aa86d24f481d299e056ac808b38011301b2ea401e39103c116b7600140ce8ad236ba48dbedadf5cd99ded088c4e831ef0c755c35b04fc627088849696d665bf0ab97216f8cc015dc271eb9bdd01a3106e10db0e1d4de8d5f07847bc9e8c24c660660131c6cf7b7109bbcd2b3d69cbe97ec4f3ffe1889ca478de0703c51bd4cae76d3b79f41adc48506441ad70286e62a4a0b091e2ffc41d4f74513a85e087e0b7859ed079e287182305821e274393c722799c88c30b5524c70939c1851341628cb91b8199c36112e6d227e1e187a07724044d33fc793cde0d69e28c6dd4c428869a984dc418d3248e249a701141b923619a8c628c4d8ee0f2ffd7453cdf719eef424c7698a82c21c312319620515206254850728290922d94bce47021678b1c2c84c3471c424a2a04bf0dc8f7a094d4ca9bbe50454a2f94a7ef777ee5412e7715b93d6101f348725c7ecef35aa8d2b6ffa3a81dbe640175f2a9cb275dfaaf64f24e2cf9d32c2b9a8a0459f87739cca310143da73398c48e247024f94092200fc8c20366f0009d07f4f000d0cd1e3764dc5ce006099b2dd8e4c066276463d9c4182952cc8cf4ba6eb3912de0138d77262e87a06946c4f39da8f3b2acb391e0275ba4a4f6e8c469a22e6f91265ba4cc925026d9d3f1cf2dd4e3c8ef4b1e0b97f7166e1f38235ba8cf63e15d8d18a19a2f54b36b52a821385238a2289999bc53111846fde8890cbd2e3b7942fe08890a42483892061c59c2910d1c19454a0b3defd324b8692a52fec7f292e7bbed2bad68349a8a0904b7cc711bc5ff3f22da117be447a4726c6c92c893d65d96a17e6b998ddc801b71c2080e31521ec904825986383a64d1249873cf909e8ca43bd2939150a42d045f7ec97bf2793ce17792e7bb494daaee48af4652bc63793dc201394ed364d6be1ce60dd4c067017bf79ee7ef49de8ed14c5e1352d3341901295f5e5c729867248b647971e9dce3b890b6114e2923799d2c444a29a990f2b9ad44f2b6d7699a36440e2129af44ca3d1f6e9d4982a770e39b498a8d660bbbff9d8d8329fd1b79cec47fb4717496f0fc33e01396c0894fb67704049fec0d6ea4fffefff51ce6192ba298a123c69897cc90417dc29952fc7e47da3163a9ed0b65e76d75c8ecf1b9820c1a331f2884648aecc8e81023c549604d8c1187622610f3444c91f8313f320982b90483468c320ba2f3b68f815981cc42305a08c609cc8c947c912f413059a20e9905f12931b4841a325b0204fb97bc803d5e0c98953881123c529ae3bc8f44f2c2fcd28317315e8e08d943880a8484421ae05207a5691328e29f35964a8f9037f943506703b515b0cb5ca994a517cab0cb3c1e9726efb433ffd726efe48db26e317927d93bea3f8a74ea3c6e7ab024f9bbb804e9429010042992e991d520ab40760446077605a683158994a6498efbe799e471dad665c9922349a6fd6d5b725c7e62a3c9c81519159b07734c9665992673e9a4411549e974db973bef93e0d669a8956e53919a26b3b0cbe1a9cb6096bcc332c05d600a84f00917c10688915a5101b38826cb7224121a13d942adc4ccc8ef6c640b05f2fc5f0bb542556c640b250a3d2f09df765e24a240fe20c7e5e8058d29c698b509e4f90e145d4bdc3c2e1b31c69b45bcb93f5021ab8e182d33628cd12a92e5496b96ccc3aa41fdee6c16d1368931da1fa1aa0a31566a54239eafa994a87550272dc1cc53d7081f877f92f0716acae785281b31d31ed30c0d9d21fa2346aacb993ee0e91b7f7971d9bfe4e5e5e525cb72384d96e5709a2488a0ba40e580da289748b5a0116ae909b1a081258d100b172c36c4a203124538420da12374708402568c105ab9620526a4c2478c544805472503b2851090378080408030e208469c4246185144198a88236a2be016865be7b610a4a17e776f92e2b930dc38d93d16d28f4230cbff24e86d4c488affe7753a5bfe3c49859fd7fbb784e06bfe81262eeffc270915212444c41d440021cacfeb1b119d88192274f0463c32878608121aa20721a810820a020a417811849350103884e418a41821594508e630f3eeb95003cad08037420de869c04c6ef9240c5883011060000e2dc08bd002741630240404198020230444144008800031a4803e1450044db650ffe49f1c016e9f2715d04448013109104302bc0825008b50026c080179501a87b1e1b2f43ac937b097fef35464f83821041841c08f1f9010fac10c8affef6d92fcf4a103f0113a0019a1039c4207181d201432401d1104f27dc76300cc072d847c28810f38211f52423dc411ea618d500f2c08f5a0c518a9ee75cf65d06b0912e24109211ebc08f1a0f1c0c28310a11d8810daa1053b6060079a1d7e8891d25a60a89510cc5b450669c942a12b424d422ba19430a4a8e08aa1142ec62b840a60835001465080985001061022c0144204e0224480d28aca933c50046e94fc5168929a46f27034d9694403f02234802e34801923d5d2795d488730423a50a175a009e90013ca218f500e3508e5d0450e301a48d2648bd6912412b27b0dd2c84c3bbd11eaf44fa8cf13420816982e73f96db9dbfe7b92a97b700b72d254691b814ff236da9b4ee77d4c66bc1afe6149c9c788125d44fe342f92059b5c405108004528190280fc27fc6fa8e3bf0c24866e5023523334b22674c328468ab4491048b8490f942cbfb371464237846c40810d271b5e4236fc1042912384224608a589108a6491dd0349de7e1d3e4869e0e99f848f1302551163548921504e088480d0278fd0a78bd0070c7d1a108a6fc41895c45004435126a4653c033fdc3e267a46b6682c1a787a2361cfd7689245eb3619c8f327d133b2855a5101f9263afd932c034f6f24cb7242d0db124652e0974edd2665640b35027308ced04879e2c2fddfb6c2e52e3f4905043243235f6f616792e1fedeff7b8ecb7b055439fd93d33f41426a5ad6449da781e1ebc8904652a3fde507e5e9cbdda679783e0f9461e99ffc0eb837f0f44f4020ffa064e26da3cfdb1bc9ebbcfd52a7db4edcf75c5260f7bcef8666098c57737a231c3cbd1124966023c634f810a3fcd0fbc08feabc2deac3491f32bcdb9ee080303711c7c4bf531263c4020d258860c7e37546bc90e47dfdf34e5ca9848622110d3f9c218e18f919c0883c5f7386f00c2a14ff5308c29ce1478c5530c3193146be89cc9045fcccd0a4c50c33463ee6588151e1838bb861f818c5c8070c1f92e26f0279cac0478c3192f287a4321c21461e1c22fcffe364a8235264502393410a3230600c6f802d9d7bb0a5f3bafc75f27b256328c5530ec14df69d6de7338132f4ba31c81823f5797b54816f32678f3390ec518a3186403af03dbe874a947af001c61123a5071931ced0483d281066aec7125e8d1e3ee064d9cbdec21c66598e0ba7c9b29c2ccb09031e61088391307cf278421e5ee4d1f3400018de8894e68d785a7ed324cf0919825e491a21ffbb9141346fc413a33f4627771989fc51f8a36d224950f3463c49c080040c40c448855f287d41c9178af8c20f3ce8c0430378607884f0c8c10b6a78410c2f18f1824a8c51cb9a6cd1844850932dda0a48b5484a450a915b932d599648c8924442ee3c92e176ca3ca5adcb24d0c4bbcc23bbbc4dde29dca44eb7997a89fb11cd4cf764963377b4710704eeb8b943665af799b448932dd48a8a9449ec90811d243b4476fc98a30b64c4d136793939c83fc93014f879bd0e3662a47e6763a9e30717b0c0051a70c1e3c2dcc215b6c0468c9102bb8d1476db16445b08b2851f3c79d49974b2e4f1384e0b56fcd7b500cac2199f271f0b76602108588800168060215ec1095770c115b8a869523b65d2f7251328c13cf2bc4eb268afc97fb2719d124af3b6159260850858a1a60a65a8c209aa60a40a4450218f18294db6506153418838a6e0c61476a64004c7650e2aa1b4eec948c10252a0a460041d48a083c78a2974c444010c2588824c141800053ea08006143628b8c4182919440b41ef4606f91b9981cf3d24e126ff49feef490ea9d0a4b71307caff4edcc6bb7cd21c0c37fd5cbefe4c9e1776deef78489ea00635871e73ac31c736871173f8e004203841064e70e2841f4db041134ed0841cfe60b8b304b7cf236d5ec7e375ff4ff2c2cf9325930c9fe479a5cf5422799f167e1e8fd434196613d80da1f8494b2b30010d2680c1842af84b2f945f7e8e093ec8c1871c2490c32487ca12f28891d2bc118f265b7867fa4c5d82dbcc12ae250880064ab880129048821a924046125090049b2fc038fa8891f2a4967d9a0cc1fc9c0c33cfdff75d7e5bd83d0df57da7b3819becf27fa7f0cba5161e070694c441448c14297f8ee65d66f9902042c210241c71843e2275e27e677b52c6a9a9f9cee3b20cfba983a148de115c8ee0430f8c0003233031820a158a308222401123a591f2872090278d767ed93d994f5ed86d21683ae9ffaf4b5e9299d39b0e11dc20c21444003204398630c6102e308424e03083919802470ce0e022c64869e1e3845b673269f2a42575e278f7dbd749b9d3640be585f2d4652fec366da57b8e424276cf514fca9d8a3c02092dcb9c89f4799d7fdedef9cb44288d6fda8fc23794f046176f68f186cb1bd60a42d88010b0206821082308824c107e08831b6fb881023722e086e646a6add050d324186ea4211468fa42b0db92e0ff79bde765f7536c528e421eefd369f91e3449cefbc2cedb20f79f276786c82eab689acc323479a62fd43cd96964983d4ecb0f7328474c64a669b2e5c152e6388fc7e35e4bfedbc44120bf9347a78ef411e93612873181204dc7632379bed3640bdf7e7f1e118d82a1a1b8fca8f014f3fd4d085226ef24bd5052fcb74ceadedec0ac25f56da310942c3334f249086aa79d65391aefbcfd3872232229504a1eef8857d3fd14de47e441251d0d087e176e4c788ef1be77a2db90f01cd329f96d06f46abacf14c33993c7e4f303214888317edd46e2f93b71a59209ec369208dc402ebfb87c22707b52ee384f934e20c865d2b69f238149c2b92f829365bfbb0f3d2f094f4ef2ffe93cdff9ebdfebf4feded6f9ee3d997f225e0e132e833146207850450f527a10798005e9c9801fc53b130f9ae08115c1ffe497bc2df393fc4c70b26cff12fe9948546343839364c812d110266092d8e4e08844598cf18718a3ca1031881db0c428e2f2f662e462ec40063e4a88f19384183f71c4f841428c9f23c4141da891a203338c10e3a708427450e486fb9d3f52f27282ace1853590b0860e22f8512da088b47bb2acf348246f8bc0efb72feb16d2ee59a38a18bd1909ca246b5c6bdc358058a38728fa9ee35d1e89929019ff24401357fa4c9225c6c8851cb0e17ddf4b2107447290e540c6f879dd2622ed9e2c23ed1e1c88010746887145c4659979239e177d1e0e4a110733839907072931c6a8861c306a9820c698c51435788c5478d29cc3700ec37f0e1048b7dde08c1b64117b64e71e949c677903fc79927f9893061f11270d325ee7b96d67fb4a1f662e6ff065d2e8d2788931ec3c2f64e1b81e2f86e3f2bed4f4f292e3d26d46602ec2715926cb726cb000349e80461694570333e214343002153458990114628c4bc4941978310326ced8e38c219c119ea173860f32a823c6186a9b14853dafc9164db6dc482a97bcf0d3648bd76da70e464a19c4c4008f18b071c41130471c2129fe9dc765df78bc9164d13479d25ec6440d4d4d1218261c178303c0e008305841a49ed3b9f340edfb4e89193330e389192b2fd0c20bc078c19017d81023e575608ed132d5796106b5d23602b9ffb6ed816096524bb00574019032be50c61b658437c49432bc3280284307326c40462643a60579b4008c1654a0053163ec1123953add86446636333639ddf6955858c00ddc348ddb3211cafb7e0aee6ddf974e599b9a7cd01482260898bc93044df23f2026efd42991d48aa63d29832cd9a4b369529699a6c9164a6f3dcf752ffc9dd26b2eff8ed7e3b5689acc12a4b4d2737acbdd261fdc783eecf2974d3a23f0bf2eb3ec787209678c98316e60810e58c05980638cd47799479e7e142700401a21c8a51021727f2091295f6ce8c11a7e88cfbd4e0d598851666f0505a86c112247d4ebf007812135a870af6b22874606e6064646bac81efe803474017ed4e90bbb4fa2944949fc7fa106e1c4187f24e9a30231caeca5d22c9b3b7509cdb2b933648f18e712baa453c2ff65c505f480fa7925efeb9490b652fe72b26ce6bf2f1223e84682361f6eddd67f2646500db73141d26d380e86731b93184147c01841463a538f11e4004e132388c6c9a5d8898d1154c43211718c202297d6ea94bf0f467b5c0cd86d4648bbc9e77ddf10feddd69f774a783cae7f61a784e34c44788ef929369c9e8c041c12e3a70df09f884eb7d57835cfe91c7a359cf38a0c7971d9bf84b47b38ce54439bd4265513dbc46a729b5c4d70131084810937cc10229d57f3e17fbbf36470a5266c7232abbd2627b5720068a656dc5e90cce99fc4088a99f5f4a737c2b96d24038209bf5c8a11b4c4760a372e7f26ee26fcf2cd897b31bf376f0988e4231282f98f843024af7b4ef2ba9b2e8f72fef390d4cac4694edc8b09b74ec9ef70796fdd687fceef6c3a7f84cbdbdeb8c9019ca6e6d4c1c40852229332683282536343932353a3c401a2263048443be8514341d3144261d840e42fc5141b18e61168fa0d8480ac912d4f7a1e993bf7a0269a2f202137708931fe00058931ea0ce73baf266707795400fca87c13636c8012316261444c944016038813a0014358130618212fc0018c8ec084be501363ee3619a4ca2264f7dc94428290dd73572841080f2e9ed37aeb70e001071e4c24cda978e1f9ee06323e1353b465ff0ec76512e80519a3c80b36c41845fffd8e3c62f47a77c71c31461ddc01468c113cfd139115f1fb279fc723ba637413c13b6c04ef0022c63b6c8876ec61071d40b0030d3bc4883d76f4c418b928f438d08e23517a618e01258bcbe711e1741600dfbc25599665a2ee39df46a2ad94452510e49bb7c4241265d9e77d5feef24106884a94cc90761319d26ed233247f2698fc9960704adb08ecbccdeb1d4d8c20ecc26204e11841d78d1164816c1523a882a88c4c07002ad818a31531c60f1556f426c40b03164060478cf143460acab8e1618d3794f8c013365c64200c1dc4183f5adcd18095ef069717c41841478628a1052d8068518618238a0f5bc4f1051274a10325c41801e08508f8f8c891a9618918e3270b63f040157d90000b578cd1862f341c4a30220204a81063fcc8a1ab1b5070400a29c4f8b24b25182f27fb307f9b080966993f138c0b787a23282d53f082f4051344a4508518e345a9d9127adeb786186394c228c638a94aa9d9d2f1789f1e81792485192947602e32041d44e889213a66c02446fb43197eb224837ca6fe5ce60d6ea4d2bf918f498c3b7801688c1330f122823ee0715bf6846fd291b2e4794c0220004aca3013098000a8dc75c9e5535e899ff8b9891f2c7eccf0e121463b6274c2139af4bc170e61821461443ae62842a4b6f46a2c27c411c30ddcc20c8261f7deb7331249f5641211d245aef46412114948a1c26dbf6512528af881f1c212116443196e90827683ce0d5b503a9df7f1c8b07b1e4981da048e7697bf981b84b0953a7fd06443cb8a8a08dc8228411342d06d5ce77530f163448c18d8f21706f1a42699be2db304bdb0db44fc896542179f9af8794288af24e5497fba00d91092e38d1841334650123182a818412d31825862480e2b4272f4808e40126391253411638c598ca09518412a31c61f2020e047ede75e47caff85e0f685f9e351021f5166a5fcf1482f7c90114580888835430811846c00880151441bd0026e40408014f0c38d5012e411b294b788739e142244aea894f23649f15cb47f270990f3760862911899d80134f3b9417c8208df3744935d5e5129e58fa73365598c1f3886f0039400100202a004f4438ca003b4808c1c5880049ebd719d7b500a71917c23c50832c019201f6250630cffc9de42d29639999e124cf838451e078777bfc19fc9cfc9bc803d9954f2bc1afa795b4f26754af8ef6c3aff3dd4df79a290cba39329a6c8873443b26cee7ce9148a443d99f479e18b4b8f179365fc7b3c9d6521e891446116f14df4f2b2a2b249de47843fe8713249ba2fd9c8f07c4d89f415f9bed7b9e342da4db28cee9076132eca32d2ee9909c17c441322447ea68d12c48aca134f046ed40a28ab5811491650c5882a248be8a445220a050073c051871c709811634c028a030e2a463bcc249e1f8e9437e8786305313a8142869c09343d0105f546166f14894ea0904f404109a18e9e238433628c516729040cc408c3bfbcc16d06864810d8c809020a8270133bd3076e3a5fe6a4f6381d84941829bed5b8a146c88d518c91db463c12c68d1f110cc1923c71405023c6cef4fd9603042d22e5d53cf76e7e40861fc4e00753fca0c90f7ef8a08e483dc9db2c1c86d29c745b93cf90368010613c2640afe613233d9d4f1095366e8c7186ca32ed094de34cf9358ca4bef366a47c8f87e209ffc4715ba8848792e09620ff9d0c4ade659e3d4e7bf279a404330fe88df22775bacd0b75961ec8e59085e51bedfcf949dc870ffef63de947a5a736d2163ad1b42740fe791d8da438d0931d8c544276def66d5fe844d39e90df72eabc4dca4cbeb779c0df4e86ccd8c8649988e39ee709274fb0703fca2d9e0ef83b9b0e8ca43c9073bf75169e69246873738ad946de77a3b3c5785e0e4ce8d5845e8d57f302500fa01d6204856204a5c4082a408c2002c4081a408c201d6204e5102348003182021023e8478c201c6204010064438c20941841a018419fcf1a62fca821c64f1a62fcf411e3070d317ece10e3c70c317ef888f15386cf1862fcec11e3478f183f6288f11386186d889f12d8000734b210b50fa05103992ccb322cba37014d8bb1480d8a10a92e530331e208cc2ed8974412fb035b68c082188350421385af43fd13a176b68fcb1bc9eb4e9c57a240b0b46d5c8994354d9648262d753c1c4995b6d00337ae54ca4156909041e41172a5b47d176d2a52882c6da1287c2ec84a690b553697b748883c85cf259184640941d3a7699aa458564a5ba8225b4edc97b98dd499be96b0cb5bd364969da753dac21c6aefbf8b34f95c6947d33c214a5bf86d3b42c80f4d32db68e1c699483032c60824469005248045ecc924de793a064bf0ced372c3400d1898602023a581dd86442b791f18769e9c3143086650c08c1923a569d20b358dd32b5ae577f26825ab502fd823c6cf5391a1177c3146510cbd8007172021c648e9ef75f8cb30c350ff9974b62ec14d671b75a60fdc54bcded1700e53c3f33520cfd7b8a0880b64945d76414e197594a1468c657411412565f494a17d193646fea1d77d88901147ecc92432cc88f20344029d0c97083ef93269b4bbd7b2337d3208d8939164598e7c91e0264f9a04bb2c29275a4f46a23df19c02f31149812b2ca75085650343af26f46a501c20cab2100bb4a03bd20b4d5c923eaf7f5fe2f98e0540c448016159810b5650b3021b62a4347eca244f87ea543003156815d81865429397c4a6389209fc24296842280556c49217822878020ab2400115e30b62e0408c2e22a5c9168eb49b943249669a265b90c83401c5a84ec0478c91c7d00942a06d2492b7ff339dc00813ecc0041c4861bcaf94fbf73c1e2761a8d1ce25d0043f4261882114c60662d4bc5072ce0b79182b61e81002430c31c68f213038a05139cc339ae9db78bed3644b92ff3eec59eae4d20b182a31c62fe24022d324f4c519f18b1e4a82322729223b982fb42f96004d540c7df123464acace8b2cc418a9279e0cbbc709bbc7c931dc968978c1458c91e7182f7a628c5ecc1b2f7ec831250003157a1d129926dd064a70939f47811ec8c1484ad3404d9379db91fc4fa50cf2df1b297727ee815a865be6919ce769aa25ff280c2225055a95655daf933cdea723c137914c4c24a5695de6b2490a8f27941eefba770a4ba41f25c1693a6f833761d6f94f47274b49491c2f87b49bf01c93631420821e624409825204ca0e2100021299262d37a025c800810f92778c36ec20019810e0182308cc10299d6ee3365052537859b67f27cb78088a4ae07fdea6018115203812637402050884f8001df10332f800e8040ac959ba21433c50478c37881e28c2030ce0e2095cc4808b1670a17161c41664d842093632d338059a349969d42993341c0a7c9d5cda91a20a2cc4185f384d690ba96e5be2dd7821e7bce719ed70e301e5f384e1f6f17cb9db641eedbc7fe77b1cf9fdd66d4029382024c620f89723daf14aa29e4ce2f96b8ad49d2c0bc10dfcfee6c90ec17ca4db84dd93403073320fc8014bf9cb799d7c93c33ca3c51c320b4d9e1668c418b5a822ca4c8b9ca805057e544803270df0c8a2012234f0c9401c313a814266208c18238544a6091110fca8efc352e6590486b2a040dc220b95204edff65944eab1a88302b1602384c58685b661016e20b861911263943cdf6160093794c6e3759a4625125acb287c2e396edbf979e4939d2528c3079918e96c453c2f8773ce068e18a39398824426c6f852a4f336d0c4ed8e86f421cd736e84ac50811517b0a21493b06226c6a892d287197d74a08f9e0be8118fe46d094ef747408e83e1f16a606cc0d31be1e00d4dad94807974e37138bbc9f76197779efb24327ce6b927f3dc93e1f99a12693701c3ee778670bcf3624e5be6fb8d2b3d91b0e76b9e2b6d5f8e97c39f6fdff73b364c4aa419ae93c33c53227d45be679c1ce6199ebfc892d3f73bde06b7199a11988b3cf932e9fb3033796e774ac2c7e1db0c58520286603e02cec084603e42012062d4e3538034443e3e02084d60831fe575317ee688f1e3041d9a10e3870972701192c00a62043f107c11effec9ce5af4db17c6334840a3c02d7f335da4208c1835b0e50008a0f33c508299779d0703e24103794011ffee491e922ccbe1f13a2ac0a0620354d829eaa8c1142a9802670a069ce038a11163a4b4f04191fc7f92c32ce3db8c26bba72269e76d2bafb5f0713a1b4d764f456a9aa69db43ce51f957a891be1742446f0c5e5a489704239713714283b0fdc4c1e4bfe4c30f2f38848ea495bc8e90dec1e9419dc9e7cde83de68cbcfe43521a92f974ad9c4bdaf248f3822f37c8ca44025c2d709f13c8f4b8c43c8304b9d6ecb32d8e123eebc1177ccd8c922ca8c45662793ce3230ecbed3e93650c94e4ead62d4a0d8f921468fc331dd5103c2e8749b4eb799b2e8bc2779a0a9894925c2847d44aa33e9f07c4dd8e37530218e14f7bb03eb88310601b98836a0162970e53f8fa4224f5d0665e8ab23f27cffba384916afe6d3be9418b50c817432478a3a22f579b24a7146e4a468927960a450a172985f725c4c52e492cdcb8b8b67c45b40170745ba01e923dd902c89871049009c13381c709aa34fe88831b6b468b285b7741e0456362b3061db6273d982d87c183961948211384242070a3a5ae834d199d1194057a3eb5007e299f062fc114e061e05ae05bf21beb2a1b0b7d87b17a1e3887145d364df5424c8e20446e609c9228fd8c2ef1bf7792ca40fb7ac85d25a281349d2cc26099a151c8984c4d1f138151b4d45e23cd7d2e384132a365af78c905cf64a9a264f7a5372147a5ab2b080602eb5749e12d942692b1c972512124763f9bc0ddc6c24a5514d9eb88f4553c2bbac22b72edcd9ee3ca9811acba6c98ca2a86cd164f772dfb20ea28fd03964373209b2295bda16b40fc4182568e26e64cb775e8d8c99912d948ce45d764222219d50b1a1feb9bcb399a4a04a9b37e2912b2a12147d3f0a5b327f1289a62723a140196ea51516158984b49aa4be0f339765f7252fa706f46a789e88e7e57ccf3f9b6e139a6cc0df3e2f11f84c016bacaa30fed9ba17563795c0470a56bf305eb16abfddfb273de51bd3870e8db165fd55a9b6f69d1875f28902c5d6735b5d9c35e7b6da50b02cbe70d5d755e9acf6d2a029cce1a78bcf132ccbb16adf5a3bc63e735c3a39eed95af5c2f4bdd309f6ff2b9da9bd305eddcb1a6519976d3e4db0f4c5185b18bfb0b678dea3974f545dfa8709badecab1d617d5dc5ad67ee4a86ed5ef578aaf6e696df528cbb22ce6b3044e67b5dee257b5ebd3c79ab810f928a1d65ca7b53496af0b671d8aba21fd9348f149c2be16c6b9ae184fcb697f172fec68b21b97ee1347ce7d57754ecbda17d77ec5f82001db17b374edb8dafbbaea3c82c56bfd8b62da5ebaf6498dd035ce78de8ed57ae5b9ab107c8aa02d8bdb6a7bc5dfca773f11a66531bcb59e94df5d596b08bcf6c7aecab230bc2d6be6519681db169af0078e59f5abcf7a2fac5bba6eac8bcf1b955e5eddea6e8bf3dc79cdc047086fb5d67af73aeb4535c796b01871c932097c8260dd0aff65e1aaf563d3c2dcc016affb6d652dfc98531c810f101e4f8bede4dca2f3ba98d6b01471d9e2f3030c57d8b4b0eaaae6534daf157c7cd0e7ad16d57cff6fcc72ab8dba71a6d5d5f1dcd7d5f31a6559f7ec878d4d3756ed85359637cf5863e0d383bbbf627cceab5ad56fda2fe501d77a3eaff2c4f8a97e8bf33cade4b3838d613c6ba5ad6571be3be5c04707d45aba7fe597f5d85ab68799f479443ef05983575c556c625b6b8ecd8be500a396ee96656d6b614ab7c541dd9363acf6af9aef6eed0d7cd4c814ab6ac62e6acd7d5dbab2e273038cb3757db73c5bd8d63b5fe093c655cd3a6fd6745f7e73bd36d0d6ce1ce3986f5a654ef9078d5e5dfd74e7cba9c62e667d6ad0ad8c696c6acc66dc279e2e10f8d0e0ba2e5d37bdb85f98a6f839cd053e33989c5af5edcdd6566cd1ba93651f0c7cceb02afd135ff7e669eddbb70caa0aabd8b52e7de94531c62f39fb1383bcad5d656ab14a6f8beaba12c302a3b2e403039d27ed7beacf4fb1655dab1601753e66fcadbeffa5d79ebc5bfb386e7c5e80edca5e73da0bdbd59a177681852fafd6a517bbb0bcef8fb2ecc9a70c4cf3c9f3be15c572dd93e743c6bc2e8b5edd5af435c5166f41e7afa7de96f5ff7862d518da62b74f6bf1c5f0d5abcc82a9b17a39b555ad575f93e3b627547c56d02f4c71b53a866dafb069c38f0ab6be97575ca7ed95eed38229b8a845359ed49a3a77ace228c856adf5b23e4f6cce8b5e6258b75f393f369f5bce3f27e0955713eb7ad1ff7d656c9465a68f09aefd0adb9a72abb27d7f9f30a89d7f2de53d775ae7f60163d35e5df4f77531a6d662a32cfb6262135f9bee9a1f7bec923e5e5c6a4d5d39bdf879a7b88eb22cf4bc12f079b3be2ecd98d698e6d728cbfaa78bb9339d97a5ff9b5b98d6a32cd3f9902063acbab06e5db4d79f5ceb8cc0f64cb3adf3e7b5f5760ce41f11504ef17d9eb9e6f4fe858db28ce7ff406f9465ff0941b56d9f5d579d71a5f5e3519669f10101c5d5ea0a9bb4f37bf5ccfb27c1c0e703fa3bc6dfad8a697bf5aa1a65d9cb0b0be88a8f077435ab8bb1bf2cafdbaaf3c345efd6f5f4eff7ead279dd2db2d6d3cecf57d5b199abee40a7b75afbba9e6baa2db63e1ca015cfb9ba1c57545bdab19ccf06b6cd7c5717b69c3eb6d91a6599149f652fbf370ea726cba41872936525d2ce32293e5aec4e2ba63663b3dad7ccf3012c475cae8f06f435ada517b3b3eec7d81a655997b99be75e4d963df7ba2cd39c7e324031e6995e19b3feca58afa32ccbb2972d7279f2c9824e4df5e7ac314c53cce6222e313323301719817934e473810f16d5ca385fb3db5967c7398fb2ece5a548961561c17189f9edcbc9b22c137d985d783e18e8fbbaac7aedacb6cfab7a9697d31b1981b9088b4bcc0c922cd35c74fa3cd2933e657cae98f9568c5bd65bacf26adf519685af83c3b284c5884b2923296512fe5861e7ddf4d2f75e15debadfd17fa2e774cee1c949b26c89cf05a8c618c35cffd531abf22acbf6c70297ad73d6ead699efb5d87e2a60617ff5bc2d8c678bd6aa7e2cf0a1c0c496f75cabcf18bf2896ed357125d29633019b2bf657c5f7d4fa5ad694005639b52e2c633ae7f5d5df64d928ac11d06fd9ab69cdd8fcb96d35f27a976522d104aaa8ae6be9bfe8febbf5d5546cddaf6a621bb3f9efb4d6cb14f9ea58ae745fdb3946ed75b2ae5e314af59cd7ac1d7f9765dfe35c3dfcb238b5fee68b5d4aaf8a84e7da586575aa31dd316c5a1549d43d772a793bcb5e9ce43c51b3f33ae76cebebdabfe2550e41176aba976b7e7fdeea2febd63dca327b4da207bf5ca2a1bdb3772b4f8b6137efd971a50e00bbb66cff5c71adb762bd8fb22ccbc2c7b9be5bcd7a5dfb56fbdad575ed7325530e26c56bec5acebbded3a2d9ea92555913c3a6c69c5eb8cad8b37d636ceaaf32fd79693eeae8ae3056f599f9fc2a639422f5a9f3b61553fcd762fd238e626d6d3edfdabc7aaaad519665194ef684daaae3afcf2d4a757e6b9465150256a5b08ce1b739db6d5dd79cfca7d8409349ff910d5fd556565f6fab6b5f161ee998f473d197f2063fcb5ebe3c02878cb00babb2cef36279775db94bd5b930adbaa5ad8c2b4673555f7a388dcbeb74394996bd4e973f07748bbee67c62d5ea69ede5f471aefa779e7cce8b716a39d68f2fa516bf7a85f35537d6d7c2f2ffdb7b557a62bd6dff895d17b62e6e59eb6178bec93210275fd9b26aa7fb71e6b49a5aabacaf365b75de5eab3be928cb4e99a3a2892ddd16c7b02b3f9db5b64451b1c9af9f1856d9dcad5ded2ff53ce5e4d67adfdea9bbced7da58112830bebe764c2dae70b75895651cf77bc813d8faeba293ff57d6c4acbd8413bcaa9fbfda17bd98f6aa6ae25e98e2cb2d9b1f738ef5261776f5fbdd527da9d6940a617255fcb2f6451fa317d519bbcc2ca970752f9fd54577c71aab5589aeee674caf5e29e6b9d23a26fd3346b8cc9ccf14f36a57beafde579ea32c135d3817cb7d5a55c5b1a6bd627694652b49789efd3baf58578eab4d4759c6f2803eedb6da569eb16bd78c636eaafedc2faaaffdb6775e6daadebd7a3ae7b6b4452f5a4377b6fbea15ade6bfb59d77af04920ad376773a79656f75ed279a3982595a553d31cb9a9bdffd46aaacf1a4fcb2d5ce9677ed802a3fc7bab236c659e7ee3951cff30e8686d77dd989617b61d5356b1e65994c91cb73def94e7b359ff4ce519671f9d3f95cb298c8756a6a75c518ff6dcd6a94657c13bd9c3a982c3b759912b9fe6217c518a3d55b6bd65196bdbcbc6093cbf7218d8b4c96f1df4a59f67db819e122eab62cfbc2923784771b4f67128566eca5af69f1e695d3fe161f6599bd265148ea49c85cb85677bfd5ebb679df3aca32f0c65c159bd4ba7b5a1afbbb1f83d11bb3ee7531deab8dddbe84cdd8a5fcd257678c56b38f5e6a6592992b81db0c57226d2e59463275354a54ba71c6bd5e169673c75796bdbc4cccda93f7abb16ee56df19190a9e9bcba5fbabaa6e5b51a65d9083495449fd7454bb8eccb318b4f8a2dae56e36b94655f1eed2041f4c4e67e7eed8befbcf48eb2ec0b41d10b13c944862692112e5956afb5fffbda6b5b34cf1f6599e8a330abf67a2fe7f5a2336f0c8fb2ecc3ede319025b7aa985655e5d7cafaacaa32c2be29a96dfebb5dd96add3ca9f0e751fab35df6d3b9ed5c43a1d6599887759e4f12ccbb21718169e9ca4c62279de0f7b757afdc5e6457565d5fca32c0b3f2195a516b6a97d5dd5ebd25d8fbc2cfbddd97444b22ccbc09287d56e2bb639ce56adfc52db4759c6e59d176559b75d6a7db6eae67f6dc5cfad6a9465d5b418d5bae216565d77f77e8db22c2475d1d67dde6e4902d33b7f7d4e6b655915a3a32c13655996596ad3ffc739eb59619545eb28cbbeef5a2ceca2b8facb7b95abaf7e946520ff0745a2f075b2ec2549963dc9e35dfe46d9056421799e48e713897e20214ac011db1385a0e9138908b052840ae53f04903a841195e46dd17f22117d72ad5ada7f15c19f082afa111043f4d0245a80102a418880c8065091c7218001720142005189a60280244005012a3fb01c0088018ef061f6b0c243f8e51004b203888050f5bc2f0129471420ff970002306000e1eb20400710881ca88a00aa100150c00f0e040e3d99a4a3e3710d0080bd0bb8a1c7e309196003ae14e55a5524d2e9b6119847124462c0878a3e2fcca2b0e781883aa8210078a4f17952ee6c08001e3d20a20017dc4a5987cf153ae410dfe8420d982580e10b7878e10e3bba500717b6a0852c60e10a56a80215a620053a3e51f840e1099f25c49404f0184a03141f3e72886f8c800d98941b180b1353ac16532c0a9234c0887800acf6c494ba454ca9568829151031a50a1253aa8f29951631a572414ca9da8829551d31c506a1430f368823866c40470cd9008f18b2811962280d0384d2b831948603760889008a1812c19318124104628ca11c0670c30e392041434ca9d121a6d42420a6d41411536a928829352e31a58626a6d43089293550c4949a30a6d46020a6d47420a6d49420a5873a624a0f6188292a71c4501a33c6380002840a1072c2460c3931420c39a123869c8021869ca42186a2f8118a222586a2182286a2c03114850362288a2762280a2e86a2a022871c7ea47c81464cf9a2075f3421a67c418598f2851d31e50b31c4942fce10801f3910e0061c02d0c61231a50d9a943644296d481153daa822a6b4818198d246085490f2c510dac0418c318700f03084083134a4093134048f181a42861822f22386882820c628801b04a0030e38a6b4a1134338c4c4100e47624a1b2a88296d9820a6b4118218c2a18998d2469218c261c7942f86008036ce882969d0624a1afa017488028831650c2da6a4018ca1317662688c0cc4d0182288a131581053da282386c690410c8dd1831ea20e2957502086aec82286ae002386ae202386ae402386ae682386ae48428c51071e1290851831250b33624a166bc4942c8e1053b2b823a664e0861f3655a8c1646611001bf24d0a1f7088f12304567411800a34418102c42c8152478a45464cb1da8829161f170131c56222a6585d4cb1b28831222088e843022214318284883e37f0a2e05f2a6d5f08662430f3b8946c301263d4e9c20c8a38f0a3c01c18194e13f9d80185023664c0862c6c98800d12d801b4871840628c6a8010f05943042911669d6d277f4436e8c1f3dd0d58043a2858585e84c8951ebea984fd8f64493e9bb0ff1129a5eca0a042f6f04df43afc454f76fe9cd082316e20c148c84b7fee061d212e5224e29c871225709b099f091908a01461ce6ce55a75ce98638eeb08078508f6d238db3c2bded76bd1448232047be13bebb4545bcb31dc9da0c0612bb6d9525de96a6f8c62a32c7b4357ac631ae76bad7f016b5084c0f3c538de7bdfce6755e15196bd749420f4ef15679c3f77ec6a5e474350dca8d9ba6aaf179bd3d26b95508090f955f5ebfb55bd5c4ffe82f2838ebf669bf7d5fff2cbe987e2833d7fdf7b59135f9ce7a76d58aeb7bef69d3573aa731114362c7ebbf3ac985ed8aa3c06a50715b3bbaab6befab47b6f7e42e1416555de2bac5e6a228938ce84e442d901ce5655b1adf535f9bdbd92b61148ed50414511141de0399f735be5893dff8a8fc070cb5f0e87b2c66571c6269f97b555b7d6cc41aff7ab8b694a2b8c62f7c201adaecf16ab32cf8f59538d8d2f562fddf5b25d5b1a63941bdcdf97d2ead297ed96c67d94652f61cf101d9434f4ce1d6397d65fafcd671dbdb87c2e8062037d61abe36a635badaa2d4aa1a0d16fae6faf8ad19a3186554c506aa07f5a97c6f0d4b457b86e141a58979efa7a7bebbcf2d533b826b6faddf76e9b799dcfe3c97c1de50cacaf3db18a678ef385e12983cca9dd9ce34c37c52e6e516290ad3d31ac1fef5e050a0cb6b6d9c2d69a169d957559e1166306e717d3cfd6724c57ae31ca0b32debdfe85f55a2f4c2bebf2282ec02e8c29c6e6d5d3ba302e67d9452923e3cf17b69756ac2f2cd751969dfe89e8b3ec05858cfc1c57b69a99f78dd9aa1f41694195af8b2fbeae79edb7b87628634cdbe7ed15b5d79cf8376541b530d5b35efb5ed5b57caec076dc297ffed657d676aa025e6bb71dd78ecdae2b5ca540ff63cbe9732c5b3977cb434181bdb8f2ebafbdabe65fcd5196692862d09a316ad57aafd795ad7c9439817282fdd4e2587fb626d5ddf25196e97c4fe22826a8f0b42cae6cbf93726daf519671f94350f48433e92c93d1e93694302cbd6db6987ef576d77bc1b8f6dcd5625a57d6dabff617dbea58f7cb3e9df4c215c6a17831abdd5835b19c7bbdf87e9b2c23014a09b05ad55e3db673653b86e55196ed3c11f5fc9cc848cf7f243421c9b2ef9f7c990472014a179cd3eab2f0ad34d5b85a15096675e1e715866bc6befa1f65d9cb8ad73b1a1615365046902d8d77e693f39eeb5f2d022c5bdeb15bbd9db6639e4759a6831282cbab0ab3df2d9d1c5b7da340010186ed89ab5b5dd7ead6f71a9a907c1fd24881f201ab63fc5aebdbadbd2d4e4759a6d36d27ee851dcd11140f600cef6a65cafbeb9f181db9ec5fc27199844351b8b02e6bad5bef55f3c573e66197775e9204650b8b799e35db9bbfdacef928cb3a9e5cca281db8fc66be3536ab75dfc2f809140ecca797de16e5735beb9fbb6c205fec67d6755f9ebf62598b69599765d1de6fcdd7be540355e7f4afbfb3bec6f3ef28cb94a064a0df2a5bb7e2dc56cb77af461913942ce84fbb37fd3b31fcff00142c28ae13ebfb1dabb456d41ae51041c1c0c4d5c61a6315d5f35ab77a59c262a409942bf645315af78561f7caf5c5c9cb0a8bca131640b1e2ed755937673ef35f9dd652c974015a55b55617cfd67579fd3eca3211efb62f9d725896b01861f9d229c7a57f92cf07502cd037df6feb9dd7f63b2b3dca32d1cb0bcb0b36652459f60903a5029c7ebdaafcf65618d5da42a180f5765618bdb0dab1c66c5f83ae5665d58d5997ce56bf9909901aaecfbbf36d596f33bd2ce7721ab0d9ad9bf9acdb3e56efe6a03eeecc98ad2a7afb95f9ae580784066a5999ea5e69be2cafaa7a86f97df2a9edd33ab3de55083243afb0af2e86f5cf77e75e47203ebe578e5dd6fe6b5b7ccd5e067be7d37bfbecf9aaf8a664e0bcf28cdfbab7b25ae33a067bafba2bc7b65f5d7335f7d8d8a69ce66927a697adf4a819db5a2f8b5fbbaa13e32031e0d93bdff8abebdab452fea900280c18d5bcfa0a7fe5f6f68a4759f685a01124ef23b24179586b4d9cedc558b658453718aaebb2a845b1abce51967db76992b7b32ce70b1ddf3db3c5ae4aebbc6f4702c2c3d65d5d15dbb8cf7aeba59f80bcd03be61cd3daeaf7baf6859d00dd61ad4b6dd7f9baae6b29c64776ccfab6eabf70eef8ead382bab0affe957e6be9dd2d8bdd11a80e8e51cd2fc6f5ee745f6cd980b890ef85fbd49aebaa624e2f0e680bd885b3d567b52d5dabead6215996bf5702d2c2b4ac6af3cc1bd369d1fe49385016faa5af852b4c6fadbfee0d84857a619b62aaff5af8e2bd6799087485be2f0c5b0ce3d8b4c26b3cabad7abfd5da97f751962501aa42ad6aa5fb9e6f5db8534ca980af959f5e16adea85ab074de1f65a2bc757b72e6e7fd2151597099202b7aa4ce9bc6675e18e7ba6c3aab3fa8af57bfb6b3d3b0d280a57a774e3ab676b61b5d2161432b630ec2b7cf1b716d3f50917c656bfd33ecfbb3fa6c139f4acb07961d3668b5713db4eb8d6ee1cf76aababc2aa4e9bf0385b186b4b7bb62ecc2b252026bcdd9dea5b556bdd6b6d95a3dfcace8e5fe73ca7c5eb126abfaeeadad6b5ed754d4b37015282d65665b18e51caf1bc7a4e024ac27ddce9cd9635b16b6a5cdd80e2b83466557e27c7f0bdd7c22012ac8bd97955acc22e8b6db68e70f7a518d6ad8575955f631c9011ba75af4eb1e5f96e6e3b56844e2dffabde8be29d5fcb8088c0315bddb9f735abaf7533011a02c766c5f6ba55b6aec774c3816985d58c59f5766d4dfb46de3cd3fb6fadded55afd009010b0ed964e4cafe595f77a839027fe8d2dad565f3ab3e585dde6851d8d1b7df7aaaae6a5f3a26f61d6080808fa5eceed85655eefc5f57f60ab8ad29d2b56edaeaeadf79c2534448890bc8f489665221e900fbe3eb759f75d515d4dcb12898680dac02c6a6dc758c7d6b5f1c66c7caf979531aeb3eabce31ee82bd7fdd8b2f9d6ac39074ba00b0c8807d3561cf3ae298673cd131b659928cb8ec0c4d81c6122cbb2ac04c6807640f59c175bf8da76dbdf73f3963001e9605657f36abdfd7dcdd9f71ab656d6ea16e7553fedd3e600b35a63ace297c6c195a9cd56df16fe795d3dabb1ab8b62d6d5f9da17df4d2100ba41be7def2b3fbdfab18cad346eae70cf33bfe6f75e1ae34036d817b716d7aa2d6c5fd3de81d0b8f0bdf7769c37363be57794653da01ae82be7593f63565579ce9cc3218168505d6a59b357f5efb6747e029a81ee15a6af6b695d61f94eeb5302d019dbf2ef14ab6f73ad8f611200c9e09a18fe3eeddc76667be98f054031c0d6c5b0fc18af16cf6a6918e4797fdeab2fdd2dc61d9b71ebaed8b5349eb7eb8bef5196894e5a74e24a44402fe896feccbffebc2cddd81d65590422f09f09f4b84d051559b6b3f119900becd417463bc6f7376659265219f362d8dcbda2d5ad70e73c5f2032acfdcaba9ae789b3dd778fb28ccbb2b0db94e86c315996815ac0efbdd66b7ee55bb5ee7694659c28dcba2dcb28d01878638d5915d5fcbab2beb24c96b93800c482eafab7f8cedb9a9faf6b5770d5af18be1c5f9f2db6ec8a8a0a2aaedee2d5578edd6ad50b94827b59d5e6ebd2566f7df18a02ece2fcc238ad77cfaa766cf4f29dc7c964d9771eb761588880c4d0945e3e7545afe7d45696080b8d4b29237119814e402fed966379d77b7ff64bfa3c229f779365a4cfeba730834c60e9bcaea52dd667b7b3ff28cbb2ece5858625c7a5e6fb9086e47d44f69770b2ac040a83e7cbe9bedb5e96cefada60e4d718b6f2ec56eb7e693bcab2ef4f5f962d01fac2d2bfddbad5ae6a95e7c5bc9895752d7be189f54a637b5d90804ac07165e16b2fab57eb35868db22cec3965261e4f4e10501795ae7b765c6fbd7aa5f9740244020b6b0b5bb86f5e599cee091a01bd9a4f8eaf6b2b9f15a72011e4ad75b6b2beaeadfeadaacbb2971b9770e34a385f1805280455bf5a67fd8f613cff678d0c92f3041310087aa5d7aa7a956fe757cef503b9e2d3766a71cbf2da2feff922dff378472a90073addd3aaf8a6f8e67be7be02c485a5efe7bfd8635ad56ad62deae557d757c595e2ab2fdd00a8036f652cdb5a379e7a6b5d8db2acee3800c481f9b6a2175fecc2b8ee3d411bc0bd669befb413db7bd52a03d2e2b236b57475a9beb8b5b1cfd1c0755d1cbb2a5661fa93ea5a03ca40afe8ecb9e67cefc66ea56f405964abe2eadad7b5315aaf6d4759169a4aa1c926078485a516ef1bf7a92dabb17d490084015d59ca31cbb3a657a65c7ba02b7635b18b62bb2ba7b6ea8e03b2a253abaaeea5d6c6aebf7d8f4017c8bd5bcc62ebbeadaecbc2120059e0b298625e55179b1cd74c4115783b2d7ead5bafc5796e0c44810a5b5c3de5bdfaaebbe6a32ca39f35d0f9d59c18ad2edc2debeb8cc0470df6e7a51657abea98ddd555c5270df4c2747555fdfb63d6aa681f3b5fb672ac6b45abcaba2c45c3be72c5b0752b0bc36cd57394652f5956e47306aaebfe6d2fcaa9d5ad8a7db4f898215ff756955ef479b6b2cbf7e1a3ef3dad89f1e5d763dc564358725c20f02903c6d7eeb7169e17fbc96bff90215fabe2f5627a5f578bad31ccac73b71846a79dff9447e0b387e6f56f9fd85fddea4aad4f053e7ad8ea2fbf9552ab9afcc2d5ce470cb5c2f4d26977affdb9bd9e7cc2f0d3a236bf75f1b6f655e12c83c0270f5b31adb4b2b4defc62ab53f10183ae57eef75695555d189ed5e84b22d1cae70bd6aeac6bd6795feb0bd395ebf78347edf7eafd566c2d7a59bc8fecc70bfaba6ae71a536d73fe7a8db28c7f96bde878472498bd2325af26cb743cce057feed818dff42bc6b55559bb2f983f765456b76c35f99c15c5b7d79e4f172acb35b6f25ffbf2ff7d3f7568acf3bf796216c574be34984737fac3858a6faef7cc955f98d6cbb7d067d5f639dfb9563baf7bfa68c1aaf63fadfbe2176397f3d1270bb65f975bd4726be58a4e5cc5070b15efdcdabd6bffef16b63f567cae607bbeaabb27362f4d279e3d1f2bdc5959ccfff2f9766a8b83dee692f3a9c2f598a567b698fe7b510ca3c0870ab366fe76578a59d845fbe5f58e26a691a8e4b2e6c68196c40c3206000066d50400a310002030241a8d078442d178525b1f14800159a8589e563c1689f33088511032c828630020041042666668689c005c149ede1230b7b67190eae794153e2967e036c437e4678548c68698720183c58ce5c710431d6140446665d70633986a49d4b09a06ad7e125265a14301dfb9cf353bb2b541006552f6f1cc393764785024d212b8a05380846179da13e5fec0164ff7d8b9bd86a82d943ba5965088ed7df9340ccad92dbe0d904427871ca08a2178545c7b09d3526aa24d9a7fe8ca8ef687e5cf76ea33a423dd1aed8fe6fa960718d388b510842d46e1154d7be434c8b96e0d338cbc47635431df99af2c71ad770f65c220e0fa9996da553a02e9548b51c17e0e1b46d522244abc62ffa6a08c21d2aa6aa7efdf8d187896a189b88d957956a97d9d43ce559d3255d655120df26f66e512c85a7b6261e02cf78c105d1998cbca201ea7a6157379adefa27248536a8b6ec223dfde6da27d9075029d248e5445a18bcd387eb22292946cb0df98e8778091856f3b9770ad14c9e1d8404237b5908b35a88da0aed53de312093c9040df08481ccce41ec12925c5fbbe0921f6903cbf375c0f73c6b778a0f862f77f11ce5037dcd7f9d76b55a6b0e859cb873775548c677bcad2344de88bf71a4a0f3a6d753c60a007194ec2188718bf686b2236d56f0a532699689b2fa2f2290dd2a22e6d33afd116f351a99a8b928389b25f5366e60f377156fae3fc4d59f547ff680b1c10527ed7d2d2481a96126936e0c5e1f588e5a705d7ff9ea41fe4a28f547dda145f067471039f928f490a57da31defc0d61ca6a9f9fbc5d8f26f671daad2e68d5e21f5d43d1ee130fb7a02740a09cb63c1534ced3ab795b3cb3ce3635c7d215b60a6560ada38a5ddb3eacfac51c17569409355e7066d9cb488342140419907426b0f7f07f237680583b1f8a04b780d1b91ef212c8ffb135406afd463ccee9feb2850806cda5b5b4aebf7276d9e3198bcc7a0bf827a6158c149c5547dee7e1b543c9085f7a9b727f2d2c49e56b4810a0feccb9cc5ba5e0d4cd9ae10162f8ae24e4a86c40f20fd9d09d8e0a988408b630810745c5f4fbaa3434d0579ab2887ddd77604b8e15780bdc77de293213042e3b05caa31f5b1f257445ae0146a08cf4d531bbfe926f348df27ab264cd831fbac0c9bc0b766050fa98674cf7a54ccd236b2cb0aa343f82364f9eabeb0a01c34db4da2ebc40f8dfe2846ddcac029ecb507debac0f57bece0b687c07d80759bf2cdeef86e587540b4f9c1f9115037e7574326ec398491dd558f255167ab4eca4b17bc049b640795e20568a2e83d34e5b9789fe4b75e82a69782d1a036b336b9232c07e6b96fd5163e40b4a5fc5d1f6356843559eb4bc7c0c28c54d6eab1e5607e7b328cfd59d1f61f881ebb00439d122f8a98a3669bbbc493b8c0a501304d8a1cceaf84d1d258b3a3f51f0be221691b82100be1274211e94681107f34162cc5d5dd7cc2ee5894c9bf49bd4589d612aa44b68b22a2ab3d4e603d216e396c56899354397a3da00399a0bcec1766a0029f4b5b9c0df5a8d517ab102636e937e832e27d693d6ede00bac1c285ad9fe016350a88638715bdbc03e7c67d11da65811b471d5bd52592eeecc1f7a29f45375adab5de6b21a6fa04338978117b50b489b2064109417a4e9a9841eca10efe96f7c9ddcfd9bcd7d95992b611544129c2a8f287a76e88fc44079229172be03e54126abdb717309d1b93f5a0c2e617e87b8ad04cc526c2aa9b0e0caa1ea032bcfb88ad094116841fd5aa135dd3601a9b0b5bb1a8acd163dff5371ac76f5868e5d17eded87850d2b961afcd45d02d67dfc79739991559576b56b6c22f8e0f4e8a18ef1bd62e6f4e25c6ed1bd66a50426ed9b6709166cc6c680767cef1edc017cde9e0c71b310c8c10e269618f78b79601eab067399df731f420c0f6a1e149944f650a26f03ec8b7222399833a4053d230acc845edd49603a15264894ea0a9bc5aeb2686c92af884de50ac4f9e99bc82a3034756ff85cb8f59e1485687cb8b20c0ea64c74ad54266ad51ed5828238d59365f7446a109df912236635e072a577542c319cd41d7dcbe614a650b66a037b752f767c7b82c66f2aadb4e2cc84fb3554aab8710d83ac03290dd69eba59467a6c30d12574eeaa6295545d2feb771204d41ccdd8bb1d31f16699a3619b807e06dac79478b11b472770697d785e536671ac363d8f7ba1a0809b07d0ab1406587bc4590c76f6d84fd4368f97bfd6a1fc143c9ad7720d38a03c8ff7d4aafd307d8f2bc58709f91125d29c1ce67b90903409fd11358b97dc7909dc31049b2a3674d249367a40b157c7edddf0117d4a75526012268e77a46b3a7c8e7442f02ab2261f58183844fe52bedc2b13d0d1aaed46f44081fca7678bfd1ad1565b7439d01bf1ba83d2f35c8ddee60f7d2b8371a4f72f2b1da5ae57f3a1516ab2def13207604c01ac1bade555318e74572fc444ba7653713184c51536a0077a5b8731a1fd239a06c48035cd7e4dba8de21a6c294da3de6392152c6f2039570c52e306270a19fe291a2e2232547d19b2bf09e309ea3432e662337833ac209595201ce4aa82bc46dcb741eff1382edf824ec13311e5755942d70aa183d5a7a4bd18e7a7a6ad0eeac3c9e2175242e32f54b91270af9167fe1ae6e46edcbb0325bed11e627843a7bf02cb6481a24771cc2360661bcf3c4b384c6e0871f29b9283e974f2706acbcbd0b61f8e02174b1e5c14e68a78eec8c75626ba4c1037004833f56bc3f7070ded104d2615ff6ebe17875eb01f5dfee50533d3caf02e60dd5a1455b39fae27935f6f214a783e15dbe185b005cb330d00594eb4dfe01115b6848fdb80b3e2d9ff372bbcab4fefb97e35ba42a4e25ae7900ee20036e6f64dfe4e780bbcd39330002dfaf197b5b3fdf35c9a6e070df3e26ed89b1a55410483fe5a91fde41f9ae1d95bd181b9805cff94a68417ea3bb5f2d93109bb20ba14154483e5b680f9d8302a81e98748110f6f56030a68999fd7154420b0f393fa08a6f3d768ae37c224d8d208452834cc9eb0a0085fe74444abb4633a6ded10c455605457e7723e28928a9b3ef252e58703d00e28ba7dc14941eade1401fc3ab02f440ab4d557815380ccb0ae32d3bad96fbc2fc797a7fc9502fd93a10dc9bd58f4dd11eec51910aa285f2ee6d4119fccf7c1d0230b81f39ade312d0472ba6c2a266997e5035f2a979b8673d1356e97d6e1e96916d01ec41d82edec5fa01ad9d1602fbf9a74504f1a037ccdfa28cb26feee0ebaa863b5ec4dfe38cc8567a98cc88f55a015fc1adc917a2b2c8b60c7d6d1b6226fc8885992fd011d6dd99d551914624734b48a1df8b4fb9f0624257c60dfdce85f4540a5233c1cc8f1a95c729c0d9f49bf26ea4a4aefc4177a1d12ec6062e9bb467b348f898a687eba88d29b38b32adbd2860ed9d0631e2464b47828f84b498c6357b33b10e0a6f1d3ab9f6c470dbabc83de3e8b2a16799e59c73b8803643261b1842e1c3a18385761d5216b85bce9961dc6d89b26b9cc90f5245089cc6faa286a0693bc219eed6bb371a6b8fa9577689441e99f13fd6dbad1f38292433883c0d19cef833264cfbfea0d7490aef5114ef7d8cf17928e2e7cb8fd1d63c221b37fe24920bb7e596ed5e6f08d40213775df1c177d24ad1899bfee963a4c3d8d69daf3ff8e329f175d6dc11a8ac7aeea0390e8f024bda3997819c588347af87db522bb33ee056477df6411501fc71490a655296c1451c7dd4c4e186c74790aca81420b9cacb6bff81f877702099834f43cb3b77ae33b2b04bad922d0371389baa38479b1306ad88493034073a3ac2c40fba31430a7346024e16109e6162de3e3d2135d513c3c2831e721ec0f0c79e2e7789cdc04d9abd146341a6bdf75f8bda5124bb7636535e9999c0f5213837d2f9156f31db9cf8d6f5e7a204e7646253f8bf463228fec84e47d4653a7b7a994313ac207a1dfb9d4df9e64262c86b07f4704ce6d66f70662531db15f50542d04ef4c32ea3251c22f1d9d557c74f51f6e74598a2e8b088a45a0ff7a6be8f2c39d2621d0c2e6e4bafb17e7e026dc1ec990c3cf50df39f92f36397f1f533c0d7a886d0b10f3be8d9f74cce05e0540ab2174b48358a6df2fa8ca51b76b5a1de052da10d2ddf5ad28b597b345397dba64295561a88542481dced53fac2e9e69562bec7d3351bf0017fa438b17e8fd72cdba261b94b22bfaef6ea85bc4b0445dd2bc29566f8697621555652c7183946f03f63c4d4c32714f1ec9950838050a03b782297ec9bba68ac9cdf8a6cb2abe9389f8b6ee6b0bcc81ee321541535001536456a687aa849f6934f061660321e5a05bbe2939c7f74e2818c0a6aceb6a0925765aa2fbe0847999655c443720f3a4f659e9b76060bfe296bc0bd790579ac9a2099623ffdb001c2298db8199126ed07884c9e815f2895114f7e3104d55d58f553fc4db3570a12da12a709cbbcde89be66cd61db6d69237bf2ba9b304a458564619fd010a6ba465551c8ff03a332d4d7362cd7fdda140b347bc206ecb3d73a1be0a48170595d990b4522f8c907b4a4f425027c5bc5b6002289d135d1cf2222fa2102bddee8bb46edfb4483241db86b3848e3ded0a14176e544545bf45778f3330510d4e055aea3911e2b1bf95fc9460ab4e5edda9b1ee6aeaa50358929d674fac51c4c6ee099e650a9a41f55d63bd78097dff4a20317aab90f7ef4241d78664701593f467e3d9a769662c68dadc71bf759919381d712328db498926ef72d954b07caf917bfcac77da59652b60f6c22aedec39e54e11eeddc6407f8cb3edffc3aafd88fbab1bfd2df5c5ded527c0251bda107a2204c06fc9df57081dc0b829842671ab7c218e2b564081ff1a33556a28810bd1a02ead7eb8befe5a53ac65d1558a546676c70022f6a35bf54cd0aa8a80b7478db82bab14805510a14c48763e5d36ade3898a462d6f5afcf9d26bfb5f0c907a89f7163f585386e54ec59d5d31ea36fadbf30ace1b7de64455c1d7491f5f41c793294d31ea8cfe62fa8e002838044c9f55d3dd25318a14aed858b4313e93c3cf982fab3644801cda4a157e846b496c5626dd34f0709d80304e45c294d0357d26c20bbef77fc1f00e5b4df4e8d16fa8d16f283c8d635d7508c3cc4ff23745bc10285f4884d7e7b8b59b571d17711f54bfdc4cdc101ee791de2e231a9b2e88df4e227403b024dc07e8d5a756726b8061dc201a3d12a7855f4f709870ca41adb2a4d7e4fd68e6925dde52f22452ada22a338666c1651833de02bd5e68d6b1658ae886e170aaa8b8380caf118e01fe911e09cae04e5735cbf9270763671575817d106928aa1a74791ea0bb540d7abe916a8d469d6ced70a9339f1d0e287d07412b8d9d649c0106f6a63997208fcc8130d549431b3ffcc15ea10f22c926167af84d692628503a351ecd28c593aab9ebb1fb07f7f8f89bdc8491c6262a1ce6c467482432a3f49e63061abd5d1eb39c3d988154010aa88d7a82179206111568038e2f87861e9486e3ba25106766410e2d4e0f580d60afc941054cd0cb46627cccbc93d95f2eec94438e92c10e22f68afa04a262cd11f7d5a1ef57aa14956699b32d774effe0c609758eb6ece4d13d7817732c0bba3dc67b7add14d9014d26a746bf71d0fe9295272715bd8edeb967d5d81a0fe00cb351d05f6135a788006839f24d32b313952b07181eacb9960e8e4b0dde2fe48435d78bcbcab91ba893d2167c4807b317d92dbecd1565d80b72e3fec3769166b53b44564ada646e38e8b2d7be413e660528a80d1bb210d221a56f99c359417b95a83441db30ac87bb1cf853421d1973e9bc30d2a13435bbb38bd33b2b39584007fc316eba477c19182fe7ada1a0845efd0dbbce6f4a8c2d6f7a12d8aeb087b70bfb4011cc9447bb00e554de2447ff147a746c811bcc4e80db886ccf1eb1be210d5a3aba45b2f8f05ddce1f0eefc5558f44a90398f97751fd5ec8ed0f39290580b63c504109f461ab65c58e7b46f3d54437a26f7f3dc02c6d2b528ac8744c339a10dcd0077befed425a2d6c0bd8778b21af1ffabed98708f20d72215772a6e5f13d4a2e66bbae0f92bf1e2c89d463b5dbd6699bf0e4de362cca410fc0656ba0268ed834cf399941254df5646d4108fda9d1f66e50fffdc698b90d2e4517afb94f4b6cd789a988ce691e7689e584147efc05a01da3b20bfa903c064290ca63d6bbe1f19b9f5f9f69fbf4a70e586600e9534a832ea79b0fc1b1b76b39e167f032ce6e887495a2af320ac097c95f6c1d682657c990a24a2888a981feead850d3a00c0cc391553206978919f32290a09fa4ac413c4c8c15b3156a58812b0580671e26f39e8ab31339d4ecea5d5ff21657425a65474c46bc681810f09d264ebb927516c1c58bf1a9190c7233302f753870141dd7b4902204d33c3e0d5f8117c234fefeeaea88c0f604520df64c0013d37196f00304c1de48527f7adf60100240c1971007c873449e22c50265f816daaf99aac13181333ce7968a9e7f8dba8f181bad0569ab14e7b60e9d149951b907254af205262691a6b16ee50beaf4fc18a091ec68a7f54782507bbcd124d5330da157a04704b1ebb983d1a5372b4ebd06daebeeff5ea46fd7c6a92ceebfae40ed5ff93217c77fdbbedeacc346eacacd07478934317fe8b0af2712f1739a1579a174657144b68f3d8fb185a9d59b5adf922faa4ee7c64fe17dda9f59205e5fcc0979c3c6ea7a33700bf2edde88fbfa907f5bd2d4b7cccc71f989f68c8c8725e9d1d6fbc95f75e692ed7f5f9df8e09ef0e9730d0d0574e47e751c56f4e3074070bfe2d269fc5d73c6a7821b4f713fc10b69c94ae9f2840b8b97f7cf179007c29e54abbd0164696bb2d6db7d6437617a6f62b8d4c469b586c4a515a54805ec9dbdbd1f663c4c675897377d996fac9f0010b58eca12befb57300a01280318061846d7c3d078fee011cee3fafcd45997438cdc2f5bbb56d09ef2870263ebfb639ba3ec00788d4c32f78abd939252e87063bc68cb3a4dbead100c41ce24715527f81e92d2daff994f465db72b1afe703b788a4543665f5ff4813dbc6b0526b167a44a5b791328a6bd33092820778bcf99d5db2f3fb507aecba31a16dd643f989ac00dfc5f135f84adb068d3f3abe264ef2cba2048e95b99e0a6fda661cb43012270a7b91c02833ffe56ec58131c245ca077a32ea596eddee3af477e1fd21543556a274ce3a1714fcdf43016e220f0ff6d1a8d2aafcc389c32cf125d17d100cc97c2fff198ec57d523c4c55e35f155bda67a3f51ffa541ce1c0c94901b1453b2033a86f0e315a633cb461c0f8b31eb235535c924ccd471cec23a1ee92818f98f3f57c81d9a21930fa01d1709f65ffcd8914d59f785d1b3276be4717ac79172828a0ef2fa88c7135ec8a3c7a5cdc2bdebe362b16b0217a758755c581a517dd0cece667c3c4734b09254c2eca98e0e62a5cfdf0b487832fc9ed1f667700e163fab3794ad267da3a63954d663d940d017cde822257dee163cbe7fff9e05c92e114e2beede7b161692bb24412cd1ed8e87fbdd14055885d56dd724cdf4397e3015098d32bcd17bc6f445ebfce7dea4f291a2069355c78edc8fdf835321d94eff2eba4a4fa6e2b585521fda2b3aa624d4458ac3dd795286af32ab2763ceb50378ab2a1bd56ff3d5daec33aae3be7314aeed18b547ef7efe2c56bf039c350e8cdc1e006ed88aaa532d8b2082f75eb95f21f5dcd1fce3fd3f101bee7d99b7b6f5f69b42748ba02ea3adfd9105358724bf54e8aef8d0713b9cd422991702067f4b5207cc1b364413c7c9a449578cfc160e96aa7bd36da58a482b5246cf5cb23c8b44351ab5241bc4babe9711a3641be8ac7c07e4cb7d7a041fe3dff0e1a53573e703e2c48469bfc5e2ab75a28970b13254fe615379d026d4f861abd51e5b014f794161ebaaf47d815b34b31cc1550a26ed75f61da2352e32ef80c45a752d63600dced862a9634bcd66d609591fe07becd6b0a0de3e4b6d554e3c6df4e4437f250dc6e295caf94a73fb3af6570b82f4bde8e49449a18931149fb5cb326e4d15eb38b4267b00f1625096c6ea1e21f3f60c6a97e34c81f01b4becfdcafd5f99d10fdea9dfd5ed2e24ada98c4ffe2a79b667ac789f2767fb92dedbd9b542f71b5f7b955a84ffa1d75b294e8bb5f7a38697e039a95b7fe1c7f1c97c99ef026539403f0e239c28f97b129d2872cdc1ebbefde518a82378747cc1fb06a4fc5f8bef6b14a3ea11222d60dd31a7d05177f24eba81b6f202cd15cd1b519cc2808f99bebb34e18628e8b5aa0e6e211cb819e23a9ecb9d8a01eb97a0a2526c94032f37c65a7ed82641240b1763411f4b7af87264bb22ed508613e6480b21ab6e7ecc91e280ac4671de80395f671789302cc4725d36bd5e098cba46ad0bcaf9687904fac7b13ee16858fc9a7d790f25ff557bf575e597676add47d911bfc9992d4bb4b133328d731eb5ca82fa2fe81befd994bc8cfd83ae0ec3f20fe9d70379e4cfd607490c2795db13a2b18bce7008ce579f887c0b48136187a1d1905ce20444267fa42600c402add28e90070259355abf16b4d81ced516596f2e290021fc9e17423da6e3ecfcab460a0ed222f0bb63947d409ce070cada24ea1f2d676b83b98d2ff41a4d9c53af611fb49e6852b51adc8dc882a18f85c1df6c3cb468b86d05c88c39d7353dbc1ba27f5c5d8729d1caa4037ce66260d0a2dd9465147def6eacff9b7eb62e707696fd0965e9570b7f04c039f2737de48f2ddd5fc5c92649695b2f750bddcf4b7357e56e8d90eee89141c32c663f66eedf1b54aaa8508f8250a1ea650f53cea3b15097c71176ce7eb63f369c381385f0755e483e844969e7db17749110ba5eeb424c5e712036c4ed63aa09381655a73de0e5f0f91d794dbeb5f75e89f78ec009b4c697c43b4445eeae1565919dd77de00d90396672829d43137bd66bc9118541b984148560769b100ad7b8e488a652b8930044f56ee1c997821b00e0305bfdfc32ab7c670869ea2f5c55213b3fd1467090f9091855da9007f17a33bb0514b03560e241ccd4993a3314f13ac865a178d5ced302883c7a825d854286d691d52be02a36c483285707645a88eef500cb22ba9a249dfd705aab88d917d39f1975afc5a5475c34e968f45c36f6cadedab04d2af522c7acf67407e47e4b25e85d6dea49006713d7851094ab2e857ce19177a808d8d92b09879f21270d85174eac20237cb49ed314cc4b9871594e525a9f313c4dc3b8f104b47f78f31e0a017e27d37a61b2f85d46ca094812c31bd8ac870c01924611a5416283c03b65b294c93d68a4cd80e53b00934b3080d472e77247580134c60ce8c7977c0240c629e3f4f462da59be8c4136436a3bb14145723ca65e6334476cfa9d480d6b0a06ce06144b6fe5d6c290a8c5f4e679eeee4089833012e89f3a326bdadf347e72f39f04f3bb823b774e56da60584fa6b45c61ff11b4a0ed541f433bfc3ff1da74bfca9ca3edf7e5db83effc321fbc1792f6857788dcaac8a0b9adfea2deec8434e7e23846ffbb0e7773afd42827615c1f2dca07b88dc48aac25575447bdc87fe4758559250f6ee89a51fedc6a314fcb1fe207358ee723dc8115683c952958b16b36b2d5df632a713d99b5e7371aed60ca02d21d019f7ec2b01ba571facb2970d26985e29d5de7bdd03e2d731558800246c9cdaf5908e1689eca7225c625ada37f23bbd132cc6d2c83ab41493d840b8c584cf07ea353519509dd21d4d26da490ce1840e54aa585f512c8b8ae96e5dec598e4e355cf4c4c72b6c0bb8e4e31a5588e13df27771d45a45637c9dcf3e90b16f715d5be79e4c7ccb3e87c643500024fa7805462fa0d9ea12158f38edd2e430d5e6529c0cee96b6cf2e071e811dd8ff027743eee51fca80b0fa86b8d53a0772ad3e77c48b39fa16e1dda8149e4d8b6531a913f4e95e80ab2d73b07e5b01fd730f237fd5843efaabfd88989cfab1de3b76b94fa49c6726c5d9703dc40bc0df83bf4c53e33ee0938bd18ffc5c533ba15b2fbdccc812e1e1e727f59490390309ea1c76d39337b8ae10676e79d8003efcf38d7fc529212b22c0a2ad05e985d7f29e7b75349009c16c66445e7098a7158a1be32d2766d5df1cb30ac86dc39a147acbb1f3a9df133d149d594ac1bfa5f67a3a8fa6395831cc0ce9ef1f904323999ca5b6f3eb742190f06ac7b6cf4b96b7b4224db2e475ebbec0bac41a32b8e585cc262eb28764ec0fdcdf6e1ad65c42f2a38cc48ac47f0ed3fb9202d6e6427cce153b073d5f5b169d93a323e87bea7d92f930d7ee192cfd94e4db00760b12962e318d2d280635f428eda363556b197e99701bc3dc898ff3412673af3eab3ba20cc0ff3496d3a3d75095c9f1c06b783729874bbcb17ae901be22f0755d210ba10408863a83d4296f3e5365e4195360f771bddc2e7451a744eac026e8fe6127faef3cc459fdc1d99306eb77b6eba3e7ff828fcc2b66935295f867fbb3bfc42cbfe3b3d0796b6c9ea95c29602222e7f7a061410d887cc3586b3b4e2183006fdcadaa43818692ad694ec0c28007770ef74fec8599f5e0d109425b2cc8613a3a647c6af62787a79d057998fa59d9d987df2ead9a72a4131b24b035c9a5f1395c3c4fbae745874142f374db8b84ef4677c0fbcf0960ae001301df6fdc082a11985cd7bca40757f36cf9febe7cc3ba6fcc35025d39e2e8ab81eddbd7632022f5eb4d4ea73a3d6ebb02cbfb7e1df9b98819f7e0c792da0f25cc89bd1a465409ff10e7f00c383f2317795ae5ab44e040d27eff88843ca86c44d2e6b98988302447f2dc3dc39af417d5a9e3f9131f5a406bbce95e821dc338a90d3c670c4d03afe9868a6d93ffa69da6033ea9da88b94b00b332198880141c3aecfcb4e6bf98fd2741935e0ead83797c9f36f73c95101efbd09aa076c322c55adfc34b2315e1deb9a95b74eced0ed768d4be776b05a65a19d8dafd7fb74bd437470ab2761e38cc3f29cf631e93e50bc749f908aae1f7928f5d9cec83ccace9a915b62c0c928dc39bf35ab85dc7918b15196d264aede92d8aabf9773d1a9ad58e6c4fd6553f969521021c3e61e40e8c12fafe8fdfc7653935eb2b42f81b8dde3098b480352ecab98117283a68fbd7d558954ec75b3f808881d3b8bb63a1135b22f8d3a922b3f994fc70517c6827f4ce27b9f5f52c4db63040957d290d96d035974ab6586a21735c6e148d63217129c1509e9fdff233f721c4625af83867056189ba00ca79195feee7304b5cab0a1aeabb73e5061ace047b93a419035b44726fc2d00b21f0821260d905fc3f75a2def94e925f75976ffa138b66dcb647169dd59131ec02efa7254c0bc097667f6e4b3d82f447230e2564c240b443f598aba763b1d00ea5a9dd13fdbdc543429270f8cb38cd3f0aaf831ff564cc1948811aa751cbea38a79010e41cc0b91e271934de25106b6174e91137f9da568b25db4ac7fdde0a596d3af5cc1380a2a20c1e541fcc3a92469c14e4ee455f26d24b87917f96b458b740570c7f99853161343f8677559b832890160a0976b3187e906bd891d407d98bd1ba5d0a781141777b8ac191d3241c87df30311094316566600b822927cf721467ae88ccf1ea5982eb2a0f8d41a8d394766300ef82c0d376497b6d2d0ff229431ac09e93c4c91018eb42bf0ab0c58e35d6f1da01c21f32c41f39bfdedc4eb876756373363ee2c1345e2fc733a293903e3f3a2aa53712a4e25f927c4efda12f2e8b627b1271bbec7b1d585359635c763887f3de6331e18401acad026166bb3a4045cd8c3a10fac5696070a1cb506629bcfe68e49b385a0fe479cf879555f90a0fa263bb272efb42e68334ad1484ac8bb3d32d6bea13177205709140ee16ece90afd9309a89919294111733d1fe21ce4248e765615b4f92d4a9bbd0df17bb65dc2a091fe800501172a123d57483d1718885b0187b6260c97bce09928dd43377a226dcfea73e86f5c39beb32e362a67dcc34c3bccc6161f41717107c2a5beb694d2fccfedd4f8742b7b0fc31842c1b4e395cbef8dbdb01bc1705e326bf834cc157b2747f068265ea9e8f6a57480073d71005c0136851b7c65614ba48360b0d0eb113c7cea2da30052399631fb31fbfbc95d3c1fb1ac799a3940d411b026a4f03e39803f326887893bd891199b5e75a97fdc46d3e84a01e22d4324edb7b7352985020916f8299b5d82080d3b49f759c803872796d1ff1e6160b108ed284253c1e521027b740d50cb5dbbd16b0a1db91683016d979117d069f6fa4ed54b55b299184babeadccdc814f7150c380779e8c17f96409255e2035239a2c1d5458845d3759fc95761b6507370c691a6a03f542b9444e3b256fca807a7decb90018ca6d94d92f893646aa0aca2638c507075b40bc89dd57cf8e871e8a9800da1c30473d899a1db28c91421ffe3e439313e12717242cf7388c79f4d2e9b12b53cd39584dbd9080d39e8bb104dc2934c22e46f1ba9a4d04d1f1730eb1b70953216f671cffcfb9ee80bb750df36006f06eeda6560c8d33d38fbbb961adce26a1d9e3438828c027ae425e3061d34690181ee3839b44a97444155e72e8eefe84078e9c9665e1fd4e355370e598aa6ab29285d21d7fb85029436871e282ed0045282662e327cb94923277268ff1c91e1cf1501fdbd85f19d9ad1149f8c40858f300bd2487d1d0b66609bab010a15057e977a01738ff5ef0a2f0a086eb5c1684f74dccf3b4f9f41841ca3d38fdaaf01cfbb123ecf7b61b6cfcdc55f0bfbb1cf7b00a6881a4135b990813517bfbb3ea8fd7a82e92675b9adf29349cadf49ed60a7b696f4f7b48ea36601bf15d8c86fcb09323ea5ace023973916f6fffcdb11d0215ddb87f2e7f52d6d94a8f23be40fafc154b4fa30f4bf12aa46e93513c6596c14922cdd6d43c515003a9000e4b5d3cd993a43de9edae22b77adcd50ab5ed7dd045ce9d0a22c0208f5b2a39c2435260e5c7749c3f12ba629c01302637d060db440e0e1b6889b5bd1aab9734e51cad898a48d0d0b307fc7f8b7b836a7c2f705b0c061d470ff0bad22634bb3588a6af6271bcb144c5226b0cc22f871a844a07c9128392ab9a11a85cb704c8ccb8ac7cd2d26fa150473c47b57fcc046ba93b7f193c811d3d13aae0ffa96d8ad2d79d484546b5364ec944fe263020977d1c60ca1d5226e6eb33c84f6cba163bd5065df9c43cfceb2caebf302add7a9be08a1b59be95166625819e1bef76ea589683b0f6511fd288b70e6374fc395be93431c87e6de9af99166fd06cedc5d23ba57c559322bcce805392bc722c6689c342f8451d7c5fdd5ec588bcbdd637b7bde644aa32b71c0ebfaf25f833f39791d6a829e09e28ed8fd4d390297ba1348e28249cd147dd04ec467a93a182eb480fac02bd77529e84b9e302f569a64411e034bfb93d3d3264e7de43cc1eecea134f8eb07bdbea4111265a9683b9ac1740213d369688b98dfd22915ce80c3e51d77f940754f1b28088c492a7c93d810d65b1a67abc3c53a9bd86905e1791df14987732076677bc04097fd125da162f46fbc010362cbd2477ee8d5ab1fe899b6ff14046f5a42ed458563967a9173ce33adba3ca378178761200e66fe2f526a476ea42f4dd9a23118e25937c59a69aa3427f48f54ed041db8e6dc8f5cd1aa4b5f5b2b3333b4decfdb078d1617108774dc57744eab8732a4608df311a226144771686c9233300d3f249568cf8b06ba420bca4aa8dfa8519655d66e6b5ef26f35b873977817d39a9383dca421767b2c206065cde3a8a80d431fb8062ffdb332773ba38e6e6e00a9a5ac9fe987ea11f9ceeae1bc84001ab3e5c667aeb9dac380db8691eac52b56b1f330e196fd6c4663d44840a243349b468b8040dfc383ac1a027fb2308b0a119f4f7e8ed455af944b57195a60bbfa394c4897fb1452002551e93e86960061a564073d52585c03fa16fd88e2d2082b7e354a47ba24d1cc75ed02e3d5bc5b16674053c0e3f07419cb103b1c9ed44f1d85dc7909e84bf882cf01fdf83c67fbcce2ab778a39bce29f918d85359b604ddcf51a526e74460df7d9cf2ae435234b97b48af806a980162810f0b0ae17e28e8f0fb6b1148dc3364995556cf15e802f06ccbc8bdc63bfcc5352aa26521060ba00f0ccc08d92965207629e0a3f86dccae80125060bca79412bd16efec7008cbbcd9a9358d5b87aee773f64e41788325b658f688b61b63133b293bd47f592b46022f9fca7042a9de10e3a8ec4415b45c96eea71edc9343b279b950ff3e27617272e950c40d36f78b8b3987d39ccb0b50bb075213a7a684d10d4546c80da4d091b6f1ed7b078966f0f15c744d066a0f181a72017d99cc88609fbd716edad4b05a4f5c335e28dd7606638e7aa7a39046122f8d72efda3115a3b753767326a6d4605beeba285ba5b6b98801a06e32e999c2de562d3d6649e9a017cd516c0af1f845f24a49922503d31047f242191c7dd4560e518591b2e7f35425487bff407bfb9f1ff59aa3e3e0aa8398d43bf52c2cb2a3a324029cb43298377923a0611dbb0a8da2e2fdb0ccc75592cb00bc48a14b11fc0e059f2ccf510f19d29d1bfa2e4e93a29a3b22f07e9cca355eeff0150d017fd0b59f8084ba8d08cfb09136201b7f0e8582e3de83b8bed7c343c1a9254a7e9249b1852647ed77fc9444244781c827d2ca2cd814f482ec4fe762144b36e9d0876a3f89bde7191534fd3140b6a5a869084ee2781e32dabef8c14d4df9afee78bf7f1f241b8c9dc495306f659ef5d00987ebafd27ea22ff450b1a97ae4dc55c682ecdc41b56dd18d44983e65d92d46f202337d0364b8f69d95d25c451d1de08808275dab5505391a52b4d459a3733899649bd3a99358517b0a8adbe187a76884510d4f5fa28274bed8a4b8d8b7664c5a0ca8b6e548d01c323fcdf0dddbfa2aaae16c3a9f96478be3b32107cb90244e6256b3d1f8b4535b453b2d6c435107d9460baeea77021153fa31fd1bfcd7c66d685ef00b9ab986d17b5de08f98bc6b583c5de73b50f403080a62ad831a645ebdfe9fe41a1a60d010cb703f500f71674e13a28ba34fb4ff7e11af8191a3f4135f541bb49ed352da68300fde085f840a4db248c021094b4a0ff4f8cc0514dc4737f8af9e015d199a61ec717be9e6c0d07cef8b5325915088f69a84d87ae63f6a13b2cb6cdb7542505e9a4fb5f5d80fe1b616eb9e4cc4e188aa6227ab105ce1e85b9a02f9d70a5d71b9e8d69baf6081b29b6392e591d4af213133e9c32e2835f67c028bed43ac45f7b7f9eac0442fd625a58e684dbc36823361e31223552894d113310625f25119bebb6227203ce8fe586f9d146573568fee4620d722915562b10dc76eeb272c4cc3eadb9ebd751d6c3f782310f5b39bb5aa03d0ec1a78fc32222ec9d51d903cf1dd25b1108ac2ba1e4ac86829a81d43a361a0ea910fbcf4d72fccd65fd8d9f4c07f4b004275d39da2baf3d6999ef168e441922295f41310157d10edcea5f3ef0e31a395ae001db5c6a2e904c4fe7449ab5c74219ad8873c9fb62b0cb067542c2afb93f38bb9d5293d45fa3d0efb2131f126b21a758b87975b52ff2933ce5b8e1b18559d5c6e187ee717238404a6a061c66a1c794fa52a6f0766e9943ebcb3caf2a10051f1668a73fa005cffdcbf2981cfbe1fc31f97c6e3df5df61ec0cda34300102c1047eb7e789e5a16727c44b4017db664ce0089e20595226ff766d37e8f2bd76a6bbf8ef3d9a98c1702c71aa4ecb7ac290d8e3a9247e7cd53bcaf70918175dfb6f42738a57d15dcfc5af81454e9de42d731121b3e888bf388b00c970427d0a979ef23868cb2518c000519d1f2975c22ba76622285261f0be90fcf459d84997e978061ffc8168504a5768a5cd6404c5bff21e2029de2a217acad7e1211b03df3216a0c5be3f0ce8e847a18e7bb4f98247d4a4b0cb6108531f865e94ae8a2e829e6eff54343de48f268450b922c06f1b83d91da0fd39bd9f15328470d9847a2b35734cee16202a52d28960f8ff5e3fb545f3be13bdceafa952a1194f93454fa8e2ba18ba86493f3bc455f4e7ec1add3a6fe096b1b7f50b5ff3c3f73cf6e99deedc4cc3dd606a7b9c42cc779286c314358dbb24008e5a944a485020a9269afdab74818435c63cffced0abbb40928fa22cbaa842ed1ec587fd31083f747aa5b8c697714038ebcda58c7fed2add589d9925f1f884f7a44b467fc0735bbf46c99c0f2abeaec0bee2a6aebb4d3e5b99fcb0e64e311712571f607d4138eb924fa0e936596a78017300c6e153c118699f20c0a05d3edaece791abb2ca6db0252cbb8b80548012e933fb99d4e78b00d8be07a8031826dc3db2e3c8ab54e51e051c69c8fc9012c57a1047ca79f57d25de60fe1d7dfdf1e78596dcf1adb56b28fbc092456e55d3d961d1bcc31fc98209fefe79fe17fe4f872409a9c2461223e264d4647ac7036059da1621ddd5d787fd2da1b270d6ae153c2757ad3239682b3af341a840362e105596ecab65e89cefff30179da29afc6d254f1d5452d2e7c273d98ed5d2bfa31e749e3f54e69bce47b24c2dd66bb312d2eb1941856793520e8ad055c7f0d7a2a671e133b9076b1690e01b4e289bef4f81666ebb5b9e129fb748282d81bd49ef69ec218f485653d763cb7c3d454d35cfee9070a8c6dfab212da2e4cc539aa2441ae3b2a212fecb5d516a9509c884e77640551a6cff3555b7e63e21cb251e556d41fad3a4522f42403f8bb495995ae083062d0a7dfe47f7c49902310a483a83315e426022e2ae04a2c4fa2b0c85eeb068adcd7b399af2c774f03af2b2fff435ccbe46b396fd645623edfbaecad4ff5b3f0121bc8e71421c789ea586238bebe08d16e0cf513cfc6471b372ff3ddba2f87e2829e6318da3404f947f96e2180c5b4cd7ab3d82af337b593a80d2010a0973b545a290dd509218885c20fbf152c278ee1c3096ccb0bd39cc9727e1d0ac7713c08c739c8fec9741be102b3e485eb3bfccaf81e2caca75b628b30ab8b53e74381fb26e13413a434d04bb97ce09e97759135dec9945024d7032b1a1098e9ab4b37e4698b7a4b469bf6e2efb157527c44ef6234e0916f883d88890be667556e8d436ca40b084dd45cc81ccf8722ee3aefa5b40d68beda65037b2249666b29279b40fc046a2306de9961d03f0b835c24205a5194415b394e05c28c5ccef7026bb53ebc23d7f4caec893c0de4f3cb4f787cb0e0a342f4dfe0f5cdda85ceee0cb1bdf901d4fee7887fcca69fd250d32ddded0ee660eff25d91f98703a097f23337b2a3bc0e7f8c9798a7d39091b915c30c30792cc3b9223f3b3c3bc1a512fa738ca9bd0d1a7b46cc02e5491cc6f2863c88e351848847e6c61944b77d208bad642349530e5104870c07a0c12a693a985742939c90968a52efe1986488e1dfed6d056778bce63d7e29063d128a11dd631fc5724cc169f3c5dee2003a4a350b91339e51dca7e4736b1804f041682c0c70576f5c34d95c406d1f39f6a12fd621b39900657602d5ddfcbe1021271cea0d3a0e412819a2086863bb58e73b32f7ca174d1f63d896b161d2e170db0fa030d34b26b886c106e083f2f169b6d0fb9138b1eb65c277605f59352f01525c6eb03481972069ab17236592821a0b65d44415111701c0729d39c43888406bd03f0c61a839707ab456c6d87bceee6a5fdcdafe70ca9d8882821d2f778444ef21d59a1fe9e167cfcc253447ba880df17d890ac167f8c00f05d4556a167f07995fd715800688578fc57326896bb0355687387c62a08e28496d504e93be3df7865a9b629eae71456e1209bf7d15354180584636fb6050454f0ab1604aa5aa7fb046866a8f8138e88a50292152aa6845e0932d37e0119c04032c45bf51a23790c615f9073696dbefdab783abe044450dde6ae9805b8b12b247896ca5274c71c0a204425b93e948645a41b5f63ac2b4720866b11a7b59008bc72dda8bdb8462bc593b99688c661e2e07fb033b88f95d334a8ff0835cac04598b2bd5a4cf036e2b65c800f091d24202b36d8829dd29d7d17eb5db89f79f8bffd6265f930d3ac16ce05a64d7e268405b7e24e45eb284d5429d8c4f141314e956870bd412acc36a9318b8ba8893a25b2cd304820db3c84120572ece7a18f60daa38a7762c6c3691bd2a17a36cae92cae333da8196d1d682dadc854d782bd9e6371b07513773b324c0c0fa0611a8b8d2576600bca090cc14aea60d6f33fc8e6b1e539b7c75555ba2f9fa1c05d2e9d4774662d3aea9d57e43f8af0c0a4dd0e69633b8abb10ce5042ec7063d96d81cc2d534c6ff0ee41fe461ef79dd844b8b0b9f73b22fe8ca4eef841973e056062b61cfbedb0aaf6aaecae248d2feb503bad197073607c883ca6c0319dce6b3f22c29c7f83fc1f87ea4dcd8f7b743c4cc0e3a1caaef8712d71ffad0fa052a83afd3dbefee85377946ec9654e94e1b449a614fd14186cb521d6f6f891e7168c84bbaf13428827dbb157a3ea08090c320a76694d9824d3ee618cc145b5fec671198e0d1c39762065aef07abee58e0ee670eefdfcde45df42689728a1e13f40dd645a748f095a0c15ff4cc7957a0dbee9ee80913da27d00be9e8ac06344614856bbdc15a07bf4942c07558c300b41f7a15471b9e6d61a25353f03e8b873be7db28aa1c5086401d922d875395e703064f107961fe943bf1586905d6ae2f4af1553308f4660a8543a18c184d06a56ce16e53881961502c531a2aa0c7d79fceb27f483a4ee2aca9e3fc170e301341144d1146800c06ccd91edcf2d6bad16439d3e87aeb41c37eb459dbc2f2d4380dbb02db681073f340d0fd3502395aa35afe3dee3711320ef430ddb9fae65c98304cd0161c48ef4ba39f26fb1e8be0601cf406f78d1c64be9ddd5f2d6bff04f0f7a53928ac48e6d5d2c977b7747c526c3b271f458aaabd1443a02677ed8206d14552eef26847f060c4d5d849983af31053418ebde252a79d20b76b701793c50a8c53b4c9233ce9d100c6662362ce844cbe296fa7726ef63213ca573eac840c0d6bc62697efc1282051232bca60bed0b73b35f1ba64ea5c176ac2943ad5ef44c67f6a8c1fa5b7512eb298f4f0729c06621d9dbdf787726f3671d66ec8cb6dcd500fea7accd1a85d1e018f77fef7a98cceaed97afbc7c4395719042d20a3798c3b8d3a3e1f3dd9d2d4bf3a827ff95517ad0206808260c77dd6339e2f12a1d47fe6f8338c6f8ab5f714cef21012327a7cf577412a2becaef06ddda4f9d44e59f5a7916cdb9a5f9e61769bed58f45679a8c8363449dc05893859ff93c0a1612f801744cad8ed610ffe8d5301b7a3f0503ecfd09e283d508c0d41e5de165dd03defd8d7b3cc8e61a08283fa41287e72411629841a1f18a8cdf90ee12a10962629e1eeeb3378335606c53fc8ac39c0fd3215adf22c3cef45ae4f4d419d73ded20914b63cc5dc3004aed3004edbc7f376dabc9ec48fad6964457fbf6eeac0667ed02173f6f69a12944f6c0fd21a2a36b72120c5c82e921abb5ee01db7060f332d3fac17b42e186b7991e85f3fb61e830e0b7822a1d3e6ac837810d8a97175a27a12b3a703f18288b63503ec8d96f32c672eaaa623e66adb8c535fc2764060f77fb9a6881b393d3742b709a8b5286cc3cf323b7c3698629743ab6d48c1eeae1c0228c64875003c6e62ea019000d543dd5a1f4bfa0ff1bd503886c4307eb70c46bd1d9ee6918d6694a79eb0f7213d0bf9f8cbdc4bbae4ef2a938e9441d80e1e11471f0b986834404e1f03bbb5c37ff5bce6f79d767695ebe0fb8b06fa5881cb441c6741de1084b32b787dda6efbb5470395bfaf71241243220747230841a6ee40d8ac545c94e10aa475f9a694ecb72dc246fe4046875d41e47f686496fdff2eb13836d8f45ea18fd407fecf7bc9fbfa82ae8c4b6d07997b6cdac016322841a35713cfece7401209f85658fcb1937066a504554f3c7896d86e03b587fc1b0ba298ae623dda3fe0ec5d06bb048be374a18117a9c6d8c6df1abe3b54ee62ba3c4fd73e7f8abed9611a8c830e686cd57ae021a8ff0719c7b7cd27a2ef8be49f5fb32521b1b5f70b1fbd78bbe706df1b1252fa39103d72ffacad8a04a6d03e1db4d01bb2d5666cd6f45cf418ed02e4d18b85cd670f015cd87518776accb8868086bca9fd16f68048f435ea5ed53f2124143fbcfa0446a007ccc54b4c50088262682041f8a1810347d6bc77652ca1738841ad3ae5e90d4f43c4da88282f9ddee9db344e9ce64528bbc3b0b4d437fdc10c35ac43f591456837357d4791265ea641f1bda365943766d92965570be1531baf0542efeb7e18e7369308ef006c5830d052e3d9d64e36b5cd6c0d978d2d3241aa38f66e966f1c613fbe743b709507aac4ee882546e984f2d65c4fe195dee94008290c9ca651c03cef3668bd603cfba080213c61e20ffe52d2cce5ddbceaae7620af0d2f28aa28f61075e9a8a615452e166e675a75c08876c120fb3c8bfe0fdbda999a07751e70151472849eead80cdddf01663190f2ab7a5256f033203378789baa144bbe4cafe0830533ed2a2689970ca22616bee14b3fa047bf581ce79b27050006585eaa978ab1f5abc15ef32fe4d587a70f8b1b1f8d948722449543c9671818867951dbdeabe019430ef7d9cc2fed9ef82625c7b8127c327456100cf0d60b0fbddd275171a8535b36a4e08b1e4a42d39ef32291ad5285aecd8b86d87302509cc68fbfe86c62dc3f0b3984044a2b5cffbeca7fe9ed013b38c1a0a4f445b355a49d9ae84f600ad28b402acb7a6d2b8ffa40b05cd15acd91e725018365d52786832b23681e486639cf6d271ff9fc977278d7b8de72f5ccc7c5eacce7bc3735d7e975576a072318137ffc18f67a68723b577bffcea64ca14b338aa5c1ccb73a3bcf312272d55e1c2c9c90cdacc776185eda59b3acbaa64fce5854cfb47d1a512f67fad25458ae82aa65501f6218468146fc21f26315d3b849efc6fa2378460b17608ecf25c9e1760297c4f343c18ddf9374efc28de671f45c3cbf11bca47205c7b2d281e9518325fb6290bb023194c3e064d6215220dc512254b40b8d5b988cd7719ab079c96872cdf042cf6cbf47095a08ab8d40584f160961f3c0cbff0f72db16a82bc06273e308df2eccca83dfb438e225436f68e1d79d89dad9f47535e0ba0767c18100d30ab6e3940a45016ea37066fc039cd355d8dcf0ca69dde005d95c2e4c5ef8d0c61f467df5ca5653d93821b34a99e5de6f5c720e6071476322ff3bf274568c16f2439b4871803103c1eb8fb3646e3f4bc1f39e57f7c74410d7d3bbe2e03fe8a21f6545b316f52d40f4f816ce11e948e408ea7a333506fa0547fdb4e4dfc19f23bcd5fcc30d28cea5492a8addd8ba59305fc510daf68da3f1515a766064ed3f58818ee4ee678d86d8e06c6dac1f3e2905dc7600e625285a1fb4abbd2e92f9b92a60ce9a035df561290568d71fa275b286c4bdb3d8cf9b8d2521442d652f6ebbd818568257010e7f9c8186ecc7e1bff3e9172b121cc05a6ac184fcaac66bb5804a87f2530fe43853824de78b4fc1709c533e5d170bf4552674b788cbca387a849a9c7809e44056bd9141a2fee0b37be5a4cbc389af5d48089f4990850278e924702d55859208350b882c3c7a7654318aa1100aa8afd6456d0c0e47aba8a8f8b43a6d37f5a7f79a58c80e18c7d12a535b4cdde0959f6eefc5367b4fcce453372cc3aa3bfb2a562ac1368cec4d7fa2b2cfe747456362e70401dc3694ba1259512bd520eb224fbc70fc852b2bdeca3d569644021df0ff0b5a245134923d35f7a5bd1966a1bcaf7ff5c4fdf06818831fa670583d20818f505a878be496b8653cdff0a8e56b77bac685eefef57cf2452ce83a4227cc6f53b1daa28a0a2418d453aa62841f7c97e9c8112244240331251b3a5e922d92f51adfc3a19a2b845f85b158e99ce6bb7e9d77fbfd3879a1ee8be451884a112c3677dad330d6956360e587f733d042c6bd967688297d1056236ccdbd0a2c59a87b2c2d4f84d3caa5372f540dd52b080ff9b9a35f91730884f1986a2279d2ea06911db6dce741f0c260b47a9cc5284d56fa7a407ce71a3d76c27a7649846c586f5ea5af3a0a1710925e5b83da7ce272e28061ea4ce9b9920e0caef7d5cf55d061a3e5ac3452daca240e174daddab736a4e6d5b06d80cc96a44d6459e91491467f647f8d0ef8e34aa66080f73ad27073f8078cf500f37417084aa23d9c90ca12d442b2cdafcd48ed74dbf89b16d0d6183ae5b3b573bb96689c6bdd43e22fd77a473b5e851a7aa2c5e23039611e32b08ea160d02584a4f2a3809b296e5aecbd8bcd5ef82a1a92be5ba1c22c002f5260a82aae9085c4ba6a0dfa7556db0bb3856b8c4ca13b360510eefba52e68344c91a68946d7d11bf7e7e1e6f0870851f7aec2f8de84c8acde4ca008c74c11201968484986654bf092fc76e3d98c2f244cdbd198c626c21bcfb499db8b147fff4abbc2cd88c58fb7c504e6584596e030258873791acd224b9afffc7a261b4ab2c6fc056a92a9dc3454f29a100a261d6247d1ab457770a689878e6ed4b98378dd46458acd7fdacf4938cbf730949d65364b9acb14949836fbf964bb93eec5456e48a90d8f57037479e04d7a00832ac5befb614d556fa4d5ae491aa5b3079fcda72042269c9ca466c4097fe28088978dee7b7bf7accad9a1196d819695f63cfe2a8bde28fc9c2fe2e1eeb6f5a6f56155b6e93ddca3635be8d8571b7c9f81925a421b240be54b12c3150e73f2ef25072e080cb41af66a6ac81dd24ef825886e03f574caf9df9474f1193a09d7650364fbaec3e0ad70d9ad02a7a38d51a0ec48305ba5b8617e56777cf80a66ba3a3899c5f54b96ea11719d85f447a3d0c1bd46e7bb1eaf67a1713af7e450b22de89953209d61c42c5ee86a851efac38b5b436b9c8aacb84293315111083d64e3aa931f859ef48bd4f26e369546fd3d98852c5dc1cca2e427ccda7288daaab84ab2c6501fec642de72f6be8568963d8576a1e7d2724c50435317aa73d4e5dae5fb2c4de2e5de850ade5c0457b919002170a8d923aa94b0863ac676963f2f26801bf0b7335ede78e689b9dde0312f81e2d2b8fbf7fa8ab97ab67b55774bbbd23b3029c3c9d5e8a93087e8a370a99fd5cd8ead0f87b2c001739844f740f0b3ddcf591ebb10292a4981207c345a7dacc8228accd36057861750df28cb877381aef0d3ff625ba745dd2cdc04199ff9890b89d71afbb7fdf632363e4c51402140910d1f02f8ae85851ef333cfc3f4807fbe6a6633e9a4062f4c57986835120aa8d7f4f7fa9654aea9f8662031ee05410478d644607a61c2a7f42633746aede0788cf7c3dd2c1b5b1d8d7cc1ef982cdd21ede222463be9e31ac3c81d46aaecfa745ed2962b246b4edf92efd01257328d3c2c15d77c6c180754d1f963675d45be85ad43ee134808975ab4277c2db56fb2bfe8fca8669504938efae0c57647e67858778d6f7fa747997c9436b9d3e621fa04c0e981f003112d92dacef4f4225f02ffd60995c9023fa7111f41f26a04ff3b58778d0463e0c2dc299937ff9df9f96f9ff2510aa89f303023dbaf3f2f365922cab0a4695eff46f04bd9f1fc8e04d62d5f1fa0813fae4ea1538a35f5b500c28c10196b90de6fc44535841fb5df8f2433fcf171993b5e8601626e426d83a0f28ee785d090d60cf3dfb3452844e232d97236d22314c08873837cd1f142ed01cd341192c21d7af05e9aea56e2c2fbdf556b8ef15d75bdc79c3327116cda468c8a1a7208cfdef1a0d551e107ea5ad832816c817efd81010c278c09ccdf22e3d100ce5dd1ed712d6438ec4d80190919215c3a4b70d1b419e5d7e511dff88d5b1c990418d663eb31c51701b657ae5592b57608f05facaf6b15201d0f282695fc1edb93b4c4bf6feeb0818ea1abf5af5392b7737401204e5ecaef6ff7eba78f64fad68f066a416814755723d6d3df73baf46e4755817c2745e593a913c0a73c1f559e6a3ddf4bb4518f84117c8ad708159366687d871f22e67afaa14cd73199b38d0d8f09b8398e5e1d0e1c30bd929398b527305bd45d8ba57c8573f6d36520e9e780f67ba5d539a4976841ea6b0d8673e0b62ba5bf14bb14b982151d6e8b43e6fd5bb679029cfe80fae589b832918682436feacb9fade32641d705a3796580d0a77bee6cc5f0c25ffd03c9f903ef1dd39feceef660a2f8e403ff218ae63ff1f5c88e62e54b8825396aa05b762254194d1367a122a22e70995759c8c3f5da8f76fd41775155d8591ff278ef560fcf05936bb404819a9f8baec42dee62852949576af6c719dc8b9292b105ea36aea9744bf40942de630ffae4ae55ab1b3e8cea045e742df2a8ed63a20cf1cadf5e80f73d96e83ba8f494ce78a9e4e9221b58c3b1b6a675c13dac1824cffc1c7e1ea33b04f8d894242c38b111587fb4dde8f3616368208779257c1ed64298bcc3a5a423f4f410d2671c310b479d1515973c31f83d9c545bb99913767f627ce46f0bc3967cb05d33bc79018172447cdb27146a0a0c830a4236dc877de8f5593366b256307c0bde1f676c7b17e9444d4c68f7477e8a40418106723e1ff0a10902a93b3a72ba30f5a9f07816e9e609aa9b7ea573b62449797c41ea71973e591cd90c9309b9b1d70eb243b19d9ee6b2931a83657e6911b67132c4f9099664720e3332da0d03048e3c1e96cfab911fa0b6db711dc292b062146406d97ae3e36e585714e890191d7aad654b7d01324c4b60b6b2ea693621bff411e97c46fc76e9bef73c940441ae391263c7acd80ba25612020e2134c034ab23fefd98e8c76795ab1ee4e3dc95fcf2ccbc2ce95b8191b8991f292f1448b825c2fc35b587228f1a624db0a8f93f692a46c1088cbc53a9a040cd3785d035b020d2db5e52eb5abb47fbd4b98e49035f94913a95268f9cb59eed65f845bfb86e0b1e2609d41254012d74545fbe3146c8cdca226e4663f081076739e83b9b0a38bfd467738488bc4758ad4f5c5aca0cc092cdedcc25f6729a841e843807a55380db9f88c18dffb2431237a7e02e3d35b42a0903a0eecd6e1db4dd2b11514d05a99d6851ec9bb2f608c25c6433f2fc1fc9e6961aaf7c02a3ec7fc7848beefbd3bd41a5938764fc5d07306b2eded698ccd2fe73e4d00fe0ad85b7b6da2dc3903efce6da493abe560b6a541041f3253d8ddaafc031ad16a0107013524af422986e069b591ba4319af2efcc4bd5d25401727ea361479674db76fcd128ea398ee7cfea85cc99ea776a852367e432a215d6aae41c9392ad649caa3fb5572b63fcee93c639335f8fd567eaea6e0836de040ef96ee7c2aa8adbc5b68679ed81d91b4fb35f244b75d65747e1de3117a928670d605330a57511b8757e1de8d60b946b2437124b2e84669185ffeb6cff6825b2b53b51424cbd3d0846171e2159d23922f8f83452803481d5db775947204021df81f86feb6bb111f7f9b7ad0408e53dbe9f125f7e5b7c0a08f59a7b9715726f5f79a910bd95f8b6c58ff1cae7655f2229bf9f5707c9ef485102a33a59845511542349ac1b92e8bd2a5071d6bf0a13288d7790401bab7d4bbfaa82804fabcfd287feba30b666c0f378aab34f76f28f6bad1ec29a0e71c4ffad982d03df17f5b0ffcac23ed13becafbcb929518a2a317d05c64b8ba5e7d871050ef71b7e2c1af9483c04efe8e0606a8e93cdcd25fae39cdb8fdc97756d6d2eaf51f9fb0f5e314f875f2c6859923a9f8ba8970641938146bbe12ac1f99bb418c6382d5a03847357d67c8f6d5e77cac96bff7f995fdd905f9e0c1a9e4b718a5973f6fc203bd28038dfe5b1efb5d4884fa38ecf97c39583cd0a46e8e713e026a7658333eeb9ca6c76557c86cf6b1e53e8842d7e75d2ef27f3b7526efac7d43c6e39bc02c34f2575eee74fd8b3d185b283f8968df61cd53333dd5fdcd2d8dbe6d6845ae06e4792ddb89b0ce2dd3e16d502ac5a448eaddaee7ea59a85aa7525dafe9c79cf7fbcf22f5ce616f139cb4e86cf3812572a8fbea08a0d836c079076a6c07219d1327fc10e318a44917401617646165f061c3debe9f8f1b4c365fb08f938a6e3aa671c61b7cef8fea282486fa02d5d290638566755b2d4cf04901a48d3b8a567b324f03585b918dec646817dcc02e176cb38c878a061223bbf8e27d4b10c3e0fa9f5fa1e4223815f47663f150c7c1c1048b942bc60558a0e132889a8256a4d97ad9ff7408b309e2b72f58f06bc883eb101314703e1b00557eab1f1e402c7aa6a78b20416c5c7b9dc53b52b67295bdc494486e49225932d0d5108776bc5078f0797e8258e3fc931c4e1fcdc4cba19a1e15c89d2563b23a5a2de747ca3fa88271d9d2817606593498157b64894730ffe04bb92fe9012e1f4a761a88b07c20f892a3ea5d6819b1662fd4dc3b3055397ffb1cefbafbcc72145e9f594cc82a3dbad0b834ddb8c37a160a40d345e424603d74f98a7b3967c6b351bbf2ec8367ed839f7dfe4fbc47e2d0a1e0bb63f38c669743ea1cf4630e5a0e8b5d2c1bc2677d26226f2d8917ce1dc688c15e298771c205a8cc10997a78a2c6e5b405b89b10a88b321e40c466809da64c4b34e0cc433f924cc37f860d002ef2dd7afa162e5a7bc2bf290d3c8d416169c162cbf41b1fdc1aedf0cc4c2db0d4bdbe47b1ff1ca950770e1758f3b086fa43d27c2f56bc88134c4ad1938870c3b7374294c44637b2c87e67abc65bbb3895041045d1a9dfd7dd0ac3bc93bdd6c75c07911f4024a6e8e63b0a6ef9a37ce44f73fa5b14f38d2b3ba2b3393222cd4f584287de60157d7eebaab2dc382db84a49fd56a1d32537fe414df215c011a30283242cf4062a1d8a94ca499c227d28ff995507d62a237d1e4f2a8e5d0da60b1abf9d773ca14c1168165ae60ea3849c9490fa06f1930e8217d16012567da6cbb7983bc8cead8b3a3f92aeb2848853265b9a05be638a7f87d76a8ccf528c3160c8ca4c7e1742418ed1dfc462098d719ec033cb85ac9c59e785058bee5297df209f94aa566a479a386ab144dc91c24db44f1936bede4fc464ceb3f706d24aba698295492714870c3c09b2d3857ff77a14b879bc23ac65a2f86e26f57b72d6f81cc38f0dbec41097828043b64db7d137440362e50c8a2baee6187282058a03deb642519b405b960da73ff18f986eb22844099f82bffbf4be9a7ab970a9212c634b30d54de6cfeb1702cec640f5deab77843b78a03c6582a65912b29052b911dc22daa09562a43404b79535634798595ef8e30f9d8cafe147e6e0810420145f258c2c3574348f7829cc640d0e6dbf6fb8d827aeb780fd7dfb978dc2d7a1ff5f0234f6a17dd0ff123affcc29be8cc0bf42447497d5ad6bf15ea26f74dc740dbe1020043a7d720fb35e49583a6ecca029737d2d77dcbc3add11925546187b723c410c0fd636fbf7b336032c5bbb6bb78af77e91bd1f6080268cd994b2ff880807a9496daae284238e5c14c0e1e1850b4b4fd9fd90f09d214e5991c730cb6e0748f09bfca2bc6df58efefd2b795f03e851ff207bdf9e6163f5ee7e8733ac288a525fc795bf722c1d64ffc3b974fbca8a2b953efa66918e4281ca589618a760f88c199eeff957a9d1fdaa543c74c2d6d1d842e53b5f3efd69a785768bc938f3379c5c9a8458b2ede1206c57694e1d9ac7efb598347b8f4b43c966476ca53b3e82463a25fef659cbefca93852cb845e2beb54287056e29071aa7daa2cb398cc00545b22597387c2d663964a1e3e9b28d72b762bdb32f1640cfd6a02560325779dc05e206490b2e3a99fdbf3125e1fba422cec746fce94d9d1de734405df1bb686cf37520074db7ab9a5435e28135432a107983b15f9a18dfde45ec2ae41e45aac9de69361bdc781273c93fcec071e30eb80e4189465fc16b2e87b854a83a030881fc7369b2247878f7a9ede5c5e16fbcb60172fc7a428bc7aff7db4ed3fa04bcd314c0d12501791775b2da29167b756cd2bf1400ea36f023e22d3122d4d2b1e27918d8be87b0b8dc9ad3d67ee336e649d6c3e2b4fe0389c1f315ae01cdc82fbef3816418772c1ea939388a84447ddbd7807c21915fdc9a3c2ffdf9e8333d047b83c81bcfd38c6ad12cdf6bb6ee7709d14ee1c946495189c7c0ca8e2f0f66a58fed7b285b74f15a867d7caef94e8029b62fc87a251cdab29be7ed24b8b41f5807e4a917a5640bc6ce91ced9dfa96bd5b18006f3f320d73effc97c05396e269acfca17c8caf6c5d1a9d4e93a96402c4b78cc172a7c59142eee9a37f01fe7ed2c48ea1f4d67ebc0e02fb1242ee9a83f3e0b8378e1629794fdb55565cc595a66c7fea8f842080138e3193e389acfe176a76bd95535bb583229301a8506264140bd33d7a0445fbcadbc9598f904f3a27a2189132f570ce702006f1dd02e1e8f7c3b25105e4e96d4a2269daa3a3f6709782df44c21bd454c990c77704e81289202f81f48b6d3d0d2b834c8d4d383c8bf8621d8e3c933ef546ac4e670908ad6c49e496b8f0d6a1ae333c6a2ef8936eb839761ae64ae3c6a685809293d3b961398638a61afde34f65918b4e91cba2902db8cee8e540c84e3a2e545250a1d1f699c5e4f2baa538ce39ec527e72f9445beac101131f0eaf492a30319fb56fb0b5dce971d68750680b61149dc10a31b3ee4012e1cfe33b710e40fcabdc45b748a72c10e86fd7b62e411f29753938a7bc26d91471d9ef02544d1d4a9c37b083c7b4d5ca330683ffa4836c33438479ce0a4cf89a558ae46ae962b231b68f4b86c78e378a40e0f9be00a3d5eef8eb4abe10e1bb43f2f1ccd3cfa4f13d4339374ef40ca7e05d7eef26df8ca057de997a46d1aa3cca67a32d952825bfcc0ddab0733b2e2905d3fe98d0b25adb2c7cf87ca64eb6a4b806f9b89d5a74530b3a7f7f027b6f38c0908944d039a0b7d437e6c8f11bf049e77b9e83d88e8369ad693133a6d918b464210cf183a7d9487a7b6f055bf54a514d5df77baebd3ce45c1fc461c41f288f700a7110fc922da83bfb5a1f8fa5dc69fe2897c3c4a3ae98e34e33779bec8d9365667c0b77ff4f99b9ee72946796a9b269f6d56ccd033b98b05207133356aae51a4cfc4b589a923c23adbeb6f7d4673defe73e92a505b1555bbd240208259df931a04770099e220f8179c70f26adeee7fdfd8adaaafb434701cd816d7256796631658618ca854e74d8a6ec9d1a4b5edd283c2eef85a2a6e6791e60a4dcf41b02c3cdef21eb8226deda47e9b38d92100a8e84b7039bd62ae0c951c60f8888e7c0bd204aab16d9b00a13b1d61306f870abb17c3a43c8adb06874cb2020d47422c332fcfa4dc832471698e99a64f1cbd862e9fa2c0fa469b77be190fe9e1f18154c838950e9cb4b7360161a7096b74c6df7e982c87d700e4f8b1ba8580cb3b1f1f9585da8128b09139fe371fccd3cf1075126c3dc534a704333fd83791c8543f5411dfd2cd9a02fe1a62002392606d01646134dd32a0eef75baba56626f41370c1127e4ca5f47d3f41739f664dca4eb8deb75b371184be7f4b0dc22a69dd98aec1ce80694e72b1eaada24587489408d707d66136775fc63b0b746e3b5423677485603975a78c29f956b2f944517bb2d66fde31a877842cde163c094e2eb0bd9298b6280bef17a46d80b59b25155df3deb9ec2f395ea177c4cab596e7b055f69ee0cbfd06b83b28cd7f32f62e2ff2cad698f36d1f46f5c4e2b74c22975e032a29969b8146b480211371bf95aef87642395847614e4eb190f2261938b82c089537394dd02fa6ebfc2749ea027925e3ce45f24b8cb80a1764c435105da672ef1d1a27dc776c1ae256069ea71beeec0774855f1cba35a978ad67adac1549e811c833f4e5618218a4b141916f17221165786913b724865a74f38e48b8a950b8d68d445a1b46304455384d19efcab4700e2877182bb2df0b34ca98f6935e8bdf12649d2562051baf1f6484eea18b4cc303f71fbfd852bd91fb9f08052768c22eaec7f28c75a77917176a010572c1cbf3e098e0b33236a8d73803e061be5da3918c5eda3c4c93424dc0763ab07e417158b77255efdba0fbc1eaac4ae8806a2eeeffc78d2ab1189881f1b6d1e969750916f67c3212a4c87000bed3206b84e6c50bf4a49da93683bccf1f5d441879da72373e7be91ce9d323e393983498a649509c932d976e9f6d062a093b72367c1a0f73e31d62592507a6510a0f9cae5c3106daee23e195f248228c4dbe77c15a252586a556e4bd38a16cbbd7632b64792c0cbae0b5e260728566b844b0d798b824429b6100aa61af3707c7c8607a414fe90bf21be37aa4de51b02dd4f68781d92c3b568f21f60d0207bd58259f3c6b286779d6038af61641c4dce9ee079b68bfb10e63bb1c6f25c580d57f9b4e6765bd1b9aee1d8c4feb59af48fc59b4e3c1d51dfcfc0f52355cf3f0bc10e260c162782ac1d1f3bcb0d61c4c9c58f08dc93a638755f97d4c8cbb233593d5228690a62803df1e7a71cb805f5f112c47d3e40a82d0eb1841855470e77f84974b87ca876bc5ebe975f6c0e8f84f9374121204f3c814bb28af37fad69593f05e7a53d682601b485619a4002efaa20d2f3c13e4a0160eb96228a5e76785538a64e642c65de509d3445a1bf31244910802537d45b2719574be08f2df6ed140deff11e2e9bcf61e12663475fdd586d66952d2e95521c78d9e760d9d3d8f401d14aacd064fdc8f98fa939f1368274157699a6a11c642ca0666750109e27073b670dc4d460cbc16b0ad16c3e6b6a282cd6a03a3dcf171855b6096a9b5c26aad1c557cf9dd6bfe41a0da9ea3a306a330b4d71023bf70f00aaaa89e21749de20e2fabef0788521fd21aee5f716a090f4e33c223384eb74506372692b778ef2e18f57f6bfe728d07b76ea5a5db672d94b731312053c75af884bc5a241897a0c211095d25928da8256a5a4c70db4dd234fcba339cfe71d00fd1e9b8a17bdf61dc384cd9ff09a1f0cf212c588e6d270525cfface497566a26963c70f1af08e685ec557ceb0e3f5f7ac06dcf70ecead6ca81740de11af46c419a13a2bd323c9646d7150699b6cc672690bda7f154a80774352fcd11487cc8399ba29f96b2395fd67f7c8ad4c2828aa028f3ec00046964f4c83db7bb7869611f1fb7b7be1501fb1de4c25606a93c32aacf80185c9f448fe0da912f718473f2835a381fdf8fbbb05857555a9896e95cc27a4fe9c5d76646a4d9d063ba6e208f48f5ce8346d4ee5d64d123a7a20580ee480ebe605c90e0d18262df2d53ae4aeefd3bf1c9e3d87130fa2faf160d2b94be5e4f89b628d35131082076e1fed36871f8203bdbd6d949db4f73969342164cfd1cbb86aac8c627c73d9a10a2990984bcf4c32618e8c9ac65c339cc283eb50706adde5a7d901d92c57dedea6ebb6eed8c5d37fb95d80d76a867b7bb9b81bd8feb47b0fded31155695b22012b192c2ab293f08a0ade9a6ebb92ae752f0690383e59f1af91436ba5b1d236e18d01f37bdf3336f815db8ec8eec46368fcb4567d839541fec30d14b960faa539f0f8e7dea1ee3635db48a3fd02562f8c6d059be7ae61386137c6348c40f925f46072f241bec28efba39965638ac31d2329d9f3c5fd3c22857e4224507123af02a4c02e84f4182b2197c5c16fe9b485b48d7ea6cee6e3cb84fe64b30667acfa421a9fd546dfb43044c5f102781bc4372867e01e3dcbeb251596d5e8e31f70deb1157fb0ca69a1b4a338cca966d5efa47c324132ad1f7e186ebd6723055874ec9959cc503fde976347c3994594abd212081c94f628f9e224a941e2e1f6252bfa397be9ad4853ff53c4f7dbf0c5e15d2aee3aacf44772783eb6f7c981b55d6ff4f9768834ed432b68c90f31e88e7dfc8b00a05fae91de021fedf36ccac7c1b0d0b7d504793132d91519776b49aaeaa5a0c268aa83830e85efb43cd166d2ee870224eb0413f1e41527b7fcaa757b1c6d28a6b2dc1f5d3fec1150f4be3432acd38070ed5190f50859e696c3507f2cec74ae964aed4139344d3c6d61d9cf91d5a0d2734c030105b9c942156320baad8c15ac74d0341d3a506dba491b6b03b74fa60c26ca8ef06737e941fe60c9d77eda52010ccc51abaff963967407aa3f2d5c221822d5326ad52e90c0ea99bb4dc2a7be40599a1b7f2618bab2fd030de49b3fc84721dfd0f994e9cd1902e481810139cd972d477d76ebd92b04eb6874c8fb62292f3c0cbf739699337fa4bcf733ddf6fd1bb89de543ce8dbf81bc219b37902680b36ef002cda1643879920b05e0fe697a68b9bd37289807951acb3226b55e848ccd3daa50b1eea492b29fe9d757d6ef6f719f24d2b1256bb12e0cb4f5ed3bdebd7a509b50c61eeabce60c497652202bec5c32dc9da86449f2a53d315b7da16ef574cb15bbc9432f961a484924ebe8868ec28d236f3973d89a3c3d1d20b11f639209b0ae4f3b684609055fbb85081fe9f88acf0dd80819ad156787767d4789751113a227338bde2be5062991d707bd91c63bcde0d4a2c39177d348fa33ae596f55414b7eb11c0e31a2c39bf021772b81d16570041dd823fb8a57cb339141b51d0c3fa0717d124fd43d9d5a8cffb0b149c8700890fdc310907a886b600bd83510976041a43fd0709218e2f414d386d6d35fb24ac13d56dfb13fa5470ed7c193fbd422b7f0975d73519434f7f935419276f2b4534daecbeff91c747d91263c79cfdc3c09eea909af0a138fa043e75c7454ce3f80073ec6edf6927e1508a4134287465a17930f38774ac50fc6602f66a7ad7bd9801c587bd17801d96ac689f7c62a9261d9f74dee6b0ca8452758a87880c0cd693f7a85a27edce50881dc337e5f9a99267437991b19d83f8490266a0f46a95d98d516995e968a2981eae28526e81dd8dd7f299d799301fa5bf5747ebb9b9a419ee4d627e140e4e11bda80283e6e2e1c015aa57a868c1de7074d9c844632aa4e703b4a69ffebedff34d4186671b912eed1a5a9ef6fb200c0e69496adbf7378fd42e3b411c37a3047d0f7a30d96bacb2332928df558796fbf7025482111032ac964675e108536ef017d5d99bba973eb21e5705ef78f821ce60ce72f9e79a806b50d7b5c8f39f83161a38ae8c093492d9ea6f3b7a931ef860099bd9d5652c2b70ffb6642b91228cb7720eece733193a7b469045b273d5c9a8621210ebaaaae28056ef222c17d070cff0595c9676d70f7de9b2f347aab8fe32efbbdca06135b2c508d046fd7afc46d9f3de6dc7d66bbef3f70fcad1804432633a02111e691f15fe11461b893de8cd1a068a5f2185cd9dc68b36dcc36d9e54a2b816e2eb69c44ef2700a933f1c4c266389994550a0d1841d97e50db67ec37fac7d8c8cb00de62ce5d58aecda6bc8940e459ed25702c8682f4cc91742bf47ece1626f9f9c6cf3fbf6ab863e4226b8722c72c1181f5d0d65a19812e6262bfc30fcd1f712df45bc3e1ef093e48fdd1aa4ce71bd58ef826a5f003ffe8b2a80cb0fb67e953dfc2c6f2af25abbe2c3dd5f2e273d50fb815198951b59505397c80374a1c0ebc9baa9f5b9e3d34fb4c18c3e01c41e237090d21679d33350afdd4a4dac8f84d79f71ef945825b309a231bf94c5cf00633de9359c06bfacf8b7dae4197f37e62f1ef6873ecfa6c72924b757affe544ff870fa8b3901478c3b675c3d4265483e162df05eaf3bdb3557d31fce0afe49c288d9440b3d23f5e87f8af664ad2aa4f769ee431e3e0036f5761fa6be19dea838df59f7a5dc56b82a37f68dc4d2936a6956f0f7905ea90d41b8a09dde4dea84f7bf3edbcfb6689f7047150923b2af98771f7ff1b923a19b508a9f9e185076e9e9eadaa4a97489b8fd28e7c457adbdeef36b0193dbb179807435e816557cb4b387d308ecab665deb4cbd4529e596f8c14d3a04c2e2b84c436c38dc95295a9852657acfb839ec145e80890127469b55928cd9ab5cca7dc5299bbc81fed686505156cccc684a1a89e91c2341f2933260e0e6ac9a0a97268b1936d0ac17f086e4e5f8a44a3c95cc4dab0922f4152f23a329e6861ee5eae378a7c4df8767659fbf4b3aac06dbf067010b30e193ce489c60cb7dbebf05067f9f7a5ad1ec51914c860ab5999345106a97c3d921c8efcf8ef7a0c9e91a8c6555213b7429e35cd06ddc967a81e5ce33926138c366ca0475b1004b0debce77098182a9229aa32da4943db892c0b54d1a01130180e1428150f97a80fb69df7aa5fcfea6debcce2ce9585a9628133808d6759f0a904013a20602efc5058fb932f1222e80fa316d7c5313d1d35a3b23d82d1d59931edbc552f33444acc4920adee4000d4412528e7b0f398ce9e139f805e68da1693b8b7ba8b470a2e1c8617758f4d088154b4e6809820747f1fc5cb5e4d1c615dfa7c535c81901ab699a6f336f475ca4916e1c5390630f298d0fa2df68df0569ad2977d3cc270d44eb1d8fc0dac71de2d7617d8940599e36d5d07c08ad337b448b5a5173529951fabde116562c34d9219e0f23285bccf41263f34ac04f159be7d994a03e8a1e70fe1fbbfde13fe27316631434226f4b5a97af75fde227a75ea292e16963686062afdee4897443d610f275ffeeda8ee67028caf576874f5bb1196318594fcfacc71ffa850b7782a86efb8391a20240801d6ee257ce107723dbbe407aa29176fc844ab2d3aee0c235afe235376ee96d87fdd1c428e31594b39536540049f3e1c7aba4847511ce0663a87517eff45b3f81a48d66b4bb606661d0d586136a335fddf700bd56d180370e5fee56f56d35e760b47137f56a773c70304640622f1a881acbf197eb4d5fef14c35e3c73a4c41b839868bb893049dc105300ebd1422881d65742accc01e5a4a69dcef901878c5d95e1344cafdd527c26c4a46833daebbda3267dbed7f5bddebaec1cb59df98b4c338e4ef02e5044cfaf8b59c772f06c8572a21dcaeda871908d83ac4f7d8c4055cd7a01d533eadb2cdb4552926ff82262c6e0e5dbda2675228745a68f56892441d84fea41f5a3d2efc261dba2bedda38ee7f2be94c2c1d3aa155d0236199eff6e15fa7bdcf6d74fdb33d49ca8ef8a42d723f48e4a767200acd40806e1f6e031e21bdbe9b015a6239a937abbd1823e3005d06b6f44e4a103c24687687d4470589f6c757aefeeac95995f2a86869526cd7894da96ec4d6604a427a8f030aaf4fc8c65bc15a2696bd253215134c2506ed34fc4da690b734154a8197a003a11df3e2068d6c58115062e12ae9ab1f2588cab0e31e41d69ec6f99476c6ab28ed415a0098b1f61e26aada11cd6a6e390541aa97eed5710e259aa6454a26ec1b00f34435c7be86a50ffed53fef342e8663c9ab1023904714cb0fe2a3fabfb95c9d14065457454724ac2851c4daf0a3621d9d7be029744547dfd9696e40ca79b93a2a74c7108c600ec7f16fe371e7f90a2af96db67e7d77c297521f2f3098fa87c3adbc9126e673144b33c5206bea2e3ebba5f4cd856e69394eb914f8d453c7c63bfcde87883901f7771aded2a3e249e760317d129437004fda7aa67102d7d8719735de3e273e7a7217772b38068acdf235a6f729899693a761250c0b65202c979a880f53b1289c427b015b660a4951c1875cfba0ab58c3a13cf1bf2a5746a7f89c88ca5379dd53099bd72b25744812faa8fd035dd831ed6e1b4d1e7a0304c81a88344442e6036a5eb9f688d25c6caf2302f203e9e87930d201cb77673de8c50031c99533ead74978fa9b4313fc1badd4782625dd1bebc4603d16f3d4a2eebd2c6e0f36195ada944d44721e8143e417550bb3121fb2c0b31358c7cc822c28db4c2bf1ee0be48bfdea21d6f3a7016c86190bd42c5876906345283499f460003a7cc2e728859454a7ee1db413b53e6d89585848ca8b105be8d91ab6d9b44ec4ddd828c3f9301fc3739cff33ef5879715458f7672db81a10fcfcccbb3082a5b0eee706497edaf17ac58031d2f1c8c928724e51e6cf1bc142b3966b355efd8b34942683cc2ee13ea75dfa06fb261486ece04c639eafe2f2f94ccc45efb3a7bbc39bff9a19afc8968163629278977da7dae99c89eb82122bfdc6f8f4c9aeed19f0264547c7d5db13378117e01cac7ad68cc7ef607425c7b5ac9a7474c1e0e9946722369d52b53c434408227afe91b7da5b74bbd30dadc08a75d0811af98ce7294e3007e1791adb2b6db350ab7ce8d74de9875759ba7a0733b16decfda99c4e2f61c59e61776ecb06d7319629b3efa7b564828c5e3b75695fb0e809c5bab7e59cf0b5b6e16fbdeac339b839ebb62cdf799c0c641757203d8a7780381ac4ddb35496a1a9e216d0439cd4c68ffa85dca73ecfe355e502150b67852c555b498f12b099e01094347390a7b95d024e696bc3fabf5d370de41940a94093ac272a08e901cb5bec786dd1180633b10d95dd0e1221a92a5b8c6048cd636a9f981efe0514772a3ad6688f2953c4534ee848a2652805fb46684e5f706b333e9a90f9f4ae3652ffa60388e90c2442145d0d1633531951529429c8e8bd6d1e36b2ae2357ec5d995c8c64a06c5f0e77dfc80c34fe2717ce5c0a56ae202b14343fb44a8683f9ccc73a388de9d3140ab9e2b5d0cd4e0eb7978b60a436adc204beeec300475cea3ecb81e6e7511eb8bf71cbc73960fa119adb2f2eaf599956dedf15cee1a397ec28bec054910c3f01d34d5bde3c524aa0e522972f6cafc2b41d6e37d01316a5a53f037e6a055d0e3430ae26e93cc3333cc3333cc333460f9abfb75f5de2524a298933f452ff0f22774a49ca44b10e06fe6f38085fe181d66dadfd56c36d0e080e020e38d820f20a43ba9ea68b869a2cb9c2973d6fcbebceb62485482b9e6f31e4957e1733e3ac3807799945bee72c08fd2a92212394de5fcf2a8f2a1ab1f65e1a3a8fb89754ac5e32a8d3d93325362adc607e59655aeeacebe88ac82990ef8278b15d8ebec91f66ac2996adc4d397cec718df4a19273dba14685952665e3aa6b66e376e440002387e7825880e0f502859102185da9d59f4df536414e9317fe1532b644bda193e821b421011c5a65327a5bec3760c5528dc11b73e5d3a08b53950a8e1e2a5d1ebf0f4fa27dccc31f6ed2e3e87d2136c50da1ffbdf7374e90a851203914e1c5a2ea5267e1d4dc739818a298d67efb209ae6aebb66531cb4b214dd831df9db89e87d07299d8b2d23b5e6e8508cd12443091a79bbb1da532d5f3dd2a72896549d8c83235ad40c4126649c8d9dafd789ac4150ae587fa0e868148258eb983c9f867fa99cb0a259ad3f13fba284bffe0164426d15e7ff4587f512ab640441276688e70378f26d38b8248248e598ed6c955b329798b4082d568675ad0922fa5cc81e306228f40af86c8709ba2746950c411d8aaa61aadcd27e61c81482352265ad4984e743c7de1c8800823d21d05de3f753977c8ef8d9aca08441681b8fc0f9d29633ebd83f4e8a1821e8828c2d68cf1f8f9584ae44a0e1f3d7e748042f1d1e347874024117df956e6fc219be52422ba0c17edffbf72c9f323042287d04ce828175e4d78529df8103184b6698428d982ce389e1e2285a863492df74f97cd26810821f6d20f59f15c6a4fae502838cae017388e1f3dcae017804164108530e5a2a9caf4f5311141a0aca48b99ac644e5f2b39727000c70f44029132d9bdb6bc73298480e8425e34c375ff5d50854231227f48ba34f3161244fce0cc7e974acfd69ce20f0a2587481f18af519da46688953305227c38ba649a6ead3e299d17d9035a963f64d4cf3b1d9d4a19fc82e6e12ba81bc603bec38719644000c70b44f4b0f42684c9d9380fa68b51b44769571b79a840040fe913194f5887173b4b574e7a780b82fcf01de480b59201913b6442bb4dbf725b3ec9021c3d82f018e302227638b72ce2c5c5a5bb501f41a40ece6a4adb574da3ad8bd0a196427510fd79fbe322328735e6a4d4c8dbd6949b1688c8815751a6deae5516571ccca1d46485e9382f6b2270c8a53d7922d5dca5d6de70e79616734e671d565576ecd0131fde2ce206a44bf7ddf3f29796a60df77aa7d12f2d226cf88517dc6c4b46e6b50431e304385470830438fe04ce2300541059c3729d1e9d3658e528c7b8310511359c74949e91a93f53399c20928605b59745d31141c32fbededba989ad8f2267c84b966b30352d85ce2b22665812a37cf396cbbaa02e034acd566e6739cb221132eca3c4837677c54b3f901e68096e98d5193e821be5434be0059131d47d2e69d2527cb6f80e6d1e3c44c490b664d24af63b2853876111e962c8884cd7eb80c1f9785ae637f505617fa1ce52cb76f3af88179032b71b32c38f7291481796ca36ea9cff8e92db41840b79cbba2de82ccb6cd22d9ce1059939a77259934e440ba78cf7a52caf5e38d9c9c98d1b226a10c9c2f295d01f77170b82e88e0f50283c3c4810ddf13f44b0801af96f49f75693b55ca1bc763f93a94454da225630af6cce66f163cca811a9825ded92a7ba58523faca040840ae9cc19f1c9b494712432855b6a39c4e9cebab59b881416aff47d8d089935b5225140b4b71ccee482423a9fb83b552d2e652cf28435bd29111ea369f5a888131a3b3d97776ec272124a5d8990d172dd8a19404e44988076532f0b3a63d04166cf1059c252e79ed116e6d26e501c449470b5f0f132cecc0bae8924412fef9c3ee6643e1241029a62b37d38b1217367032247c075a3cb26611f34781633322062045c9eadede8fff14fc4437d0707820031a3032245480b1fe6762d3427d18a102119e62a73fb330c731aff6c6f2d66f81046dba73c95daa942a1840463dda0d26c4fd88b8bc038938d09e59aa977c42684fce2b1d5bcb194daa77f728c7123004c08f1451f364be32aa362f7e21359ed635accfde1059ef142eea47ccef25da1507651f5e5bd24d3d3b821ba28e6bdc636e6c9acf90a85920b749039c76ec6aeaab642a1e0c28e9d4995a696975e5cc706426eb1d678aae9dd1ba16e8542c940882db40fa66aee65391708a90572c24c6d5b834ea75768f1ef6ae61332fd8f882b14ca074266910ce3b25a8e0c6e8320441667ecd1b3594e2d66aa2a144a2c0c5af334e7caa453b0e833e9746f532e0d444f3410f20afef64c74fcd798a5909e6020c41589b6db2c888f659d7a854269c52a1ec7ecbcd47452aa5028160861c5e2b7582ffbf267b6708542f97192c303377cc7ead8b1439fc718405c052767fc088223005a0859c5d7eda1d533baacf20ae5e48c1f415a158c9c1af51df3b40733157577c778e9341da4a8d8cd65b9aa5445f48887192a083905f6b3615a96335010628a839c8ea6d582fee408424a715cf1bd76cf973e0e8490a2cc3b9b2d78262dcca642a1780a1945262d35aaf57d74fb2a140a10128488a2dc53255f96ca3d5758a1507a74074242b1776c676893a5f3862a144af3c0105020ef547d18d3b2982b53a15036e41368e1b37f963e8be1d120c413b76c9ffccef83176b272d289e5acfff2c9f88f2d27329fcf1e2de87e6f1387cd2033f34b2f4a6e2a14ca090c4234f1a9d99596e5fc0cad5528141684640269b1214c9e3c358f1e3a4e5a1082894f5378d0f112e69eac50282b08b9c4732e2f8b0ea5bde2c5db1266613baa7d88b2d7e013422aa1650efadef3827439cb308379e8a044aa64d46ed0593ae73a892c932719fb33325baa42a1b0204412c87b6530994eeef78b8990489872f49b8be7667c411090b1831048785f371e9312a72bc48ff045f1524d7e6de55e19421c7116f561469614d1fa3682f37441cd09cf9269ac4239410823726f29bc948713c26517610eff2c9b8bb525b45404fb3a4af8c775ceefab109208af25399dc535e5cb398840cde871973c97b56a789ce046f3d031821b3770e020e41089ce589eedecb33c9621da6b49cfc99a3e0d7e2112cf79fdb34943354b8542d9c10fd744082198199d46f7878a593708538dc7e0d26f9016626f41a01e4eb36f6bd0252027cc43470b420281fcb3f7dc2054e6d84200714713e71b5bacfb13fad0324e7ef408a23308f9c32764ee39ad4906d9f97390810307853288103f702f2f8a0a7bc9943e5578f4414fa3367c14b742a1f0212d878a7859ee7bf57e41c81ef4bfb67531442635ab42a19c84e861cd5992593f5a2a148a06d18e41481e967a8476f9534a78c6d420040f957ecf1cf4ddb6e0598542a140c81d147b51b3309649144a8e103b18c4e9db6f6b49e5572175e8ae93f430bf6e9fca41081dde90193f64fc74b555c81c1671a7c326917b5e2223440e7d8e793da585cc5b323742e280a80665d52fea7dc873e42003c78f1e3f7e2c21040e97bb9d18f115bf8d3969e7c1020aa58710f2065e64cca7f7ecf217aaec588d41881bf2cef27d7bb7a7ca741bb00eb52e679a4684101bfefbb76a7de95f6a7105216ba825295e1bffa5abcaa881f71e21ba4f9e86acafc673aaf5dc820e1ad22c5599d6b57c32e533b819ce3357c6ef1fb119ecabded3d59957ec5406fd252de6e1af3dfb4b064d940ee9bfc9e5e01903c2f3d4c8f65d0c7a99e6ce146a4365160646747f734bfc788b826113328cb72427d6844ec817103b1bf37ba64c695c5e38ce89ccd351c34b2e5e5dd8c5d15afae5ea03215cd8b427f99f4b8bf392bb055f479aca871bcf3395163e99e37e4bfbf2b6fc1915846461b1429c7ac93f6589bab0f08a8f52fbf94ff2722a14ca0542aeb0a03ec698c73563fc4f8fb187102b98692efaadaa82632e8bd75f7e6f32b4d33108a1422646bf26b1f4327d0a6c5dfc67fc5442ceec8210295c32f7c7a510d2838a4f42a2d0affad69ae65132760f8102429379901f932e5b1507214f58984f1a43944c2f67614188138ca34555a78ee98369406010d204469d751213e529c592410813be538f9fbe9e39e9173b66c88007214b30e588d3418cf6ea8fa9e80851c21fb37d16b46cbbad9f9024743a5989107af2b91e104290b0a60e6e1ffe2683161f841ce11837599d50da345e6e4688111a61e237731ab9d22e4908298259b3a485cd9c5edd414308214297f9e9731a21b4bf2013c418c6316851a525ed50e223f340450c617ca52e49d913a24fdfc1705e1637798899cef0aa80d17bf6192d798c6739f88b5eb0de109ad39b8b396788e18b4ffc9dec673da57df5a273793d4b76c9e9e7ab788176ec32f521afc5cf316617e6946d1fdde541865e47104317da4817638b1ea35fff200e040812c4c8c582d906a54d84150a8587ef38e9c1e3c43520062e6cb16cb3b43eeba77dd52d1ca5b3c6e4f227399fd121862d0ebac74a8a07b1fde255b5d85b7a0fa75fbf4f472088410b566d647b98fe182ecea2f620464b8acb7a7c1143169ab628a3aff12b4c7c03c717c488053fdaa3ac7c85ce73118a010bf4b5a4bb3e5ac55acb2bda582b51a231d34703b2430c57e0bb1b636a51a328737120462b4e6abbf5548d878fdf12c460c5b2b84b2a74d69cc3b20044418c5558ea2597641615115da962b93f6dfb75122e42940a43369d88e7d15bf6a204315061cea4a54ca9f9e4e5ce0ec43845a6e4bb42bdf23dd3a630d79672ff30d6492f314a714e2f7856cd3106c4208541495119b3a42088318ae3d8956eb7a4b307e1988118a2488fb8bfc90b77d51f8e7715fc102314a5c76ca1646a49e756397ae0cde3060e3588010ad66c94bd1cef197ae421c627966f7cdd25dd22f4596278c2d09d37e5976b1ebd83418c4e2c3e1a4c5b0aaf8aaf076270e212254e94581d9977408c4de0b6ad7183145923b54a0cc4d0c472d499cd2c9f4c5a6a8542f911a404373870830c1c301023135e888deb1ffef26407138976f1d2e45c7661cd0a85c2831e0f04312e7126cb5d4f2ed899f5150ae5063c7400314304625882794b4d4d31a1413f2c46257e6f31886d265342f84a10831288f5d499be475cbe5402312651c892356ae454a1507e98337e90110028882189c326ad0f1eadfbce1d81189158cc92fc9c1fcde355554e82f80d02f68ba9710583cb62f6bbde8be9d9ac61853c8b2b5fa365ab21548900046ee4c8110108e488000442b050a30a898a8e3e76265ab6ae0615b6507ac254977c713d534896b44f919dbfa4c7526874566ffb912b14cac9193f82a01a51406490ef22a4dce878310585e5dab64d1963b32c7c42f2d14cb52c5cf356359cc07fcd968e597e41fc2b53a309bddc2d0b2e4bd660c292e75a353f556142b684368b6954afba1c3c7b3594a0da994cdaa5f2f0c9ae910494dccefb7c4266c6540d247042275955219a1a47e8840a69ea5932d929ab618446aa8e6e39c45efca703480f14dcc831860928142010c8458d22f0fb1947f59fd272546b10e1ef60e5269f848b291f19c6eb19d745d3f1b1f11b11c6c1f47f505a16939c938130128c5d8c752a1f6fc3ee69041807a5e4c7ac9117e7ffc82f8cedb77749a4c8d2e7882f9013b627aa4764b0da985ef8c2a68fff2594fab9ce18e1c5a7bb444367f6977637db05da47f46cb8f8315e5ca58bc5d7911b5dd0d059bb31b9587e5d7339f63f820bd3c72b73fa95c878476ec15ba816fb0e7f29a423b6703ff58747b37413f3482d4e7a4bc6f4ccb897f6115a74dea7c50fa3444bef23b3d8edb466398986cc261e9145271e2f4b6a535f4a6f2416b54b42e43ff49c7a0b2c9697c3b8585264ed3423afc045b1fe90416b64d923aeb065a95c4e1bf7cfd31e6985599019afe9235fb3b861459bdef3870f17d377c4c82af0cf82d06423736b6554b1bde792f1d28f8e58a9e8b36be96817dbe7f40a8532828af48cd07d9df162dda63a5a00641223a7d0bd6396b4c8dc280032c61f464c8138f5b3412869735a2c057a64e60ce6212c5f122976f58fa9f194282d6623a330cf934e72b4934e1f34220a5ed6e4296329251f4e23a1a8d64ce858393a48cf8d80821d2deb4bfa6e45eb69e41328e1c2df7a5d9eea6ec41387b510e9fa629c91d9914e582ea86b17c4adbc293981fa31996ce388d2edd944da427fd249a61734843461ec58e73d7ab6c5d14826909d4c6892e3726c494c285e2ea59e698a98e912c9b02f8636174cde258d5842ff0e6db5efd2c80e8e5422f131caa5deb01abd28b18b619f53af558dd08d4cc25cbb2ece6ef87ac78c4862e1ad84a93c7d2e9d3912093dbbf47315d293957c0412aaf6f5bce8a157ff8d3c42973f27cfb4d1d07133e208c373b8ecc14db778a5914624da622c6b8f51fbdc248c3002f9693769b599ebd88f2c62c12b3b8615d1fc4e8e2842eb6b0db22ac4349f238948a74db29aa984e90c1a41c4a7c73d5bb3a43cb65ea150de7f9c0c61e4108aa97097a5158d4d194334ea633dcef345c8af1009afbbcf7b2d66933521509f3fe6f82c6899d1574606b1e82d6dd68c5271312808e49d898bfe2d8cece84820f4b89e5328a9215dcc3163041058063521662eabb71af9c369a63aae36e5076c43fcc855b52cdbf561f394f9ad5cfed28267840fdadfbfbb6e902fa1c7c1c81eced00b55916f595e3db4f2beb99debd5e5063c748ce4019d7a7b3379deb4bd2a140a19237838ecf76588b8acea5065112377f03aa7067dfd2c667848306207834781b41ce46ef4df12fad7481d728da2fa3e5b16f3cb1d18a1832f88972c733f46e95800a0303287eac3ac347f4b85053c4e40a194a1e3062372304893a13a524cea9e1eb841060846e290cbe7a2872ea1f326e1081cae12cbd1b76ab9e496819137bc6fdf3da276a45918821137d4f9773b7c4bbce4c991369ca51ccfca121b69a31136e461b354a621b5c5d9d7708c23469f8b65965d55c3969d4dbd4f655a8b8da4e1be0c3af3313bdf722a4146d070c9d2e1fe9378a8924d307286eaccabb4898b5b403a30628635b664a6119b9f91572894e6e12be89132203b9f3d4bf2a3fff365840cfabd68799569bf9ee363640c09df2d93a6c546096b440cb9741f73b720e2e91e41788c81829130f89ea4caebc9b858a7ca090646c0b09cad2511dac33bd836f285c6348b071dd2b3f758f14275dab42c586e7c535b2547ff380185e2a30c0ec14817ccd94b899abafa9e55a15018051f18e1c21e5c64fae039c7515904235b487810d7ac9ad6bfaaca881652cda09a99a46631fc0a855219c9c2416bc63971e2b4dec4d186112c30a3cb53c89930dd625d18b9c29723da622247df5f1c7418b1421b6bc2b4436612dd52a15070e4b881430d235530c76d70d70eaba1ca613f18a1c2d154898c575b42c85dc6c814d099d244c3efe9f18c112930737ebe797ff73bd4c04814f8fa2cdce89831960c14be103bd36a42c5f365980164cd0042a12c234f58b435fa4b62ed1c38809480423901e2150ea265b48762c409974cb55956dc329ecc4813f497a5509742e4087da930804209c018469880f6dc39669da64f0f8d2cc14c11af9625296a771b51c2a38329b939d4dd637c878f3274004942dd41658338a5464817ffe1e30323482863ca12fb2fda210a65032347a8f487df9d4ed9718c11231c76344306253de6735b305204b4b78f6bd2db0811b857fb2ccb39bc985a960a8572022403348661e6955ab628da317fa5073484d1c6115bab6dde884043e00b3482b1984b27253cd8ed7849021ac02873ec781ad75edc74033734808342e1a1432bfc0beb85df1c3266fb19990a8502e402347c817c9733a14c9632158d5e945b5a1a3d59dd624a150ed0e0c559ba455c94139f2d3fa0b10b8476de94af994ae3d685d5a9748b7ee9b8bdd0c805aa6469507f49decb9a131ab8b0f72c84ff9a7661ad5b2ceb27773527f1bb8d862dd092095f1775ae057bb9018d5aa03ac89ad1dea2dfc54a408316dd0b2edf235e7ccbf42c8cfd2993556ff8cf96862c12e229bf418516fdce310c1ab140c7ccbcb3d3a0b3486181944dee418b1e7fe4f40abd4d633ebd6ee45fae584c3c69416aae5ddb5b81d0533a9febb22699648a4083159f96e473563cdacfabc893740d197b448b46a0a18a656d4fd1c15bcc92bb0081462a922e5bd56596ad7af44e010d547423f775ad72fe3d758a64d2a66d62ff832e8d31a6a8e3a5cfc8a8b5765d29d0d4f21593691f5dce193448717251db2e6877f09a4771fa0ce6bf213baacea230ea4b7ee95953d1008d5028426b524266d7bdce4061d0f9a2cae519255f92c6279ef92aab3b75399f47c313ecc907d3f28acc3a71da933a5a1942df7e4ef0653293c7ecd28b3dda446f5df69dcbe5b691390d4de49a2d4f8b593613b8a89e3e587a66d1843ab0343071e7ad781ecd12193697b0eb67f53cbbe89965093d6fca935d518542c951031a95d0e52a939d74da268b7da0a30c1d417cf4e06106fb0e4e58408312ea8f6f499379bd564ec2b3718d51ed354ea02109dcf47cd2a5f44fa0118934e7b7e9708d9b2fd67142031a90785e4f7cdb7594cd1904c840e311b694df9afda47e727147984187929e333e068e203ccca8ac8075eca0d108c53f3f4b324c748edd0e1f27dfe3644f7a30c68f13b4f3e0c1097aa0e363418311cdc7ce26c33f34f5408ac6221e99db6577bdff19a3085b54df5f7439bab59508f7a377d41c73429616442c7bf61f5c4c17dcd615dc20030785c621dedd9c4fed85a813cb1066e1b5a5d4d1d5527a85d8e25fde7c5a3a3a7b08d18b69b6ef2ca696dc93406310a5cba55c107fd321a60f6808c28b919a694ba671d50291860811f19b7f26361a8038e750da624c67bbcbe0f8008d3f18e7cffe5bceb5253d30a0e107be3aef69bdfe7926f5211d3f7e8e2fbfb7f462f8609efb3d359b64aa8df7c0a596c9ca133ac9ef2a148a5985861e9279bff4af7fccd89ea2910733b420a74e88b9f8bf191ed0e23126eb129e4bc45577306ad02ceee19d3d78c6d8c1fc3442c7b511d6b97180461d10725a2beea5abfa91191d14514ac5facd42a94ed51c1859774a7f731cddd39083e1c50d1bfdb6c7bbcb018d386827649306192ad4f370e875d5376b925e1bb45ca0f10644fe05b5eb7bb7eaefa0e106e374d0a6b3ff33d068c37deafd5e368d364299031a6c5892cb1dabfee031a672a0b1063c567d6869bfd36ca3a10635c3cb29d6acca534b8322f633e7e6cda08186a58c62ba5f92d1826f950ad038c3415a8bafa7bfd2bf6898e1d68d359b64e9a0b72dc35eca476ed0159f64eb021a64408b12f2b29c39a32991c618cad60ca5573fe9d86f854279010d312c9f902feac9e8bcff398d30acf5a759965c16b58201edb2195e8c395cb37c61d30e531dcfca4fdd5e38b6346e3e4b85ddde05a3bafc21e47c964c2e34b8b02ca8e6be7b4e26b644630bc93519d44cd5bb280f6868c18c2eb65c3ab9ac27721a59e04c6d38eb927f9777a547ef82061614ef9cec83cc30a76aef2b2cd67b85725153f5bd154c5255548bb40fa3131ffec3c7d2a8421d2f1b2ebf4bceb8542814a641056392f7d95ec487eca942a128d398829ab9cde3bf549d9a8586148c317d5016a3c39eb6547ef4c08196710244078562011a513099e66fb8cfe9d32a85b2d08082effef2b81c4f89c613d0ffaf22f6a6c5182e1a4e30f799b90b2f9fe1c126ec1ed6944c3dfe1a634c48e6eb50e2a348ff522e8117b6c4ee6ecd86ea42a0a18453d966fda42ead8c9d04c342b628a663df61a781845f5f94fffc1f814df51ea5fe41da65348c70e60b8d9ed521e45d68142193b1edb53a982e397dd0200232c6f7ab6f49262d7c86d16b7a51da5ad4db2b61fc9b4ae77c3ef7cd4b3056edca8f3983a826cb0c22c0d805a1ce5eb24e17dffd22a52e79e8d2d95a2ebf036910f1457aebcc5c1e8f72f2d38bbf5e74bcdf85c98ec789082ff49739f973e9e5726617bea42ff5eda9adcc175da494d8243b8fae486f73b17caa733c8a0bf27cad5028273a4470b18dc7983f735f5a8fb730b620539416d47ffbdaeadd22b638d353580bab5de2712d922e8d8a0e95a62595836004374280e30c1f01114468b18c3e4bf56e592e6ba950284964160b7e1dd38c5499f1fa061a446481f8ccb9fe451b6d33071ac4043c7820120b6b4d5ff47bc7cc921658dc1ea684eac7ec51a61b01d5d8bc5cc6bad4ce14a17bc8f70795ff31074d409208d3261dbfe5d53c768904114bdd82cec7d86f9b2692431c3acb1b836e3a21375ba1505640628844675efef417dc84ae107cc8d492b6702faec92a94931f3d4e82f80d38404288b36c3a2fa64e4ebbaf50283948068186795a8fc6e872273b34488f931d3ecad0610a1241f459963f994e89673169478f6e0a05c80b480261d2322ee72cb91cf7c501a16779f4cd6d4a6a8e567ae4c831060e2037720461f7f1011c384c70020edc20e3c60770f410c02b48fef0281dffb2e3f74ae92b140a0ff4870731c347194148fcb0a037eb6ac5b969cdc381a40fcf28fb173f6b478f27024605374c0a6e1814dc3027b8614c70c394e08621c10d3302089c04a00a247cf0ca337e3f0b7b624f7b40fb35c7ded1b93bb87a6843cb6250766b1e10f3f40a5d756a9a3390e0a191253c883615b1dedc813bd5f0e2978d4b266407bb5fea702d8775f8f577375e8ecf92d2a281840e9d59b86cf5f91c0e97317df46c519492c961d99169c428f91e84290e6e9c6e4d3feea5410e87e5d272d87069d46416f3066cc6f45b54c5cb597683d9473c8d701591696f033f2f46178432fba41d1b70598e2f670acfb3c95dc3b2dcf2a7cfa206d4a750f39c5d5b2c330d5dc6a073f66c61d40b4203da4aaf3fcf08559e3f03a36573eae81a89194e37ca6cdc5b8cef7c1910ba15a754ad78960f939041ff9735884d578f231a8341fc7590a6e34b61321231282ba2b7497398719b240c76ae8edca90b18facfe8c267b9c4769099e40b7dec399dbd4f67e33b5a478e1cbea3c7e071020a05480e7af4a844c00789173ad1d91d3bc4e47523e9429db46abc9fd1a2acc3010917daea8cb3cecaa8e7926ca1976ce55d3e5521bcad50283976f820d102a629e496a68e571efb0149161297c5f377d9c7d2bf20407af828020916fa182ea6da502d2621572814f73f4901c91596e5cd2e59e57676fec3470c48ac80d0f6ce8f2103071448aa9052393b1fb72f5ea62454484dc5e5a0c465fae852a15072e0f01dab6320998231e95376ba5eae01038914b030791a54f56578903160401205364b563a7e98b2fb0a2450e04c4dc38b964b8f9f60fd688dd59e1ced9138414f3a35943cfbfaf1489a807ec5bf389b322605244cd0fd5d1ccff5bd5b0e7af4a8ec681d582059c2d1948ce5ae6175835fa150729028c1f0ac5b2da66145752a144a144892907e8892f16bdf22299020a19b6dd5d2386f93b5c2e3041ca804d1e102203b7668e0460b6edcf01de87802c911cca5f45f85d233551f8911b8935f77e9b26c9e42c9415204d3292f99d3b75e50222142b722f5ec336b0cb1c05b100023d81806627378fe12d986307a4993b23b611e4693c148df0ba6225a4c3a64dd6103182915328beac8bf58147d49e7f72cfe27f545a74267b91151fd1b29d8e8c562aab555e2563c79bc389febba878be9abfd5d545a397aadfdf477d445da056f3f19c3dc5e938be5aa7671d43685b8122e9699fdd292e9da5765cc2decd80e9397353cb0618b25fdd1dbac7b4a645c0be4987849c429dd59ec68d1a7c87771b37bdf58b338ed35c4b7ea6cf62c8bc7ffce3f6d7a878d5820fa774a9fe794d67260b15c6f2d6e791efdfc15e9794edfa0c7da36e80a736bd7867f8e0c226ec5b27c5a3fbf389e36bb2a56e0a55236bd9fa68fcc2a4ea7ee77ecaff74c5385a1948a67d02672839d0ab3270daab35c22c425820d54a4e77268c9eec3858b8c39851e646368d1944e6d5a4c71fcbcb81a722f4e7c4ab1249e7e5f6e621ea466a448b77b68b69c446b5855a370bcfc93ceb29ca9836c8c28b2150b799ef4af6859150a5d8eadd3d276d0a7696340a18bbb5eef797674e66c7cc2f7ddd91a39df61f4045abc4ed92cae8f9664a3138595cb62b8fcdaa6554ea47347eb545a92f5b9dfc4b9c45c882d8faa9f99614313e7cefff9b266e8ce582610a7ebd64d9a86b0920f6c60e252327cf8282d98e6ce0f6c5c027d79fb53a8b899b978e81881a1810d4ba8b35e5ac3a87b8cbf031b95487d6fcb39e797bf346a1b94b0ad55e49508a134b54ca2d51cf3364c7f48af5c6043128ee9d7df50323d739648147b1b1f646dd5b7aa1cc8810d481c33b818fedb739b2f21b801821b1fb8e1811b1db8c1811b1bb8a10108ac8d479cd3a6b19fef24a37b62c3117b78e944a85d074dea4620c3f38b714f574c6765608311e5c586d6a912f7595b041f7d3ec8d71db1f071604311c6cdee60a6dfddd46723118d7041cb9ec7175e5b1081db9b7cb4df92bee721aa9031897c399698b7865896b3df9cc6d754db62a31049975d5272b3df7687108bd9a5bb538e7e8fd2201e11a625ddcdf2498d0d41eca2c7a0c1c5b9cfbe0502cf82de1611d263d85d870d409c3774892f6537dee71ff2ce295fe255f66cf68359ea33f792b90fac8c92239f5f3c3f8b0f6f163c7ba82e95a1e61ad8d8037a4ad7eecbbf614e480f6839c3dd4c937e31bb79584ee5d5878b3419e12125e4a4cd8dacd0d9bac3624ba11bd3b36c96393bb461ea62badc2519536ea30ede5aa62b17e3c97e990ee7e0b126fa322fd39e8359def74e4296f8e8cf0c6cc86197adf934f511fdb662230e98ce7d69597639a56cd4061cda345da1f5d3cd73ae0536dee069b67dee74a7bb25d760c30d7516a576c30b4a948bb5c1b3f6a81b6b2193ccdfa800d110d860c3b993347d2563dca7890a36d6f078e6915f2542e62d3558ea2dd9cd8b9ef262ba60230d95187f1dd5b30fba4403d7f28976b08ea7561a0347136c9c21977ef352c54ffc8bcca0e87c96c4b635452773c03d6c9441cfb0d95bdeb20736c8603c93695d8c1d323c09878d3134762d9ffcb81c83ed64d81043d91a7b5f96c7555ddc46180ee1971e464e4debbde1011c65d8008363263ebecb69af367e63c70ee5c00d1c144a00ac60e30b7a0b9fed54a80f3b9f870d2ff8bdfd928e51838f6b6c74e1e4e9b14f4e435ecc63b0c185f7bf575393eecc030c36b6b07690eda632c4644336d8d0424a88fc984eb434731a33d8c802ff395e90a1378e9b32881b6c60a1f76419a3e90f1d6c5c6179f6ddcdb50575f1b26185c65cd239d7cc68398a40f860a30a779d7a7d0af92f1ba58249796a99c2696246a9c7bef29897c2e2fb9fd498ff418b1f05931674fe8de9ae393528bc2d77be1863f804345cfd975f8a9f2905b1e1044b7ea8f5fd531390b9edb7b741dcedc60c1b4c58f8b45f13fa65c1a3ed031b4b30a89349dec688d49645099b0975a3b3951c3d4a1b49e005ffd40612509dfdc473929943ee368e601099fb93cb2553be201b465077f48a7bf28a800b5237c9a0762acc638308b85ff5b77ab6cd2f358c2599958d29efa349a908358471eff5c9974a264ff17dd40806da74631419a15c8e31c0384beeb6b749891bad7550e317fd9d8b95a245b7923152a8e10bab74ea8b994bc7ce632ffc1d3d0f99d76ba43a851abcd873866e8e396e12ab7a506317c87bbc0aa52d67d4d0053a97b8929926acfb450a3572c19db664d91bc2e37eb8d0df651195f733fd596adca28d1fe6b5ab85fda411420d5b988410727764fe52e60da1462d0e769fc51279b1af846871bceaa03b7eb2d4b0676197ced2498eb671b10c420d59a044c5cfb36c5a9c5d81502316c6edca1f9bb97377f1420d5828328b4198b9a4af427d85b2793cae851fdb2ce80b355cf16b85cc73cacae4c782d46845f6fb59dadfa89a6a07e1e13b60454a669a5cc89c2b64acb18a3b89ff2c97a58a339d879b1beda06b948a3ef4c73e9ddb9ba48c0ac537c660274ca7785396d6e8f3f70f962938d7f8cdf1176f4d2974419a703995f6b82226c5729f32a6ec8dd76dc9428d51a4a39b9dbaf95fe7cd0a6e94800b3544e189be205553febda40e455f6ae1ef2954774c51a8018a3ba6cb10d6d5ba2d9fd82d43a4ca6e8b7eef166a7862b96643c67575e5ab5fa8d18937bc6f4ea3ee3f0b3e27ccf14f6fe8d9b4ceed269e97c42775317f7c999ac05a3bef996699f0ed5a63bfba9c9fc776420d4ce4ef9fba496a56cffb12dda746bf52adf13ec612b92c4277a8ccb92f8495d864e7142536a579a7fd774dc6971a93488b275496f28ec9b45f43127f7adbd14126b12f1d0edc78418d48283a4f799e0e241899314ba671d3ce8d8f703cbba4be45db7c458e38e9d2eaa9aa94ab961a812a9541eacbd9d3271323d096c6c7b23f6996c48bf032dfa596f918a3cd16d450849e31c59e9664929f6a2250b5ed2183672c31118158ba2cc5cb9d4de43ec4796bd5762f0b362f1a822fd77331b305d99c1762537a64d66a8a10b9c7eb71b12c33b6981a836865637ca991417da88620d021163247efd8502310880e9db22563d261571ed400849d7a4bf5acaad35e7fb0d484de3d19cecb647ea8e3538a67d1a742ea35fa90bbf4233a9f566af0c1387ba525bbf3a464660f87d679e1624dc8bba90935f450fa8a882f5d99e5d6f370b0ce6278616cbf465f030fbaa42a77b73d2fcebb8319354b2b5bf4a839af6187fdd32eeea33d068e1ecfa3461d907bf97cd7b5715b920e2633b12a42fda75fbfa282ac31870593ede7a1abcd052d0f6ac8a1165476d25d1d488d3870b126febd1f5e2c1727d48083b9dd7434312fa897336f388fd493b57946b7996ab8219d79c35fa7d1221bd66803b7255db48b2f6c58ce7ecab3082da617946aac0121c665414e065d50430d67b23b39fbb7fba053230dc89041d4734799744d0d34a4ccfc5565ccf38b9d3378aa4cff252f25f357c1a86186db5c6367416e9ed296322cde684187d1efd17532f88286b54e973ac6ab31a4c5eeb896c5ab5f8c961143993a8e55facc9a108561f13e6b9e4cede9db89430d309c65339d74ccc152bbfb0262b48f1a752d67da1d3dbc70657a419476decda31a5d386c67f9fc056d8e1a5cb05f2ed90e532a53630bc896cc4bb6fed58a26071036d4d0422e06b5222c8492f9c52b148a0f6a64c116e672b46c9f4a54851a5878776637c860a211483301642660668c0110e031014301430a9403380810337e8804e08c9d80090082003143052101f01ba81937e0a13b6a0800c80f1b2c00c03939a961128cafac5daedd531e634c65b132834229c37f9cec4047ef501dec3e8090c004183ecae05f1c1d4176a0a37d717404d95101a22727364c7a717404f95101b2e3e4c486092f8238905dd030d105abdfa3c16549fa28592e104a7769f5e72ab83894de7b17c34659d34c6e9185ae972a37a6e80c1f5c86eb08f2a34c6c717404e91e6598717262c3a416be831e6594e1658c98d0e29321fabab59d45a3346338917959985fe3a3843a5527a658ac2b9f37dbc91ad1ab0d4c60a16779392bd14ee99abce2ae1b17e4bd28031357207faf4588eae48238b5c2931e3ca835b1516613569caafe25993e63c77857b1689eef5a647c2abd573c074a068502c444154993e95caacd2de6fb26a948dd6e6bc631abab978a092ab6dd51da3a96dd6a6b720a94a74c72c47b67c71488188430314599227e27fc72cc2e9352e8d2bb2ce8a83906395a0b4c48e1c7b7be2c5746cbcc9a8c022f59ad49eaa7461b8942974e47a130e78f7b0b9eb41c3e061495ded3ed24f4bd9c743e61c634f178a1f1444a676ddb319983afa877e8708149273acd39cc9bbd9ff896138e0efbb131c7549a69934d1c53ac846c97e5376f269ae0fa3e87ec127b618399c8844e32e69fd3976bc3c452b9b659dd7709e36f10afd6ee62fa688945cd6877d5ecd28d5562d9d484a8be1c25f6edc08412aba8516fcd3e2663e987c924d6382d8de5c7a70b49222573d67745d4cfed139844620ffa922af9d5db2d0812478d33e155429ccbda23ec3125539d3eab2b9d2a4798c3a5d34c19c7e44f9346e4d2bba869212e5fbb3d306144ca63ec630b5eaa6ab388f4e80d1142668e0e2f8a68e47967aa54d9f73411cbe9ddcfd6a3b59c44c4f9740baa2e9c964a8b39c4297490a1736e8bb0d20f45410f13437096da234779ea8c9f324c0ab1fc2f3266bc326fedc384106aa7e6d4d06e3ae88b062683b0f4d7a5de34994f4c82b0f4be6acb49be7f8e4920ea3cff98711e3d7870c004104b75a3ebffb946a9e60f8ccaf8599c72133a0781891f72d1e1638b5d324a464760d287349e7e39cba77498aff860a8153fffbc1b8df11eacf7fbbccb5ab90ff5c067972d3dc5377a6ac903665ba3a32354a97ff160eb4bede13f6edab14dee60d2f417ea2e968bcc182676e0cafd4bbd860e657b101e3d7e3c084cea7016e4febc649feec080091dd2490a98cc81d1b39fae43662207aca47dc96aecc8389ac461c92c84eb6db24ce0d08c58c717d36bf877fd03266f30e73b1d9a94d471394ddc909b272d6831c86cd2062ce48327f9e229f57554809c241336d4a94787ef5297c4b32e305903f39e8426b9d18289d1440d9c8be9ea4c4b7daa799334745d21cfe49eef2a3041c3f9b4c68b8cb1bec50e0e4cced0a78fcb765912a1eb53a1504ecef0119898c154f7ebcc49e9fc7965b06af3c5b1edcff01c04312143163245de9a6bfcdc8ea1747b4fe2fdacd7544230110362ff221a645c8f3a082661b0ff3ea9b91b532647433001c31e5e8c252fffbe457d60f20537f4acc98c1f2e4b5d828917b4fd513245f494e991074cba50ba6ccc5a9fc385b38fee705bfb313e5b4847dd3fc579fee8f25ad86ce3b966c5f5bb5950942a2d89cd4f63a38485b4e849fbd2be4232dbb26eac8cf9bc2a384caca0e87d6c757984fbac265538abd8881325fa46df265430d4cf7cedbd204f3799c272e88e6b30751aee3591c2f2729c8fa5dd5b963b5148da887497e54e2e8916139840617341f7777bbefb78750f133cc11bd9710fa6d1d54b3371021bbf3e631219e271323e306942f6f287109f656360c2845774b0cc2ddefc96bc073a7e09a9b479b9c547b8d5233051822dc9d8f082fecaf44d128eed8e9ee7d7f2db5aa1507c9051011324e8b2658e08e4a0019e1b10c0d1234800b86072844c8f79502d8b0c5a0a9918e1d0fe39b8e6a7b3d0f2a3c7490e932298e7f43577632ae9711322a4f3d2058f4964a455950a100d41c9302cff512a446c88bdb172e225c2a8f32817f34b2ded6cd723c84949301acbdca139433bcb75efe871f281126070ef69bec46465384f094a7ee1b998d752b3eb66ecd016a0125ff0d2cc8d78f3284aab4a492f0a11d594e12c327004f1155480680852092f2ca534e76cbe6f616a1e3ce8b10bd45c28f92a63faeaa542a1fce8a1e3c40325baf86be54ab5d4e5cb2bac4c29c945e26b74f9a67753092e2e9dac738c85c9d261c92dd2f7ded2824e295a4725b6c84a333ff3464ebe4d86034a6ae1874f9d3c476d644e1928a1c571a53ee8e052cf6631b3583e47e878723654cbaea04416c5dc8db211a5f582a68292581c5f4e66b926c92881c5d5fd22a21b3a41c92bf0dbadd22e6f8ad14f50e28ae363ceff57eb2e6fbe72328392565419ac6cbcd3950b6be5048802d1c0063ad0ceea630567f8085e50c28a545466416fcef10e130325ab686f4375b55c4afc73941255a4fe397ae9134a05ae22b54d2b46c531e7c5529e94ba8c9e2269ba39b598e4ca6a5330674209bf19254b3527394a4a719dff570791175d3ea44069faac677de68c9251fc2f0b2f9ab4c51846480325a2d0c2e2f3280d02120a77c784d2d09e5d83a672d23c74879ef0f851020a46ac4ddb537ecb2e6a860ebc031e28f9844964c7923b3e9e63ec09a49516ab1f353de9e9444ab8f05ff676d2d6aa40a08413c9d120e43e8d8ef89ba8e73bc5ddc8ceadaa26cc2c87d951520572868f201397bdaa6f5e13a64609138b6cd269f4c44b2c23f69329f32a144a0f203c7a70e08c124b70a2712142e75d9bab12977ebbb5ec9272972d4ab02f78744b11eaefd39360f7c5ec176d2f9104baeb4dcb62c529bd5349243aa534746e8d293d95150fc2436f008993ec79f6e072c8acfd7bf4f8e1e311e7857baa0fb1ee33027144420b1f4cbf1c47c94f10203a7678101d151e9c04f11b34e29c644398f8182f3488116b7bb99d9c3f7d939f78101d3f7870d2ea3f16b194a15b164bffb39c931245ec572d8bb11f4da19c9424e2f01b64d347c6b3f3a183073428414442863b131ac3686f9107cec37b5072086416ddcce752ddda6a88aee2d3ffeda82cb3819414e2f05e99371ada7b44669410e2df164d9fda381e37e647c920504a8c1a31ba3b5bd682f8654166c6af3e2d7fc604422f217d732cf3f61f1068b78ce789aabdd2ff80c6559139ea47f78f8550e2073fc9b8cddaf6e12cfa2f9996470b27d7f1830c324af860a611d3ce2ca8640f59a9fcfd1832e62c881925d840891eeeb917b7ef5fecf34c95e4417f9df7d09f8fc9a378409e16ad0daa1a734befd861c66f2004257748aeee998d75763033cab98e76320da31d257548775969cd2fb8597874b0257159ce27efbe2e3e0773d0d18ca39a5b3455e5a404257240ddf5c70c32cb26e360906b27e2eec3bb076b500207f4345588fdcae85f97bca19774d4e5a71647f9a9c40d293bd7d2f8c29fbe9747491b6ee1655912f3f2e754550f9c878e12362c9ea6c50bdb593465d6d0464fcb90395f3c976f50a2063faabe954c19c37612084ad26008557f6e2784a91469a0040d694b5977ff7b2d2ee8819233b0b5769a25ad4cf26486e3cb891a71b24e6f30505286b3a548f92c6f922fbb42a17c0919aed32dabd6b8974c104ac6707053f1265fee848d72502206a386cc3c95db5cfa5339290943bbfd92a9bccb198352086eaca0040c6f12a6d40665e231ab151b947ca11342fb6676963c08b752468917140f2dc98df36d1793ba0b4ba5f46977dfd0fc599250c20535bc68d23eaae3644f7ef408b28210e008d2030ff8a0640b8b0ae5a3af614b4b262d9cde2f73fda3667cb9240be775988b4f622a4d4b0916ee1893c79a53a5f4c886922bec726648efd64aacc0e6982c112236c6ec2b144a0588193e78b4a0a40a87ec9693b6fc2ec81c522839566002203c64504285636f9e8ffb5225c70a4cf0e3044078fca0640ac5dcf9090df12c9a540a8fce0bd141eba8d560e5e4478f131ee88f93207e836dd7f123484914f86a932f6d6cc1cb254f7ef408a21d288182e79f4deec83248e5063a7e98a0e4099f165f2e1962ba83582b5ce2844473dca4e46c8ed261dde1a30c5f414913ee7d13e671e53a562b61c26de575f2b446f5ee031da864095ec7b62c49996fedbe44099ece776ad6e72f6a9504d3a591b1296ff43404b22548307c72396f5c1415a333f4c70f0541c91116de94b0d262cc7aaa122364da65bbdd2a13524b2545d8b39c35d9a9998da36a4110337a9ca12450420911fab8f9e8b2bfa27bcd91e386ebf8414604ba87095805140aff606f81092020803a900c030f23444c89064f4f6c40220c437e165c6c7b97e38b709441128c46c58876ad5af918cd813b90109000e3ec17a358a96641ec9e8304383240f28b74743ab9c9738ee7487cc1fe9752ea5d0c3229bf42a1e420e985e6f2c6b7945ea39a0444779880c70c4878d19c5a8b5f551ea33d925d78e2db591661ea42ad8fe934b7b38b1feb11e4a402c40c1f2420c9453ae8bbb7a61a6d211e6390e0a2d19ccbcc1a46678de528c10d326e7c60043742a002925b98aebb6452cdeb61671eba83560a25070770e48035c80a7ea480c41606a5e37d66693f5a65f80e27a9c559b657b5ba5bf7dc567c9ce060ef1e1cf0ee6102125ae43562c4ded2cc4eace4f0201ae40524b3a85eb0cf5da1c329fd55964416032089458fe73106072440028b0790bc22ddb2d8bfbc2c7a103a24ae38d1e143030c2069850e1f1a70e6d1430124ac5800c92a1a40a28a131d3e34e0820690a4e2063750322440828a53a4e50d3e7fbd16a341a648c74c9b2fc7ab3431030142520a069090020124a3d0a51be1e259ece829cf08a283470f1d6e2011c549024842410012509c1c80e413f8e9de9c5cd49e3037bcf6877197e35e72dcf00249270a40c20913924d18804413273a7c68407f98a181039064c2fa60326a3db49e3081c9b0a5327fda77482e715215f1928fd612dc6d88cfe8a712811b102841042070c3ce482e482a91ce26b447d5faf5dd29a1cb9eb7d363a6f47a2199c4396ee6643c659e650d8924586f4f996352d55754790149248ebf1a4cfc857f97aa3c4e70830c1c2490e8c2d3bbd822f437ac8f5876a93e6a65a742a178101d2db86123b85123c0e13b360b248e603fb4949983c76b85481a615a912e85ea7b06256384ea49bb707bed77d752a1508040b288905ba8145264d150180c05426130180c0004581c0b00631100001820220f8924f2a0602a4f7314800143322e66522c20281c1a0e07239138141287c3e130200c04838141811445722c8f22d135a965f4f41bd49e87bd5d7d2e6f32014811b9f526bed06b1ba0917b8e1e992d1d800728288ca9e9f3790cfc04fc4cf75b3b413e7a16e1b19f8531679bdc385f03035d3ffc2715aad12c7f236a84e4bb73c7aff3ffc87fc50ebb64891e7c58570c7a51d72345ba4f25ba5827b918c8a86ee45cd4c7c0bd185dd188f1ffd2285f977f7898468806a0112f363427d683a581971eda95d3d76377dcae9f863367af8c084ce31ef918ce0d5d0296aa683fbfceaea845e76ed97963b64cf3e1d8b0ab120fc494d222004b530fdc74e04169850983ca25d4f90c68c3f77011aaed56123ae39b61a4e14407534a3533bd89ae85387d78acbcfd2c1aa3e285157f9c027c2515f96819a8a60f499b581e3547f170fa8c7fb508439413ef5aaf734b95e1fedf8c8491fcf186ff9f993417e0b2419f5d470f698eb808998a1c81701e1b53bb7cabef910be31f463e46e50a3b1e565c76ab5ee9d2cb2caa67b3f6705c7bb634e7dcca81fe511cd52002dcda81e9c490023e405e86ed0ca0da41bb3af073ce122f946f61400af9612025a98424a4123cf81260c666b9b0ff1b7070ee89e331e66a60f66afd72cddfb6796656cd96cd4236de1284ba96231395d05dd8d5a0fa39459e6ea2e1daacb2e73a1027d501e977c7f9c4f88a09aeaa22519d000386fb26379975c59c04db17d8a435407ea6c90b5eaf1fe266b81a0a5d7f2ebdd1ecf5093994b18c167ed840165fff2cb82257a2a0ddb956aaeb71a9403f6375dcb81ea65bfa0fe949181516dc7b686f490edd9bc374ab63372a67a5225900a9435c811b112ac0edb0f04a8ce6228c5c634ba44998ad7ec5c8945cfca968c4388eca23e980459019e8cdb02bb541312c15d1c696825b99aa78aeb036a67489fbc486b1359a25f505b11fb8e208519bd21b440612cae07a535c4e64ad6215a42575fc65c3ad16d49af81511db13b29ee00003fe28130c4c774c7f98ca79f248d47f3df07c27d730f82b76472fcdfd88bb4e276f0a44f0eba2da997ae8c61b48d989aec95a3cb49ecd2cb87818cbee60e9e860ff07826943703908287e05fd7b2075104008e6b44072330059c04a80118a48bfd99cb2255c6243372c94e600036c3354811f495185669eb614a029d77dbe00ddfb37caaffe667caa840a44706c0d8ba10ba054a57def2391f221e611950416384c8e11d496abd9845fd0c256e5c177e8b8846eb0617c100b798a2f63456b29b02507209c3c811178440bb10ac77a508ea3255749f9cb13250ed7f6f74ae40e23849e8ab14150aeb755ff137314bd19fb0119055282bf8a9bf397715fc30313d4801c63fd968b4e807862205944e710fea6d686fa6659a84ce013c21a1d4c492544876b8edd9d2b3c45daa5031c081cab04c3271453d95f7c310e211d9e1247610564a4b35641869572698f10cf43ad589ee8ab74201d8b12227de3190c4b6548bbd3f20c93e5f5b18b4517fcd5220f387d5a3bf4b339166296a8b0e39e5775648d62dbf928d64633ab91a75c91193301a5a51657a4c8d49bc245361e5ffe4d61b0eefb746fcfbde64f6b33e55a182b7736d813e9ad019e9aa4d1876b95e0409aaf362614c57b97040a6d6f2be2abc41a95fbf222aa6d510b6821b7011886fda389a1c2aa64f44d14ae9fce33d14871e58a47d7dd0f419005ebd477415c382d5c3baa0bfc53f2677e1ba03e606d8d98273afc911045ea53ab2919c75772dcc980313818ccb8e9dd01bf84f8f867916b112fc9ee95936b931ea0c819839e3fe85a9d8c231fba6e945a1f76a61442340f975e8010794f354a482a16d219a1a41af48476d4da504e82a5228c9a20023bc8d1b86c0201f417f7482d6f838f16698d01aabda65a09cc40cf73e58446ee9faf40834ba26349e896a54239cd882f92fac242f888cb717f3eb9362d31371f32de9fba9f6dd61b4f38fd6d3eb5845f1c07d57d09f6549758e47c8ce33ff6739188ad01d1854b560db58143c70c09aaa2582494bfa990fabe92fba1ba5dedd4cb878301baed0314ea43e2a70f03a8a262a7e58daf8d86fef030b3337c12332fbb1bbf8fd4ba28ff8a0b598fc0f72bcec9391853a58e93d3a1ed297cc77d24c9db424c7c5543570bad0baccefd814e9b27eb352a56945304bd7ace7feda1dce90a5a634393f24a6fc5ca88335190f44658059ba262b8976f65288b69b216cb2dd00847f28bbc124cddc43172ef9e79e70ddea923ae812cc6a7cec9d736ebee0a0446de3d3f7eb4f170712bb02a17cf6dc9b39e3580b0d1f513a3fc0361cc64444869bfddf02a575b9fcf5a684cd51bd524eb319b59fcdcb23a4ae2569aae184334e10a3b2eb578ac66e328438d9611a0712c30a4d527d45c61696934c3d1500c24e7021abc4f152b20b0c97e04c783c3b5d5b2381005fa008c18de79b638da64a0373ab66d68ec9e2a34fe2e4201e08356ea8ae7c639c22f5948c430c19a209dd69ed8436b31afd2f54a859582cbfc02a7a9fa05a236a131b31fc5177f2605129a620edd0bbcf6b3eeaeb1c2f9ba8e47a4a535b0762616d681c1ac0b055bd1639e7442eb587191d660ac531853d6f0e0b9ff56cf5c4675e17340ad628336645fc6eeca4289f827e4bea3982e672d8d2c6fb2dc86775041fb4768ca4828d4f106ff00f9652b685fff8bdf23bd4382de54b9902d36df19933d67a3f0e2cc433cce308b54844a546db0fca441c838b0fa7daca13135cf6d58485754e8220a96865d454c103d90235a0cc8c31481facf8bbacae5a76d0fcde9a91e6b0f326b81fc6e5c84f42477af18d811a5054468ec54c300f490879d88b5cd226f0085ae910af8a8d92f59d64b8ed5c25f042c5d4a1afbeb93762b4f143b04cfc47eb3819dd46a17d39c190f1b75e22d6a892d0fa6e24dab60d154334554a8119500d2b4b690659b4944be108dd345f45025a14e09f6ecfbdbccdbcf8a9067558012460b20e361edb692857bd7c0a0aecb9e8900ed4c49ae450fcd2ed710d60633c407aff72a48ac5d023edd0632e946ccba396f33d2820519d66d655be7006e335bf4e114bb5aa05b810e8880fb59766b37ff56b0d51ccacf08352bce428d0cb21a375e4c9d7ceeeeb5942c96b0b851b0c3d04d000471dc1b8e8a12ebeb2f0a0604346154136581f2eb26440535f409601f7be00407c5a580be235835c4dd31073b37845354d04b6faf1056491ee4cd69799699bdaf895151a07162482b7fc364d4ebbb1c26136af850531b0f3a21a1ed7626eb03360e778c73d71b5d56133c813fa5053fa6de81c007bb123687004e86acd8f71c0abae475edbf2573fa0ac140ea14412241d91e69de41945b1415c0ffc0419a4f24b79c056c08ab3100ea6e8657b977ab12ca388e05008c81efc35928610414f80c961aaaa6e02415b8f956719700824a0d34e161fc929e44c3c12eb3b82c1d5cfc8a8c49d0add3129eccb1d3efd2c8c787850b7a1c3f13bc3b7e9e4d356950af900ff9c3d4cc89a05238111277fb9ffac95b8d8bb2a03032f0766b2fc26844de3c2af9fa9b40d184b00da4accdd13f8df1e01fdeb20fed65172b3c4c5010a3b63410bb890718224198444d12ac36d0a8ac0f46ddbc47cbb04e7603b5b147e173c171b8985a244eca38ac14685d24d338620019d54130a82866bc70c8c3155593daca248faa654380c3b3c20a4638783b8e8f108ec89943f885cd02e3f0e0506263904b4ac1512b47909821055015be3df002a955eb5dd5ae03c01063339b7523f6292d89853038339dcd38efda926daf5d828f42ac37fd70402a4064358028d437b741c4660525df4804d769aaa9509a7d07424baabb4d4550e156c798ea6d4e09e845a0a71e2adf9da2e5dbc7820367f8be5cb395d532f2e69362965a530da2ceee80fd272575684db530228d68e98388b0b626018fbaa736754213515600d0c6244e04a235c45d250f32743f2f0dac8654ff8d9f219c9f863cd3d99e70ebfbebe7c7ab73cade94a8975883297cb23be22268c1540dd34d362e584423eebf75330d78dc2624eabcefd49b64a082a050944a30336ac7681d52976a5a3c08195121e38eaac1eae5eec776abdec2eba1b50f1099e17846fab8c96d32dc6640eae6ac9fcf1069cb2a027357b656e63eea29d3615c2171edf1840b29ea624d98ccf7774eb2cdbc0d3f1e292181c0a4af113f4b9e5e08a58e185821905d335c6b8244ca2e40638b12ce6ab42aa148a4366cfb175a77646ecea79a5307467072a38202a54a605dee1147e07c1150a9d10701e6629ed66ae85e2ae3b7cccacbaffee4edcb579a9644bb43fc952d86e92b96017a3c68694a6977c0c0b25e6a048d1791cc8646f14bcbb586fe1c75b5c51adfa0227a95fcd15b1331af6303251d2a10d367dcadbe7d04efa3af48ec65eb3bf82faa6f2904b43258a076c4890f76ac176c083fbe708693a6a8655ebba68e597423e405dc7e140455509fa1829d91949db8bfbe84b0745330f483b260401fa325983232c1351f53496a16a5346e0e17b500114a35330b843e18180aeaa3495b152a02449ba6fc7c00c45251e5a4d082bb3170e018f47718dc4a4f4c19db202c88148f623eafc27bec7dec62232f2c40fd5c25229277514567d3eb717b6dca95b81290c82923badc0d4bc9761950b2c33836a8a426d9578fe7011bee7fc69a2fc4d9ca545bf3605ee20fbdfea9c71f00c6f56f4ee4ff700350d278a62101baf91f27bdad201a7029f86d69b9230d5390ca6df20c083e3ae684be2624147f382a7f2e26e13fde7dc6fb09ff49f163e20ba7ef4d1facf3e9fd8fef0286c0847f5ba43ee1df51f9b1721ee232441622527fcab19e990d3f10812b370021302bef3c33e742c083beddea31f8ef816b0a40277033e6ed73fbbfaa1ea40b6a9b95c94125e026b294fa832e55b28ed13d9dc64320f115e63e69472d8e4f638f7538d72f1999464e2c5f531a89cdc98415e0821f007dd7f6d2b582ac9d2c920b651af5d970b42ad13e5dc4e77ae9ffd5702a1ff80bcd2bf6c9cf2a3535f0d353d46d88542c581d3d0c6a21e75d52e4c6bf9f75f1ac76a9cabb563d83eef06a44356f44a63a31dd71acbf684198bf8eb31cd37bd7a9156e59e15fecd18f6dcf1e6c294024df80d1bb71f75ae4d6c7466011346f22a132e00832c20e9173ad8df92322999ab6ba1707a520c391f664e8b90fc5b981ae6588565c11489fc0d1aeb8abfeefd17bdd34a15b5c4482e0205acb036e4978244a3e30ae1e9eb97050cb8919674429780c0decb855578f620f0caca922f0493f81ef20098024f1e5983c62d7eeb057f9666635ae707c9e6522195f3d0b06f391d598667190a72f85024fbb1954ad9028b127492ce672c2c43d7c7003c3557d9369af8dc0ca3d28ac73ad83d4d3c875957b8bb5d13e22e24d33dc7ef7074e810c9f3078ca75134476853411e5975c7ed9dae8eeb833bc1d27abfcb465e85f12bb09066dc77ea4e0f386020db76a94ce2f0e51941b230087491744a0407d8b6c8cd0bd41927347737c6499b1483257cae7e79290c4aacaa39aba3270208eca1a00d1ac67b56ee08df879223d8573744fb4ffc951bc2ac143e10327576614111269c758769d48980d398d5ae67353e165c3d0afad0e3ca44a7f2a47e150a15d631454329c288d8d352767e97ab898a3904e4f27cb4f2b650ced68a24c95bc0bc7dd4aeaa7629ca07774f3d6e2a4f8ab204ca5b2032ccf7354c3b2387158f459de9334bd11824201534a1af705a59fbe7d7f41b8f8d73c9e943919fa4cb8ec89baf564999e89725164798a9511282448e0eaa60f20b5c88d6b686a09ab1c69becd933e19f5a171dd6ec70e5655be49a59c8a09087d6e2a1a16b6f80364d9387f7f77bd82fc451275422059f108cf32626d71841dcac622cb68cfe62179980056af46bcc70052077220442f543bccc633d8d6f138eb5ae6cc0ab77aa835bc6cb4b768818c8a765ab319e58a8ed4905734ceee07174f4ca88c8c3a75c314866dab3d666a1974b63554e8f044afc011e7e185fa9c48f8d0de00b4624d6cb306f14357e925d05664f0fac20406457be012ae66b8311627061ff8d9f04c51aa0ff63b6035d2cade07e0d39f70575109ba42a18a8a615273b4af9645691231fd7f58136d076fdc292f86a89a565184ba078a933e5aafddc98da0f1148b0eaf58bb22212e78bab2cdb3f66e564c31596c5bf7b1eb5cd2d64881a967eaa0d05bf7c4fb4a4f229629209a3ecc02bd2f44797a437c94fd8de46539b60441691de5f4e91e2e16a3d3042e8bfefca548ab29e1257158257de0f8d817be4bb4441b8f1630042c951de6e8c8e725fcf348f87e7de3769857aea6e62e5b82ee90e85b60bc231e45cd602e6d9faa8a99d97d4f562cc735a1485c6a497f5b8c0a374d3cc23e1c4a5cb65378387b57e159a9873839227b3dc23dee140d8aadea48aad947c4915201cc9086342cfb296a2c83b377a7a0190266258a7d7f092b728dbd86f28978aa8acfc7c252245a78ea891d030589a2ec0531b6cab01b4596192b145de7170df6fefcc6b8044e4751ff1ef57076e2fd12ad3533b163b6f9b92eced378247449b336daebe97c01cdabadf39c9932736e0d99f82cf65040ebc3dc812612ffcf1cba2028072022f04e8c921a82747c6405c24a33ab15d9da3575e1031e91e2c37a1178b3d3ac991b0635edb33275b5c1f924ac3872f235a304f42a464635fac2a694f9f157df7b4c3bf872e8e50ceda89e213563a5d382e81e9c9b94624751f73af8c285ba1f035f7330b15679417534d21435d1f8d606047c6bae97874340a054d527b1c28c1350d1c0e624e7961282de50869baa9b1e33d7a9312c3ac9caf06b4af8035a31d50924a2f61689d54ce6bf954f137af5eded5e4485ace00fe93d682f6239eb59bb12180ecf4f3bd2bc230e2b12628f75672f0247ab31460a85d98a834adbfcc1ffe57c281d416b2b9b23c4709656c94ced5152bbbeefee34ad17d91f5c5ff59d263bacda7195673fe096f60cf005ca1128d710ec4a016ef2d5debbc48f9faedb1bce9674daa0c5c7d54323666c34dd692917c4634e667794e9d673af2ad9bafe62804a761c197f1e27ea6573c9edf2502a9e81d8e17353d60285ae3a127cd403d29d8b90cf1bd740b23d7cbbe10df3c294773bb84fb4ebfd519c84818ac977d2debdb180f8634e964597656f6479e270f953bc78a1208cf28ffa9ceab55ab14008d89c60882f3f5ec8e1a54f7e7fe00533eb6eb8d8588a46263b982c237ee138843d0f8887148e4e940fe8858c6a15840bbcb27ae2b709e80e41fcf751d97869f100d40c355a4142e579d8e834e8c69b50ebdddef09118903cd8a43e838242f1317ea629f1fd16077113b7b0fd2dd74b91d17141e75554b148c4e1580f0d3af1bb7f3b64c4250dd0c8e3ad303fe79e27d8b8ef67aa993830f96f11440516da8c685b7fdf9af730b65b348538f18e2f5933cc84486e299bf01d127d3484af1ba261c2ae87fc514111092811a841f83036e58f7019390dd5fa85736147a4866dfb1f984997dd47828fbbc5c7920293a37e5e23640c3e573c78594838d7c9bdf0d1a931ce361f4db3b64aa8918bda753c41846ff58836cb5d3c10af5719e343c40f21904e00f25802badde411af8ffa16ef7f737195dabab5ab270a4c7c20a1c01265d77f29a8db1f912a7f217de4be92b2a561122fba1529ce62f47c5e5cbbb0d0a30651205fedecd753de60c4fd7862109de58e0be82aa15a59c6a29f0faf03bc2933c566253b10d838f7b917301b760997aba090f7456d5f21f8c5e06432068a3a56326c9d849afec524714e052e502934ab929ab804b9011559da8c7fb4a2a250f2d08bb7679b0a6c57850677d613bdc67e8ec88cf0c437e3045f081c239f7cbf64d1f79b36b1d9e247d346348950701991454a5d03cf11dd41b850418bfd974ec6e3943f5542c8f7322a2bd66b42f6d48d8754cf1afbf88d6f7a60065a2389482a09d481b02344d4a51aa9a40f0072499521962c44a9efd426ea198024666972576df205329bc834971690b92dca894a3412b1c601bb8698e7284dc6a6375e17727ba37d90ef93b68150fca599d86c02b89bad89edc8cf96da25b88e3dc61092d975d4c466092c160231328b2a075ea7ff70ff5090521afb35746d19e233595388f48faf56eb9303fe28ec4faab5cd316c9e8abc1bc1a4b5d0d3ae602a0d64cf37cf2a5a1833a1e5bdb831d12ee9392f66d7cb0e3873c58ccfb208700f994e0c4005fd1b48da894d147f209338eee5b23339d536f89744049ca3ee3e0544bf820a1168f9013460854af3d647eb342c784b006e9abf2be89ae6824059164c01a90fc65299625f8af8f2541d31db5c424e7a6e305434cc2e783003c56b917e363007243693f1ba24abb7b29351b578452b0bed4a4ef37888de3dfba71d8e496b8dfe1cc2e71c6bf48ee1ea34f4f88030cc1968653f78997b4919041305f23083ae1176455845b6588ca9af250fd8f948a95045c04bcde86684913fb469b181b241804b74b74993d0dd64d296c32ae211afc09f159cc39b065538f007540d96603fc86e8a4ade97f1ef1c70823d3e7e03d643096be273317add1cce3c9ab96b50ed4768fa1adc6bf9cccfd13cf19e2be0eb56525f9540829479fe60d8d97dfc275d93458e6c106491c2403dd51280390a0e10130eb2de7342cc1bfe8f0ae29663e41e07d313a7cb55b31a094bd0ae0024277105d5930d2175c4a53502c8683ec3bf32caa193df0e5d6a0264df05f15ff630394b2268100341f0a906fe3001e5f0bf70e73ef4a03deb417dc65c41634a1d26542a6a3346d01572f0ecca8903b6e12858f5ba7f40cd750d5b8baf7381499926c11118c21b9348c66937569f05728844e9860c1296af6431bbd3856dfc64a013477267ed24ff940238bed12308ef617a89216ca0f4679d116f66eaf2bb117b82267c1ad3472d605242ca8000c1909a811830e2c077644e69aa9bc0840ccea754a4a3ceb26cd70abe84b9e8259e60b5157516b96c6fde1a2bed6c419b8c384fdd6b56db737ec6c8c0a2f20a86387d52060a57b4edfc45a2b669091ccb2485a616556563e20fd003a8136614d646c4a26e673580a29bc6e9b2c6d3f56980bdb9632aecfaa32ad44df38550f53ee6043afc18d6c150c31c0a84427c81520ed51ef2139cac92c55c57ee617a105167f7aed39cf2e7f59a8394734b65cc2778ccc102f41130276444228e1e0257c78524c68e9c39b51ca29be66f5208475168b459b5b331d3fab124439d37879ddedca1fe7437a9efcc21cf6891a210cd56186e08e5bd957388ccf5a8efe6c339aaf13f6c2d4fbbe422570d5da5cfd2df0f29519f385e8742c9aa53aa4af1af990c6827078f337e7fd9956a3e55bcc40986873a31c3351ac022cfccc490418c0c2e134083337079ce33d342cd92453b6aa757586d56d8b480a48b0c80145a7ba95661303400977f8f95a54b37ac502f0fd38ad6b032f1d53f10cceb9956950d73e25115e8620c6a9c7c1594ea50b6713b2152efa3eabd18f48b4553f4df8d2c1659bfab6b65643207060af756bb8154cb050414cf4807570e3ae05beb395fd9842417de57e51ff7101b1f367a5ffdcf2e00f3949497129a5f34183dd1154ec436f9157144aae4121522cc3017508e2d1599b4611eb3f9394471a91a997ed37bb2b62c7b7c4a11c102df96fde2c2520c476fcea241cdae311c02f53bb1e04205743a02c5cb0f10a8adb763c071bffb7bf5ea58b4610dbc539810d227c91a7a450b27868b15f4f8e22be1ed91e17af2fa42b2d24e29836f47db6c41a4d69c043734ee8aa0e093e6312d39257d06154c8aa4a3d1545cd463e229d0d7c803fdbb39543baa43d06454021db966dc1ece30527bd9f0111ee5882e7aee74cc6d0a9f1556976f37352c22a3725400fb16e7559e42cb4f9696b4552cbadb8142378df128868deb6966580a103da1fa99f885c7fb31662a77065ec86b79b9a3f4d61f64b59d32eb0b272d67c6d16382f94598f3f09e577650e7e467f8756cd7da6a1ce95a5618c6d228397d77712434ff09c563800e7dd051278d6759293eab2cf1e41a877b440d4bb9817fae323fd47d2f1f223eea267c4a9e9c25e213610e90694946d9d25e3b71ccd2d8d8c8abdb4cdc43d64bf9b6502d8b37556a8c48a8621b3d597283a650a34d56e03d9b0e4236f8544c04ab226158c04f15865cf42f2f848f15b146f9c549d6c0b3b7d03ba193c0209f04151c200cf50ff6d59cca72aa54c84c05483105d5a224119e09655c48976f224f2545dcaf6f6a90ccd63387741e0f1d69e89c97c1a9e78e5ddc67448cf47622ee67ef85301c1f3e5dc875628dd363c1ebef814ac27f87bb34a3693caaddaec93a86ac944952918039ff0637360305d181a9d94365dc30acb4c7f3545d7e1f534a44409516f8808b186f537b7b1ab15a46b58476986701884b54e2fde0f2f9d2830e7792f3811d430519ecb0872eebb8df7a8606baec0f20a9170375633a7a7227004f21a7a0053e0117b800294c7efafa9ca7e882d7979702b310341f41d06a480e26e98f0f00d9d6a21156d43d7287649f1f11cacdd1487c76f70ff2e54bf52ae79afbe5d7c45bd6efbc89683fc312dd2cdcf5aa4b0defa0080915291e086aec7ad99ee7fe0d83442cc99b57d111e8bc80fac7f9a41dd113a230cbdd09a56bd87f62dde76e08aa3b78e1545eb69ceda3d301c9c232a78e714464668b581f8704a16844403c385e9db751235091c13f12b8249b82cfc213ed959351fe82862f959063cb737032c1a25ecb8d0da630fb8e3fa473220c0b083e6bf9c0b646d833ae0e0966c7d12612b0f7cc626778bd19320dfb8b79fb5b015b64895c01cf3e61e3901ef1c0073242a28478b5f053623e230447454c691ddc27abc2c31176dd3104ed670265833b4f42e1532c7904756893b8a037bfce97be453468265eb92c603e6003a8a536296dbe5bac8f999c624714261b52f15c41e62320c6a2d637427a6ef0343941e17d6a3d6302d598fe597c0271555311b4a00b6e6d1dcfb692e1ec9e63c3999d1ca92c0817c7aea3d6396b55ca526553adc2a7f4ee8b1d7fd2df467590fa184ed9d690d6d28bfa8c2f8e93edd656d1337fa1a31d7caa80fa35227701d606dc2024a66abcf4579dcd0023274816c0aaffdf10297eb8fa268741f181d357069c40da48f14bcaf24ae915b07e22670451dcc7b87a4a175278fab22e2ffcd1e88ed9f13f58095e794c7569f1cadfd6a182cfed1f342ada56cf816e2bb1cce9efb7180b2971ddd6f6081d21904f0f337456895cd450071b16e7716e2ec269c1f1e573705b57240437b0e70e2c2b38b368cb5806466ad21ec208a7e9e1ea217b093b5809a72b67f224c33845d22f89cd3084d3d753bc094589a02bb8eb99df3e91b7d796af83a66145b0ae4a8b6142369996c48c6077c35bd16ee4ee2f5bf22ba6ba3e882724c959fbbbdc364ad3aaa5f71be59c35697a2368b04eedcb8225396845ef18f06f931c60c0b171f02d42c71326b2e58767746b091085150c72127fc384514245f5987e1460cadcc777730496b13ffe38e70f487cdef0f48aaf67392463e6c315a1c26c1b72e6ce4d7292b3189a638eb6dffc667f74ac311053438d88589200b10082dbd353a20af3a0de89e838eb01e6c8817d5cc00fc2d97dfb21cbd931b14f56abb32dbbd0040ed3b34acb0c7215904a28569088e8a09c6dcda1097154dc5177a0eb4ec002ab61d9d8cbc2dcc9cce21f339b20292d19c370741cd082646ca517fdf523e133c6830d85644e615eb4094645789a7a6b9a11dbdef7ec79be8aec90c235f1855299f11251a1081f2bbab29174edc708f926a9035de8dd6d723f40bffeb1aaf3d9620339285e03dc4ddf4700f0cdd8af473dc464806b604c2b3cf281fa563895f9e0263a783fe327a204ed58cc16df0e93123be5f62881891e06622a3642bad30ff37b7c9802e4f6cfd868d9ccc20920ae3cbda914ad7c5dc8240b13a60a6fac277d93418121a5784077c541761949542a9a0cdf11f14497cf7b8f78df07f218bd1c86c526bad76da1f2b743253c7ee816884a540da0f90928602b9149f9a86146b94a4213e3782483e5e6311ba857bf938d7bd35de90b38e3f76c7b5df42721735e1fe017aeab87d82ec2e1d51d46b6bf25136688e0b55468ec320c5b5b94f7dfb34617be35afd1b985bdf19ea911d08467c874e19f8e7402ba33987e04a9e8484bf835556b71321b894164d02f63bc9991bccc18f90ab0f7b0368f78753baeda1aa70628b0b52088bdb4d192702c85532431eb01d03b2248d489a86e7e117783738715c1d4f22b84fa6364dc108262dbbddabc76d44969778a7247c8df8e8dd74f6bc8772783a54cdd31c72114b07852265471fb95aec4468ad29deeef7277a72250f9c02744bf24370df2d6aa0989361f2d6222088b434dd413bd72b9379adc891372cfb23bfa2db82e5653e47cee701a81806ab5cf0f8b74fce277c5a8831915f019bcdcfef639a86497be55acd20a9c05c5f9ed213d7eeac525d5b93316a10bb31760cc37db63fbb3f1e923422b9885b628a38802f8a251d34e4928f19f9515aedb8647629b207102672e07802e2829e1fe6c81916c7ac1cfc36ba994f2ba8b0a03c643cdd724d95f99672350759b7cccd84b2138001524620f3930ebc4b928eec573dd34b209f40072fd6cdb95aa5dc6b7461b6ac10c92a840e1d985f848ae07980f1d016522d99de3df1b6d3e2cb601561c7ee974e868039f8d0ce62f7e6e4ac3a1e9122500d3d0843b2c5379e04397d7904881c5ac7acc8def09478787929cf9340f754b86a1981c44fd441d6c0f4a375000c91aa5002bfb7ba44407cb4bc8c2e952e3147d92f31d4f08578da17db65ec95e8548ae4a57851522bcaee9eeed80d40b53512985d6ea95cf6cb0df3afd5364c09ca02121255fc07c0115bda509b13c217929ef423e7241cbba6429cdb45903124c09321f5b0479f9fa5a54aba1c2a4b3162b2cdaea56e6dd961f182aad90ac6694624a4470be8bb2869934e1fae858111666f639008b1d41f17ada99d0aa3bdb4695af65e358252db957ebcf0bfebec7f0062900adc86e3b95dd2330ac1bdc9690af796032efd025d3a969c3f20d84aa436735623c4dd0042d09c81a1c5f852f9b2c08013fddae3807101c5298cc5ee9392eb75940dd453ecdd421a5781b66bad5f9fd3a9a5a447aac2a0a0af44496a5fb4889744f4a88fdfb2b54764738311524369f7eca94c21d905d9f99f8a8f2ccf93f80eb4eb497c82ee199eaf5dbbb39d748219a5382231e5ab1e26d636a3139021812e3ea4cc24c56823dd02ae41d898789a0733a8bf0b536447c3f19a2ce88b32937bcd6cb5310dd7a7f68d9748309a5ff14811cae038fd19c345d7dc86da9a23244b03048acd528e8ce2d8a7b4d39bbeb36bb83059cb80539179280ae8b31a4cde90c4db6c843d77e1b0d644f983f33218ce7dbab0084e0b6fdf19cf1fea1c2d1133425ce50f226f61095f806f58e01689251795747e89d4821be50242d2af6c488d948274476f050d50b0ddeb33ec020670aac250de712217a54083efd3472717d9ba86ce177fd922e229fa5920c0c01a81cca481250e7a61a54e69dff3de125de5bac90b3d1c1ed4ad4520a8b2b8c1059a013e916d1e1d93fcfd596a9ad57a85a08984f966800049273bbb061e0e7df621b4639199730469084bf0e68085d86d07a3d877d6f8d976fd75a571409a6e60817c50698c67e9032c2e1a2219496c481a263dd55f2c080a92930d8defd85c6e33e161c35bd2cad453882720d8ed39c653624624e3bddcfd1a6e0584471b95fcfc4a9c1f0e0cf719d5d17280a1173673e3efe530e49b9721f82b549915279e54152905b77ef5c3ceb9ead5b7b0438ea2e30441d6b860485c9ca83d2bce2f4c72ec221d1b259b2a49f6c10dccc0813eb7482aca1a67572de2d887395928d7bfc690280fea7a3e28ba58f80a6683b5b113748d2496a4322a3c5e4c8aa9077813a4b8a7fdef3e7fb213918b061c45466ce2c11289ad10bc0236677cbd519b502516c6a5cf3e3b1b82ea8090e9fdd06739e46c3cea4a3a341fe010a688647910e027939259a4bcbc589e519389fb52974cd34559367ea3c020be5057ccbe18b5a81928c49d73ab1f70f0d83cbf4601f04e8e60ac4c225fdba05c2e59521d34e8ae8ed43789b349e0641e5713f862d9f0b48d477729d2515c1b4a7dee126311a7b9cf8065ca3880b119ce79a2738180035ba8596c3b508bc7d91a506a4b1ff81719db9db2b66a6528a1f9cb991d482b9a72309d8128ff019cfc1de1fdb1c922dff5c4b371e2ac1becdf9bad1d05e1b3c4be9abf0f19551db4f35f82d31257141967e0bb7add1c4a78e33b28c5764e7be027c4bd692d8f7362c1cbfdcfd09f6a8ca86223bc06c708860398a74e174aece3c6185c632a404e5d373c406118d1bfe651fd9566b97fa31a75a3cbed87314553db6213efd00eecfca3a2bc8f5f8fddea0ab1af1c9b754e33cbb7ef2e2012b931632f6a167c449d6203b3d73daf0d71e0b7f8a811538bae7f677662f8825e89b4259f28c338c0199e1cd283ebe98c0e6a8c5172ed62eab06a280b02a2143c60a54ec7efc13b40836fbe2b966b23dbfeb972a95d295742129ee0a08c8756b05f7bc7aabd375bf9e97d8eb1a493beae209edfa90a3be18aa2b2f7402fee529d086078a13e8c9c409bf179020fe3e977561ab8c52cf20f12fe6f6b9bb83928c2bc8ae087d8675a07b8e85ff9a5bf6af98fd0d970afb183ef5df261688bf91c05a0a59e96ca8e7c3fd00c6d604d2b15fc2f2214c44948e56c050250798f8971824a3ca5d94094981c4a0e20611ab4364383d11368d5c755b109d477c0df787f3c458d097f90b8c51a9d6f624db101fabd2e26e72700edf9ba48496f3c1d1dcf4bcda3ffc6b44b220ae61fec885b0c5945e96475f85504294f51df65a5044db4de586f814158cc9f5b1141b0cd747050e1c0210995c6ce3d217cc6ad4c034b8904ee4d6135fbc22ba8d0f084c04849c5050090e0068bf5612880a9c27182804eed2b44ea2af03167cc5fe3ce8669252b19c9b30ae1098d1c571377c197ecc00c2471c34c7a0f10dfb1ec49ba3466f84a0546917f71605c5182504931bcb8a0c47d26d53c9240f2152e92f0d58af85da8432a9b51e8d7716307842f5623089f553660ddddac9a8717c526f403951bdc3b545fd4d1227b628ebf4b5f1af9e093f3bdc0306e0bf34a79230f7ba68b10b0520f6ee76fb33c3868b21fc9cb709f1295eea301d0f627aac219125c4eda5417d68ee639fb85bf85ed7204d1e49f990c5338000a7c9025a3d934543d138559895227c244613c2b3dba2f28ccc43ac87b9c4f0181aed1dce5f6bf9844a9a3bda94df38ac9226a03f076f1e39daa5ea18368b002fc39cb13306a445a152738d273c41103a444ec7679bea0d8834ecb8b5d0df7f8961b88b7beaccd77b3ce306826ca83f35f79b27580bb48e20192f928dfdae3100f4f94ecf5016d227d6b97be94d01cbf5aa80a323dd89a146169628bc23d89364b0049c7785dc2afdb3536ffeef791f520cc9aea30147e3464b3b1baf161be92d74ab91eaa682624cd93eb010c61c5d2fd79a9e6efa752461f206f9376f050321835e13ab3b19913db5fc61cc77ab05d5d987ff68786633846318b245eede4df4d325a7840419b057270956f448dc8a3ca5cf5e0ff4d63cf0f5889199a52c800f3c3e585ba562c854f64d501bff55481e6378c0e2b3de4307f97ab80d8543736cfbc824a8377f982200051eed0b50fdf473ce92f8baf471de9e4588355a3f1c142ed1efd4a61c93b65dc2919f98986dccf94360860b1e12ab91eaafad8055299dc2b028a20c9744571ea3d0dcf4bda99b30965372fe0fbcb68c211e2a457f08fca10ab78ed0a43467f368a71e44724238f16e4ffc7efebef4b23d17d0d028185a2d78b47b851cfce56bbe1057334ad845a1e82c50073d2dbc900f87dd5ccb14f5496423f325bbeb949ed25f5fce1a98d53cc6095acae6f76dcaa77196751ef6f3deab3a96b9be6ca3e050ab725c2d426b0c6e1beb3e6c0fb6c9e765734e0c056989e45d46c7d6d50951f8ec9927b57da21ba2b39c453927aa529745bacedc8873a5685e4cc57b6758fcab63d9ceca84dee5deb62e0823c6059ce39457ac68c402652d6426e430d55697e7e244799b8d4f2725ea2e7470e55c399ec987b0392c297f951fc79747334261416e54f9fa2978ede7a9512546e015bcdb4c831fa511549232d683d49be7443608b3d3d91ef32825f8af6c4f8cd7938a1a01c02ab3188490835a580de91c885e1b855db98a8dcd9905233a0cb50c798cdb0e23cbfa069038d9a4e4641c37c5aecd23b9dd151e808d918b742f550a9cf6a944f9480ec2ae36c158417449c9363f395c3da731a2f9385cd4aee3c0ffcae53e3a480c75c1b690fbab3b474f73ba2b03a858036e9703921e1d35f17314c4eea7059fee53eb4083b671ccd553d78bdccb7618bb9fdfe33e62fc4a4cc5e3e1d74a7d50d445407aa209629e8b5fd16b363218bf113e3b4357e756f7f56273d5a24444996dd95c7319c7442550a7387f45bc1060", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x5e8a19e3cd1b7c148b33880c479c02814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x682a59d51ab9e48a8c8cc418ff9708d24e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00000000000000000000000000000000", + "0xcd5c1f6df63bc97f4a8ce37f14a50ca74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb373285fbd4c6fce71acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0xacf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb39fec29fe06b54a1c58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3a8f65c4e14b8c350e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0xe803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3fb08f1ab6e14e0d4fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0xfcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195037606837a8a4a9086175726180e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0xe803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19506f21f0983582bc906175726180fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0xfcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195096f8eb862d21fed0617572618058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f7b1f8ade68c95ad6175726180acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0xacf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x02000000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} diff --git a/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json b/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json new file mode 100644 index 0000000000000000000000000000000000000000..b364139b87e2b83fa906463f8664fe57f38be4b0 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/asset-hub-wococo.json @@ -0,0 +1,80 @@ +{ + "name": "Wococo Asset Hub", + "id": "asset-hub-wococo", + "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-2.polkadot.io/tcp/30333/p2p/12D3KooWA3cVSDJFrN5HEYbt11cK2W7zJbiPHxR2joJXcgqzVt8K", + "/dns/rococo-asset-hub-bootnode-3.polkadot.io/tcp/30333/p2p/12D3KooWPf3MtBZKJ3G6wYyvCTxFCi9vgzxDdHbjJJRCrFu3FgJb" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "WOC" + }, + "relay_chain": "wococo", + "para_id": 1000, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xe8030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x50cd2d03000000000000000000000000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x267ada16405529c2f7ef2727d71edbde4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da90395122802460ba3fef86b6eef716f2358c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da936311af37f3d62b64610d04a45b423a8acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9a79b78a206a5c0e4c36a85f8342b9ea5fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9dcdb4d826419bfb6cb11a9e4558a0deee803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x110e2473746174656d696e65", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd00589c9d04bec6c5c9114f1068ca261d6898ea2b6f604b838543946d20353b4808a1172684cc7f2c32f33a1e6d3deda1da9643964377abf0d25fd0ab56e867512ce027e7200a8d6ec55d3b5793e2e8ddc8de726f29a59432a51480120611ac111ec0dae74809f3f79485ccdfe48839820b0d6400034e6fc09ab3efee0d37fb302380396c2ed7584d726ec34397aa8bf9ba6bbc73e7d0f943e715fbb93560cfebb2f1f0c6a74b5526e952c57ee812741dbad41e3a06de78e81ce81ef7d3968d15f3d0e6eb0d3ebd85cb43cfe9523f8410bad5251d9805ad99be42bdb9c971ddc33fcdb12eed983aca7cb57924b3f9a4a151f2bcb5e82dba74d81a8cad357a855f4a7fbc1d3dee3f2ab320e894b71da053eed3d2a3432abd39146a9794920a61790f4b515191103f7d2f20d7acbda484d07d5a5f403246086343d3777bd81696f7de7befbd4885e2993367eef8e8b32de93eeda850fb98557e9909cdac36cb1bad43fd23af7cee05645dc15e8a2b12e2ab74a178871067fe8a7ce98e064d77de68bdbcf2e72dab58ad553a21a9650821beca15f8d1afc4b762fa98b5ead1dabcf2960df58f3221bee3e74587faa75b54a8fdcc7094f0e99dbb0bc879455b953eddd12bfdce67f7573e798b449fbed7111ab32a84e59d57eed38dd6e71cb36afac87b01452c0fbd51495b7ff32684e55fa3ecb27db5627af626d4fe49a1f6cefb52e2de65416f89fbe77d297959107bcb84b07c6dcf8e7d5374d2389ce6eccd9be2346f8f3e9bf4c957129fdf2d52a3b34b1a675b7c1d698f2e697b53d21ea33729a5efa5048877e200d3b76cb7883cf25c3a841ed43cfa94b48ad09a292afaa11e2fc4675e7a15a1057c5b23cdab0c596ba4f9107ca1057caf91e60d887e272feb034c2fb3dd22adaf23cf5b26dda7cd6635dab32d49d9639b7c21e123fc2ec32ca601e38822333c30818011648cf0d2fb80250ec0a8d97e43e37cbaf6c9d7720dc6947f29302b9f34d3d75752d2799ea2e88d5c5f1cf897fa1ae1f9f5a7e479e5b3a26d55f4f95e482a7f3e5dd17da6225f47240dffdc0b68b9066b12e5d2a3f3055465d5f495fb349f8ef486ba26ad53743e7a85bff215b62a4af9a3fb6eb6e6d64642ed718eb4972e335f23ebfc8f52595074e915dd779790fce77bed105d6634bb3556cdf975e7cd6f9ab4ce5712e8eb956cd2428a037dc51415bd007e465aa34b9fa6a7bca295bf7249ab034c65fc6e91caa5fbb48ab24bba3fd9da8bca84dab7cb7621f7cfab739809f1bfcc14d99d99354c5107122f80038d379af0b3d6dc9ebb5d06bb69123bd624f6f8fc3d5875b69e9d6f7876761dbaf49eddbbb46366d0e5d975ba877ff8ab0dcfebecabc3adbd51245850731abe3efbdcc5a1f2fc333d25d5bff99cd79655a26f5ea91d160affb22fce9f2f75fea8056a408219677ed61bad58be55e8524c517cf44af4cf7773d8ada1ee890826fc107fcca6ec1b2fd4ce9c79987dc1b24e64d2c2cc8fcb8a2a967f596d5ea96ff7698dd2f0932d47d7f7d2c006a1cb4fa3347c236253b72602a94b5ae0e8b996a90db9e6d680b557f9ad796bde9ab796e58a6fadb52665320063df3ec0face2c5cdebbd4deeea64bed3a5d72dfa721cc7cbbd53dedc77d2df29df3ebcc4365b233eda15b77b7e6f25b86b3a4f9f3d62dabfcedbe7db237f6dad89b2f7b505ba6cecc5fe941d37ffa2bf09acddac581bd56fee6ebb3511db0e6eb7b2169999ccd62dafeba022d37fe8a355a1caa70d10b2de0d9dbfb62e28a8a9e9d2f2558d1b35b5ddaefa2a5abd33d85b9bf5daaedebae9dbdae6f93b649ce0f80b533690fda96f9b4a93902736bc09cd79b7fced3a52a6fe852c5485daa3cfffcb90d5d6aff4e4468f9e739ddd33f3afcfb5ae49f635d6a7f6ed3a5e6cf9f5b5d627fbe3a2f0bda13d15c5f9dcaf3cde752fec917906b12fb3689b33ad4de355f409c2971be747fcebd90c0acfa43977d2dd7b8266575a87de5375d9ade3ca74b71468aca2ae59553d1c27e1deb52f4e6365da2bcf98c947f52749bb44db29c2f24fcae4956562daf3cd27d8b0eb5a77c722fb7d146ba3fe97e45ddfcba6c3d46f8cff6ceae919af39b55e8cf9bcfb6eb68e5175ac0baa443efd7faf639dbda0b664c9756f9ebed5aaed9264d77edd6584dd26952f3e8dea4d8207559e587be14a3dba4f697c9263576d3a5fde68eee7b97d69bcbd6e38a9a9316875675be39cfaf0ca68a9f0be62200dbd31045bfa7223a0cf07b12828bf76fdfeb06ec54e4c657f7ed3e2dd9a5dcd6b3bd53b167afd857f9edae4bebeddb25e8ebae4bd17f7d46ba0f29ff5c1eac597c01c18cb1e87b25d9e8932f25d06356a1439f7d29c11efa5eae49cef7027aeed3d0f76a732f9955d34b8fb44a1869751f7d2f20e933d2da808f3ef7a2b21ac4531e69ddd34787b4c2243c60c0c90f40d4203efa3629ba4f83749fa242edcc9933743cf448ab0eef7cb215a97326f1a3a442f16156f96326c467ce9c39f3d5f4cf275b90eeef35d4fe65dba4ea9e1ddd26b137ba4daa36cfbe3a2db9696156f9ebb3293f5366abe9beebd2f3f5c96c3df6d9d662ed43ac2e60cddb9fb70be8658cb1cf663dcadf17fb5ecd7d7a2fa0769f9e6c31dd6fcabf1704f6d97ddaa74dccccc4dc01609366752af6cdb74becedce99ba26359fcb837195df7c2fa06d52739f2e61fcec38ecfbdba4f5ce7096c86f97df19ce92f6e7ed2f1be2e76c9be4b2ea7ebdf95e4ad83babedec3ebd3a2d0bc27e653035e624e66e0c9816e7e5442689d7b2668a8a8a8a7ec0ec9830c4fcfeeacc0d80010a40006cdfdc0660557ebbecd28ea9a3ccb75b5dda93162ddf8e7569bddda64beced378b037ffbea7416e4bf3298981530b7066c4f424cf155febaecd29ec494f975ab7bf867fda64b3ba68e32bfbe5ddaaf39bfbe3a9b05f9af0c26e6054cf6ed525de76c9bb4be6e62fe31f754e4e537ceb501db375700d8beb9d8fa42cb08bca5882b2a6b0a9614ac255841b0946025c162c35ac322825504eb07d6180b0d8b079618eb0bcb0b0b0c2b07161756171613ac32d616d6159611da0e1a196d0c98051807c4026402ba002e31b330e398589857985598549870585f2c2a1e0da21462149c175785ab819381a5868b8193c2d9c045e168d0bef40ede10bc8583819b62aa317f307d307b30d39863261a53cc3c63869966ccd32c63ee607231b7985acc19cc2c261613ccb4625631bf4c2a660de61493065306d3cb9462c260be6042319f984ecc263a09ad84364223a189d045e8367a08cd461fa1d7e8310d8426d33e68335a4c07a1cfe834ba072d84fe8155036b8ab98539c794a3c9b062604961c1c08ac27a810585f544d7a051d164d08afa4c77a1b9d072f4145a0a3d47d7d155682a341c7dea321a4c4fd14f34146e0b6381afc056603738094d0cce81b4825bc02ce0151829c2810d9c00082a534420e549098e98200139e00064b96121c1ea8115c632c33a4d226616be01db80abe02f4c05d780a7601af00c5806ec8563c052300c380a7e0143c14fb013dc0433c12ee0259a4b45a6fa41d583cea3faa2f2a2eaa2e2a2ca41b545a5459545854585830a4c754565457583ca065515d5978a8aaa06d514d518ac846a0624a85e50415135d15fa0b84079c14a83ca02a505ea0a541c1416a839ac332839a82d5056a0aa404d819202f504ca0c4505aa0b54142c329610ac362c1f5847a08e4019812a0245048a0ce504ab09d4102821506c5048a09240b5d1633017bd855202e506d5048a09d412a832141c1414283aa837a82f5041a080c066a83a283b283ca83b2835da0eea071d054a0ccfc159a04e4d0c4506250615060506f505d505c50595036a0b4a0bca07540fa834a831141a140f281b50545035e036282f1c86824163c14ca0bca0cea0c250665065503ba0c6a0744065416141e18002435dc1633018dd0565057503aa0aea0b350545036a06940ca818505274172a0aea051414d413941354131413940ba825a816502ba0ba502aa052402941254121411d41194171a18aa088a0b6505a980b54166a084a08aa489e9179483ce41dd20e5987fc82a4437a81b720bb20b920e79072c82d482d4833320b320e8905790569055905490509879c8294828c827c4342413e413a41ba219b2099209720cb4825c824c836241b1209f208d208720d590449042ec2d243c82148325208320812085c865443fe40fa40f640a6d15bc831128d1646f2408a9167c830d20c7962391a07ac05b90349861c438a21c36021740ad80a0946c3829bc04ee028f014180ed985e4a2b520b7682ea416cd825e42d42282894d4423e0175a08f9256611958048b4114f0b2fcbcb82fbf2d278631c156e066d8dcea285d172d0b6685ab42c1a0efa8bd64187d14fe82d38e926b4180d467bd15af40c7a05d41a4d4467691a341e4d477ba1ef602f7017b80a4c0586024b81dfe02770195e0223a1b53010580d0e02ff807dc06934303c86d1601eb0183e8377c064f017ac031683c3602f5a05ac0567c158740b18070c86af60214c210081059a090ba80005de1561f22f535da86e50ac3cf94013209e40f9a14993c9cd8729509a34a996a148f9c093a12923004193a11ea05489e2c394284d9a08a9b030aaaed043132a2098a2448a142a0c18ea018a142954182080ca0a6b454a942743507c6802050a0868a8a8b0544030254a931254813202a1265180f8a12950445082273c7805c742e9610a95294d9e348902c443e9610a15080c4d1901951e7a7818aa29f840a507283e10a9a4b0564a0025a889152b2580b2640a952856ac409900ada2b0248802c45781125485ca0598d0ea8d8532f4c48728529e5c69026504504610010af800250421784201015450582b413d40f9a10737d6cad0142855a0fc30258a574d9812050438d512b6872856a644a9321404942625900204104f9a5481e283942823f809ea818a949f9caacc8aa0c993a1273e3c1982b2434da504134491f224ca509429517e546c6c500f54a47ca00994a111f4002508283d2a246c152a0cb0aa23ac15285186a254a1f2c3d0089ef8a88cb053a844197a5265043e3419a222c54a932840fc932a23f81f405e12914c1a4e88f935cd3d15153d9b9a10e8d6706b30101c1d0318b00c58c00296015bb9c7cd5c75d5cddccd32bc57c950ad5b57b9dde7e2baaa7231be0729e82aebb957b58bf155eec15745e7d8519583cef5c2f75cdce7aaaa7a303a18ab7695ec57b9aa6a55bb76b1b57e0d5d4357b976f1390aeac4172be8e4bae7de8b313ae762007e02e064a8a273ef558fbbb95f77573939392e2727a7aa72727272ba48d5b1aaaa2a56b1bfaa7a880f2f4001b2ba9a8170bf4ac87575732740871c70a8aaaaeab6aa21dd5d75d5558500aeaac7950c55cbc0c37c43d5d3aa8a5fc5d5907efd7698b9c2b8723b1577f30cef55fdb85455cc554df55ebbaa7a5d5591abaede7b55abfa55556b55ab5a6b55f55e1fc0bdaa498f00cf86aa717cef55d5ab5cf5aa0254068855acaa573d9e57bdf70a400012e5ba7a03a8dceb8ab9ea19aaaa6a9eae5eab5c55bdc7afaabae2ae6aa866a8aaeab9f6d195ab5ef5ba7a5575d355e59eebea55ef41e71c15ab1823350023ce45f7aa2233b4f79c7b0210800b400002f0deabaa9ddee97e6d4855f5ab48edbdf7ba55ef7155bd57b9c734341a666eaeba5fc55c55ae7a55d58fbbe2565515572ecaf8a2e357b9e798b9bb7aef55ccbc15775575f59839ba2a42a713a3a49ce52a6b06f81e5b33bc58cdf0f801a0c1d71673f77b55535555bdf7baabea75c5cddc91691e57afbb9bb92b171d25a3833ad1b2acf76255f173705dc32a565106e7aae79a9febee2a36333b7e9bd15de66526e2fc989d6bb75cbdc75c5555c5ccf06d2589cc6e9cc78f2bae78e356f15996655995d59a65b565040b092d8625c0d0932a50a64009010008e003141960d80220800007384001aac890b3058062c50a942a4088804a0f4daa40b942a50728559a3cb1e2430f509a1020a874800200d103941e1c1fa05481e243152a50a254190a00941f726a40303482264353a2540102069a1fac4499120504240b0451aa40b9d2e4871e869e7c80ca101025a8d2030d3e44106568ca08aa34e9c14a14110c590284808a142198d70401c58729519a4c89f2e4871e4000022a9901a44409e21142c30d2908a947911e340009c00f1ecc0729517ee8a1c99094113c0101141f76aa3c19b242036645c8dc0250a1526548500f4f3e20450a952a01b07902a5ca901240096a321404942931f81882120221232b4356a2040125c75a024ca11265a8872756a63ca932d464288a08444085d4630b1044141040a902445653e50914293de0603e4c810204104f9a4009c1932a5486ace4d0488172058a9426413c1141084240450a111b4a30044185044331dc5000028c4a072840930240097a22e5034d423025ca0f569efce04d04315c9902a5f512a0c9142a51ac548172a50914285540d0a40a95a1273d509122e54993a120a0e45c9902a5f9d82e41152a2280220278650a9416802b4c2f111111918988d7c99a1e9189c8244dce5411352293c9999c245aa2e728274b6432992a9373b244444b44444444c444a6289d9898a8393199d8c444a6e68488c8d49c6c13392726222632111135274444ed6489d8c91211b51313af131313b113222632b5935d2744a6364527265ed373b226e864d76432999c13139bd8c99ab89d98d8643235270d6874f0eeb208ac3cd9557ebd79d75abaa849ae08ec6575dd782e7a27dd20f276c8ccb918f3d8d0de16932e875e46df87fe6896e8584c3fd12753e9916e8940169d69db6187b4a2a0e8a1b78b89738e11d89fe73eddfcd12da69fa58ed6ce1a67ce44fc7a0713a77dbf3aad3c78f4c95657599050f3dacff76916e7584c3fce1f358173a1e6556655be6cca39e7b22dd0a9f6e83e4d561e3eeafc3ae422e4c77953a12f2e33c2f996f79cf3b7bbc3bec5ad3fdfc2eed85f86b59df52dbb3b2ebb693bebfe5be4779fa899fa392f7375aa07451f7975cffcdb7ab068d93ccefc549e658be9874bfca9b26d3b9453535ab24b41cee78d03a1958707e2373e777178374f884fb6863835841a420da1865043bc929eba39f3427c5a59756fb57feda97eaaffb5c73933ca97caaae5a35d232fab9603719f66511e7e442bcf9149e34270665784fc74cb9bee1ab1b2fa9cc6294ae37c29912f04dd4a90e5371e64f9a38134d029a7a1a8e596d3b84f53d4ca84268ef7c0b92ef7e1108756ecaf1bdf0fe243e88dd3f85e48b8e8778d08c9ea4df69c0608a5f120b4f2f034d1875866b0e8345ee5d3f8648bc66b741a57129df2a724fe732651889fa2e8fe83d7f3a6958f502e2586dddcf8535e9df454fbc82bc98ae542d36b10ff7c17072abb22e481787d6ef97cd6cb84a657aa726b3ae5963f4aeb73ca7ddaaba84c0848f6c5881ffea3fa51d9f4f0e15bb6779e63bee565edfb34eec3a75b3b729fb6a1b2edb4fba0376da7bd07dd52d38e6558db69a7a195871ff98cd676c9f279c58b06399fcfa7452d2f60d3f9cc57ca2de70bc8ca18b32c6f599d19957da9bc5d95cf477194b87f2edffd181d88f92abf8d11c38d6fadd1ca7f2504d5f453e20fb57f6e7a217e2fc35942f9732a7b3b5ce197198e12f9d0a5c4bfd23e66d0f9cbac26312482f1f52062ae4eedd316ccb95b1c96ab582f8f416f2fd0ab68d06b67d16083f1cebb4872e92eedc4bb24fc5ab0ca5ed84bb77be9f67af341bcdd1b6c125e40d05bb3a1fd732fca25a5a28c93ad01601750e5998cd3239dde28f429ac49f7a90ba8b9941425259509c547f96c926aee7b51b37974d85c3e8f147d9fe6d3728ddee636b2f1cae7646bb11be70be88be50dc3c1f1b73d97d778bd7a30af3f4ad16b0e8eeb3ce983a4938a14699273c717e5a2b6e33cd25d52748c6edb1942c4dde2900383b7acf2f0550acff7e8e142cf6b104232a13df35f687c362a44480cfe326f92f31e990e67c19c03f1bd4842fcd2a76c59dbe9e13d322126a8f11e3c6442cfa5f790cd85c8cf7677aa10efe13ecd453f7e3891acca1f3e24abd86e69975483fc0f8f590df2958bfac2f176015138de865efa7689f21ac45b9810df0b4848b64dea0b02fc114b05e26556a3f770be807a587660fe356652783e48e8796d7ea5fd17ccf7a557f692a5c6b1987e6a1ca326a8117a5e8778737701f14004ff5c7ef95e12d89f9a1a9ac554f493050bd199329a90052fd881c7999f1adf62faa9c9b68cfcca76776af31e4232a118b22f983f1f42f761a05f6a3c877ee1e23f352e69e5e17bf8881271d1c94b172e5a8610e227cb9ef9a1c9b808f9c1322330bf30cc2fd976dc162cc352c540065d3ce182327ee0e5672fdf82398d6f196558db715ee35b68b29bb6e37ce4eca5f5d4644eda8ef3d110aff2cab6ed0871f68265f5e62b7bb970701cd6dc49f321599542b28a7d5d375acb1ad302e6c6b30061b9cceacdd775435220cb0e8c729e26b99821a1fc8626b9fd46ad2e6094df00b58c31cadd3581fdb1a8ec0b17ffb1b276935529568c71d24af4715613e424becabde21a696c9982ad7629e123b806e994c388e134e7249ec7789f9e14652e5c03f4b8dba4d956a4cde7115c03f4d920749f163d892633a1f836947fb60df4489b4b0a7dce6849ead3e0a524fef44c524ea249d2295a4d4fbd4c287e739f96cd278d968c92b78d6caafd204068f577fe8356795fd9cb3bb7a143fc40d0ab7fbeadc7881adf82d560966c3d468c7ccb35ba2eaf3182c6b78c684623af71e737adc7081fbe85c6478dd3605e931971f3b305cb8c903f5b88968d2af0d8b2c61b46c803cccf163094d738e6354ee32e7ad579e73de88ed1011bbfad677f2ae99daf103fd58677be98741da44b31d84bafabc6bbdda9372fb3c6b46067d011a6866edb918e51d976a4d3dcf0d2473c2ffda2db762ae9a55bd4db8e748a6eabc19a349d7249b7d5584d9a99742a9b8b513e17ab9a346bb64933734da2bccab64914e57b49f7e9244e8cd1251ce994ef69064b385f4054c698fcedd29ef802921963eef792591227c668d2be4f47c6f87d1ad2d7a75f194c1634c947448c2a622aa09e80060daa882edf7bef25e1df8bb249ec1009f4e83ecd316324888a1087194428f306128e50f140081718cff960f2700ed69627b51ef7b3be3af4e32e98fcc874bf10f1fc8061ff02bdd1a1f6405fb8f80fcc88787ec0bc0c6789fbe6ceb9c6679cc1c5ef29cc125f80df53182a9ec9f01a7331e97b010d3520e83edd5efead3b5f773dc048ce51e96da83de5d239e554a9bd6532c31c85d48609ec514ea34b2e7b589ea2b2da1c5e48606683b51e3eb59de7aff2a962fff8d4a4e7ed02cc79e5d33f314d7aee5c5226e3d39cf54ce69ff3a94bd09fb398eec18a8a8ab4fc3c775d720e7dd7dfa71db59a84b51ef7f35a269bf4dca797c0aafcb764befa3faf6be69f3b793e74c9f9f31f3807fee741607b0a33c53b6f5efddb8b736372b57ada6b91dfaac3ef8af95d27d9d03df2671dd2b91dc0768c13d8f89adf316e98f9bdba34fa6a732a2a2a22e2a7e6f4ec4fd579e8db7a7eca48d186171880b9c20b7ea8872719dce0e1182d54f130ab5278fe653223c2f6d9b7f5c81f666f4d5defb0a300bbf93dc980055ffd9e64c0e589d8c4ad6710c57abf63b4408328d8a4915eb1df6af3ebf5e6d72baf3a95546df8dd759e1bbad4dcf4904aafa8e923b5d25e3a0dd532f70298f3e8faa34f67d1502d344e042f019af38fa3a1448079ce3ff3597b452bd27d1aba3f7b45f7e92a086789e5d32d9fdeef685b236b8935b2a253d0712edfafdc519c2b3b4279e555f665beff42428d6f56d074cba7b326854e5d5ef95e4aae6cd748bdbc799509f119be98f45f59509dee9c7faf25fc5556fb839c5b313dbc96f05b59e53e8d29cb0e4c7a8dde96f43bff2a331ce7d09dc70cc7398ecb963c87999297ed1a69ee325e238d884db3610ce612607d27124b345e9dec9f6f37adbcaf0798ca684db99a5e394bca832c9fd3fbba2ef7e9b6da55ab2a13a2a9a9f1ae46d528be6dfc9c15bdf2e713a33818e615e6238a83ad1d3fa2fdedab5135a2c1e347ed694634eed365686823a9c95c939a53d9a4e6230a3da8f2e9d5a79bbe1712f639a7fbf47457129fea555555f9e4afd61a692e79b9d98dbafd80b92221fef2e693a2d53de5eda2f1d69ef28bc64723ca87e08f7cb245d1da4ff945ab8c7c083e8defb5a409cde8a214ddeb0194536a5dd2ca31c39a94fdcb6e9ad4eed3341cb760a2a9cdd9b74bce1d84c2bb4c52cea96c8accaa7429262dcc3ccc249677ce2ebd51170415bcccbe4ce895e82ba4724a02b49c1e7a75590de2db940d4297875e4df04e6653f60d1eaad8410d4808e3b888f99cdf13172a7eb60569143ff14b1110266891850a45cef94b110c4ad460092f5500e0058b348a8680d837fe4b510d4808537425015a4e4198e0a17f1962dff88959d1bef1b3199675a22952c8a00d21ee282afa79599196a2226f5905e29bf5e8baa3cdfbdacb02354e6002157964397366af2436dfdad4446c622236f58365cceef2cd9b22c182a0d3f015669c4493f62727016571a8c2f35fd64d2b0567dfcd5ca68508233fceb9f8f849a24b36df7c88e505ac4a794ea249cd79a2c083163784554ee29bd78dc237c7b28eb51dd3cf72218a2f62f045166e1415fd38e71fa645ce8a14d060881990f1a38508233fec5c7cfc6821a27f9e7351c00fbba35c14f083050c05d8b1f0d0769a33996fee1c0b180a3c7719169fb6d3fc6558c050c0396758bced347719cfb69d2abfeee9c45e97cc76a1881e7cc142126ee00422587860fb6372811a64482185196c6c21c7cffeac571e0a7851d10f7b125da281bb10b5899b93a239479f3b8ef23d6f2e9fc7f7a0a30cd45d34e979bb9ef3ef890833fea6496f368b9dc3c7efba9fd0dc75695d2e0eaf7193de286fd01bf4e6147409a137bf69ad357fd0675b4d86739f6e87ced0711c8e2b03fa8bd0b5991eea984fb0beb8acf14e263f59bff8adc581bdddead2b21c7bfae76e717813521b9af488c8c1f334e9f95eadca27d25b4fe5cf49ad67faf39c2eb926497f7ec3e2e06b44faf349b1de915e51d93bd265ebb9e91de9cf6fba44f90bf2cf7789af36fcf320507acb82cfb8f4e6bf66e461e6739a24a5e3446fdf8ff3d1f744c417bf2722baf89b26498794a96c9b24237d6b648dacfb34a4fc446d7addb89842fc9d0232482c7fded40a7f7b5f49f6a92ce8d1daff9c69155e23cf87e40bed999fded711cbab6a6623b8f9a19be7ac5f537e8bee80cdbd006639e573be4939d3cacf4ed1a6d5f4cdb452dedcf2bd94506eb94f23893e9de9748a5adeae25d2a573b66b84dda72d5a3ba37cd2dacfeed3aa75ea8a7ca19647d1af475a87d804b9dde0a26f2efaf5d93dfb958bbeb6dfd3a90a262cc46f56b9e872bef48afb754797d0ece2509dcb84687eeb9ef9dadc5aea42d8b78c8bc098db3dd279a3fc5afe9df1108a25de3ffadc1f6c4f4fccf1fecee79bee524281297ef015491e4330f83a54140237be0e752912fa3af40432f1eb08563006086eb871a43223c50bed9933792cb9214b169e7d3e8b2fa08a3516bfa71590f9f6f27b5241164ffa3da5c08d6f3edb8257c59a17bf27265af07cfa3d2d51840fc0efa90567be395f4c645111b41c6d2fa996256325fe95fe105461246ec9f3ceeae90553bcf3f6771d7190e22c39e39d3f1af4bc5a31bdcbaefc80f351a13d73e60c13ffe831ab267ae547154788bc739f6eface784887fa9df3b584c8bb25cedb210d72de3ee191e7d1f752f23c6643f3b749754f504cf143fd30abceaff0c346fd21f57743134888ff0212eab61acd9e2f20215754f4ed716ce1e7b31add397e3e0b5e47b6ccb3cf7d1042e81ac2c6104ad288bdbf519e2762d36b0806a3e1ddcf5985e785b85b5ceee62274cbceb9d1fa9c6d3d8f1427fa3e8e92ea5b2644f35786fa91f03c0f294e74fe7e86d47dfb46970bd3598dae1d0f69ffa49ad73d0a8ed6178f67da1e0af199873ee3368e6eb4eed3fc8d6e995fcaeed336734d621ae91af9016b217e9bb45cf332ac4934bccb6e9ac491db14669b8d46c1d8abfb7d59d2f8ee6e7fee8a82b1efbb95b91f6009607b52e28a17c0cfbd00f6bc259146121e30904416adb546ea12ce53220a6961c0491277b81fe75a0a9c701d0c74a9929c74a9623f38779bc63b77fe802eb977ced3a53d2961e69ddbd03defc74917d378e3dd5ee1dde379e745ba549bb73b1c25aec87dc3fa99b3e7adca90f5cf776915f621f84df975ba24c467de625a657d08fe73be9634f9f64785887067bb45f83ac2de7c3e68f175849b375a9b439f90d613fc732c2840015124eaac9abebdadcc6a7b50cc6af3f5fa7c7ddda7dba5a4356f5945c1cb2a7f37bbcfa68d9bf712f6b6841dbaf31c481fddc76c4e4914f18fbec76cbaf4dcf97c94f1c8238fdfebcc16597f94cffc5e455b64dda71fed22219e1f535acc8582351f304b3a21737bc09c73e75c3677be3a6e00edeb349d05d1b6ce3e9dc5d7916bc97ab3ef0730e8fbedec93af23b47d42baff98406f8f34087afb7c96bb1eb0147abb76581cf82f25701d66952bf7e959d15a396baf3a9d270deaebc82ac1a2effa9c7bed40f9667c0905a16508218abe4ae5564c5f552e544960071e67deca92a96289237eba15d3cf6c9b5465759750d985a47a08e17bcf39d75aebee771de18fdede5cabaf2355b6feae23d5ef1aa9fb4b7196445f5f8f3588cd82a42b915fa1733ba45b63fd9e88b8e2dd1a79545213c5ef093fe6d680b1d79b9c2eb56fdf76d73abd4db0f66a6100981b734e97969c4e425772addb99339d430755e197ef8ad379b49a445155ca0def9ca2e488afb6da74d5a3b64bd5f973189b7400cc831e0f015beff648a5fceae83a1847358877ceeb7ecbf867bd86a96cc188d31529b0c214c61633c8a20d3ae490e38a196aa85b220c127444a1c7efc90675b49e1c8c400713c26cd1861800b0c0b40216e8b8230c2858e0051d47e68580d6a150938a8777de2867f5d16a02daecb94f63762ba62f43c9906a8ac13b874d7897ed1ad9acb6ac018ebb47d5f43e4d60ed754f41607b12a3e5d9d7fbed1671ded61badcf57096c526dbe4c5e56b1e03477dfdca7dd2e69b3a055e29e7dc9b41c48d85420830d3efacd151f2194523a94504624624c426267fcbc41e38b981bb4a0cd5184151a4481066108a1032c8a64a0c20ae42f1a4fe0c14e2af2eba429308082175660a30ba72464ee073ed79a6367bc29065f10620a2cb294a1441a3ff49b93c47c3b638e2775a9928a74a93d9ff1c6b3db744feb3cfb0ed6de57e30b887b80c9df7e1d481e6e65cc6d3d4be238820865ae10842694e017a85620002deef0a28c2394380d81c817bc9cbe7002f27bfac20dbeb0c48bf2864da3e47adccf5a5b84cc29ccf810a28262050ffd06ca17a3b34b965c62f46d3d45b8e8e2022d3c11c70ea6f0135d7629868f8e6de1e313787c84cf39c7ccbc739b1be7dea5ea9d93b4c013069ee1c3062724ac2046117ac083a229c060c61a2f3852668920a4a00d25c080053956b8808a1a17541e90a1851a617041420f706e90052b8a689ab05205357070ea220658dc60c80ddc40e3893000f83ddd4007ffe3770c1737683a363333475fac31336795f2e8448ad8a0838e7baad4bc521e7d5294f2a6bc51ac65edbcde540c52599599cc0e80f9ef37ccaa7c59c5bee5fc8ddb1df6ed52f7b89ff675efd3987b622ed6526258d65875fe32e71c66aebd3a5f47a57bd73ec8b96b52abced7fd6ea94af7b5a4c90360fcfbcdb7f5f0cfe65085dfd17ebe96ec8c96a3fcbb380cf5f792057c4be7b89531c40641f8510512d87b5fecf867852f4ba8f9a206cdefe90b1944c82d3abc1c2a3133cb0f30e0a2280a4f58a3e80d21360823cc1598b8b43c41451d79308185327640c68d0dae30c306752801450c1153a49186154728234817141a5fcad880090ccae12c85227edeeb7fd15d86458ebe8cb59e7d6f0c21fc6be2e73d28a133bff7c6f8e29f133fef6199633635bfa731a8f88ab90a4c5e4c81074098c269093ed001902e4898628822e400074518228c1f988b7b03223bac80c20c164f588111365594a9e20acf0c22b0208a234811071a2cf0510512aaf062f3104208c374a18587eb7efc9eaa0883b91f5c5d4458c51546fc4408cd88438d2184fca25105186ffd9eaaf0f215f3e6848e8e57f1b173604ad83b9736cfab6c1fe9c5ccd934895d12e19c738ea1114611ef62760333eca6edb0b357b7deddbc3b7da9e25d515151d1961fe7365995a2f3ceb1267117d83efb6698cd905f33b420c4c3df9318707cc55c7a994d7c81c1dfd03c1a346f6bd24699dc0ecaca1a613d6c2ca648f685f80c0d33c796bf69d2ee3237d9680dccb81a408199bb01e9e29c7b300815d28a3146490121635a555555d3aa8a30b2aeebba4634f0f744c5126a2c0cc3b09a1e3d7e4f2715d8583e7cf8f061f3830a2804b18000010224c88d1a510cb18408112264084ecdef890a2dc060e55c407bfa9b266dce25e43ee70212e2334fad91f69c0b0985e19a3158dce41a691f2284ed898aa2af96e5a8c561e5e240fd9ebe0cf1374d2262b1f57bfa82c4dfcc8a92113ed79ad71aed1a59ffc14415c3ef690c2edfbf6664e10899c46e018a1618010b5cdcb8238e1e769c4e592a2d5070606646efbdf74e6524e15f966a8c1345545023c82f1a4fb4f13e7e4f658c914500c5f1a50b2735bc7cc1849a0e7cc1c416c06002971560016b3ddb8614ec90c20b332df8c2135863606e97d88b8a8a86f8711263bfe952f5bc17ab800b840be012c71086a0820eb470c10f1c3db4821c34bfa71317ef7ecd88230a17d0ac81cd00a7484c1b271d68710116ae1acc600b21ef8867a24205605e40471c7810918535c5991a3861ad200354c0838e3a8ec882125a30a790630c0bc81ce0f734c50e1ec8ef698a2a5e133a49f74d93dc8d6b6657e3439330c8dced9c73103ee79c7bef393a628c51c6183dfa5235146812f662e49632c618294ac618a3f4d9ddb223149c73cbee9c7b8faeacf1695273e6e5f77699d939e79c73bbecd8c2981fbb329a796284fc0086903946d8fde01cce39e71c747f8739e7e07bef3de79c7b0fc2e79c73ef3dc765ee00305f870e77d7d570a049d2a14787fc24c65a6b913ee677bcbedfcbcd0cb1b60379799979a5dcb8cbcd6dd9490a39b2c378924e51b2190671e50c47496cca9fe7344932659612724b29655551524a495194cc82785ac72ad4e079499850438d7508630da9f9e6bbb92164ee6eff77d3761e764512ceb5bb0b88bb9b6384ccaebdeb48b7ec12b743c8ddceb0095338f101b8c250992ff27ba24116ffae6eadb51a20ba7999b98edde5aeae9bb9460a3373736bddecb5bf9d39dbdde5e666a6d9b6d6cdcbccfb84f77a16c275350d70ee3dd79c730d1e816198a458b76ed9beafe6872651dedcf7796bad51925a4dea76d72ddb39ee4c3ad75a6bedda75b773ed5cb7d8dd4e8528c46fc5f410baf4086b7880eebc41081d4a192384efbd07238c10528aa2282a46d8ae23f07d61ee7677cf7abb806493641226d8b99386ceb596020cc39c73d0db9f6f3be71d2f200799b12717c39c6bdd5aeb31babb39e7fdded6e8d024ac49cd6a526baebde75c6bae35d7dddd5c73ed3d08db73ae756bad5f151c4d1226d450e3b918656c527b1e1dfa94cfe3832f93ce3977ee3908df73ee39f75a6bcd3df79ca3d5613166dbe07bae39e7da13a0bbea2094cff7d560a062eba4d505d86ebac40e1deb12bc8060bc92ec634d7a1ea9d5a4f7dcbdd7e28b11c2faf361ef1e7cf03d5add3f08b36d11c2f71c36a18e24f60b77dc8c7105cdea446abaa4fc43ac2e60384b9c4b9799f32a331c25cfa33f8f33a3bc9d68e0e5757e4f33b8e3e353591226d490d54929a3afabc9691256c57d956ffae8f0924d8a6e22edbf6b873ad44f51499858a34bcf179378e64c1226d6e897cefe499828d36b748f6c3bd0f7933041268adfd30cb460bf63a4b8e2c3d891c4ef4906737cbd79e837bf63a418e3a3f705d41750f42e5379e555765559357d1cea979e840937224dc2041b4ddaef0b280913649ab49f840935ba64fa7dbe9230a146d72461228d26ed57f99f840932179318b3244ca8d1a47d588489647fbd6d2b0263df1c2617c15bb0f58ddf7e45f6e643ac2e608df23b20f6be9ab3c376e6299c0ead03e7d042dc704380baf3eb95fe2e55cde66e5a0fa9ed3c97d02bf6442a917f4e6a3d3cb49de75242d237e97b3e6b390747316a51d924e715a5e875a4ffc7ee387f36103172030018deb9b322e5e7a1f500d1769e4b49860ce507827d39ab3fbeddccfbd7a0973edf728f38b35923d892da1bb596d43ea95c527b45ddee111bcc3a228fb877991096972eb33bfe791c02a249cfcd7017a884c6cd3d7cce0df550ff1176216676bc83c754f6445e1cfa975df6c5f209e13abc8036838b83252de74b3a5b40d45e55564d5ff1ab54d2550263e75d52031aeace1c13f73dfdb984ecef4ab2cfd950ff74bfd7cc709654ceced995fef6caab267a766ecd61797677ed5045b61aa0bb4b49fbf62bfdd2eb7be84deb099e1d5e3bb42ae32541879712f7edf05ad25efae46edc4695b72a136a2f2b352b4bd2a5ae779cef0533470411b7832f9847a25b36c09e3b4712f47c88df79cc82da87f8f94dcda5b93a57b01d6385997fee7fd3cdcedb598bb1bb0ba8f97bef416bb1e7f002626fed39c8dc68733595a79da76d939ccbdcbb90f83fe91cd30ba8edb527c78508a157716ee535d8288351419557de3ee1b584ffcd08fd29a91c5610ba75a4ffd1fe8eaf4b8dc5701aacc6efba2969d073e990d617953cd72e252fbe18331ce947fa5fcae8d261352b6b4e5ab1cb1a5d47f8f431abd647276556db291a44732d99987529812e7dafad5c7a76a47f9b34fb7d5ac5d6bad1e1d12109059c480982b570178e82ab602e68fa0705a48a10b3b64b41d09f5555e95da107b996348f71de44792991ecf2b94b099cad1d6f7b23a6f83a626e97bea0e55ba89db9e3d9fb52d2454ed22badc4451f925f65087bf6dd1a38abcea11252758ec53d252878d712f7adb9e9db85c4f4ce65979af3b54347aba5d52e25ae35b791f4bd8eb49799c36cbbe4983c6f3bbccc55fe964953e4a6a3bdca1d00d62ce66fd72debc63f9fb55d72ce1710678cb5bb2bc97e73dff09db116ace9c03d84b93b60cd9f4b37def9ee2f067d2ef67cf205041dbe26356ecd8d768dc02ae4e15b7e0e1ff2f5acb53ec7f78b0c3e047a8e4f7701e5f43581fd91c1275b39947faf1cbaef2e1c9f3e3d7128ffa48bc390f6d05d192ddffc01f1bd806edca26d494284c4dd11b2350871222fc4a9202fc425cd0bf1e8d3e974e9397452978238f4225d0ae2fe51ab0bcfe7ab82b8bc92ec07f1bd808204b974dc07ad33b80fff41eb0f27e213ce68411aa76892f37204561f99a2978447e6adf1d8d011e241bcca6f770c696632af4ecb3b6f2edc5f3a06dd44aba091e823de3d21908867de0432df1cc7e76888c70be879bc8074e0c548603ebc797b0c4ec461f0494383cb0b68069717100d3eab19301a66a061a706dbe921390d3300a0c74e8feed1463bec83f2e17b1df1e17304039118ba2ce144145e2666e1d07d8a9a16911968e5cf7c2e56c4f7021280ef0554c4e7f2721bd110846e938450d7c39281d65c8fcc5be388e8c54c8482735040578bc3be731c1adc799ca24b333800bcca225ee31502f08a05c06be4e29d373ada1c553c4f13980ade5557c4bbdace942cafcd8e77beb5d5f1cea70f0be769709f9eeda37db4110d8ed317927e1d1c217ee857dcbff7bcbdcaaef0c3acfaf0ccf93a92f98eef85241b3204074221412014820361902119ce92cc777c276b5c7469c79d37305a0fc969bc8bbaa4e3ce5b4b73e924bad45dba34c49df712456873a349ce0540db1b4d721e00dae06892f339ad9a0bc90cfe9c089dc171e8fe7c948697d1e07c21c111e2dff12b2e73181c47887f885f71382e44f33838de0e2f26443ccbaef0ef64f5790cfe2e26cd71b22bfc43b2fadc87fbb4474386b36406c7719c2cc8874f9f210b8ac187f889b84f3fba3db8b7f57823e8d077684ba349ce49b4a9d13bce69a06d8d26399f8136369ae41c00b4956952148f7946bb8a21b4a7a0ed250a21b475682f41bb0bed2460a0cd85b61623b0202ec46b33f3ce6bdc69e91e2d60e073e7cd8c2bea52e6ae87b7391a1ded8e2eb93b9fce1a6211a1beae051d19dd2742f95f5ca23a18afbda83b8fd6904b495b44a87b48bfc8e04f86d3d747e61df630ab5cad7f3ea3135d22e20e893f0c1e8357f744fc22925518322b86eb92ee8a10cd43c7a9d1cbbbe8e50a30c4902903479ca3280927a6c8628c34e41a5dea773e65a05ac03c27c27fc0408f4e509f94c5d70e411c66357bead9982db87cb3b06b495ca249ce61566d9ae4fc65d1892639cfe83e76614d72ce5cb01abb1071770141cf683f0eddada15217e27d31217aead18997d57eead8b52488d3ac5ee1cf99f26282bd0b71be9804f11c9f4ef91f6d67ce7c0eed213ec721adf21cfaa4b1883491181cd22a3038f409831371488408112230401fd07a741f3618204e1022b495c01959d6e599102be9af28781c9f4330eb512704067b212142c43de71ca1f99709d1fcf31868fb9b0b09f6426ce688bf10bbb13100a12c48376788b3629839fb0c03e517625930cc68c540f961a0fc39941f1ea9441c1209f1d067eddaf278e85df96370774ee45a12c473b2fac37a48bae81f123ef344b25d233164f5390c9e93c5703109e295ff3519ff2abf107f179205fccb8416f0cf73283fce3e6e37b2d20f24c4a3135de277de2ea0203e84f2c72e5d12e2cee3125d0ae2cea3133e4d0805e23734086d2e4d726e432bbf8dcfca62430899775e6b1e56eaa1efe28064dfc6a1f3f6f834c9f37b01e98b49f3e7d6b5e4b2f8daa1fdf8e10cd892e5ce7d38871bb806e7ce7f16071cd68873e7f506dbb6137db7e7729ff663df07ddef41ab4ba28ac368ed2bde390dad373fa2b5a778e717ad129d5b749754170acf3ee9107ff38a0ac5e63753c0c1f90d9cc3720dcf9defe270e6d9a9acde78e1d9e5cd6f169e3d66015574c9f2f649593de810c7a810ff41f9292a029d0f1ae2d0a7256fe4e4f90173492aaf2bab3cf0fcf4b9d8c8f702da0b683457470acf5f59a3ac4b043a7f6541d3737c424af9a439396ed3a51aefe110ba2f0e411cca1ee7ef87c38cc9b49df6d95ebe6b6aa40c42bf70f12a1fce6bbae5d3a2589320f48bfea035d4a649d07bd01b9ad33b13cbb6493a0f336ac8109f7488ef35736895a2332beb07b3d1a4768cf21a4d6aef41990c0c2a93f9f6bea24b550acf4f1fe2658a2e0919e2ed9d45979692538e7e64d81a69afa1364d6a1742bf38b7e845abcdbb6cdb4edffc80a9f1bd806a1cf32bab377fd18a8dbcba39a74bda2fc06a7b692fadc7797b57d125e8ed17ccaed1e57c0159cf27b5c168957233a90bc826636c4ef73ce49e5d686da8fb2a53e3db6bd2b8997ed12a7fd2ea6f01f18bee8fa810968fd524d480d01b68d5a14636c96a924d478135afd6b7e6738df7df317770793cc43ccfef183c9678eb47d798335e9ef43b260f3ae65b3e7d58cda1cfcaa22ca7b06d3d34cef25a52fd152f243d3cfabefdd7a54bcfa7cf0b68ceec07b5e69555f797573ea2157b78391cc1cbe1c87dda68a8ab8bd6f623df4b497b1b77d3abd1121f04da643695cf20e83540fcf2bd98d86440b2da3f8364b5aabc5e5eafea1a8dacbd90b4af331bf9452bf6262c4441fc6555145ceed32e5a398aa01a27fa496bfbcbaf4b49334d5addcbcba7f4a1fe2b136a5ff9a14f5f1793da5fe3974bf75af99c59e52e2f9d1a6533ab5436d40fb3a1fe4bfa805ee3d3abf4ca5d6c5a8f8f25d06b247f8d0fbf6a668653b9e5f2f2995525974f2697e523672e9cc3f451368178e52e6f790f5af97bf8bc908c7c6641d36bbc1a59f2029249eb92523a7521b92c97d76549ecf41356104208ab1a994d672e3f68e53d30f741697acc0c03b3c6f26a4dab66e496f4e9735a7c04e700b7cc1c6299c1a6d799d52df3d087da8fb2a0cb299fd6e5b0f5b81d46d36566d13ad4fef299e148af1ccea17ecbeb96f92ab3ba800db5b7bc0eb51f392cf375a86986dabb90581e34ca2a771713eb2d2bab564c3fbdcaf808ca471710753df892ee5fb496e02f3fc15f7efde55e2a994fb9b52e7d3a07bad47c4ee7233807fee9d6053433c6b84b97cbe528c3b180731a9780739a6cdbcec84d3f6995d5bde517adfc978f689d7e21995e5dd4f4165d367ed2fd2ae323b88698bd46c4a68a884d1d972cd1dc3b982722c4d0c1df34a9df1a691784edc90c2d1f7f4f629af8268688931829b691b0f17951e9395d92365d8acd7196486f4ee3ad563e7cd7480f97b407f541abf49ae6557a6ceee3593993b2e405045d52cb6dba147d18a99249731f595f4c9ecf9165f33c4aef41790f8a03fdf27dcc7d9ac66b688dde8e519c25cf69fc394d86031d67c9e5945f4e3935f211bda845832695c9afcf6366135b5bc2dc0f60cedb1d4d4e977096489f2e7d3a732fcd884bddbe39e7cdb1109f990fbae9d055115ac0377c58054ee7f0b9222fabedef01fe7cd2584d9b3faaa4bd65ed0bad499df385a4dd496fcee75e4aa45f3e6da8a49537dd7fe39de32cc92a7420ee807e78b7d34c26ce6b7b182defbc993107d00f9714f3a6359ed325cc39ba4f6f195f4c283975bab43e9dd3a5cad99f8ffc519c1f6ee32edda781b8a4384b2807e29403c9707e64474cefc37196d8f8c86d7ce423df8b872cfcc36597003da0db501f3de8b69d1a1ad49c728c56e82da3a14123eca2d127bda149dc59a532e81e29cf75c465f03ad2eebcaf253c3658e16fd9ae91f6ceaab56ba48e9edde488d88435c9466bdc1e0d6a25e73c41cea12b591cf83ae21c1ae106f834695aadc7a6777a3a6e27b03d62fa1b6cd0a1cac6dd46cd67cbb056b246d89bbb0a73fba67d60428a8408ccb09b1c7fe3db75dab1c6e1db2dbee18a1ce6e9a2a984d70837c110c2930c1e429d2edc0ae6c41c8c7b83054e194bfccbb610758210e48b1f3300529d76904445461d300b84d5890c2c08f93d91b1c60c3357a7ae1bdf8a342909cc75b8a124e69b3fa04bed0636beb563a03d4c0b18ce484dca282555d2b317e1e912bf8c272335a9911a8fdc1ed3184648810b2344a1088a2afc34c7b667efd0620c22145991023260fc34bfd99e057c31033258d4a185195efc34f7ed4940911c45b8020c146020e1a7b91b6bcccada18638c31c618a5fb748c9b05456f47a2c7f7de7befbdf79efbb4a0e7ce8ae99fcf4a4a29a594524a29a595054987d0ad985e42aa72cba7555d973319ed5252f9d59792ebbaae8b56ced0ba68d0c82f9f23fafca2cee525bdaf7801451fd1e8176dd3b22cbe9854ce5550e5ecb3a2cf993a26557497557eee9c9dafe74c8364f57c2f6931adbc5dcf2b1a24fb7a337a45a373b68ede5c3c6930b74b55b2d7e6ae35efd6dc65dd5aaf2bb9c6adbd323766666f6627ba478b7422fc476660da69507bf3219617b0f655d2de9ad748b7735f3bb42a90b706d7be5de987192fc9bd7727709712186326d45ce688d804bb6921461c5d6aeb00ccc5b7462c14847047163188d8d2460d10d00417d0186286315ce8720522e4182e64f1d7ef983884780d0c1eea391eb38522b9d239e7e0182d8c6931464a9a8ae470811c65ac78c30a63fcc41b3e8e894308f89ce7c900ca20038f186540d1bc49241d7f1d17c30a9bd84b7a7650e7a9c01d60092bc49c80a0e50c377e5ccf3b27461bef5e146389f79c7361e0f1ae891fe7dc73aed3e3d78c2d4908038eafce039bd8ede961c28e72913fce21a54017fd385f5a897e7194b09787af659508fb7115c24c88a69abe2d1771d13bba6da7ed742b420a8ad24843093313c0d60c24bc7c95d585c1c6b7b724d376b7756badb5d69edbd75a6bad35af1b71934209374845cc38628caf374770419a34d3716b1ec2aedb7539bc6e1dbf11e4d7ae7595d06bf36daf39b7d7563669336e9277ddaeeb75e85e670dbba85d383c44df9f55a685881b7ea273913fd3dbb1d643c599551e29455120be65cd0df0ef5ab253f8967dc1798e654f3f25885e02ca5dc9b5760bfcc4cec155e1f7e78ed3321e287f9904f687cab6edc8b6b3eed3cf596b649d8d8d8f76c367b07af38d8413df9ed33dfc5349df4528d0453f94cf46d71f55d27cb3ca1f332ef287f276b80c597ea1b278d37682f8e620843268a8bf6557da3bf7f1f15a42c3bbec4b09a2bb926bddce9cd975bb6ecf9cf989bb6ed77d89be970516f0135d73aebd6809b9a9f9a57e7b7877d63973e7cc7960eccf35e71aeb7c73cef130119b9e1bb2860a649939f7dacc91706b9b918090f05f40bb48f8a183b0354348f112e6835152724f74701670b417365a17e9714f74701670b41736fac108e9e02ce0682ffde0db131d9c051cfddc890ecea2db9ee8e8ba27c68365954c8d5c6bdad25823eb26c9d41673756a73e37bb7bb4a777c4716d4d80e3becb0c30e3becb0036b1ea51c3977d6b3a0152d2f707416749c980bd781359f4bc99173d9769abf806d75fbd32e5b0fff7463e3bbb9a104d2e7908ae8403d57c9207c6c1f239549e7dcf2e98a47c2bea132795324c618230f892464a60e28a058a24b185e28f1fce09b17813ce001e4017c38064f15214b33675cff9caa320cd21b1b1b4849c8020344810b4f98420842182105073899d1e29f5b2ccc51c9c5a48b2a18c3c51472e0600a58e0e1031bcc6c97076395f188282b78638e2958d1022e4430401c5280557481318b038c17fd06f33356e09ca4f3b035fefdf386f9d3691223f11e035a50441a36c841145438c2cf2bc03f2c0ce19fcb4863cc3c6144e6efc591847fef3d1821b4f12190d9e2f0b9eb54bfa72cdce0afafce23695ec0634159615fb4c0fae8d2a67d946e492933796a3bfbcf27adfc2aaa93820e281103218081630b551c410039c20823471992227d4184128ddd6036376178c15a8fdf784147493a7b9398e43a19894cdbd997d2bd8003db5825185cc0e8a2c4b2c1042fb42c21451c6a74c183853261bca001c975aabfeb90745e16323e92dc49d88debb0a009ce535171c9e86105254609267efc8a49628e31742c3184174d30e2e4050fbc9a3a3cfb74d1822abacf257a679ff2ed1e1f2fa2e89d7decaf242a2fa6f878f2428b8ff0b9eef922b8d176f69d3363056bfcfb35830866a80647174a10d1451144c8df9317648cc1821b59bac8a2a58ba22c3c38e28c8fbf3c408209180770861053982fcb7bef95f907239459ce1822050fcf282ae247bf6748a10820ccd56987d336cd3dd19b17b9a101bdb35e73b0de59af3c3d94571dfe66d3f8ee9d76abd3889ac9351be1d7b90ac6473d41e5748715753cb1852accd4f0852b8ce19e7bcf6a81498a1544b1042f4d14618528065047145cd8808b16b42fa81723175b3ec6181d45c598832f7c8c3152ce27456f9a44c518d70a1f471f3dc6ac4ac9d865968f113eeb370c12a77fbf6192a0e22be6110923468c90400c257891042ba0a1c517466094010f177408a10d23ecf0224711337c40bd970330fe5539c08114ee26a7080d57941c8ea2729c73ce6ffc260b5a6e6eb8b51bf80be128c12578700414a81a5c2970c0181ba881c6174708030a02c8c1113968024638dae28e2db0f01e13a82d4c08f3b0e36194110a11e60c11639c100763bf61f250e371692ea094a0469722ca78c1105f028046992b6cc186cdef690b313f7fc3c4e00534bf691c5184b9cde209efbdf8a2cb82095908e1352fa4169d209cd1061264aca08c1a3b598c89e22901811808c1841258d0c08a364863ae10832cbc4008d338c2cc43eb374c1751c862074664910324e07b2f0b30ffde7bf065e16508436051842c61f228f3eef7944514481688b348028d2226701c8da6877799b010dfb2ca45d7121a7aa5ed36ae617d361b400c0fb81082cb290b22b4c8f07bc2020a581c016b8ea5744e390c75d45405dbd3154e745b1c1cab2089bf21633633bfef5dd5d8340907fa9eb878e39be3c0ec483f74fe2dd2a50d83011fbaa79d360c1e74f06c1a5a5c511e5dbe2e192d56983beef8ba657e9338014693f61f4dc244a3499810d324d7e9120dbf499c38ed92d8a649fb6a9230314793f67d7cc57ec1a0f1eb56977cfcfaea6c16b4668ae6ea14016bbe985bcc39d69acb1aa6050c03317700cc5d701ccb6797cf19ce12f6e7ec2f1baa2e0b0fc81023a68cf4389d73ce39e79c5be79c50fc9705b9dadc8ae988f33625ad324608df73aeb5eecdaa49287e9505412b26e84cab74ca274597d7c0aa4a56d2831c10c5f202a21ccf762991ce590d0a72dea4f3e55cd220e88f2f27adb885aa7c573667d2bcb9926b6de13a2f7cadedb656356f2dcb6952f376ff865943c098d6f5e8d26b8ceb713d2866dba4d70e69e5babe1ea3a375e8fd7a269bb472cbf4dabefeda5de6d8955cdbcea17bbbb3d6edb84d31b95b03b220d0d005e432c96fc5fc80e1b74538f0cf1d8458d6e548d169459ad48874f801e3b0e85c111e770e4ad1e19d6bd993ef7d21bae1070cb3d5da0ddfdc50bb8cbf10e9fc8079debd6fa34e944d8a991c7aff9cfc73b7aede0cbd7f6dba768ef78d768d38ac3df75a66610ca70dcf3e7908d063853042d8dee473f75e9107fdadf7f01a1a7dd6488d3f5a57ccd7e870c328ab3a3ff28a9a5e9d4bcc6553dd347eb9a3d22f9c25f29dcb7719ce92cb9d5fd2e5a5c4f995d5e72ec8b974524ae99c93ef4deab9f79c94cf49f99e93f2bdd168341a8da265494b4a4b4a4b8e7c34b261448b34a9c6493ad362abc6275bd65a394daa7124948f7c52ca929685599665c927e57b4fbef7a47cef4929331b9a349da255879fd67bef3d5293e68befbd77d3a46959cf7aef3debbdf766ce4ff85cfbf92cd73fa1f52c781d71bb469e4f6739e72ce7629396e4d92ce72ce7648c319b5693a65b96f5735a1892fd1bd688b3a26561d67bd67bef49afef59ef49e7de935edfb3de93cebd27bdbe67bd279d9b71d678936a7cbb64f176c95aab06b3a29591b01a6fafe941ab9415f3ce6b726a2a1a1b8a3489721a5a6f78ca67b373eeb5b52ceb3dcb7aefbd6745daae8ddcf52c386325294a567142eb5d6ed4681ae31a6b7459342318d608e5efab73cec167559da79c871091603e7247b1eb9aeebdf75e5f40d650b7656d979e37cbeb7bef59ceede95d96d32487d1aaf36e9b4493f91a71ce44c0f6bdf7de9cefcdf95e8d31c6f99e1bd12a45075e40cf494da2bc49143311b0f5e79c9bdbcd3d1879e528678d508eedb68d313a17bd3ae75c8c317a8c31db97ec9cf318638c31c618638c31c618638c31c618638c31c618637ccfbdf377f368a39ba8c449d9a83341cc39c8109a119a49129000231640303018108b45c38124499a0f14801191a45250204b635112c4280a8320831022c410000c00c0185343449c00ed78fb9a2d8854db1a7d5ab0ab6ef43ef2e84186ec2066fea225ef0081ba52419caa8dd7b794c588fd0ed01338d80c7d8073c8c5b138b6b9521f56cbebb8da8ecb1108e45e91094bd5aaa470500c6d8881010d430e08aa5a78db39a7cee30682885f4d3600af31018f51cd2b5d814687beb70b9ebb5b2c289cb2fbb92e285b4ccab90ea15c5d48104518c094b2c20f19ce1dd0204e9ec193c95a6c40d1bad760f4dd8ed8d3f2dc812ce48f9ef5416662528b6deaac79c6fabdabbbaead5c5d3280604443e9e7c66d18c3cf3639c43a7f29fc8225a76fba766de87eca674222b8f1851e9d88622da398db5e176636e6c6b75655ee3e68e6859359f80e4c51a793ecfce02b85e71ea19217a53abc4c1e93ca8d9f47b43c2d69aa83c7ab409705dc26277528d1e1978819bf9ef612f5bd92637660640aeee08caa88b67595026cc076b86e8d9f71ddeb442b79d426880da338ef3f7a89199b997566f6c9f733e3508222ef6c00fcab618a66ada23d33a744105766deeb8ab0e92eda9491d70d50cf535b7c58ee5650d78db923653381e72d8ab5f1042e7c181b1f65e07e1c44e0d9d5536a0e4739d57ce7eb53a08042f89441571d3b6afb66b189668989a9a53b8ba7952e968728b483dc4289f5c4eefef541c06e7a36327af1729ec9b7a0db95bfe78c44978527b0d387b24a7344cc8f608fd45a26e06b923281a4bf5365758822594b0d14ebbc8a339a12523238ab2351fafac63894bcd9d192c0f3252787b8e6259c8dbe3dd4b8bc1c22f567676ea7dfd733767372d648110875abff3ab6a9362c66389f403559f48cfd9277f61a4890a1daf3c55447da4f8b64d58decea4fb95906e271ffc2a1b42d22beb1ba7879c9a6b6ef2671ec08964a432afc53c1e6fa60f3f5345b49c427ae4f1426029ecb8e82ddba569f17911249eda77988c74e86a28b4dc612151cd583e0dada18aa9d692a2b2f08137aaf23170b4971cf92ce5fb6f3956812efb1882095b5749566d3f1ff953bebd1a446a5b4b1718fe8cdca332396787a384a33f1f62fc59a226d79fe3ca9196d6d0883681aa458b4720e2598b5336726f190c71cd225aa9554c6f28ae8d4082c38ac0552631f4b246e626c740da0a5bb43b31b6734913cf869eccc6ac68664658cb06d5676460284a69c40ca7bf977be3442c3cb514e8b0d883d56b15272e1cc75616793ef8edd69efdc036d4b4b00e30d6b2dc38d242df6ca0e36244955c8dbdbfb26cb0bf25c9f5f220987da291b7a119916b08dddd881d2c1a07ee4db7be3fb4e8ce8607f3fb369e8ed5eb53401c862a090cc5415436586f03d2f3c9394119bce10098f2029f9d4dbaffcb30ba2679cc7d298f9eacf491f80334efede9dcb59aede02ae94ea4464df2421abae4676f502c3725a968f20cb22e1e995df9b5623665e3c814750146126a0f3e6077a0393e187b9a9681dd0333094de60bea8f8e1e042c0181bb34c0c8c5247bee81d50d39152e66258e680ecf56c4d70a7c8d8c8de35cd2ac8a5a4e1546470ec34cb377e49e5b111dbe5f580af8456c92761b2d617e32e61b13596b3c8e46494143461f434cc934bf7507daf9e0af10d3a11c04656cec005bdce7490fea96e125932b5bbc86bfa27264408d7c9a04ec7b91a4c12bac2a7582469e5c61b4b9256c6e363151c8a30c78a3855a1b9754e38de2227cbeb70827d975377b8ae24a824376cd77575cbd4133cacc7cccd7557c1dc0e1f4c805b7714ad9b6de45071f149751475a56f7a86c463736eb62500b6997ac6e8660cc48fd0f3f42a63348d2284676ac17e8e576b3eabc78c1c45361f765eef20c207618230390c39d9dbfa049a3db600873132d552f0fa8834e5f5b1b507afdc891d2d542de4b8981114ab98b08d36d40835565d13c534829a5df8436ab759cf5e717353d51242588e4a55ae6e29e2e2420054b26eb947241e9889f8a8fa1140e84d0688264fb855043fda23adb44fa1d1938dfadc11acdc40018b46c9b5d3727738bd215c1dd8476ee632381d508229771b38875a8dc462b080df022e37bd2f7fb3906e898c166dbd59831f63af791daa02f233bc2d4f4e88e338d099c92becb35ed06630b3e2592e31596fdc1bdeabc436578b850dc9b7e8cb3a2e454e1306d9f2796cc0455799c7d63b121d20fca53d47acae01406da962e6ee12c4c2b0b72450a1b859047835aec6a6f03352505fe79e658d3f938b2e359ffb4d9b35adca8194c6a20e2c34fb7b21db7f91c0c95582cc38228d96c2e45fbeffd4847e52a3f3d321823c4e6345b8aac2c1a6115cc04cab06ebeeca657b162a56f7283e9353af3cc218147d79d8e81751a4bd2a4da2c630f6043b5974a8ca1deeca9430a3c45cf5671d3773f370d80ea99a131c34b01d801a2e4075e850679e1e64565e63a72462e7f4a43c3295bae83dc821eab34c5ceab88d7cc93c268942af3238eff8fce51ff492314fa5835e5dc183de8c35d11f7797e8d4cdef36e47daa69aa3c52a1d5267caf92cddfb7ab59c72295637199f82e607f59fb479cd4160295de168bcbe0f53515314b4f88afcee21c2eaa837f6a7c919bc8e680498361588fa55a017cfa007d02178d853e107a1483a83b176f4310aad34132037619cfe82a932b059149d33999cd2b0338b22f208d99181bc12ae0a903f976b654abcad12e1e4132725da706f9c78e9cc621eefe5f7db155032c6a47f752cd6ad117b3cde346d02e9a102faa6d60915f5f10197026bb27b7f7631d4618f6c05237a3887a30eaad93e9c910301b137aea901a61d5d598a8a64cfc2aa65142ded0f3c27f416b88e3d17841a8002e9bc32af1eca8d48f007fa68bdd441e717179760eacc4ee3a4be3e55728e201b0cb2dbe9538ab0c4b9145303c2bcae7f238d645585cadc3a28d948ed0588d176f347c9d0587bdc5779f741677b027f8f1fb6d64b0a8ad80cbe6b04e343b3a6df10e901e682cae30885233d672fe7c599b08bbf3117784d13f5d2d907e95c039530706a07a0870eccf89a5d28dca951ee4b7c22fdbf4b9db9c736f6c6d2875d022039f473c565ea4c4a54dd5061c87f4b4ab41d3dbcca145c4493d6c6990feb3e092ed7d4703990f84e2654ca95a1a7126ddbf3b6e36b3f7275d359c96b6ef0edadbb220698ae6a872c863811ee2ee040068035ede1b10a340986ac24b27c452b22a25bf4914d6e6f3401357b9f14b79f004900d4c5b146666d5841cb08572f069a2f0a961c7b1067c93d69cd9c98de089063c7d4fadfb261af0d8da6d0e313b210c00a2895ecc94c1e2389d709f8d724ad254355d26e07151d8d1297c6dee0465d2f4b4ce76b48a9c9f481e646ecbbb3f11b78e054123578fdbdb381068ba76c94047c102692b96718217f4872f83d1fbf02044134de7cd9b2a7afa13ace594eecb104f7ce68f91d2da3e6d2b3b7ffffc0fce65d0eef361f6baab90efd7c3a8f5de642e91944a508cba6e681f34a2c984c60b95b4b48a51ca4ced2e91b10300071c79f6635bb2729f983c15af0041ec4d7dca12f2ac37b4be1b9d031ea749bf03b4585c13195daf45e52b5e9b5d7cb476406fe5c7a78271f0b3269ea0fb2bf4603bf6c1f58a3c764b233249fb60a47b3b766a7b8ada6d2aa959a45d9646ad039c235af75fe0e7c0b943e603765b051315af82ca7cb150c6ffc0a70081d217df41f83fd1f215eacd339bc76ca67fc9123b63a0d52fb21308423b25bc799987869fe33d74cf2e11987a345cbffd2d0602bded069741eeb99a88492353c81a9e96d8494653d312cd85f6e8de33ef07104bd4eacac31cdd4b74da3e609dc6f6c351898599c51034e32cedb15660d17027d3b8a28acb53aa968625905ce3b037fe6a43df78291740cf7b7cec106faac57ded46b0d988c6a95bb71397a6219a7a1ce246f650c3096227901b372600fed9c7b9eb2eb120a404c1f2961ebd5baf4f8f3f945c0a51b39d3a6aed8538e0a216b8207e323ad3caacc10344f45082de7e2d73bdf9dd3f513c717e13172d2db49275e2141c3d0859124f39cf255501f6d816f18e05e74f577218b41ad5195af3592e1ddd8779ce5c6fc540532eb8d73c1c6a5459b5c90a4f357b0391443aae221ab70fb0bfd5b330a1e4da18fd8968717d18c0d0dcaf2812a698695c21b250a446ad4619eabb952549baf25006e106434ed0e92bdf9f6f19b8fe7e3cbd8cd8084f6ffd7caa8e783c304b2eb6f70acc562d4c1dec630144fe5a55ebc47c5d1db7635e82a28d9fa45c0a4fe00ece474418861b4ae0df3d345629cf5499ffd28d21be386ae8d94642ac1c6b0d2fc32a840b22d93d53b223d45cf1212e51940b10424ba273b600f2d3bb89a69444af661839f1b385296105b750fc8da288f140f428931b6bd9c24102f5e25c553a728032a9c8416c808ec81e7d89b8bc2febd0bfd65b3c4b4bc6f32d059fa59b611fb3f3f12740a2b614e4fe9bd8f4dde7c12ceb0b90fd9da7965bc0ba701f5c818031e42ad3bd58e1755399293117fa5cccd5f8f2f28c8ea9e09069638f7929837aedc0684c3ea5cc3da48f49563924e501f90471dae30d7c67bb7853c9328d9d578ddf9955ebb9abf1a980c1fb045447b30a63a06fa2affcf1ceea6a7c682f7ad1af03fc8128047485a03ab151fdd1a7086e8b8e0e382934fb6a1e015a57e4f9a2b32033c97eb432574946ce9d3d942052edb73e61aa421969c02e75db2fce1c7ed34ff291aa0144bb79053a9376f98c2a7c269cc0e91cf0995b5f0b87b3270742775596989ba2b6f2ba4910ac66e3a7461bb2607bc402103c6abb0df2d82fe4d8cfe15a8bdd1c71adfd81a4844a80339e66dc217a3cc51b1cb0986984fa20db73afd21b224cf175582e553c694576188fb06eea6f809545a070276f2257f87d697bca6e67b3ec9e1cc294afd10cd9ad65df256282ff12876502bb3f542a896d5b074a9d09e57bdb429b981d7e78e7470c84d056cd2650bb095a431eccd1a9fafdb7696eb6dfe61165841829df2619222332761896de15177a563a70f05a95b6765c72764f647945b022c4ff7d079f326219a29995044950fc87fe9f6c7f94b47da32e247d13b572b2a99578e8b9667520086e0b173467cabc40c41e4fe30553d2bc6b8a4850000f48c23b18109ed0baa6106bd0248bc4cd2e322a6180bfd827a2e667a0e66b0e38a11dc092061646ab75d17fef61108370b05fa376c1923cffc0f60811eb440d256c42e8b6843710c54c1489c6f6ac97b731e795a72857863b0e027ec641512b527c114b1691844953461860326c9c9e28dea8f46b9f363def0a6b6cf0522eec9f27da8416e72d39a71c65d89124eed88caa4a46ca58f9aba05a20c4e2a61db22f469f1731f0537ca3d0c8a157a4904ce466d0185388bbfc43d2dc3cf340a808698f19fbc455c5de54d3c4399e121f0434401cb910e2e2e61baa0681611e81f8c68fc7aceea75976fba87d4a5e29fba4c19ec8d61efed593272cb3907993e920b21b32a305188d4021c7579acf562604428bc6894cb27cffaa3f4ca1325ca24b46bc9a4c74161433445f57816eb6c0b940aa683ddc1eaad4b8382b3cb965f34cf7f3848af8a659cc527e127a0682430711241492a54231d951692a791e8c2731f55f915e612a740424fa6344c802b15cfec869a78a11c4408b94fbf4d06f0caf6154847bdd6194051a26171d5b2076af1301390ca1eac24ebc8ff7543f57d9f1448a20616611f8a9c80515c701fee46c9d8500f54ad67737cfa6cbb09e433338d7a2e3b45e411ab44ba4e2c23aaff3b55d14b8f177be92ba408f9cbf6da68ce2daa6ae36539091159b230b54fe82483e96cb6bb3a757e7d082be05d8d10142cda16c5e61650ca107051e740f1ef407dc25d8d35748ae3deb47b48300d833620ea50faad7890c2004db741677c7ec282cd6be350b4c20e368d0f0b5200cef967927ba9a569ad8d4d53520789cfe45b8340a365c1d0fac705e238d0a3ef41774b1f1c98af5b1bf1ffd9d1f9412f602ee20f04f267c07a60caedc64e0b8af8f4f7f4713df04e377c73076e31d6fc717f9dba593a9056c871150661055a8e26766327fa6d94506c09ee6dfda1b93cac8f6006f9d18a2b925049d7950189a2ec1ee90cd4175e31ed963797a5b55201f0ec49792c2f9e58e36a6d0dcfd1cd7166f0f76fffc5d4551cdb71b2cd7d2c9eb83ab900eb49eb4de34e68c58edebd962753ee653cebedbccb555086c8716580728fb4d5876215de2cd40bbce651e3648e5df5d1ccea8ad868ecb4cbb96fff70e2b0facb7c2fe0d5734ac7cffb3d517d120c9b347877afb5510e7b4bb9ca480feb5481d7895f1354e3d893dd8821d32c87247e4ed06228e2b21d267b7175edb5587b47cc6702f500fc8e81b6f3b1a234f4621ae189007f2fb62871bc22b1f9e4d1ba26e49a1e6c4053d0093cca8ee6a32f8a8b950b2b18044497293ae8a5d1788a90630089f03feeb507782cbb60dfe487092099b611d7d568f40c3b6f49239b90f891a1df5630aac738e34297f32f7e308e84e8601405dc4f6db2d985c74ac62fb68fb76df4f64a05202c3b86ae8422a46b710d23e56be02ad3cdcff6942cbb7c46781141fcc57d404d0b471838bf3e26e0f34fd8294feecf3c12b1c5c68bfa7ddef5ab86a62570b682adde59ca6aaff5537f4b9cfdf6b51d66d7b4d1810e69679d9c9b631be5c34647582e85e0a629202c9fe717966b191a44f6838ee900e4b5708fb1f4e013e9affcbbca193948a7a42d9bafe878d1cc58894db610ec031b2259f31c34caf52f3653c7fd7f11ebd509feb5ef4a9f167346c0009224a9ca496c7cc0d4fbb0e12c59ea5be1984ee5887a08098e4640e81b98d5b9dce3e2d34c9ee77aefb2327d1aaf2a6226d45844f9dc657d168840c022e982bb4264428f7120e3e28130ce793293599450449b8b47b9d2f018b88f611cf09ebf92caeda4147c1c9133ac4fe412a9884621d92990d6db0b5060529fd06d9ff25b0311fae40c96884b07fdece5aa8e9b20a0531b058efafc2407cfd2e838a8a438686b350d2be9f6001667831b013451e5bc11659ba32f8c9be4a61605dada060d7cc8bbf60a27a6561d288813201ee69ed4f70dc5c3cfabca47769bd0423fef3a45c2101a9c072074dde35ac396002d168fe9f0c5c2bb5c238e74f70b07a714956eae2ea413a9c107b265a3aa9d953f024dc83690481dc981ec5707d39d0d81ea38cf8a43485a742acbd59b3bc9e9a41aa100112222dc588cdc197cd11fe487c5b5a441690c63de24827ad04b19862b904ca6c048ebfe97dca61b3719d1852188172d00cd80323656dbc116e75e1dd10bb071de6bfc47db7ac4bc16bfc7e92875402b85a7c7cbe5eb01f9898cb10abee7aa85e10f99d19e1c370418cd6ea034fb5d0863b71286b112b3b4cb319dcc827a4dc70bc0b317a35e46270d7c3291b42101824e164bc498c303605c3045265d0b3f2a5bd5c6d7028fe658cbe323f75bb250f61311534d870bae01174be74924fc17242ef56a4aa98e5acf75fdf2373e38c4a237266b2cf3d93962d44ba81dbb8d218781a8aaaf9cb6c054936375ef175dc9aaafcd6d8099392657ba2374caa41830b7eb344b2e68505c3e6097f0942ad859426e32168a36c0628239fc86c249d89b7e8d561b74f46b8e5d043eaa5ce855c5a45ddc845d062eaf5c065c539358b5ce1b83307e9abc148ab1d34fc0ed09bf4193de1b04492a94abda6f3bd1a29dde59996a0d2333d7aa6aa461def846a4abf37543a11de5b961fbb233f4fbfb213dd4e3efe7879f1c6fcb2aa112f5735dd991e9c0cf117792115efee60cacd91d906e8d9a5ce90d2e5e3a5f22a58a50157e8ff7841de6b511c86f112446ce824dd45a7d05b0086d2515d1f6fe89bd1b6e14b5aef82e58554a47ab148a3319739fb297c123c9760bf615fabdf4ad3cab578c63424f7eb37ac4015e10e735ff69eb4a4007873fb60916f0d17610dfeda7f0698c3fb3282780e3b5da758b453556e256466f9a2609dfef4f8038fbc1b27a24f0dc06fdc2920ac2f68c22a754d8faa789202128444fc5c96489420d4ee37f0899fba18ca53a9b505d3c125152f3c96e4a35c31bc8ffce6d80ff5d8e503b336a4e0f75139e1704f193331e4a03417197af249dbe89ec9b4215f058c77eb18a601d810c5b291ff0bd2e7ea63e7f4ee936887a071297f390d9584fd47b5c2826ad32991ea299067ebc7b2f2e3385b45f82854cea91c3b838068310b41a4bacf88db7abd8cbf95e272b3a9689e2b3e712992ad44d9c055da3aac2be62d7193b2452a5ddc857f7125db888f949ebe5f1d9e7046b9af129589f25bc0f5b336319022c5b50a295e3bcf898ab46dc8218f4d8ffbbc9f58d5e4d0b127b57d365dc7b5aa421d36efb48d713e162c4af93937e1dbb0bd21ea74645fcb3607a7a1de0e100f0ab4dcf621312f277b94a74085d00722d439b7278c94cc27b0c4249f635f05edc7310667385478134b56014e0a2c53d4c1f4e594453595432a4c3359a0f62033f80bde0bee87d49a560cf99c0591953d52ad863d6dbb9b712c15d749890dd009eabeaf005a64e1743f18d576d85661ed6e61275e8e1403b485536fc93db0f4dc137fd16a8a9b797a012f1e5156d5a49cba62ddbfe35b24fd13872b507fded773eeee8342073294ead62893b581efa80186e431683c2c0ae8cd0311360181a7fd31188804b894363a7cad97e8cf07d2d199a9978c2a5446b9a26dfea9df356029a749f69abc0eaf6e299d1bb9bdc6c548e87dbd58a101da4c7708019f51ae8078fc8c22bf541484eb247a69eaa97e11369f888b24a6376939381b94a5f2195520f76243ca1618f53d5c67f6610ea4c331ce77e62d5a7d60cb11977fb6f9b9a2e450f5cee9292da93df008305061051a4897271610f2478f8993586e50a1d22076b6c690ff52b13a1228cbe2712fed34684f25374f46a86d711ccb98cb002ae31946deaf055ab8f28a051e4753deefd70d359b4b1c15867f4508130e3bc4b02129c8ca972f5e3e928672fca6268f1f941aeff29a6a614b15e7cb48b74a1c91178134cac7376819a42c348812d1b02a7d7afaa55df196a700d64dfd69899a2f5eebffe2c7bbb85803088bd31d6a7e204798450b8387b90d20ad3f336793ca4512871453e32f8962a27c7815048bc915c6a33b59a1f2d2ec94289bd14e45362ee9fa7050cc57bcf044eb5f5b1170d12fddcea486849e25a69e675cce489478d8951b567ff80a89207c3a84a010a93027c686b0002ed5e8650179e009b95d737feb5b452e99f0a17a13920ab431864e50feefa07280d015c1ac68a48fc490a4bdedd78aa54d4680c8c9eaf6499684d0497108a8bfc97cf503cc7b08d08fa1022a00b4bad24ff7aa6f90c9d0428b30b30f335f9282cae7a0a018828de1be1ff5a77990fa9d76fdfafa6c27cbc27ca048c36690f62719e50154a2c741366fbebdbd7cf2d2365f9ef273d295c21b58a8cf2592eeea5a046c090300970384c0f770b17fe11ad50f1f64313f4ac05ff1b1a011e4a18134ff11320b3942d63597794474358060b88b0501882806c5628ba6a9ccdf02535f5b364f5a39372d48cc56fb8e593330cc38c42e31c5201f7b98bca68772b76c72f5ac20870f7db7769b0666526885e46f67e4f1a9339b11e37c7964e634f0c92663401acc9da2c8285e0da8dd4464a9d98857bfdd118574eca4caf79df1537415d42ccc8428835e3c42b3797b27fb1bb729a5ed2fc3e5d95d89481ad6a8fc753a27e7c7338663c31133dcd8577157eef48040aa6dbd91cdae1d98c37ff018714e598dd936f8dcf43acf9a59114cb44981f461c4b688047a19e810de0d3d55ff2409640e231530f2c2c069aaa626d8b286d8fd4e75ad270a13b80f074d6c3f0e57b3654377789a7de600058e42681f79983e72cd3af4924242a4d63448fb51eeec962375e4d79eb4f443929415c68542ebbe7e13d466bf856b4c442fa8161fa118d7f1d98019f7a994693e58c54f85d21aa3ad11d9e05b9e6b0615a3e9d294901119d45bdda114f615baa7a7f1552e32003a5730e7831ad5dfaa665d2bf25a942214801afb91f7397f5503e80e65871abac011dc3aad7caa545ca9ff7b657663ddc912fda419d62f0dc220a5057ce4b4f354d5310baaa74f69bd4d6ce8c39e5945ca261bcfb6063303f41a8b9e90949b6b32d07cff7e2648270821e343e4e929d5487687f5a1428b801e45a6ba665a396bc1a4ccb1eba0f142f866f1aa4fed86da9a669332c7e2e4aa4b2760a5e9e25439026eb07fe7e03431ac0ae7d93324d0d7589723833c6fb01c9d618bd0fb349110ca130a08c16c313c526904ac974011360e804e42c7a87a9a08b47601ca22d085aac8dec1196cc84e495462a7fed167e11c1bd0614f97c169c0ca4d44efa7b56a534d5fe4fc9164b227c36a2cd022169989a2b7679c0d642da71cf989ba75b5de869e82f0d6031babd0181bb21e0883a17f96b3d02c5f55d9f34b960cf6d74dae27630fc82280e8b06247cfce19ef7b0c00a9e5a0a663a097cb31e257cce4c0bc3bed66538f8db19a92aa80e03099bc97cfa9cc99cddd7b5dfaa329a5ded2d7a2920a5c162c8c69c8f5fba93c4b04766ef610e336685778462252670bf48f00fa9288101911001ebee252abac0d4bb937755a4701c01959b2d066513e1c630873eb1d883c875c0b74ce99bad8d39cc18da1b3dc8109240fc2df9aff45b3bf6ddefbe67b69f637cd7eb759afcdeeadd92f34ff65f3bd97e699e32db8c2a91ad6d9194410e88b72ad9a112394e3d1b41dfbd55ed1ceb153da524a9509efd2049ef7e871ad22d9d87c77c960837357812fed71e78c31dc4870353fb2b6372b7ea21658269c4d9c47c7741c1983835bc43c2e2cd9b319824b29ee621e3df66259a05354185e27fb13eb56302ccf56b495a8f971af143b8102d3984c18486308e308b6bce251d2b1cf9c036da630fe1cf887638cb871cdb2dddb8ad0ab0566cbee6dfa5193af1bfa10285d34d2d71b43eb10bf802d1b433e4b4425877f0ba11a06074d4c827f3f1d7cba510a818a697013793ec8760e54dd4ce9aa38a53da57cd18ec81ba93ff389d57af0f11d1f1b717d0ff04fb444c955cf525b6809a276402c7db15ea402e8f0585bfa0d1cb44884f7479afd0566db02b4a5c0ed315f72aacc1fa0f972c555d093cde94f08261bf6bd5acd7ceb7cb40d610c55fb813ad309f90b48730c511134b1f16ec15e0145357649cea4e1559d4f35abc3c1dfb0f45f72291488aba4d25342bf5dd842a85e6d4f05d6d20b22c3596bc87ddd95b69d85a43c00dbda903a296497f9be6a8df78ddda52db43ca74211024757d9d22099f2cceb3de52cdb1a04b9b12ab71c669963e335e6b024680082c321e81820870f4c395e687da03ca4a4efce30236656379d7fe3f81e356c8014cff439bb8bc76f8f5e57ee6274a5178d7ddc9bf0e9de409fce4d7d70ddc4a72b37fc8830fa914990818b7139bf2ccc2e94263f1d827d7a81562600e70a6c53a00b431b27c3148e5059055d74719f43bc85f08d35e2194782c9337de564d631d567ac93ebc6cd2aa8c770a00aedcf41fa1137020dab0a9bb2abe86457d900da58d621a33a05037f963868ddd6f422fa0ee879ff12e2c684f9137c15cc5f8d0dba05fcf45cdd030843182372904ce8f121d0af22ef626e4b6acb60faf02ed40ebddb9c72e7f3bd7531735b85a1824dc5e0b82a7bd8df47030b2b5950ec512d18b60ed017f20daccc4349101f2058859e94b227a9416f9c8aabfd10c6fbb2acafceb5ef13085c2e1f8a860d144a00f97e37038e456503a0b5457d4001ace46184db7cc778c8932c2c54268c029ede2d148d6ce5ad68d3de3829538a5b01dd0c0d25233bd8ec27dfec8f18bb3b5637b4e3e6e97b8f81fc971ed8e4b0c416c865bfb3b2c755283185531f836b59aa0e06d61d75e1a4c9428aa0494b6eddfc409c63e2501448759297f345cf5052b62773a738c73b82de0fe8454ec484191de30f358d7a21d0ef3cd62de0a83429f078b19f8af3809be5a9ccd5c3d65c1d597f47a6b5588f4aaa5fd42d98c695f840e81176205e31abe10e5b34e2c3278d6d6c9849a1f17d9cef1c145b08da667f19cbd1e9e65ec358b2efaeff92aa0dd833db884b2f98d1e1d9c5cfb63dc3487023aeff8e9e020c1cc6fdf846c9eda4ffb7114d08ae2b1ec800eb3a8d9def449b454334cc703dfae9abed506b5c1c18f7b81fe3ed501655f2e8456c97c4385aa997397ba04a917f820c843fbebc04f7f576b391052e83052fe630050715f63fc67afb856eec659da4b0efeb155a7f362cdfe47f7aa0aab5fa60093acd369532506c63eef9f39aa83fded5a291f8d27dd84a051d39dc54e8d7509a7e1f586e8a38f75a86a927319647bd6a94f5abad95740c6c9d1ee58c44da86c726b76941607ff150a3aae904dae0d66f35c175026660f7683f7758776609d5e02f6e88e33ee636333ae12d28050f48a931678c9ed72fa36981d8bb2d02519e8480f17dd68f0ab01801ef88ad96c8c55651bfc9c4fecc4eba16261d115b1769f0055c87b7e91ed2b57dd16fa6e2167d92ef643e3e17f6b681d68b2bf0e80dd8e449c5e50696bc6d0601466bc9de2f9285e35edcf58d77a061a3661d6ddeb3f8f058b609fd1b3547f42b6c91fc777b4afcaee7f598b49fa6e5ab759d307d98cfdab6559998f7826d5a213b5b1038f15bd68bad5d95db4b5261b1c8ed137d64ee22442ea065bad02335d045239c3dd1487e0c9385272885fb7adfd0b21f68877171cc5aa459d16adf6db2f4a648235b192fe5d544da852293e93a138109a917df9ad2e52e7771ab436b6c59f29448541c530be8e2c2077becdd632267e8923de3815627fd71f757dd0356fdbf0a82c8a49eceaf88ebf5db00ee524cbd0ef95eb869dcd1a86c96428663d75ccd8974d95271ef104277592632a628f383917ca4c0b1c1868e7f70a35acb518a31a251b1e21c5fc654233d197e55338665ad1c679be1a6c2b991b6f15cbd546d6788b90b0c795852ba92d8e0525d15fcb10391d896e71aade21c195cfc4b4bbb2514ac323efe07b922c87b279da3484c8dba4eb4e2dd7709c73294bf78807a75afe6201cd742d2d985523af063f855e7276d92a2655155041567b2e8cbdca38cd6edda6ac87346135b7b34f3544475e7cea7babe18c3c9d9942aa0ce8605efa9891b73e3a9e22e817851479f3fc6a0d3d52d52a70f0e86e96ec7eeef64cda33c14a11792927011e8ba143fb1d6b665ea08beb65aeb7e328e65d66b3c8e6bcf16f59fc959de882f486ef105fd377a5aa4caab059a52c31f6e4b59f40c962f120046978cf3b7e26e078a2cbf20d340154e4d63a3c44bc96ebc2c9417c61c3449d691910a984003cf8890af02403935f0915264b2fb3350b3c43c61f741b8094b0b23f21c7dc65c531d434d9b79e43509fb56fa73d5c2321783a0e0233eeca33ef3799ff3998f4b1fa50b0383c1fb9caffd62aee2efb1eece7cfd2154e2b675f6adbaf6be4917c85620177679c246bcba34da0e4d59437d0496089d9c3f16b6114c6e54d884ea3a20647e711052e38226d4d7812354397352d6f41b98bfc7dca84003d5f5c10e55ce949c35bd6f0ccae68e089c50f9f1f32dbc4932735a263a3b89fc99247f44a0898aadc9309421088c71327b1a1f8dd9a334f4052ce85d6a69c3139f352ebf78e259337563aae49553fddd04180c75aa7ff3565b5a19d90752c2818fb6916bb501b506d87a0a26b75ddfe16c51d2e69055277cd9f885bff1d4aa5bc7b7d50d39df949986a7f74fb19159ee69aa40b1242e8aa174c38a5c68ec5c2b33964b3d57ba646ae2835342fd523d12817a18e0356a46572fa3710276dd30e4d8dd8b216bfb3ae407cd40a78f5e5c9edbe35f0875eb3c9239e72a09fcf5489247f2e2e841508ff50058146c6ed564904b533ad13e5f34458d35c409d03df19b622de105875be042c4c2625dc8c7e7c10482de352e3aed1c4dc9fc08225d7193f707da2019e8b8c13cd23119bb46afbfc8897fee750bfc961fe8c69ff171af14eee424e7abc58baeddb577c3a952c07a09273719e637094b4b1cf92f7914a240b11a1406dd424436a576112bbfdbc280f7e527c5afa72827b110694d477d501816f86d3340e5d247d08708c527d205e937aea18656d8831ff7eb5654b9ed91836c5b7ace11d4d3f9ac560c7ba68a12a1239b718dde00d5cad4df16aa5439f370b49529510f0de300377a12b052e909fde74fa0aed1ab257415743bb644316c5cd052c26cc2068318beb9066d427cd90e88326e2555092d5e928496b9a21e316350de8444be697f0e099de2a0e339988e92499b0ad303f750e892066d0974441e125cd8a464d09dd16dd5e675c637f30809343471aaec73cac11a17089080e814dcad1b33c2b26a4a580031b8b6fd7595730a3b0831f12073db85cd63d6bce791eecc37580215399c650d5194686666aa1b8433f3c618fcc76460db015813ed7a9739ae961fd6e6c41f7ab8818a42b3db14766b4c01353e65e3d8b4d41cf321da2c8384a154635ee8f369525435c1d1694cacaf5be909bdf985c80f2807f5e289d24089c67bfadd82c3f4ff33d9b12c1671f6ce59e3f49b2fde9bdd42dfa41b237308571fcd747961127d275441f4125e0a9653ba0eb919533ccd59cb6826625af9383866e87b8a0b68637399b47658e5eff18d0b4932fe6a3701e9646198674a550410020127739fc8782e8d0c3151871cde988c0a54d3be75db3cb11651c0e6a205bea52a97c433c16d0e8079977c79daca6257e3928600541af72c0e17e881860f6d5d79e9a172a61d1781d15f6c3c38d5d1a747d0e1edf33280692b99a3e555ac0245b6c4fffc61edaef938291f7c7eea3e3c174aee894e137c19f0a5d310a1f438bb26f13cc3cba20486116b1dc927cb7686270b09aba877166d80f7806aa547900c941256d901d35ddb4d8ae2d01a138c4f9a0095490ff43fdcd09bde6a164c6517d2205d99b72e39b77b9ccef94c2cc1dff98a5ae22af304bdff7cb1eac70bd2dca1ea751b34fa90c6383d99993155384e59f63e9f1e5399be9d0af24196702212f552987c72173fa04dcb27c82912879a265b6c8ae37adb274564c23ab1cc4ded9af082157f503ae3529934f2af7b95f7dfb071576fd07ea84925bcc740e06548bc71d6a3cb8c5a95a9b41cca9d8873d119814c73e7d20c8e12da654375d275645dbd80f08f33ebff4f49fe2eebb1ae98c3ba576b12c121d6950864db467ee968940d40dac19168957662609241c65f478ef9b98cf11619f791a474edd3c6f6b116df0def512164324da12fa3a9c1caaff2f40c54d10a94796054a7c2bceaa3c47b302c9a0b1ea9e69fc9e837024408050609f51985fd3952594cf65ca4c28295c0830c28242ee555140800757581b0ea5626d6311db66ecc1de1ad7f2abc6861c10f20ff12c345238e5dbe56d22198792f9cfb36a1b5a8baa66a60d414f680dd04215f065a2958d4d8bd475f6e70cd9060b38968a46899e5b086121e9c2a7da5f51b04a0a24687f9e0ee8dacd9d399eb2f051267f924adeea8100d3dc820ad055b194854c2ac986a69b3c8e62af4ed1b21378f6c6a1100e3f417d5aa987fdb3900cb4310ef7a085014d4522749b12c6b800190f56e4c31132fce475463dc39c47955d496b95eb43d549315a3258952d243b9d13cbb7082e5faaba57af4e4d9fafdfc745639f4246853fd39281a3b069ae6983c39a31e2d330d75b3ff6ae067c55077b16e2500c081abb01bffddb4c8370dc00b22d9b84915221e40d7849fa70c947a8dac446a09c9a4a03bb0a09bc89397d6e03bd9b35634ed090edfb36b30de5f0481d6048d1ef6abb4c26d4e10bc3d9f3e7492a893b11d49cb9031d04a87e296919264c3f8ec6bbecd4efad8d338bf318b4bca321f754a11e387183955f722e93fe8392d436af9a015e5e6e44676a6c8071fcbf9dc3368271538e684fbd18a5b528759405dad4b300eb4685ecc1d9eeaa2d1630e95e3ef53fe374e1326fe294a1c9ee75813772314793c6319ffa7c43020804e6996e03d5136adfc764bf882494310c48cadd757ad412d1ab64d54445ff98d021a73a5bfea4efc26de09664765ec394a2a97bb94b47376da50527a270a62cf307b1e62083b645a6dd55f829c1463400896fba64cadfadf4bb7c172a9c752d62476962b7b762d2765c740111997263c5a40f3acc08d613c9a0de01cb54cf51593b6cec22cc3b788d39f27c96ec974647cc8b559ed09aae59702c6c83203914e47fed70860d3002ec7e03680080aee2e1457f759fb2311d5ae96a66501efd8211fe199277e415e04b70bab1927d31631259d9ade75c48f0c4203e60efedf8135d958baa87df46da77e6532cda8b3bcd3c9b5ca102228775d14a0fdc88231a877fd5cf0689b7091089db80e10ed138b52758bf8d416d0d9f1748f7d1fb59592e193a8289ed5c2800003bc22ae3cea6a39425c6d7da03f468734ae6d14aa7480204d01de93837c99053901e3c9456683da3657b29a442bbe56ce4b91d58af6d1192aca4a67900b610ecf2e51839e409baaa80a4db40c48d22dcf5864bec2e8700b0b12669b93bfd69d01d6b3d41f58f0beb6bbd4158ab50d7497c70cb1d767745dca3a0437acf93ca5a9739a618addc4f51d73ce13b1de3a74aad5b0d0ba0d0c80cdcd6db48ef30205665cd1ef1d125f285261a8ed7c2749e4dcd00499d0313ee447f360c02d87ac538ef122ebeebd6e6b3360ecac37881dfe0bb9427d2b1cdfdefade4708a803489a37ea93fb670ae18ea1a44a5032718f1fd7afa737cc581ff57adfeefe568247c1832f8d826013506c865718f4af7c41dcd523da6e3c79d5fc3ff5c7d76241389a0649bf1655eed6a0b523425fb82da8e68592e42988b8fbb5ffa203ff5848f6deea367fd8cf8a23e7d262d43de6a2b25f645731d7d8b1b2851700b53853ce88b6fac2bbab9de6ac4b09478a84dd113aaf7d0862bed21f338cb9f076740fd0af9b40e14d96b583e3a2d3ae044280416f8fbb1759eafa39290acc6360d8d60eca3c0ca92bc858aa8f7adae866ce6ff063aec5fbe702dbedca1c1ff276d6943f502d5213610a727cdad5780983b5f05df515a521e9686bf6752027d67d76bdf1c4f7c3e2a0406d710c91c360310137b925176caa8e4e00fae985141693b0c6ac2fa44368701cdda6f0b636bf7035f06c0d8cb9072f3b8744ebb5c3d171920e57343b12df218b26921afadc685ac0c93a70af9af3fd88aae3b1cece07e874ebb2621b47ef96945f255b8e8f6093c4b16187c1e743eb8e32eb8577570cf6cc2e8757c38e7b4f22d8f3ca75500b03c11fa1ff56726d05b32dac32f49ad4c2745c2ffa0897659432a68d4ecf86dfdb3f0305c06c50bb4352330e88aed241587e786b940effa8c114af047aed0f634c47e153163184991657cd6a6c3a80204cff2397c16055a29ec1e6320ac8fe7f01ccb244aae5d8a5cff28d309ffdabc115ea16093fee341befae1d3a64b08b966f5699d03fe5fe37cd0e293112b5fc9cde97b3a30735f49519fb395244d347ed818da27f9243d2abe9474805a7484003c0b9d70d4312665a0a816812f1b6a0c4c4e3928127637f0d3db61bc53071cc8848653fcbc53fa150f943790ea244ac4267fc163a7f6ee778ebb0d8a80dbe86f6486a75b239177216efcd5e1220ced4205918c5b9c924a73645b2828c50c03be0defb616d60587560dbba962fcb05610bcae06b64da5541c888411cce84ade98b687729b9c8690d341a14949640bff9cf367e0b600350fa3a06aa9357862be1fbbaf7fb304c7116d58b9e1fefb9214f63e7736b276fcbab6631f0045fc6d0fb6060a4e82ac5e549fbc2b31a0cde5d40344f52a2ea472be40563aabf2296ddb384411354ba92433aaa704e1c0c041204010c522e095199400b0b2d7f9292b50ceb6eb277d6e701a645848306f7819c1f10c17e581dda6e85f461c9ef9f5792cc011cfc1528172dc0626280086aa798c0bbd9a35b07141155f0b98f424d7e1e0a95d8a355e3cae95e56575f93f28e691d2269b20fe09c7baee3ee7c8a7bec372861846e1d98c6b174299a02178a4578823a0cee91e123bb8ba4fe9b5bd1564224d79f54781e0b8d4f3f2ee396a1d3088882dba29ee299e1d21c40203bec3e6c5801e3bd47b3c6a7264bc025bac52c71e214aab9ae73e843d6ab6304d6a44825e2ca311baac6a2ea354aed28565a63cd2a4b6fe59e07122bab21ce653e16c4b27846332b6f775ac2fc424d77b58d9fd4a6446383dc71d8e09d9ba56667c1e4f9532ea240908e1ccd94f40d7a51fceb2d18fe8461988da30696568d21328eed225e3a49c153563e3c8d9437aac8182ecaed138507ade4c6cf7790997ec4691f095504f95294145960096ac30d379686bb4f25e38ae120abf4ca2a7e4acab2eb1374c4d66baf747d52726a18ef1d99d5d20940f459ac328ab2c0c533700af7005b8817d97109e2b944839f4a810cf06c0fa30f94d7b3927eeff42c347b73335b5a19ee4ece453131c1a36532dabe941140375829e3d1c59df2e034e37b84cb683d6889ad724250388af2ab76c384bba480b409b17d68095c4b2d934d4a2a091b8864ce890a797778bde0f7adb34c2ba957b2ba21b42e7dcebe62b2ccbb837dd262b5942aa43806b524ee342c50a5334e5d329bab8120b8be23259a42ecc5bba5556bfa9293ff7f3e90b4a63d297b970eaf55747e84883d01731a5981d5d7e5d55644ec11b3d2151a37c7f24c8e57f9aa308c1e608628e837e13bbef3f4b7978e945b40f69594765a7537e69f63c09d4b854c6291a6c505b01093fb7136695e97585cbb3576771b2b84395346a6ac2ea117b5f0404e5bd0cc8ee7e479d2b1887dec18e1837e29953a118759c460566526b7ef88a1499e5a541792724ebf863574c2bd8c66ce6a526b8f03dd803a6d268cba2cc9c0765f60551518a35b60780c0265a1395aa6af41d37e7addfc4d03894682ab08e1de4c5d1ce3d02f02cf21a08790e001000c1aecda604059346e4214283fc54958bf822464e2db208459c974f53c102a36a0d5d6c18e345e0dd201491e944419350327a11f1d852758ab16c4672191a9df9c65992e2868497c077af24ce411026f4dba1efa92d8dbb36155074f272b314e905616026ff83f4265daf57174b93974fb327b03e65c79ae4ec12df546360bec01c1a255819d5b88bdab48ca067e4a812ac9c4a21f00eb23fdb5d4d1d3c239ea6fcaac8416eea78dd5ce5ab22df4da91ceab0d075982c29339ed1cfef4cacf6cc95d832bef565c6e41ba82c944e11f12ef402526a5976ce83302770131c55cb0156fcb97647d30252ad0dd8a9537669145a03a1eedfda17dd5876142ff7b2854d405feeb7f172f83ded09edb8d4e0720a0ee47229f70f9f923e4c85610d26686c73adb9f509361a67d616fd9dd103e7ca7e200ce4e103cad51372150a73335b7623448f33a6981f858eb000d386836917a356b5a2613a30745070e318c808580149194ec37eebc6ebea2fd492071a3b8a2236ff604351f750e0d64d75a50bf2c05738c1fcad2fb8720b29e138aa38047dc0f0133e7c795be76697825bc0ed33a3bb28b1e87f7c85918423e182b63e4a8312af160b559cadd76631fd08587429ddae5dacd5995ccfcfefdb3fb3e7d8782f793a21e37319c10930b8fb4d951215c33b5abcbfdd94b55524b7cb1483266f47a4adeb274adf13415791db282512429a60245c2fdf27c40a0c28f2df911b54f917b6a8d473b9bcfaee978cecfd9c6fbc09b8aa517d525ab1d9f6a35b9bf946fe909db051dbaa6029f8178e052bee3e699a570a248282e650f3a4531623bb71cc036e94e0056fcf96c34b0d7715b2466b43434c274a03d2b97107123e8fdb38835572c4cd390f26072fb6984be8f7ff8368d98c81e4052deb6d07a3fa14a3835589b7495184e4e6adf10a43c8d9f964cfbf967f71e1986548cc85ea1a9f300c87077ae7cea4929df51c9db187b6e8ca7f14a999a6c8004773fadc4b0c0e0e6705888ed0cccd8b977404e61977d060aeb8ce8014e810b9aacd234a36b10febf195308dc0bd2285bf2a4370a373d0b6d65864c4946d1e0c15022fdf7572a5429b840f2fe0a9f60e63acbee6a83707ec50857e182d0e77835729efc42b1aeeae8b4b7c48cce2d4fdec1a210f817b42e7d2063f6077a5f82a01e908cd70129c7deaebacff261da55ce1be2c475830ff1cb5ed68301ff4e80e4066621c3fd406f83fa43d4353a044a727ea7c90d7bc00b05d626fcb912a49f3150822b1958916a2a157bedf3c4a8c59160c48bbdb1db1acfd784732e901cd72e07e4b3eaa287f73a05be3bf359e8a2cd3db803a0ca297b337e42ae900c80080785e6045a689bd0ef38f9ba7cfc1e10eb54f966dad615efb7394b98e1061a26b6320185e030a4f373848c51ccfd359285eac2e12f9ae08549e0bee8c9075b939a5ebf0d70d59d27a049329c4172847789b6f7b6c625ca00161a32b6a178cc0e914a1c4d8c22df384e9d157c563734e6470b879e1aef75194e115d841bed04359826d977daf70db14cec4c7a45ca9da57349b3a1764d1c29630b231777f3c7c7ff147725be365ac6c0fc1792c298c09020c59086e748eeb6430e35025b193c2193fabf16f7d3cbae3fbf62040c0957d134dbe6607ae1d43d0653283ac8516285ec6d8612cd217a28b48d27bee104c1c5262c163a6f2d34410a9fa6c25a1c2c28571e5132b455b5088f322541583ead35503dd26242fff300fb0bb844438d5da8d0056e4601aa13e8f3f205270f5b80c20a76678ba12ba39d8995f8f833852441cdf5efee7ae485498513c61629e9b38381143812963843242e98f242c1da484d0c6cc655dd450f53d77223e67fa46d2802eb075e2bacf16893cdd993fed5972cf2c4d4ebfb04b7091b0f716fadb5e434894f3984efe4002aa6d38ca1e5f3302bd398c649a9ee1deeaa43261524fe9084a1385d6ad1fb901116572aae144ce83ebfdbfe18f36845f48d58743711c503bd1be33e67822338324f8b5ed4bdb0a5ee225724fa8bc748d8428efdfade6d6a8475fb46e06df5b931a42b05f8f30424dc03b62cfdebf3ab3074891a0e4506b9a40066fa681f03745c07b170bb07fc835e90bdc144f0f6f4281d48cd1e59cfb62ea7ee6835868c34b2afb4992cc41ca86100f1050971269483152c5e486984c7f9e7833b7f95a2e3ece3aa5fe5ca284a5270075f2cc0c55bf86c034b42dc011c725682710b74734736188b0084a731ee7cf3dece0d819710dac09cf3dac2f808a19b147cad2d2498ccd068124a9cd2ef58ac23759c68736256bcfe6190afc978f508a7c0a691c4e9a944b576ad5f0400720508f497538c5bb945467a882b0e3199fc311a7420a409554951b9805e7d63826a6f899ad8797b1d46ae59df10dda61a7c08e067ffc7b1c00db7f44a5cae356789e997dd77dc99eee48df2f7714691508b4281957a436989420b731ad609c8a9fb21bfc600dc311a618bde38c96c3f6c80d279a2bc83222ba66626c978517f42dd580a31fa19748a63135596a01ab5fd63a956929a43c4db182e266cec412168858bdb0b4f0470119773c357c16b003a04b9918240f00c13dfc5640066920c3740dc7e8ffe0980ea4661ca80abe10171be02d9b4d74aba785d4bbdb9355f18c8477084be84440390fb5cb8d3d1cbef3154c1a394f49731bf3b3a69334628703e0cf3b5d36f773f15d84abdefeb67f3be12c713489eee3d94f3007d5ba7e55913d96f767d0cfa56748e9b75c987a593bc6b39e611c79cb6fc958568aa2d01908f236eb0043db1fb663ce5484af119fd596ada0bad69a68f65b72a5c21190b288db9b684abf1cfc13ecda5c08174474fbe4be1db86eeaefe3422767cf470c39d6d0a75074f51da20c45ae08257b9c5dab08e08177604c21e37465a54fe37dbf7108b5ddd6a83b02fddbcda1955b04b6ccfb230b4c1cb1a462091b3ce483d6a260d5615405e887866a846824e7e00357c4161738546390051475f710941543b033c03516bbf70252de2d99947f3132ff59804a8dc00d4785028f1987e40f6b60492f089b503016778eade38a1880aa3a55bcb54273e0e242fb83c52b7cc9d888ffdf180b525db01bbc8b01f382c5ccc9e6c3e465014b08f69b112b8d32fea6f89c5395ccdf51228d78911323b2f2010500be199dea51bb882c8a139d941875453f6095799f9e9a34e98d10f54eda7daa90b46b835eddfc0d0eac4088bc75cd3f2a6cead1551fc5198873ccc8d8e170d4b1f592f175f0f6f95e5c0dcf827f0d478bf2deeb8da1e31b39229cbdbfc113402e83346394c6483ecfcd0b7b968665d691efcbffa6d5c678a40c5c0e8576dd71613282c6e74284c2785b16ddb76323913b663ec2e9e78979b6dad38006e2bf8f2c693fa159a10251213d8b4409da36fe7b6693f9c6bef0179f4271ec1e65edf630e0b8661d6a51592750625e5858842cf263ca4c0db5e5e9e6707bd715e6074c3965cb317b56357e4c3a0656575c888eb78b95c244d09102d56482e922f21c50d57f456b6479624314fb464fa272da9a5f6a42edc4ff601ee2540e1b4fe07595dd1eb064150a799c2148341f0c52c60a4362e135e08b1f1e809561cec75a18e8dc57b43e80df959da7eaef062f05f2590da821787eb96c6bb041290c3297b07dacf4452ef38b798d3eef1c026d2513c1c574f5944730f4a4f980c22f50e8f9beadd277ca3d811246d14c3183621e9b6c98382725c80cc7f63f4439b5c7ddddcc641749f6713afcdc25892fe1c5daeac0a29b688ce7b8b50a818097c16caf357acd4575ef159cf0a25f28cc99acbe7b278870a35ab61dea9b2d5b88af622153c9f85d737f1d7cde8b5c9b62347ad8b75f379a1fefc4df5f8d6d4fc9dc4fd2074b9b12c4d626542abdf39aa100cf3c45379fc5edba4a763bfe6bf9615ddabb5d10216edf383b4a6426e769fe87364e3c26e9c19148e1ac6468b02a8963ed384623dd653abcdb2e683f9c95951d36f3608fcdf9d32cb7c84b74959380b6f56b647439de5034e64417763c2cbcc07dafe42675996db217585a835ac3f0b0b4a9014b7e0af2efd223063c1bd144e0362ebe976c94a35ed575664d2399ba2122c33f0f062962e2f4f2a47197ea3d9dead4568496970b2207b0e7da3921fded8af3e27270f85511e1eac864f9e7265a38532e893ef470dc4aa82854cbd75b8550b0f8764cc097d7415fb8ff885c494594c913eea9bac5e2d0dbbf2f90f4a6331ec0ddac9809a63f9d529f37d7f64b16ac5fa9f1ab0110b7fd7d8fcb8f6e63d5f63adb7db5d3acb7488a58e964fd032fb7884d53584fa34aadf19651ee47b1190886bbd8cb06c33584adfac195ae0073419cdbb6efb14d90fb0c180af715ebca8ddd5cd7ee885ebbd4efaf9eb5d5711e7d021ea7833c185191b7edf99cd7ee190645cbbfa191d0da565d73c1ca6a0c55f0387c263536822c665f4a3457ce2b078a8aed02324746ecaa177202641c07bd9bbf2380f1419423c58790a75c4e26fc3f658bd3f1cd247a42e2e8b04e2e0fa3420bb656f8450f90c0842154ab4c0bddf7a9229c82bc015191719701ecab3c8227c4c78039c411d6e32ff3bcca6413c0d5600f2e02cb05c842ed9adee6d4c463defdc5f43505cbe4b1b32c2c6a37915eefe9d606046f4a0c0a8919d8fc2bb8c44c21949691bf4e39907ea44c64368d8a66cf38e8ba520ca05db74779dabb2b487c1d1c95f7ff81e4bf971ddf36eb2624b6bb3a45e5c6c6b88012eb3527a6cf7046554a3fe441506af34663a71ce294d53a554c1b9fb7b38d93837b572e24cf967ec71ba4adc512b0c8546f587b162c6fe40c62baa62d0eb17d8d3e141f4131849b14cb2dc842142677a353085d9996d88f5dd969bb40a370d76985ca4bea251a27600b57c74b6fa1f99614d2aa068dfe97fdd2edf6d4f098acd503ba8d255c29f608f6956cb33b6ed9d784a06200c5d0c04876c80fff3e606f0336252e4713b9656db83591ab21cd304744f4340d0bc582c2cc0e7e36dfabcb0d8c30e1b270262c18558292367d1d7631f80b86e8b681c59fee8401b62e8ffa32470b048b3bd9146834582a2187316010005621ced7cf15a0c2d949a47dd4648cf45532528f3057a41e8abf58acd5973d1c82bc181e38ccee64271a4b3ce6e841faa12c1e501555bb0bb67e40699c6b2b4b0f7f919921197c97487c6fa2788d36140dbe060ef125a5cd08336046aefed450f4add073b9c0c8a7c3711b5ac0b8aae1cb7cc4c3a58039af30a8e02617ee18217d659d6eb7fcd61c1cd899e660fe98d942cf002ac777078620911c2206f1a88dba9f9da87e37e9f87338d009872c0a9923ebf21ae580845c4a755a7a1a7e6ec8b8de114c08a78c9de8d33c912150ec6b837e5ec1645f516ec47ed2fa4465226907858c45d74a27cb3710a498dda5b04fde806e61bdf95d97a22aaea98532b32ed3e608d3ca0f87dba246e3a7a020343dcbcb9e78036e1c6072a8eb3e4ea67738b6f0e8b4a2001154091b0cb8a300330067775fdb24eb69c2a5f562463e646d76ecf2b4b744c74ee8fa700aca0efb9e0336d86f8f1c7e0534a089f0cd16d30c83bd965c6eaaf9f756bcc14369e477c6d0495d3fb22b8d9c750dfb11f4182db83f128f9ca5169393ce1d0394d2f0ddbfb4db806f0a3ce56828198925b7a300b858e96ab9310e14d41eed64a7f14b4a533f24394913cb068136f2daf1dddd33227d334003990cdfd40d95d1817f24f3535f6e1bbe4dcbf2a64a923cd6b13c2123901cc2da652c46c77807dd745e7cb9ac223df408f18b33915d0e01a91a0c56f8b46f460cb8cbe19a514fac1fe05f1cdfb9d6ab1062f3122b992188f9a53f56c56445b2ffb6c5e9c976633d20146e73c70d4b1aae093744f91ea3febf1749cae053f723c24606d4a1dab1cb8b5cc13d1e89fa59756f9032c6961f6cb5d2298ab7e20c36710fd40038b5dbcce9b6ef049ec2c8651c0f07a9ef9c4470c81bee036d413e18e3aa8b3dbdb07c1287c6f9b369ec090e0a2e7b2cc2397184ebe0e92f15084298fc993d0f12b0bf302cd72da3350e9d8526303ec97f74939cc9cf70de607e0bc44d863cc36af6baa5f3a849eea92078bbccce2b0dd73bda5bf2e6a0f23892444ec7f2e8996dc8cc0003332b3827771ae4026181a9f3df3b3666068e9160d6a2192036c0b9666199c79b0860f744d23ae9ab433602e0b926e01dd3415abb92471222a85bd8d47b55e4d5d2b0d65aabf2453d902312720d22e88c07abdc186d832df3a3ddc3b23e512507b9e19f6c9fff3685b6cf8fd94ee7cc13bacaa9ec8dfffc6290678ce0066588e763b4a1c354eb97a18daf247b2a34bd0dd9f598380b9d04ce7cbad5c116bc7bde4ea1a0e3446519c034483e79ec19a1ea5c88d6fe4f201781a3a00c460419bc6c7df876f1dadaa4db78b3cd581baf051a2f2378f9acdd6041311632680da2b5ebf07577b4859b83c3ffbc3c738349a8ad70260a4176e1f2bd706d2b50b7b7dac4412ae870217605410528b1e6e84be64f9942840dd46c3899a7ce38ff78c477cec0da437505aba9edd96560b62c4d64e6f8554935cb232b024170b97e24d40e567f5ea6011a72bad5d867055733347c3027abcd908fadd86bd49037fab7afd2b639b4088ace7c8190fa29ec04c57f162ddefce70d61a50e7f646f80cd8383571b72a54801fe73cca31e020008049b059ca9e9fd3ed09bed6bded75da9edee8210e33e07a0fb41d37d743950ffed01b0f9c4968788f1751f9cf1e808c608045f1989a8ab897320e538434bddff56494421d1ded22398bed8f194e6d8f0920fb41ba0c78304138e9e685e2632b5f962b185b3168a491b85f79ef117475896f911b74451b4817a2b80032776d38e78d70e0170601c4a88d0237eef5457c346ee3f9a3eda639af4051022d17a7a26c8f63cb87ff98b82727fcc406c5890bd3fbc2e11efcdc66671962bd2a5a85bbd1e552903a497fe62c07d7e97f9576a4e656462465ea2638c9b5c82394632477aa4f0c3be2770e14e151df678a7b209e4ea45e231392a8d2c58fb43f99d868521f590575a6fe8b9606abfcb0b44a72381553430d2d2cc3268d33ad1eeec75f3357ae8b71c850bd8ffc12ee428cd2227962e7d0283e7ae70ee7f3ccbee3f44f686975267c075566c7e18980f2b0864dde2004501e14b53eacbc4e356cb685443f73f9f0e2f05d6ef1fa945135c9267b4e60d16bf2d13a5e9aedf98ad4b32cc25c883525af21cd97527d91c1049058891ec92048c2e47799f5e30b911da9f4317790b10ec266b56e26c3392ad866c9cd863bdcfece70ead10e5a365c8b8c4c66faf23d8268e7860be01065d34abdd6590b131cb374c1b5e3d9a6b06d5aa62f32c726d9939213db5f27ff73a9eed07745c63302500ff9816ed5e7d7cba1c90c003f4bfc46f8b5d5f76f2311cd3be5842290e0397e81dfd0262c5114f2ff06ff44007c506d72ffc265d0e5b092f0050c642a98197db44f3add294f56cf6c2216d208d9ce8dce016f9d08d7c8e3687c5e46e150e6ae00bc19ff127212e63ba15a63dd036b0061b64640622ae12cb274b1d57a29041607317b6972625cda94ffa9b364ec5de8e54c821a58c29d511c9a424311149c6f833a35a52b88690118782c55327f63147413fe967890fb5a5a0e508ea882d49ce1861f49976140df8192da3ea3000bf79a953fccc4d89128a4909ef4d8198cd80561909845e0380ab1a40cf877727fb9a96474632ef2c8cbe368e5ad9d59db0269a6e44910525b0001b27724513acca42dcfaf6b2a2f440b0814bda0423389e8ffd605d5cbb813eb3356452d6fce83326413d0ae22f398ba66852730ec7023fe65334831b8001297ce1141fa90f02d0f8dd0b775bbac77e248e14478db7b446ae32618cdb714e6814ed9585db0a96fd5d33f0cfdf704e1223ccff8b47304622b246a25f06508bd000b9487ad44177b59cfcdf912e26bdc19159f730cebdb048746269ce1088792b0519c5f657e34cf177a13363c31f824bad6665df627586da470956c9a8b332e6ee3c0b8da159e0f92f18a88d5f5d8563cc33f2cd49a5012afe7b55c67b3f8df61f5d65846f97255af753014ff1fc6d07a108dff1ca6703df834b6cf80b652f1354845782c1b5d61dcc11f61609b1e4f4bec1d7b1e7083ae87d6465d70f6de501cdf9b998bd09f632f7f9388efb1a1f5a39912b689498419621eb0a6ad23b1ad33da7d00d0f39094d6592654a61979d046f42dab6f429edc757e1513f969fb83745884a769ba4af9804f5edc0be06972a37829cd285e73df8b50880e1e1d6a5896a64f29210fcb9695356fb49f8abf305de96fd1a256719be12c2276813e94786da4112128ab01d83345641e46978fb142fcbc5602ac2f9bf6737b631e4691d118380afc73cfc2043701fcf302bac962895830542a4a7305a8ab8f996ce5d48f24022cda533240713e8c753741a6c2f28f867c53f35e61a067ac016874f0c3338702c8fdc1c11c082656e115b0e7e7ddf934393fb9608e85b06d0ceb81beb5dd88f592dd8db46e42427624082b09dc08381846dff0cbcb7595be50eae2e2d272875b6e7698e5e660b7de49f40ca60376f3e88d25a22a88ded483e80d48075a13f4e1339b616b1b8cf4e13dd27a86eb41dc063e3ba44032bd75abc2263039387cdde1eb99cd39a12a3d13b2d263f40c3d95bde1d029bd095d57b34b3743597623c5a1d4bac316767ba74754f3f4883ac8f6113d6a253cd46a1c54c7468fa8d3eb7ec6e8d16844a5d123ea6d04536f237da4aae2cc7597c49f9f34ba21ec2535bb2a98baabd233d6a93b2b4dd37ca8b779ebb06d98b71edb869ddbc85b9f6d83bc75496f2c7ae30305dcdf2542c4197931d43de02e0f763b2f86ba0f1368363fbc18ea3d4ca0d9f427d06ce6e5b3e3916f36fdec8c600abed9cce7f683a94b695dcf8ba13e6d8fa4ee9cbc18ead13a9bca369b764f30f5b90527b5b2775402cdc6f9bc18ead2fb3b1c71535e0c756861acb630d63ca34e1786bed94c972e0cbd303b4c9f40b399ce83b391ee6ca4cf0b63bd0f2f8c04faf03cb853af6cb389d6d9f4dd1f8e222dcd608523fa53942349acb7347ca058c1cda70849e01cb18b8f86883cbcb4ad67c8b4d120fde9e6b41b1f0d111d1bf996e87bbb3ef070a4f50c79488f5e0c7c91d633c8f3009237be182bde9a935b8f4477b86990e939f1ce1b1d74563f2ba8b74c04c3a905a1dea6c93d4ac2496f7644b075d9da86ba04a6dacd1fa0a74016b39908c63ed9ac4304b76a776e53dfda867a8910a92fd204f4d6336041a8eacd5a8756beda6673513c298a9aa669a228ea5d7210091428f0d4eec6b7dbb3924be8a9ddb90d9d3613c1f3ad6da0974893eb449ac8d3cfc30b043ae8e6f40502c9ebf292d4369bb60d4ff7a46abea21a94dae2d88906a1ac792a87eaf3e6f42b6949b3834c6fd2299b894c37eb58360778e9359d63ae51a9372a52d41dd20f260787a7bb67bd0804900a7ad23bc4efe5bc03e92b39d705d97ae0a0c4a767dc1bce2209dc7cb27003cb809b0f165bc08d0299b0bbb5a665fb48c10de3d0022b7aa6f95871822f1c943ce9191877254f7ab418482ba4b0a207b1499502777ad0c00ee6d4e673840d9c27ee9e32708f1825b0c970c220d77bef411ada0e691afa10f77defb92adedfbcae392f1fbd9910529cebbae8b4104bdb7a54d94859e9dd4303de883dd33ad3b5183d75b41a226e8702cef676faf62aea19d0416fd7d16a886fdfd16a08bdb51e7854001919a61a15bed7aa60889db52ea58c969a7025e190c5d16290557a55551662eb593715c4d29b82a36d5cc938a5adb9c77bad8696e7e357b187fedaa3c16e65b9ad4771aa51592e2f2f7a2341a0d75a0c2cb67baac8b61e490b71c83eab8f12c499a5148786a5bb043ba54b766e83dd223d6c9ad4aade9a8e55d42f3d750bfc4e4d526b31e0349ce7cdefd5e3cd4f021d3eebf0810e290e08f4466f4056606baa51250c7128a5015b1063c966196c411863f567631178c9c14fef5d713edea7c33741a18114076ffe4107fef4480743a8037bf4da757b577bcf38d0a345906f5400e76ebfdbbd7e53bb9eae7bcd93facee9e8517bbe00eec307dfcb1009778f9716433b6cf73639284536996a553be0e92ebae7262b44064f1d90799794cdc7148e671d9812bde5d467cfbc3c3be5ee54f3a6ec4d6628653870bca6a71e1e5e82bda65fec8bd5d1a37e8b6d18d4fe3c8bad56d4a3ecf5fdd1a3c1de13cdec18770a7aeb99eba1ccbe47aec61ec9607721c85eb361d7f05da462bc43243cbd8706bcf1c61b78a2a40ec860e9e6dc2ee2409214457cef2d63355b06b5a23744dc5a0c570b96a7cf2f584a1dafd65b8c7533112cdf2a667963c152ba19c678f36c378bf2cb75b38ecf9b4738577a7301b0bc597e6a79e535fd9255ea175a60da8c50438ee71685be651a309574bad95934070b4ff98ae2b09cfea56774e086a3611c6ff00afce9191c3792da971eb5a8c43db1fe1c6b2b79346e8a7bf268dccf8e5b37bbe0ec944c4ec9bc3a4e9fb45c3eb1a6699a1a364d969506ce3c3eb19b33fd350dafb81fa2cf4a62b3b51c63655554895c44527429a508dd68810d92d112e43a7d4b6edcf283a30064720c96381a4d7d01d99e17d397b7654e2ef3e64c6f892edd325f1fcd059c1157b1acba54f3f44a9b795cd18511fd7a743f8fa677787cc7cd2e54bda4e3feec78cbfdc13d0fc9703fe4e7bd743cc31f7c9d85e594e2c8cf9b33dff2292f3785c7cd2ed8b3fb7a73dc21bda2d5338875dc1c25c5a1cfa9ea2d3ac56197ba53b29bef9448e76ba4e8cd755d957ab09ca4098b26c4a2960baf4032606c8ebfd8eb2ef685b3d8869dcd2e2ced028fc6197934bdf3627a26bbe0dcaa54b7e83492e36ecaa3e99ede7934177037bbd4eae61aaf75e7dda157de1ddca73b24bae3e6cc1d973de115f7233b9ce3d39bfb519d8f7ece81e575bcc7a800320dc65945add500f38c03cbbfb41a583e85c880af672132c89b339fe392deecdcf439e96beb10e98e0bb3e3d7a77a8147e394b8b8744fad5570532132e0f82c44062c9dc7b30cbef2f51cf6a5c5109f23e5f844834c1c5f1f0d8ee694c8f7b300622c96cf55de2c44064ccfe366193c3925b8ff02bce27e44faebba446f2e39a569ce39e777e4784dbbf98327e93acefb757530b519ca80e5e7a4d3e688104fab83a51019708e0baf381fd3715cb22f3a7a46bae8b8fc057a06bb3cbcd2647aa6e5f232f4cccbe569e819eaf210703f2ee7a32f1f819ec92ebf43cfd4cb53a067aacb2fa0674433eef20fc0a1d5c0727920ad0698cb3bf8831bc57175b8b86018865171b13bf4a8b760b114ae15d3e79602f71b8b9d7066592cc4b2d51c9fee013c2b9b1dbde41dbdb96e8e539b4d6d08c4b23abdc9aeabf43d337a7a294ead6f7a435f2d0820a67708c4f29985584e93c53e5c33db4e7ad4f3fd6e8266118b6d9c054e1022892ec0200b2f20c3055250c20424b46841141610e1081faca0890a9648010c78546004182828020c2344ac91e4ca10534002060a96b0730421a608e2c9099c38720320626082235c099a308433d20413bca1852efc70410c379ed006175b90a2852ad800c21a4fa8c1240b4aa4d1022c308108349870e48c367ed030a30a57aa94e1051949b8c2155690a20a3c188309316640052553f8c288caca174248e18d28ac010533aa881146184ff0c209598001a509446042145f38416589174a74810417548cd8828a104b7843096b6861c61431b20823095e60918514284820c211a230821351964051a208485ce1851156782144156f50b1c6145d98119b8f180d08c3062f1890c502a0fc20420d5128c0091a96d0283183c40c5d182143174224e00d04ac71003364c4f0118601bc88218b02402100110610458c13a325025022004800800b237a7021040c6fdc35ac19178347182f78b1230b1d50608890230a1c4ebc2c7151a20509962d8c106d2144e88d6c0dcc8c2a06288ccb0b9ac584228910ad27d5139109aa065312120b6011af0ad1f52f55f469094670e37e14bdd5e0e0edeedb262b83d41d00dcdd4dc3bb323474b78f12d8c0dd175d197799d86f8d2dc8e81af628b6f4607e77d0750f214dad5dc3d7574772d3146de561d8333d1bba336424484d93165ce0699a26898214a4aa29529ba6295252a0549de8a58a0ac269fa019e0ea7699a8abcc728050cd0e20a9e24f81e30b8f96821036ce1e6a3c511385f86a24f44221ecec1bfe8e0001064e07e019ae6d97415bdf4ccacb3a79880ce132f8c7882060bc4b032844d93f786869a47a7e1c812b8bbdd3d720486aff93c23a4046ae306050a6bc8177a706fe066e50e1d3039ea9126f0ca2510477dce2652a76c4ba92f957a8fc8834b53515bea0e7983c32c301445519488baa24e97de7a50486428ab0d4aac1e69d2ef2f4b5cdf5addbb0609aa0d4ae8da48baa34020ce3a229053ec514ba957951e01da54d4199237382c3169d5065b0e0fc34bef2e716f246e4a38ba36d312bc30ee0e4b3806b2f578b34752ed91d42c2c42ad6a7b3130ee8ada7a48ce888cf50203379f2cc8c006c0cd278b267095204d75c43d88dbb8db64ba9b1ea7699aa6037924c0ef3db58b364b23d0e1f930351fd21f05f2307c081a479b2711e07789ead06d245da240622e724337d7d712f7dca97e4c48aa1e69d282b84deb198e3469ee4d01f2bdd6a84982af1d164a1c86c2c439d70f8b28ed62010408a1346141058b31f00bdc818ceded4566f85cc734092a859b0f164560881b94222001bb773b24bae013041144048188293888628c06a851a93045067674909ca1868f124e3cb104226c78c235a50a367e00854001105048610c145ce1063860001a6f545348d90196b841b9c2105e5ebadf468c1831d2639361630088aa8dac07c3242a6e3e52bac00223d2a8c2942b4fb8c153059e05f848214200b8f920810a528ed0020b071698c28d8a26661c0992460fb428c1158ad002153fc8d84182125ce1e683042b40505d7dddefbd8643f0c19491233da2da250e0ca7e047d3cf11bea66b0559871b8cb48718ba2c82330bdada97481fdec3fa7c689b4d5b59a8dac764870d84b6d10a72b86b4d3f9aae625d23f8e0e673851bd8076e3e4648017e4c7aa6f918a10ad806782a7bd31b7a93ddc7a4092ab6b798c224f7144cdd7a346263bd815c5c4eb9bc511809c0bbe378381244036caaef389b7878230a859ae8112543430fad0a1e22e12ccb60aa0527bbb99bcf0f35449a50a00f2f11f8be3bbc18ea44da87e3cbfad442bd6e0f36ad67c8105bf7a21ace3fe0da056cbdc5f6e0b075453b6cda361bd9d0369b8c3e74472d9175d8b211591732828748d8ba4b6a134e24c8bedcb259aba04b375dacc3d43a8cbd1c5b6f56bdeee88da337aed5fa76351406a857d6c119b6c43433ec9675b8f54c08609ee38e06c16edd1cebd85b8e757a41a73613f12104a10f11fdba9006c17e617f3a98e6b8ed8107ce8179c321db030f0c7390a52ec79bdee07866bb07b3305447b3d16e54d11bbdb1af69eb3483e17acd7edde596cb2dfa4cce5625bde171496f76dcf794f4887af7647aebba7533bd1fd0c1a1d74b2bf4da72fa0983a441aed7faeb35afdad02ffb5aec539205c91eb2425633a9f9ed60eaf929a12d9719bd69b9aeb7d3333c4efd25e9991da7fe78b25f198f5b56e411a2373caeab9407bde88e5f1467c78e533b1ae6d16221b69ecb258561c9fbcb9b0671b975b3cba5e8d9cdd9ddcdd773763fa083779c1ef48b1e260787a93b4c5d989fc75b6abd97cd42173dfba34140bf6eb60e7ad320f4a19bade72bb39948ce7550901dbfea77dc7cd5bae3ed85466f5e784d4b1876e8c340c1504314ca1118076e3e5754d9e231a1fe9a681a6743fd3dc94f8a2a04030ca1eb030fee7d1ee09dbb247087270111779bf478e8301cd40300bf07c001d0c3362c433d423d1eea118281a237f7525a3cc037a9a1507de8b5eed8f1da72185eaf4aadd96876b30e9e40b36922386749bfe1ebf59252ce467140373b0c7af6b64dae87deda0698ebfac0037cbf2f09faf09200bed9908008bc4daef79b4de8180d72c1f0fb466fee2f1e87e1573d0c370774d9806cc3219b89e06c2fba65b30ea65487965f37ebe096d7f4b5cd86cd81c7ebcd3a98c72b7a93d9372cba15d9696776617e73e0f196f3b8cf48e3ecb9d940729b77fa4a6f6866a71a15a337a2466fb26796d54ebaee784b8bcd0e87b29b7570f6da7aa67b3ed120d6af9b413b6ed90fe8e0ec8dea509f3da3373baeabd60e8b5a2f9c529c175eb8a340427fe1668743976ebe601bde1124f4ece67a5b8a1e510f759417435d64216e71b4a9bc18ea353da547548e66a2e6ae82a977151f2b53c6704246123f3d69f44c6e293075ea3d85caa3a1de511e4d10a7de3ece9ac1ba2c36eb601d7db3b793ece664b76e3fe91175fdba59c7b3db49349396a267745c9653af79ddf3681e9317439dbaaedb4b3c273d93ebafe7ecd2b2cf498fa867f63169a2d25bcf8f09a6baa747d4ab7d4ea434a57b4c72e81b96d76c54ae730bb5e2793114f5217d530fe90de82f33c75ca3369cfd35f198f44c966559665937d6cda1b74e511de86d263777123da2def2562deb583bb12c6aa71a92e2c041df38a80ef4fadc3d98a29ff4865e166299d9c642e8afcb4643cf6c081cce4ead107afa90cde109b9b23b4c1dce2ccca9ebbe60ae065a8f32eb308e379c23c77515470e1c386ea401d3cd1bc0d9ba90173c39cbc6183fcd7961701a9e17863e67fe7dde77fabe0e9eac65f3106c3d46d774b065854c5c499f6c1661a9c61d421cc8265327097409c2de7a48cc3a5c310cc3ac8330ac56090349c76ed5d83c57bb7a73ae57568caf2ed96cebcd1063f5586e1e1c2096f2946ebdd2ad28cebc6c1d0f79e88dc3e145697733946cae5887481109f47607e54e02d75f36a77a11ec6c7e58a2a09b7530c85dd2af3e02e70acab9582ebda65f9d63a9aee6c15574738cd3751774bdbaa4aa5ebaea8501e1f068644487d2ddcd40a4bb4b77f59dc4fd70af1773d8a7b528ce54bd9a301691e8194acfa9373b4aaaf5f056d1a5ae34511f2c2f10c8367c5dd7755df7cbaa79d3a2f48d06b95e3fad677f7934a12bf368b2fb2e8cb336cd7357e6d45ff5eed7ed229c0fd0ab5bd3a00b531dbb75994783c38be95399e96e819e85bc501407f49ceb4ed071788ed7a5517083eebc18f68bde60b24a13ae6cc3b5d65a71753937db1d834bde316ab23e6dd6b999187667b3c3f512b3380d636f8a43551dbbcd6118766140cfc12e1d845d3a865dc2dca96aaf7a41bf405d84f361ddd9fc822d795f3dca831b8db348eb5c459c8e935a9ef862098ce106e58b1560284ea4c0cd078d3408801b949e34308cd2334b26138e7c61055fe1c614dcdcc0ed8a2d2c81a1b4c106a52ec907bfcb366f9ef6b252b2d7f529a56cc97cf6d0a74ff466122d990f3da3d305f175476f8abcd834a1def406ead304a2398424096330401a530f81067470c31805e2a687f07477678fae4f4fa669a26ea8537a23fdba3948d729fb82a8190ec159ba9089a7c3283d23a567b2bfc3295bf44cf597211508067ebfaa9a8659484a93084b78ba33649fbcf7362d2b852e85a63e0253d47df262de33f4c1d913d11c2c8a231f7a6b986a783ae509d11beac21eb5278fc61979e294344facdd3c8fe6f54c3cf85d4a2bcbb2ec56abb2ccb28ec0399455f5d46b9a16e17e640f895eafe8e60e655928cb2ea53443a76cae588748114a3a4d325dba98a249846c4e7c113cd9fc30951d628c7ae8b61e611fd29892b2d029e9589eae83f5989bf2606c9aa61b250bcbb11e1d9683f588859e9117f33e854e5d88431726bb74ecf5b0bc1e7a7bf003427dfa143a4de27e4c0f5da961cf94e7a238f4d3a5546a262fe69de52e375797b760d45fa8b74c8a433d2774b3935428147ac1de4c42a1bbdc66126ab92cb7995014a37cb0b432cbb2ac2c62773a4de27cd0d73c9105bd5af8ca4a97924227d49b1ee81d3a7995824e26e804bf67d89561372794b122dc8fec30765d37f4e97908d57e6e4ee8d827e966e72810ec353b8cb3364775b0b25f53e8d8cd106717c6ba749adf13fc1edf6b8dd3e9100a5fcf43289cbd7aee24587ac1d7b390978c733d27bbd8291a64e28b0d0ca3e0971d64618fb29b8750787a757327c134fbcb5e76b39077dd8c5de9469221dbf0348542a187a62a293729e5c1f4209b7530e84d6f40529a8c4816a7e16049d7fa740983d3b07461b2e748a79eddd946d5c1218bbd519cd0cd8e358c595a84f3415f279b5f5c124c2f9b3b099e3a49d3349be98da23e499af9e9b408f7c3e1e94d7970a3f4c2698fcc07719b799b5897d62beb4d71986a54eaf0d365531c1c8652f50450032965bb7731c61829f762aca22ce405578ff4267e9aa6a97970fcd4144817e15cf3e0f6e924ce8773af6c17e17cb84f3f38275987a727d92c44273a490bef359d1bea3ad8d9e9ef392ae74857c8c4efaf0cd92612e703d35c821a52118786e3711a8e17a67a4ebcf4eace362a0c9078294ed7c1cfe63904bb53b68a3647ca421d6c854c0cef44e27cb83f4bb9c7856c734eda703f4b9a539ad4e1214ce26ea63b0a44ba5b76dab61088ea0e2d6be308bef1334195ee7a7a6c9461650a2320999246196054fdf923031b3ca0e1149bfb994271f3f9a9c239d7ef4a19694008a5e98a922b3c57e674f6ca138a55615996943f55ae6c019ace42f97181b35798502788de8040a05ab59862594ca0a61f1908414dd38f0d3084104ab08a7e9e8094d4ed4d3530a30d49080d32518616128c54486dddfa22aa2258458967024b90ac000565d860084b14e10a981ab518040a52550f265970620d2bd0606206577c3149664041a9c0005aa82184295819e30c2bd85056f89801e5c2cdc78c242825a658092336339060899bcf9537ceb841110de50c154081822b3f3f3f434c5500518320a49f36a0244915b6335690a4a93076ce50429226a9569185733db5c6cf4f1540d4e0a70d21e60aaa304118672881a720cfb8019433547006142f518b2358c02f50a060060d647b34ed093000420655b842250757d8e45805ceb52dd02036c2016db8a0093692f840081ed84c5494318432a898709be2a78d1a5841096e3e558802f6816770d581cb10b07caebd77bd708165cfb783df7b0826b8070a7f0062f9c828034f32dec0d91018a6df7cca88014c5f11a6e6b396152958c6d9b66ad64571dbe653c61358a75dff604e494d9b260d4301e9f4f4128197ae6303c303fdd57ae497f651c56978d46218b5185c9cef2175cc1ef33a1d3ab09b5ea2f5ea71662113576f33aaf52aa7bab5425ba922ade3e0f34246404e97da34fdb519f74c1d4a97d474f8a09b7a4e3a4c364acdd570e9530e0d88506772b0097933dba8efb04738c3341c2100e183f0d1be403e70ee857a24f60cb567e8b78ec94143cda3295270ee81fbc5e5781d40900e37286355591964ac0c811f6e54206982b30ca6262b26a8a47e8fef3d6a7a4f928216ba50473f5c10c38d27b4c1c516a468a10a3680b0c6136a30c9821269b4000b5220020d291c39a38d1f34cca8c2952a6578414612ae708515a4a8020fc660428c195041c914a2608495280421052e44210d285ca14a14c2f8e209539c00058c2134a1074c68e28b1a507981175048411750d8e1e28d2dd45842194ab0a24513a628210b2324c1078b28a4e8000936384212465841942a48a054294111d8b8c20c2ba8508513a8d8620a24f85041841f0cc189109648218320b000086124f94118403cd9421467f8608c1e840145173cc06207563c1104273b7002073ae8698244134f2822074f3801136ee0000b4cacb0040a37a062832c9628420d844003286690831e1a28e1021938812706012d6f3d032fcbbb25f48be5e6ec97f4169b43bfde10f57d09e8135ec8c42d7794e5fa70037fd372095bec4b8f5aa8ccf2eb6990811d17b8f960e188abd64bccb6b4b4b45c1897e7b4fcdda5e5ef2db7e5eff33a58b2d9650f852e129d85e52d36c35f77f406e9188b8d5864270ed98a332bc2d042ac816eeb98ab45372facd2a33e182f0535474845be2878e20ca938c14dbdf7eef786e145f85de9dd494df474d8e112055a0c73fa89459c0e852c2d907d97e319517353c1ee4da5c1e899eaee5da567acc8bb37193d73ddbd7fa048c30d9c053770f341c30a4c036e3e59b0023f24aac3d92d51abcfd782fa767ae4289d2e9b756ee2df3b8852d00df092976c863de66425bb1fec787ae4de11d58db012b7f3687e6881049f11092681a5e711764ab054c1bff9c30e96ee1c0f96ee33e2de6ef4c89d05d53991fbd4e0cc8d0423bde177079d53d2a3062fddec92e8c1ed1d511dcecde755598215b2854c2cfd398a8290a22005a7d75517d04a45a5470ddb565424f81eb4817453ecbf17abea55f054c34b6f0bffecd44fea4f1036b4dd97fe5ada426adbfddab586fd20ecee43d8d26b5a42787ba0a4ee7e77a77ddfa369064dbd3fbba384ef2ea11e257a03a725d4a57bf4bdc989ba45a64d13e9d21d8412861488bbe49c831488bb64e125fc5e950c8e8167c00dca1b4eb0f4d6234327b82fdd27e892c0d12991373f29b80fe58df092e2547710c286e12b2ace5af4e6dd971eb518ebcb4bf567e91b1b2e4a84efa5b171737d4e3ae78674bb9c93d23dbe9b3b3a179d7cef1ebef7e0045f59b139d48be067f3c3d09dc2c7473fa4317441e26117f214fc7ba33ac853cfe68a0aa6342dcf11637f6fb1edc5f8dc697aefd21c79ea8fca539f9ecf9c3eaf022fa6ff28789f75eed3e943a2ece61720f0efefc5575bb81feff14e8f0a7daea8e0a9529cecef82b2e939e23ae5c574882574511cf89c78b35318e37b4a8cef2cf4afe7a10bdfb36a074b296167db84a594d251f4356dab2d9c8f57d53c6c7a9cd5e6096f4f813ceda552c1a0d7741ff23c9a087962853cb89de5a8bb28a57573e0e9a525dd2ca459c9f1be16237d518789ca78ea4a78ebc2509ffec3cb0bce31bf234df37a7e78342e4ac7dbd8887fcd0a96a7bf268a4ec1d98d81fb205b7b9a15b713e5dd1905b7b42a3b29ca360c2184909a6ed585f3f12eaaba703f1c7e56b0bbf41a6c4d054327a2e6b1866c3d76a040ab417ab30253a0c5e0feec0e3d72cdfd30240535b7283fb85ff370a840cf34ee6f000a99f2f15487fb411bad474b5d9270a341266c553811ead8f4146fa54f36de3c714b97f0e3a9f2dd09bf705530fc4352a94bcf6ee73b505ef619517fe819f7e60686900aceee155173f3c10dc2394518de490fb41ebd993e756ee825c862d874ec4ecf6e5d07579b5d6e5632cce678436d1834ef7ed9dc03cf37e76c774a2a7ae3a6a98af1456aa2e00461efb418da5d156bf259814fec9925d5a54fc911511b4ebb01be35d134b16b97dad4e45ba3ac685d5ede25d523bd99ac25d5e327da626b56758bbcdcd09f9ae6d0546c12a62810ea4d755314c8f4beed949d1e5b6c537753ef1c5b6aaa08a0099a87d33a4cdf7bf47a8f3aa5f35def149d77484f13a5976eba43fa4eb34b22f362e09b5a929ea13793cc835236d0a5bcae794da704bf5b36c7cd37795d9fd3b2fe2e7973ac3becf3fa93d3cd0cbb19e85ed6ddb39039dd792f9947f36acef9e9ddedb81fd3dfa5997a5b8be280dc2b10c5a653198b0f746aa264a814d775b97ba75bd6ed381fd4a5a5af794dc9f93cf1bc59c89c7a3aacf72fc68a57e64cb79e85387a9917034f5d38d773aa0bfa24531d56f312c93ce852fa8bde50cbb2ac693a24d37dda86a54b424defbd5f7717b5e6ad296f86489c0f2a5ec925c18d4af385986091520f96fe92f4108fd3387e8ab6df10957afd04ba90092328de09994831d68322e592c49e17233d438c3d2635c6367790cc243d43bdf63cc9b2d51d4ff7cea3793c2c8f14c330ecb465184669c5421389fb81bdc690455fd315c32a86c55b41f1a0b9130f9a4a70aeaacdb15e04470c048a36435c51af150866a057f1395ab9b1950457315e10e87908156f05ba39f4a04b57e5406f1d14ab14a5c77aea460a7af5781e0d74e1c1528c8fb17eeeb81ff1f5825ef3aae79904837e5d2c8f3727de620175cb5de2ab17ea2ea07a592ea95aeb4bf55652af4b8b12ea66962a4a81a584312c62ccaa6e7c4def381fd67cc84ecf2ce8d7152d494994a674a8e429c1d2b14b62b5d6ab3e5f48a89497ba3f37279e1ef49b9db3402020f4f1d861ad7754078a5d0a9938fec22e0c3de8567e3d58e27931d2a57a4b3e879edd0e06c9672133430c7aa438f23958263364322dec11561fbad9ed60eb8e07bb84dd2c64e2faeb929c4840a04ff40624a38469b513a6b6e118638498d22a36bd999711546b3d4ec3f5c260cfa9a75e2f75ecd57530c84af968f3c4f158b539e288033abd6e861389f311b1357770743b31568f317e22713f6612584d14455d27899c8e349cf41cbf8724d7dc7cda4847f6edd1a33f216ac58d8a2439c06da7f63b3c0db8c9b41733c2ef513b94692a92244539bb416f13d4a0be30b8674f6b5a6d49495114451d5287a72efcf5771ddc76deb24ea939c9b7b55984658fe45451a92a4ae9711aa617e67a0e3d754afdb2b959c9935a7ac3bc7ccdabba703ee0084f4e49a37a724948d30a787cd830829b0f1a56708e3e5838026a3d1a91ebedc5bc60577be49c4d7c31ae69bbec345d98860399faa8440bd8c93335ec98a219910000004315002030140c8885c3c1702045613f14800d95ae50643e13469218053110c3300883300003020000000000036044003eaad01da8dbfb18800c46d3e03ecee1fecb271c7330d90780f7e199e6863dbe3e86d2a9c5f2dc501160f14d2b224f282644d4fc403d7087b59d36e5d20f5dc89a848367ed9d6bab737d0f7e952a763dfdd4e31809ee345a4a03b267bd3e7074ddd5b2679714da955de4d6117e1c4acd3be43caf6a45eadbde87ac828841994e204c80749957d5be72b0307b91e90e27cc1d849bb548465301ce2a17f8a1b48f0afbeb612ddb50166513a3d4f7ac6cb9f4164955a17fb20db7d32c8e995241c4f4181c032fd8f5468e7511b4ea1958c059a7444ca364f7c9e26287dce5ad4c5178c7a2eb4b1cab0f73535cddb0b6a75b71f15a0611c1437d4401a2f4aba163d50de8072571f2e34de52189ea83c20814413bae83c4dc090e7a315824620413a5ec09c97f338b59a72f0c940ad7c52de26d9e009aef67424b7c1e45438024f12f40f069d76881b90302f9ed84b320e095b1a8ac14c3e7ac571bf650d9fe2e17c7b3570156add5b3bd32b196e8b1d9196a7c297733a8d91f2902ac5573f650ebdd82b526553c1cae4893b2b7eeb298c2e3ecc0697e16c2cb02af482a0c34d54dc8cdfa97911328f8f19b4f79c6fef3c0028b218d1257bb8d3417e4536ad98c14b41768e5419499c1bdc945f09e5353f7157c08ba61baaf2e4fbc507b8d51982a0058a9ecc358c123828561ed0d84a467edcee1ad7ced3e68aa253897f85b663ae863657c0a3086f3166af20fc4e6de9eef13e5f2d4210f3324448fd549c3d337696dc4630fb6ac07c4aad67d5dddd9121b8024b0cdc29843728ef176a2aed0c167206f858b38a92916496520181cd311791e1e4640b9a04d3d7601bc2407eb8fab9d4907d39d3e6421b8a9c000cd165dccc7131c90d2c26f70823b8d8178284fcd3dc0aa70a401abc58d81692f2cc2bde632d9458724ede2c3f46ab690d474d7ebc829dac7f5ccbac2e7496321bb1f969e77e68121429e682c4145e5f5dc15ed1119c77b805406f1aee009769de4c98cd0d4cb739d922a263f9433914270c91a5dc5dd590dd92cec10ad19bc468b1da37b40019ae09fe4d5238b83cbff75ea56bc37edd0d9e375ccb9efee149b625032235542508734901d5b886d54bf16dafef173491ed3ec4ffb37f5eb303769040422736725e0a70bb507a38905a7102c6e7a78f83f22b6433c6d48432572ad76eca7c40da1722b9dba16a80e0f3b982a90884c1137354fc020b8314abdad577af3ec7b074a1eea8cd743c9c414e8b7ce33f722e9aa33325567c8110f0ba178347a36042c24708c53cfeb0175a684688b867b84869bc773ea4cf4de80eb081e70327f1eccd4e16f3723e42ee2d39453caa5e07467ce0fea244aedb4958b09618b0c48b92c92bc92df52bcde8a5ad407b9cfbed9170b075bcacac0218d4fe02463ff79475ee8ef08ba223e940cb40ed2e7f48f426f0f65e8175b0d2fbdaf1c7afaaf151725f36c3e2b71ae8e056c8c3d0485427b1a46f7ebf646b6daafbfb322c21e906bde61f694fc7ccfc19f676b7d48573b77010573348259bf83f5a50c306455e6862f6ede120931755e3a644434f191d94c26054b01fb4dc8161a9620cd04eed651fa1d8b35062ae91131f3cc300862733f5e5f173bd24a45ebe421489e7fa391262154a8c11fa19b7fc26d9ac1217f0060e0d4708ba406af2c6be2aa83882e110c77b83f6af47b36ae6b02a37347550dd4d7ba3c2f845a394e161a8ff949e7bd447d082d62fc90147e733c6963321d585257929b5305a08002e4839000c4150f5f93390e0cc38b4714cb9a21a02b9e4e303e1c664e5831518b66ba84a349b08bf4be3e197776f3cc034a37329d71cb2ce30df123fdaba34999d626b40d500e5c90da954be0f1b5d630e1642e8f76c04bbb79896f298489e35ad3528bc3db35bc86d04edf582e559bb10f556913a856600241a39df3f5c658e3bdbb35b22e8b9b63edf47223214570fe949b68dcaaa7ddc23195786d9b8df186b64b9b449635b7e7e7114a7d04075b3b659e48f9ba65443f9219e2d5980bf3caa504377ea43d239b1646cda01855aa4458536c613ef0aac84253e8d891b65633b828d7964fa67b42cd88bf0c1c4a9884c0d2b806b853e7bbfdff3fff67c78f4624cc8e85268b8ba266bce992100e3b2f6623073834a7f4fc066dc407b60151161728a99df2bcf015fa2e70a9fafb45ef18c89680e6aa89458a697a4ce23c6f99778fdac2c700e17aa4e0dd75a1bb478dc72c05b3f6e7d423e9a25a2e2dfe8d939ff0a9dc13c637c630cc2bf3e4e01b1563da986232afe52eb5a4806fcac0caf98d60042b9c9bc8a8ca20d31975e06f4f1be2ced24720b53eac467137773288f2a404cceb675256ba1bf3218fcb3d031edee2599529ac55407148058541f2b996e3c9ad81497908f1dae31c68b7cd9c2de783240ce5c04ad4023a44117281bf817de70db0ca17981bae0ff079837d58b5a850ecdf8a19bb7895bce4c6bcda0e292193ef9a5400ac139ccfa629de1827521257d0e029c2f14f5c592e482b2efe28bb418315ba90c4ded229470db4c36f456161bddba0a155eceb38a10c42d1f589adf3b9673a2c21672bad2a3917d6b8a1a9484896a271d586ca13515178b8c1d0a36af96055dbc91785689f7a9acbbe6a71b8ccb92be500237b63ac5c06efdccc709276e186e9380dd4b6c56df605e1361a88deae649480976ebec0c52cceb5f803a37a24cf6cf487fe6b4ae999b5da1a4e151723e5d215950550d0745554a7ef697b074c02d4071ef9a827a99e754a015c389b69a6a5a307ff79d60859cecd9fb67a435c14d97553109778d07b6dd2de1f1855586ccffe41f3f5800fa362949840cee542771a1acad986fc92aa7006f0036fd1d3da3bad8d2aaf05c88efa54a2aeba73d75dba9595d4ad41dff762c5923daee02dcc43f795375ce5d44c11006279b1e94cd9c3c5a44f91c6c37253dd6431c44ff89715dc76971bd945460b9edaf4673921a11e1b62702f886320fed40d52f4e9f302ca494ddcf238480e7a302d97bc20695a4641fedd6bb672d08c4e4bac23884f891dfd85ac1b95a23d81e07c332a6bb32172e0d30fb551bb8301e2884520d908d3df00a94f3cba4546473985dce71bf9f914453fee285d4e06e9c861f4c9b5f74d2b7d61d3793ad9c257356350f6057c47c519250ddb0ab930f2f754f7f5a2bbc6fb2dc86f972648b70befa660be30c336b8db4ebb6dc744a093a42d67c635f07928d0ba0ca142cb1f05698c69e0c19ec6caef68eaec01e1b85c88db05d18e5529b9ada5474d089dbc97ccb34c58389250d1f06656f36fc1f8e04fe16fa6513f14052d84fc2018169042ae6dbe10ec8e7d82c72e289fb20f19433c01f753d1154fb86b565bd16bdfcbc6fe8ee6b43dae33f6c585f30b68794d58c667ef80014b3bc05db5fb2f8f896e0b61229a03042893bfe458dad48e91ed68da7045326a7bb80c809ee709a989656beac98d7d4379861bc4fa9212488e92c89ea66b9f848653d877d65930a99ac105fd69c97cbc5ba128bfd54b3d2c66447bddfa2ccb02d3b3ca236a4bf4c4d9421827a33a93b6fa0896ed09d6e6062520022bf6c0b26b2d1d481fece631ccc344f09b91b43942704df8081b5cdc3f70e4f0829e4c32988470c53a2974f447bf9fc571d2e05a0897bdb64a3a18aa2f68bfd9f08d267c0276af87dae528075b25c4a3d60e6a94cd662d506bd6fa9067cd37bd3b25780c34d6c99e4359d4f4a3cc45d358d4b4b6b0b4732ca24df98d04b22c2736825f041199b59565adb929b57bd0b17b40ef78633ae1405fbf1e7e9ea6d3b4a5e0ed9ee27d7f7d7cc1d6d3e8da115975ee6e99190599149b1a52856ad292a404764defea1cb200eea7e1f0abedd70d1e1e428d665aa7b8b46f94018e33aa3842372961b11c1b89b3dc45a74c4c541cdc5065243ae7a077727e9f848905e6844bfc40ab7924c3d9dcba191e61f8b30a259c9c3da0913e3d1949d9dc06cf10fba293a50435069bae8b6397d701cfbda4251161f36d4c89c645e258e56da7fa5403988cba54a7692ae30d7ce1ddb76c31e0ad3b8b8417710310be44f4a6ffa7bc5b219e3112be7abbe7a7bc1b24caad1849aefc7014cd21af064879041589156903614d138790783edb6ed821de26121e180cd79a56080dd0494d731ee00a7414745133ca31b8421ae5e8736960ed2e4ac2509e2ffaaec1d89b8a16baaec343152508ef594b52125f92e48147071b845282d3ba55cd230983307f4fc51e7d04ccdd71e525f841b81178826ac374c0005c9b4eb44246063a1c8095086a7f5319a8ff7e7f2415fefd56e7529ca8b776563e840682d8944a3cd2ff53d4f236219eb8ea196906cbac7a137b1d424378940cd54185694d8ffd92ea227ac0d846a70eb99d99cf5753f8581d91edeaf18a6f82a75d6c19153a0b03bc3cbe94426e6f243defcdfcc9a7d42a5306a46e268d517e9b991f3e995aaa0014dfa662cd8b062f7f5e016ee5d6fe5daa50ba967dba03705bd2276f60796509196365209a769a36251760aa6df393958a3afc710a796d5ccf726bbc0f7dcadf1612d045261c42548de78756a4fc511b5ac391c15df73c372b432ea1be9e7dce2df7b08f5d664114896652a82b080cadeddbdedfc807aae693f062c03677a0101180127000ab68bd2edf9ab289b4209d0c05360a40dd771a8c08231018b6cfcf860059b5bd1ae838038274ea0fd9898bf9ed33101b82e87b6cdcef350416a206e0125a98fc133e21f2c695b4dbc1538cb451b89fddfc92634aea47b13e88827526e76c745ae910d455a1f5236d1cb9e5f430ba3e4ac163022cbfde98d645ef5cbbc7cbd442a6331723a137747d48d4c372b57a598d0f1ebfdcd31b9009653a5a08c473c839e902ebe4638d180327cc709be49465b8e3f341de98bac01b1da59b2ca929c16172966b34abcf47e3b011133836041d7973487a21e5911f650636ba9ca2cfc238d6303602ab6ac13b964e95e91bf6e0d996c3dddc75cd63da8eff53c84cf4cd767bc381a3f22834e6e3948725160869d822bb401f2c6f292e3ef8213c62b50bb77b85a73cc29765ec2e52d809f393502a8fc0acf1566aeee36a1d0c95b5d1d423380e3338c747defe09bb64d17eb174de7cf551d5132092ba31a8b459a63c88ce139ad020f61f76d89d63aa2f8e0d1a36ae1a32a9ecf362f3615425cd8d60023c9294a68444ae81203c26ebbfbc83611b3ed1a654843054e58001a323917e430f3fa806465f566e05ea38bf522bb20199ba9e6590e78fa7a92d2b211889a5861abcb89aee2dec9dc0c9b33288ccd459deb6cc5f6f31c420e2f11515daa88170bfaf13cc8a85904b2f48141eb9c1e545be0b70f9e289757fb20d93e40fd6a10ff2d9c9c4dffbc5b483b44fe58b46a65189a5334b23f6e0ce369ea202e0d529c1a9bba826a0e9df832f4436f91c3f3445c08e25defa12cc550ae4c2e36392be4faa341b516da8320034be53abff58308f1378c03034fd9c7d553d62cdc2e911701da88c75a8022c18d0bed30b64823c197f5f1424c7a938962037ba71395625e24f2d78d7c8c99152b29e6c6fe21624496b3f7ed02c046604969392aa84dd5c49dd250f6384aebfa022be4533716bceaf06dfdc4b2ced124a110a2ab3e9e4facca1a765ad4626a42f0673ef1d15336757ff3b26bfc5181e21d89e117edd432e464b255c8bc5589875d72df767f2f95d95584e5f872dd0a159f181608a906a4000ee9d2f9014c645478db0cff18040014d2fa96c30eaecc31c52f7007564e643711133e52ca7f2fe92029e29798bc0f4cf28a90fc9a269f69357f66dd4482b5e77391d0867b9656b1beb03d64a59c904cf52138fceda9b86456c10ef4c330440ba47452e1ff104e03eaa0be6fcfe3c21655e17a9d1447ed3384b84239c6584794abfa7ce271b75f44f1ec20f9df202a0927f0e983c94a47e4ba923588241652f0aeda9642e588648f1debe8b833a012887a16649a18ff28f5b6799b102500b31d6e0606a1146dda597b6435111a89bead3521d3a608cb9b8c241c406978583b17241870457620cb373dac65b0216884d0a0a9915a3801ce5c339bcddf7f9752653c42373954c078b21691b8de52c1cb96f0b8b31d21db29754f3cf5d6bdfdbb2c24ecb606a607c6f5b55bd61a25f12173334edb151256b4006764d9ede1ca1ae24c94953d99c5b556471f1ffe1890b3d3d77b406c8f46da0cece2d20d8826765424c546dc80b72b67984db7cec54bce35d64474505540b2f87031c55a1e2c26078774874e2acd6a3b3e5f5159332244909ef3b8f3a0e9537228a378ff8577e8824708c6adeda16648210fdc1b3d472f9db8ebcb529ae98308cc77552c909d85c1b16df1f50b27e97178bf04c8aed4667ee63f89846f6fea1b8781c4797ee9d0c5adb6049720cc5445513179643d067d483c5d7f8955a1d2f9c567b1d478c52dc52cad798b42f2e224ef00e230daf204c8ed5cea785907d64637892128c01054343b77183ef8035ff72d7e94478d1c735bfcf09a7ee9f2287cbb530dd5844aec262cba36b73a169a14f6313e9da7e56d2eb24d231745691cc16d86494aefb2bc15016c126dbbae528edc051274e091930c6b4438673972ab82b70df1a181855ce20a691168033e9627745b49685d73c701e4a5b31e61d848cb8d159de8160fc36b172d2f58f5e78013c9f284e238c6737d16054984160a04ac9825f740e553a921accc52fb766333f456bfa201747efbae18326b4aff93f8a8b764aa83430f6c7d129be840cd19a2026b16b4586dd4459788134cc07c17de3f74952404757b097d7b0cc4e79e910500862e11ad3883777c3a6248d03b051669992c6212ee946a1384bcf97ae0498ea02938742e617dd51333b7403269bd9a8eaf97bf40d72fc4cc83d62190d40285e2c5d4c7ce3ea96b72cd7fdea1a5a15ea2db59ad6a8c2ffcc4b2d48b11f0a6eadad3033ff8481a1f7b2f0bfa3158e9ce61e8e08ad508b9776d4d70a073c80540f2a53fe49b77e36a8679c08f2d99c1594387b9805501387a66fe9cc1223fdbcb90bc4f51fe48c337dea83f286c57b7973aa58b5f91c08c3292cd0a58735bed86267326344d07641c0163660359e944bc8be53b1502b6610d773ed9d2f4d988e89617812eface416e7e8ca0580037bdf290ef0d998ea5626f6330b798e475fd7a6d626d331ddd3b495678815b1dd07308a3f22055d0579cb567dd633fee68bbb39d76c6f9c8ba5d414c4c36c678d7e9f6b8f9c88876a52862cee565156396a4fe60756647393b96c13f839587a06723451326d3a222096083441b561f7db2d65946f753bf3322ee7776d077ac9d1d8a158d43c1a87f1c0ee517d825af464abdd1b9377a51e5ba985a6b72b889f486ba422e1e76fcfe91f1ef547aa0d4c8b1448e808b563e9c98b314e23bb7863cc5b4033d3425e9c41528cadbf72309960135cd8f83088c3ca9fee8527389c0670a8be84d16e1692656b096c6fdce2d8a227ac6059b01190c7a6e4d206f7bc181e41af46ed497644c36039e9f38f6e0914c2abceac004c49cd89efc01f79a04d61139b1d7bb32e87f938f5406b96b75aab5861956641b23b99964ba393260b94c694c601b922698c45e2065980994043502c28d827a4458d485ddc9f5edb5fd90dc696e3e3db18956b75648351aac8b58517ce21c71a98166e4706d4abb34d5c161251488e1ee2f742df8cee45d5ed9eaa413c8fe8a9aeb88402375bcd5ed9ff024849d66d392775035f0d2cdad157a62d34dd1a47ab49bcc16f2b22783b650329968f82d3721bf4608698eb61ea487c929c29e3e4217a96c1034575fb6839fece52113ffea924fa501324f1a8e4f8753b64cc1fadb2ee432428a75b79add51d28874f649f889fa6946bb8ce4dd6130e165666c03ecaa59f7daac789b62b99cfcfcc32143a379df41908b66a58b424104be34d9682f39d5408cc4e3f8f2136588b1aca5767688e8919c692a00d6ce27f3be76a608ea264d733ec98995507b945e547952b00b70b9fc96c4715bd9609be99d78f7ea0e4e74435b35fb8c40b7552afa44ea83ab224c97cec494d26c1ac2bba7d7e2e1ea60faac7e0f3de1c5547c75d0acce891e77d6ffea89c176070a624468d7e8e572d36485ba911cb4889475805d3dbfe0fe81b330e0499f20e6ed6c0e184ea41e90750ce45810a33f4e43d9d11c368a9e4595b8740ff7c1367f8f488a276ded3f337b665a934ed2f85e9967d8e7bbca7b7ced491cb884db90d0acb47eee819b0bb14435455e0bd96c4cb15becfad89dbf6db2d816fae270adb2f5d6ca222bf1e04fd4e1f9e4fab4eb9bdab20a0eb8ba4ac8bbdcd68e3eedf8a0a365ce31ad914a1783bfde3ea4421f61ca212fae856f8f6085f3da619d6043b984103c504302a640ffddd7812f35eee8a658b6d232f40fe3845562caba0fa665d3d72e5dd3996d7a2ae249fb02bab38055c16110a2dae8ea5f48644930cca2aaac0ab16c0adcc84394554436e4546fc18f27e30b546a0bbb68ec51e1ef40ccd361cf7fc8d628fe0183d0e061201833eb9da7c6f07544ef7b22088add3d2caf29689e64036b82fec115faeb633f6856cf86d1a4122b4d6a253682589db01eb3f748916c0c6291f3be317fc0d0e483b2726fd565dc95c40ec4c5f412f0c4900f95f1a0edfd617bf8cccdfafd88686f2c60964e3fd4f45a814fdff7b4b1ed07f919e3a24a21343da0fcddaff5e2699b37f03e75ee41c5460aa01631224cb5216d2521852fb0f89e13269b8f543bb1cfd47ba9ebe6da53704055a5e0e1be72a3bc663afbf4c89aedb1afa0fc15d71323939cf7b02c745bf4ac60080221f8874e35bfdc8756ae4839a10a28184b14e86d224bb15f93af040cc8eb1627a569fe62a7ffd692bcafede399440e54e14f87ee6c02721788769a40a35ce9e4db570556cc6655f69ad07bdcb1564ef403f3fa501de73697a44d1de3589e00faa9ac5855c7ad4770b9c55f4c088ce95c5e15b6b2ea145f1dba2325f2c4678f6382901b8fc4287ebb67d42e9b43db7c6e4bd9e046fc9c43b273602e67b53784c32c75bb346ca534d27b683aab40ecd2d14a4876abf6948e63523174c98555c0f75778c5cc277d27bd3e961653fbcfbc8d02f2d5b5b10b5b8221aa04e2d36b1b962d56e0dd7993e1c621bba5ff77e3121f576a90457f66b8df6c005caf886dd75b2d32b66981090d7c6784cb1c160700adfbbbb20009e91658473d5b45d3525283a28f1260b3934bf8caee32c0ce35aee4c160269dfe7feb53de86fe731971ed5db083057ae9a0d63db225492c110be6b5342088c30022b8ee1595865d8406f716ace64442d0a4578f1c220536fa3bb43f64c82cb376b0e2e303b4bc79e3c74d4f5213b1e3020d76033cbe97196cd996d1c32231e9b66b2169493e59c6dc99a31681e5cacc9406f49d0f358f37a1ead97d63c00b79da72f53954f5a587acc9cc19ae506dedf44a111fc7a8c795271561f623842511174fc411d674d7b61cc95d3e32d635b2e21b1210929b9a13c563bb4c2e2fbaf2f46b3a6987c602770cc32fcaedc80443ab96f9bad9a650e040a2ea514763f9e7d046cc7ebb896c20fe0e1ebdd60cf348bca0329ce4dc800632a0e3187c07d148b2b98c0d8bef9063cd1dfe6d8432422987e9e10767b018356ee8d3864b82d680da4bd3dc06e3b994e6edf720bbd97ebd32cab060194a7bda25d898bec6f3dfddcb34568960ab4c069c05e8b1fb7bc66f148803226659e464d87c3d015f0a2d819bff471b143455907f36d957406103d880f310e35b98a8e35c92f79d4dd814c8472ce4992c68d2ad9cdb5f047596e35ce7c1ec90a45906c04af42adb4095225a615d712154b6b4168d2fde43d7822e540fe00c7c61de6ca15d6aaa9a0e437d45619a0cbc360eb15fbbe7f3481b9c5524fb85337af9b96adb136a57695782f07da2e26f1919642b7a7cb44830619a5aa083f48e9e0ec1475d4af017cda58927f5afe7670e348faac906ce22912191650ea2a7292eaf4f40e7ec6242a3bdd43387b05d3a172239c01f77541af12a7baf073e7fd1a0c3d631fad1f2d6dea439d48fb58d230108b94315662524544ef86711b62bf9ac834cbf4935b0d75e62800062251f587bcb3d5c262d5d4358ae932e6507f2b9b9725500004d2433446b2ceebac4eabb36197a41ce499695294e4e12acbd667af16ba17fce60ce88cd6eb69a74af18f9779079b3960e33aae8342ac8249da93f4ec92d9f7453138f6a710677b60897d938227db8c2041c71f9bae3e30339cf42e7b501a7a70e17b87fe4fcc036c633f0b98f648f8a7a28a30ae17c1a2a58f70c5a4c08cb41401a372446ae25e4bd8dbcf0f8548774bf49b47e0d67a464c55efabd12405d0d7dc88039b17dcdccce6dd508b53cd170c8c92e0d42536e9ab3e253a5f71568601f6fba81a7ed1ec290275c9a1f73f7025bba780ff51aa605e30ee94b0084597da5a2be89b0a13ea1a2482041628ba6c7adb542c4fbcd96428508ec5bab1e37400fcb62bb049e09e01a8962234d79f562ad1157a3674e4f8d62c023d2517650f39ad859744461789ae7e9fe6fdbee924a475a4a46ec4f84a36fe97d3576f889617cc716f83c623905346ff2be78733c608c0f9315a97ac653337f087c732a8e42264f898c4280005c9403b4496ba616a929058973c7311b0a811ee30962a31360e91b22cc7bb6b80780ad747d45727336430ffdba503e875a5f84a1dd838701cc84e266bef1372b8f439d642120cf679002edf8bce548726b20614cd47d2f51b99e66d8dfe5b0a81cbed408ec8049bce8dd48cb874e72dfb645243f0854a0b9498c0d4403441b239c63ba076bce780c6617adfbb708b786f33b1dac715f944ffdfe1acca5073ce2aa0abff3fa2dbb4123377fa053d1982a9fee6326e4016bf7bbffddef411bb7f93912036109cfc6e46d5281db71b321388f9402e2ec626ad36ed75ec31d2547baf6913280a1a2ac2645a7cc088d20f51c484465e6046e94384028f2dfe671cd0e7c965ea7a3ace3a8b9109e9063eb1c4e94eced4d9ba20fdc1820c019de8ea9b27721f42fbbf03e1e08d213b2c7375aee144a3f64ab370fe73712264a96cedcc3f750755f327a7426183503ed3e434dd06cc6631f910a0b9d18ade42f3300176bceec92937cae1ce0051c199d3c920be270038d187af0aa1bfdf7f29423de2d3ceeff71102a9080e8ae9e28122474bf95ed8a832f3b0dd026906b352f134b076d2cfb4023621aa7e95ddc7a75552157eb934ae183a53415f2a040bec6dcfca885e998303460455fa229112d3993ba9f9316bb1059cd4f5426afd6349e979c159002c40a31223c4dccb8722920d86f1cf9027700675be6f08e992246c31e735891cae0a805300dad6570e4ee0a06b010eec5cbedcd4e2e858d64036294873a0ebc112b0842fa5ea457ec533f4183a0f4ace1a2326a965f5349c606d495a4ccbdcbb49f83f4141fac1101d2b2f0f89d0f5d474f7428a304c4f6027dc4a2753ae2da9d6f5881688c91cc0c54165f8d7697fc6e93f7db9527769547a930f54da3d2794de163017740e2c6d23bdaca026b8c0ca18fe487541dc32d01b0bd0604ad81cc82d705c5b00b3d464f3dd163e0118fabe976dee1486c32a831f8775aad935617143b039e22b20ebd690b18a6b91e7452279648490cb5aaf7c892bbd8e0fc5d808bc630ba5e80010a756202d02c32d3c014b3f43b6d68a8f1885424e59553a3c928a0b0a4d074f088d76de0c4592aaf010cb5225c1f24cc7bbd9de951a8966496ad290f1a83361992bc3a71753b64518c30c6d5caf44099ccab57e858f27150dc4459aa7f91cd6f477c42bfcbff5b52aa27c24eb019c0a99a6dba50998f85662f2de69c780956f5626804c355ebbb22f494ee8b15105af06c19da806a093df56fc1356f7455061691dd831df5cdc12ee6a51783d9ccff3f8c874d8413b0088a79f3179a4c534446efd44e40cfbac269af1b87cf3865b6d7d7b94677b66bc5578dd72adb6e6aedb69f46db7d4d669b3450c502bcf80760b7d3beabb351fdd525c6dbd15db73ae6d9afa96737acbd9de2a006de718b72df6adc86f5ae663682dacdbafd4ed8cd7166d7d8b93b6f5646e1701b7f90e5bb6db96f863eb2cb2bd64b17d59ad957d410b5dbfd545d97e60b745025bdc872dd66e6be4bd7d22de2eba6edd2f5bf2efad14cd7607caf6a1999638482ddcf1564bb33de2d99e1b6d955eb6dcabad99cb760acdb62bb575d86e1105b7f286db6d1ab4631f6bcd8eb614575b6fc5f68cdb36adb6e59ade726cb78ac0db3946db967d2bf2bb6532de5ab0a4fd46493be3b54559dfe2486d3d59db0580db9cc396edb625fed93a8b6e2f596f5fd65bf9d7164a2d5a5d14b59f98db82c016ff718b6ddb1a796f9f886d17ae5bb7cb96cc6b2b85bedd81b27d6a6d89835bb8c76ab574688f796c4fc65bc5d72df7656bdebd9d42b3ed48d93a365bc481ad3cc3769b6e3bf2b135e173b57c3d9fd61673fb87d9160b6ef11eb658fbad91d7f68978bbe4b275b96cc9bcb75234db5d68dba7165ae200b570c75b2dddf688777b62bc5578dd7259b6e66edb29b4db8ed4d669b3451cd8ca1bc6b69a6241376aed7ed9a97d6ab6c4035bb887ad767d7bc4637b32b255bc6cb92f5b73aeed34ba6d47cad6b1b1450c6ce518b7dbe869477caf351f6d295fb6ded5ed19f76d4add9633bde5d46c1500b67318b72d9badf8d79679bcb568dd7ea16ce7bcd1a2ada5c551546cbf039fea6ff4d83de5605ffb231d73e61d186d4f4cee625ba567dbd111b6b87db672cf6ca123d872f96fe7866d414bd8eafab7c505bf85a658ed6e1fb570e1b7a22dda72f16f71916f4743dce2e2dbca3db7858670cbe5b79d1bb6053d61abfbef1637fc169ae2ed6edfb57061d08abe78cbcd678b4bbe1d1d618bab6f2bd7dc161ae22d97ff76aef816f484adeeff5b5c305b680ab6bb7c5bb863d28ab6082d379f2d2ef976b4c42deebeaddce75b6808b65c7eb6736163a04b3afa654b0157b155f969eb8b7caba17c3b3af11697df56aef9161a24c2f277a3fa0f7113d233871164ae1c993ffd9a0dd08e04205c29098234a0a30805bc85603546102a39f96ae256b3065dcb4a8877b47c6539da37478c17131b97bbf654e58641176dbb1b9cf5cd04b85544deb2f494abc64dd70df80d66b6ac9e4661882959df2730794c59c6c31c08bbfd84b02fa7e3d681dcc20b86aeefa7c94b1466fc6f6a4e4ab5d4b016b16781b9362c037535649b1bd073ffb94a18dce41bd9a842d71b0ad03e321f719e34b2d220438d2a32b374254ca46771c2e9a8a3424d69be665b72f843aca302a4d6fb7861dc82beb4a978e220e2373ae3798c5965e7e2680c22e5c28c67d509e49686213eb62d88c6e315d0687c699900ce748c55ff7a233de0ae388bb5254089e9e8a1d4e64d48ff4621386cb960d02c31a49f2fb58b68f41d2efdf0aa6c713aa12e8fa114164046c5f1a6a06807e5558a60b82c8ea091094b066848a605b6f0e081e478e3114ed5a6cf68170a9547ebc6cc37682510832260a10400c35e37014b62615cffa2f836101621aea605c3182cea2fd4a769ec43cd8187b92dca4d5d2a018f8e959be1feeb0f278f3d087d2ebe580106b91fb25c95e0381db515368de63d02bb456dcca0490d5ddc31109f4afb84b11756f50b97ee6c25ed44f3276f3cf92a6cbf428fcce5767173816f0f0ce9f3cf7964c163178cbb67a678c3a920adae25efdceb5e281a3a53227827d70a2ea9bb7738db90871a32c3c65bba22ce0ff86fb5c29af4569de59fd845ecbc81599c6a752bf7548cd102afda5c68333fdc277c660512963945d23f6ca447a03499f24b275bd228999ee48c0f60d5e4c63d07857cf32fd9772124f9c30d13f54baf0a110d0aac6a07719cd5989f48466c689370fa59ac00635014872ef948ed2b7908cfcf433c21a0e670d884ae0c1b11e0bc2154dadb094b826a23602cafc5e780685dced46780da4c717858298e8445ca7c3b7c5f3b12bda48b7fc13d56d069ddf2593898beee1e4ea82a5882951e98d5339804b873a9f53cfdade042393fbf4885afcf194e950620529d67e1a8407c19c5f74cc36054e5f21c9f7cd02087870a14b104032698721864a03f376c777f75344a1aab3a59e039e194a15b7edaf3584c6473e9425772d3750a06d5a58829189cb837c2a250353e72bdbda67e95553f9b5321f2c612d84c814a3339ebffd8f76ea0f05cc0a68ac2bbc1075f9ac64ede96ce55c532b2577abe3f6307c55143babe18fdda46ee4061321e291560c0b97848634cf4f15162eb77c740f7db32e5fd813d4ff22f204f21acc1ea08f71c0c1429e6713af196cbebb325f123db8cf5579a42ad149a70c2c73411b9a7aab3fc71e7e6a3c0a4c984176e6b827a7fea034448982db802cc380485ed3785be362d8ac88749f088adf4d9b7d76bde335d03f5048c426ce9f621512666d528592677d52cab5cec6441e5897aa6e2929cb446003ba69f0e53c876854b970808c3590d75d52296f1a9a53d21dcffe29138d62cfe71746bae1dea02ef0f72d8d51f87c13ae3b89c8c005694030e02d8422f4b1b4a3f0edc1356845835c0cd88a032d58a57e2e17fe567d3b2de25807f39e02b1a74c27268cc9669c89db6dd0a8003de8b86c0744fd1f57f139f86dd98297ba72b91b18963eda6f65da7acff39a8bb6c974dea0cee5eb23693f0db0f0b9c5ac3e19c2b9648d3e296b4bc05b0d5089d149a46b67f83ce0d3658b30670a8997d430feca3558098917f00bf2bf97b1cc3aea86af2360798b835b7a2b7eb2b1273fb7dc1cce44826bc0c98dab7c90b2aeaf5755b8db1cc9f0aacd75b8463d5094166d2324cfa617427e9ee0120c952a6eced3f2d21ed28b113b2a67dd77503b436a60044ebffd334de0fd6295a0489ef189c41ffb42bbd781b28c149ac9f8e408fc609101fbfc37191aef37e37d9fab1ff5b3ef061944725ea477955a6a15c0dbcb03dcc36c1ae6b3607d0ce7833742c580b62469fb9cada612241ff8d8e4dcd4f5932212551c5e8c394d265b6c91d0c0d6f7229641e68dfdbf8e41b085189b0085c2a43143c88a205853958e524338755b97c5d760caaedc516d9246be027a44fa334f35a80ededc11d135bb62804e9022f274f34c6ca89ba4c1a2911f705b76258b94d8918067cea47230639fb077cab2ed0841d36478c3df90cc59ec76e725b5bbd9ae4ffe2e8e9a90848e42f7ab3db7abf2e9950e56249b8dba49eca220c1156e8163ec86cdc235e5581c5b2dd00d0bf5de2cee651b0b46f749e4a1fbdc7bf470e2e1e57ecef3bb2bc5ee345ad0301d67d1178d6501cd897db7b1a0f9681f1bdefeb17e91dd1a78f0b63f85c0ceb855b5550be24b2c4cae84adddde25023e7e5cbfa2bdae242f2d17a6fccbad758308a703c5815a01a3d314747876dfb045ac289ed727ba57efb53e9b9450b9f6a6d1aa286c8d4b80b0bb24647e227a3073cb075763e1e70a16fcf38ad07360ae907109ce6c058960e2754308bb6f16c6dceaaadbf322de1f9cc057d6290a4c0b25d3c3ebbd065746720954b95e9d956864499e17edc0a4266f1932220e8da81a4241b0de0e9f215d21b26713608e67006b471c349c636adcec7a123c461d8e0597fad72f0092588df8a1ddb4f17835206007a5f8aaad27152f57fbb40775e81f0ddaf67ac4aa136b1ea5b8523ecef7125365646a4ba7e82a736d5cc0a629142f98d8ac07c8a1355220815b4475845742258f1347699c04169a1ab245e082e1e985460823419dba67f33d9c5c294de2e354cc8160d469cdfdc9775d852168915056e10a139d77a8cd036fd21569e4f90cf9fc41544e84abbd98cc25753d5c3ef0b3cab0e4c22b35aec23b8c5b7ed7c0cb3661b65c61b159f619ed9d58b85b57a1a40ba87145ce58f8c28705371a9a4022e0614276b26d4fbac3a0e22a03b274a34352c13fcfbc3264f248348a7f120fa2394c42d0ce3b623ab87bf57408afad827accf00897b5ca92ba2491ea6bf808499eb420d1a8b955a7e8b09d8e9283afb344613547d73cc0c9650ddd7cd8cbaf14b64b90f40f1dadd704406fbf92a286e223738ebba4231635706b46b5a945d0e8f5c4990a0974770832adfe6639ccfb44dbe6b2b4c8ce8496836a1c0afaea297524989b783ee5f9afde3127248c55ab71197b736047411a1aaacb7de96c2321e67b4f9596d9878fbb47e96f20178de97c1b78ad067cc7a48dccae7ae48e0e8d92c865289a05d9df89d8e7f5b7a5cdadfe342e1e7ce66af705f320ba58ecc0689aa485353a0f841bb40ebe3b526d99e0f2c766da0978e1043b6d1dd6b527efb9ba3a3ae0a6a2cce962074a2dd18e5c019b2c57730974a09f1ed3c9ee080c9a36e3dff44934bf7a7339a07dc1071fc70b58ad2c7ae263089e849b57cebc57918532042c564030e9de7318c4e775c3edd7bd9bfc4a5fbff98db27367a454eef0caeaa89d7e185027888cf363391612697836657b760014ad01f76cd95ff470da757ce4bb64c89ffb14bba35d106de20bdc7755bb0a1e545263e77c4c95232a67fd6a104a602e5a7e2a339ec4d200cb7cab0adfc9f6958386d487ed0a0f0f3df6b38d76af0c3ed7fab5b5e741cadad2547ed1cabb0c72f0b225f1349b1956b8d013ed3557c5c2320e042bf2cee35decd09a2389ea563d3182d078e61d07e7fb234cad17282941fdcd5262d58b70146bd29d4f09736436ca887d376c4e89965367a9868f264a5844422c286e23d7fe2a53adbddd1cc0eb2af3784d0f5cefc7d737374aa9344f0ee173c3234bed4318833a8bc254a228e261f8350ca0bb2bc1837ed34d1a340301a34b660015cdd45ceb927557eee63af6ff411df604b64aa32cb55d8223f4ec8f43a5578497bbffe7a51eea493baf0af5513f0d88ec67c8b1c296550db0c7a9a5224e4c69a8028cbaa8061bfc510ecb1947df4a39cf75e5ad0f43e5381a580466291c5062755356e021eaf120d80303208b7e752d7e4989e53ee6be69cb1546f18be6549f25df89714ecf0edda799f2b1e6cc271da82960c66b5dec298b4575703e48ee5fa48aec9bb889e88d27dea5b800268007275e71a964000d9e8a635eee5da12704599faf1341c412ed98769aac162e3cdfc40d7f304fb3d36993cfd000821159e1d3a37c9dcb8cc28390224927f44a67cfa4a3ced99cdfe723fd899bf294e9689bae986de04bfaf92125cfca36e395411525aafa3b7aaea9ebd7e8349ebbe01b692960f8f9d4bcc4b58a3ee6eb5d2f4e3e7862576e95a1ef9bcee10993af14df309c78b1ae36f1f4664f810e875c6a9f530978385b9185849d13cc2109b746e49082b8c4b8284b8e45a4bfaecc3c131267d62e1fbda7f12918a4b24466a3db856d215eb9f6c7e1e62a4bae1b2c5af4ee900a8c7297f9aebf2a57f057eb7bc2f01bc573dc3c8e170e60ddb6bd546faf13a6e8e1ba864d6e897aa5e42246530f990193130fbe38defaafb28cf79dd1cc2618bf2863faad02268c483424915d45aee2059480cc7b780d801fe851b000437fd79ce66d221408b48a22136042fa3b305ff14c7dec1a0e6059295256f1858ca02b1504f8059a8ebac5492f7f15100af76d8e5a4b4da2bb994d761a886b09b6fb81b203d29c2f427f8e0e548e1a20619782d0621cdcd7219355ea8e11b44cad3127717a3eff0c988b959790f728a8e001287143447f09c6ff7e19f81c07b078f136310f007b8137edd04ef57229abbe20bf0dc0ab5c1e2e4c9aaa7063f27f77f2a06aa4327d37e4481b4b1e7706e909811d045ae2b8573d8fa8b1f6f96424c766c089c839b5bbbdc03c11583672c4eaa039836bf0c14af4a5153de5ba0ef0081549fa7082f871bbc6501e36fcc6266d847484bd518f95ede7ced54d3701129b0b49629d1cfd4bcc18fc0fae648eec475c9cda3ce2fd64eec770b4bb79fbb9c595f052240ec2749eba87538687a1cd5a52e59a643e3d86f97ebe5b05bce38aeb7bfffa9008739e0f32f63d7d1b82cdb7cab3b33126bdbe3725ad12c64770c75ae9372b7a1e10cc8c0073b7e65f2d0ebc964d90e98b5050ffa865147f7e546fbbf9c3d243b6f26b863953f3b4739425a14d3e30e1e031547f97c4818838bca79e5a7071585fc7f857a0b990a29589784fea8adec7685993dee924b80ccf4cc670f10a85166d66a03ba4e38842823208fc41e0184be25471f65f3ae148497d65f8fd667ad90e4c1a6f541163cd43f533aff5b64b886f926be27f42c38b29bf92980a75821e4114842f02d2562570a00039767f009186c4b6ab5a6615bb94bc811ca93ad4b9319e397f1648aa3b2210dd7fcff38996c94d34ca4ef81b99c64cb5fef89543fad8f064ce8f6cbafd3b211203a3c618a761a2d4e930528e8c11d7dd3e0e9b3d3e4b2e96c278126e738f0ad82c3044ec83d8a596035e7e43040669de3ecfc27d62d8c20adc4eb0abbdb2f514d6235dacb5b7bccc3226a8181a186798d03e8f42e73520086a2141bdf67a0292e2a241d82e4db53efb6bcd22dcd584f10db432d2c509963f662fdc134e3b5d43a2cef44a06f2e1c4c11286985fc2b8fd099ff841979357dfda653e66b6ce743b1651d1808ff9afc179553b71e1108a8e29a1ea1f8eb1cdb7b82ce6906db1f64c5e60e2f089ef7e70bb49d39fed2e3455746061036901893d28fb11ab006c84d5bed639a19783d2bfb8bf701f287eee9245c3382437d27077a4f28be92ba0b0788a8d0cd84a65d2a77823ccc42f9816f122bbeefd03853d9ac29401942310552f25f537e6ca354365c96da77cdfb7d2ab9ef774690fdc39a7801cf16eb420fc2b3eb6b35cece531e3b1a14d454057a150b7181b5876d49bc803f08424129c930424a13de17527c02d207b7c74371d2b6cebf4c8df0fef97152477ce60af556a38eed724296399143ff415a2714fd3995416889d7277c23a6686c5dbca5998ff179abbac5eaefc0310471d4284ec67e11556f61073f816691fe2afe917d3139697f230614e0b7305a2f9cedf5b7201a4333b2e2335e3702ea0ca9375d49fef0410b74cff452cd7738f45781d8f744637b8a868508f2e454b0d89e5f59699010cfd9867d0046a0cc7844cdd316026b832f9005f3ccb2df945f38540234097850b8607de88934c5e7dc7570d7bda65db27d340dd1474713cfc14b4ac8667090fd9ea75b8b21a395af0552ce2ca38c17ee138988c8c6723c5f7ae9dce7ebabdd6115ec9f5f873516c4432c8f536534bbe567c0184b506e03313b7520c1aba24789638bd57223aa651a08d0cc62558fe00792fc297ec8d07c9869b451661f446cc5228de61ba3a40c047c66296a53e5f0da809914238e6e65c08d034c1c696f9570e04d20ad0e208674d327a085c06be4a14268bebfb52f8688b43449511830d29caa7c3e19be1026f9bc013062b3208b0516aebbc06ed545f3199efeec08a3ecee39000a6ed5c52edce93399d6ed7c233bbbf41ef72a54d866111772e962842fcc32bfd3bcf01b9af1a0495771fbf5be487e8cbfa241975830ae184d91c13f6fbe4ebfb0ef0f1b29d908f3684b93ef3dbc02705713a4104abfad342e707bef03820f42edc6c512b78b5160eb05801be12f09b519e97ad620a0d657006fb3995f7f302115ab94021351fe310427804f72c3b6073a829deb3d3656b1ff6dccbe4677a905da933c8b50eb8a57162193b117c1d5df495f3526ea93f9fdf8494a233d5a4d8c5e003abc8fb9f60f000168f792f54c3ce05954053ada9a519003d5dc00dbd650e0aa273e6486fd7bdba05e6d4f5c653e25f1e3797b9fa87d8a9faf69862a53827d10d8d4815f862a6fdf5ce3c44fcb5b59fac79ea57eb51ca9e6c839a4a2010d3c975155657ab8e820763c576bb21f05eb37d21efab671f9e80dc235590b6711c14f6a058344963124fed0422d1750c6b2f1d40a74c6ae64d46e977450eb84a981b7f3594842464ad3fc4b2bd4e0d89f5349bfd13375dffd3c03e2a2a81a3b16a02be6eeb14052be601eeecd22618c87510f2257f6cabe8d64c1a5cd6d5bc9280c7d5b74b90086e5841d8e1bf39ccbbe821a5e65a952cd343da48973da806b16a61e22e9269c990bb9357dd4d9a5a173051a0900d6d68e936921f7928b0effa6c403318917b95bf4d3c3b9a03e69c856fc965d85a7b6161f7d7b9471614bca2e8df8b44f8a296eea8859233e402c97761ec9b44dbd4eed4a8ba11b6a3f5366276613284931bf41860453287cb76a19b7cbdb68da587edb7663f19205459819a9c19a959e11a552c5e9cd9ddb181fffbc86ef13970f20eee4f268ac0e273ed051b7f0b6413928abbf848f6844a2e1bb23138ba3fd6d0e417239ba5dfa5f0495f5e15f9fc1fa1d6c0c605c209befebfb4f02c003ba565483672d7e3383b623f07259c20d7c97e2f3598c670f38263e86708d4149bda64b3af084074b311aee33e44891dc0ade30d7e7a6e4d5579156f4543f938fd60e89f1ef0f9cbb2cb8d72f74c1a0431d3016910ac6f87cd8955a74717517a188c89e3a1001b52ca3038aae525e896c3c0fcf99fa42eba1b256b69a6cfbe9114ab3d56d0e0032571a4c7829b1eeef038bb90377b11838bdc367020e27abf9ca9ec194b3c41bebe383f7b0a97d56b50fa35ae96690713294d30b5d35e2e8f1cc6a920ffb78df234e33cbe1ff51694863c52dcb2ce223b43cd5188532940d7f790ccb500b25abcf60f2681db112d513c09dafe2a7ba8354a0a25a906ba861810c4de653b88fd11ac6ee784a2a950a77a1aa2a729d654ee16e3125d2351d86de465204732cac49604a0d75156836c6204b754a6f5b8312e5f8e59f51527aa21db3a34c5a1a9c5027afd4ada60364232e4a336d218c0a76066984664e78d9aab124936eb9263a74494ad32205de0cc08bd3b04ca9c7635cba7ebe5c8943d192bf4ca8189a690044a3027499d6497a0f5b07ef09fcc1fc1d8f9f25d27aa843c3d5d76bf815927efb0e420780682f86dc89c200ef8c5781ced2c1237e29fefd06da2c22076f2edaf80e2129672a8d6e6597df8954669065753afdca9408e7cf9ddf17dbea8522b55e986a0c650714caf07a15babb8d7fc69805bfd25a16cf2654de07d2bf5f35dcd440b6522f23278798c185ac188fea6c377436332fdc0474ed23a9b49b8edd471e4ba4ee6a51918923660c0758c72d19a4221d842bf3452ffc9310a41ab3dd6338d4592656a586f0d7bc7c41b1c8561c5fb08c542eae575f2fd87e91f008ce99b1df9e145dbe94df781bbc264ca6f826595ace0fc84e1113dddb70a06c30b970061d710502b00d09862f69c5c135714040fca921260f8b416e0137779c74c2eb2fa2242fa880eec2e69fa765ba062de7dfe095c9978de6c18d0523c896ae930cce664cb7b960220e1256e0c5e62f77f685c013fed87267b2ca5b2563e74c943d9edbde0826166ef756cfcf8a141c01ba234058999a85590f21ddea979c5d6707153feb2de493ec5c99bb570fbf191b0b39d7ec7aff3a6d587afa0abc5c1b781467f620cd1241454b77b90b94baf24daef503644a03faaeaa8759409c11a703df77a24c4799a3b09f07bff669cba967c70d4e8fbe563a91c6f3b0164e7f3429e720ab95f1519c7d8e6adf81ed126bafd9a581360c58533a0e7827e857a07f5824254b0dccb38df49226bb6dd96d4bb9b74c52ca4a0870089c0853d2e89eea917292c1da1804c9880c64b478937d76d1973aaaffdc16e07f511add9f031678d9f49dfe156ff6a4462cb5d40145d001195aadf00955f0a412b67cdc49010fb0d0441a5af0832065f09230010c930a80c51542acb862081392f05c0adfd1b9a8c28fc0b4c695edbaaecb8a7dd5ce08958e600b2d9420b5c416216059e15d354de4d0cc5c243e9d12ecebba7288d89709b82043a45c58818b23b8c384863291708425608105296ce0040f33625148316ca121a5cdd766d6c044ed1ce296f3c77e911265fa9cf304dad4c00b6a5fff6284cba7cf3967f59a4ffcbf1c3a64a471f92360cf772f7da99400eaf1784c5bd3a2bbefb9b12c93ec2b7f2e3ff6f5f1ba9e7e8c3d6412b99d473c71dd0302f67c7dc20302f6d4273c3802f6d449e68c73461aaf4c89f82f22f6159331deb86c0e30fd2bf7e06ab674fe9856e29038c0f1ef5c8937e6f61ef58407a7ef436e4cbaf423e41c6deca713168aa812f7c7ed986922aad0d18e3c6060dad1967ac2e086780a31dcf51cc6711cc75d90e3380edfcde3d1387a367983dc2041623cb2f620e6c25cf0c2c4d49895cf5ecfbdd7f3df8c99d6e29b2f1753ef95e0bd370826e189812106745320d0850181407f41d04d8140370604025d18096210f67910fecfc7cfbd416e901be40689c18981b93017bce08db93017e6de2d468232c6ffeacfe65aebfcb8e9cfeeb96ddbadf36f901be406b9416236b760d05a53cc9b79b8ecacbe765df8b71e6e2be69d4cdfec71f618ff06933d961f77163d1867d9ddfe6638f341fbed734c1f7367f5e24ddff778f49d5f101be738fbedb9b7736efa6acdea8ffab4f981040ac9b661c71a941328227b003b1a49d2a2d15f66f9616b5dbaf46db54f5a6bb9efd8edb3eaf180acb59f2ec7791ff4c11ecf73da47dd9ece6f3a08d2aeda6f3bbe171e5ae7bf8e671926d1173c6b1120e09eb1634d11454cb1250a76ac218266cb6caa65defdc518e30d892ef3f8b0b7efb2e5bd55665f7bf8be0db0dff9e8be32b9b74d5efd519c3fbc5f5a5cb0bcdfe16f43027fdc177fecf4f7b2bbbfdc6f3052f7f0dd7d8ef9c99fcbe671dfd371fadb62b684d957f69cad9f8fbecf49fc01759eff606cfca0b720fc14ff477f16df97cf69daf9fa9e686f0fdaeee80ffbec4fe6db2ab1b42b98a9418d8188d43eed58f30367ff606d01ec58f3c33d467e785eeb1f79f468d9b187ef6829fd1ae316fd338feb63e729dd84f4f02de98b8b833fba33ed435f6b1f3fd63ebb9fc7bf8347d59fecfc0bf7fc6741ff4d1967f1e8cfee7c3f1f75ca701feabe56fd85767d90fe2c4be8412fca71aa80f4773d1fca1f8d359729696ffa6ada47dd1d9d61d36a1ef2fde7c6837c1d9fba8c6750b05248487d6d0cc2286aa6581db17119ec210e718861108651d44cb13a62b309711bb7712c3698cd8824300e9160a4fcc9631022c148f9d36644121887483052fe04032c71880423e54f9b119b9010af70e8c32870b819b1c1a4f60cf10cc3cf8657d36042d2cb1967c94224bc19c18262c2cc981963254c143419e3f4193d7af42bfe754529dd63cc72b260b5fd258c14b2a5cea40e61acc47d4d57a9b15c03fc91b6fb5b8b493e03cc23fb6b7f9246933473a5f3fed20919ce9528e60a36855ccd154d5f7faff11a9fa26afa82b3d303dd99cee1989444e669669e54f3e4afc9194944aae68a7dd9b9a4ca95c8be7369a701b61ff7479a9901969b0463ae60efff2938cc15faa7bb3fb93f7d63e6097b235d342167e6ca2767485d10d9fe304e92c85cc1b6bfa4992bd1481731db5f3a3159a4e7343788cc01cbb40fd727efa4711639635d7f2f32ebe8cf47fd2448b381ece58c76ad6d9dd9fe58f6d58d418dd9f3c3956ad3411ac528f91117838b517aae04c34c314c99dedcc4d0251da3d1531f8d1a80b99f24d7a36b742fcc3dcd1f478079aa314f73c7e89d1431bdec8f48ef24227b7ef6a7b942faf9380c297d2983ef957ede1081c19d707a8b992718ef796cd37132a43343649e9a9834a53c9d9851cc6c31a32d6634da848c46da9d30588cb3947e62d2476e55e2f47749fa0b916e36233698d1683302038281f33431546a7ff46675b33a62b3193132d98c78313231e190c0df1c72337353823332195242fa9237c9dfcb3679f174d361f29ae47e441a8df08f4641ec8b946390f4e863ec182525cfe56f83d9259fc34df2c9976418ff227fbe4ff4a603869e26cf914aa35169447a1fbd788ea43f93e7ae1fe5efc573f3da5c0478f4743eedc25ce97e8e61ae807e3e6dcd95cfcfa768982b98341a8d603cc765ee43f97bd9a1774a7f943fd21e3d297fa44dfa2b9b98fc8b177f72f23060c4788de61d7163fc74f41cd5273be2a6faa4e44bb61859f471db114397bc08469630fb24cb98fd224b21db24cbd4be32dda48cf7289376c996c3435d06e5ebe23cd8255f806f369c2ebc00cfffe8cd9ea4fdf9ea66d6ecf9d9e91431fd1a03639a5c21a9bb0053ed2ec0f2e54b3ae99cdb8f98734efdd1bf6abde6bd64bdb08b4d7a61f67502cb179c94cea759fa20252625c5e4b6126b22bb223b92d9ec0e98d960387bded7a4dc74883e5c95f877a12f799f4440dee9af65931e943f1fdbf5473f947dcc7de9394d3ef4d4c6552675ea4ea9539b19d225ee4f4bbca4245f4fbbb8d97947235d44a1f24b371d43b8d77ceb41ee23f057634f3b9f0025a497364d7c4a3ece95a82fcc3c7d7edb81cdfea33653359b983479862517669e2e5a12b3bfebfd73cc8ea67dd40bc75948a01a528e53c575bcfef4fa12d7d7cd3ccda7faeac23ccd0bc93c4d98fd519b1aaff1297c3557be175d32fa0dbcecebbaaebfc7f7f5b98c4029fccd1d501b8ac55c09fd7ccaa2a3df4148f4a11fe5ef658fdea389b2ec3affee6f57221285420fcadf0577e873f828e30fe5cf7bf2e71beba8e323b7931eae7dfd057a4f3784f43966092977face13a51fdaf5f7b229be9eaa81362bf7dd7a9099ffe2088c2de38d6bcb57a9b2bada5ac9bd9b7c8d74efd603b548cc95cfc6ecb9432a8c116287ecf9ab78e3b3e5d723b36221bfdecc9539b78c2c5626bed06ab67c4b831873b0e76b9ccc8edb033ad6e47253d34c393ce109148e71bb6b08d5d6d62a9d09dba6a323f3add5da5ab39ad5cf7edb7464f56fc9265fab1b0432ef52cd130dfd8b35e19e54c655a6b6daf5bf58b3c2b366d7974cf0b8cdaef9d6d7a88ccc762af04755327b3e55555f02b65fdfb3e9a89abad65a4f1975e7e4d26c002db0663c0dc6a5d9005a4461e369312ecd2711a07ffda55b0e0024f4a88eaee26971964a31739a4f2818ae9001bd880631fc60e569d9c72aec0008cad3ae1c9d600590958772c113381eed8111319ee7d2dcd2729960057a2d2e1a1970428fbe8bd4c10f1a8fea2b5e740738a07765adc3da3edc74693e40122890f1b4bf34d79420e4c037c496da87532288d8da76696e895fa00116a1e7c2adf4a5d9a5062a0a94b7c4090ff2ebd7978db2852db0522ecd2e39e02c6123a3864bb3d65d9a5dea8d17a70e5ae852ec5b5c504f1f8569974b531a5781027ff46ea92263e6f95e761786f08318cff3d5ee799edb4eaac30b344de6e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4488937b54aa0583db2e3579b1dbfae767c5782b5d66a930614f4969853fb28b827b8a56e8943fc405b906891d972eaaf25b5a5dfec20a89d272ae5143429e59cd3d2ebce03e637f252ef028ec46474cf8d23615dd7856198a597b660fc9342d85a7b2d45a59c4e0f838483a54b81bf7b371ddbb68530873b50f7c11de7d96ed7755d34f1486d0b4d9367c0f1b59863ced8cd9fc7d84c991ba96ac933e0cfda6906b9cd782f467d62128bd5f3f5d847348d8b38ca1877dc2d5fe35c0958927c888bb7bc25e2639b0ef91801b6b780de4a82b76acc53f4fcd58861fcba3d20f3a2ab44ed5260cbb911fc613cc4a5aebc25e2773a9b8e88ef10aabadaf2bd06cb20ea6afbcd8eef46f047ca6cc52e8dbaa669da9491f37c2f9b8b38fedc74d81d91803fea94524a27a59252ba79e816900063608c8422089223823394c08811704a60e4660c45643b3ef1032ef0a0891d43d5cd66ed18327164d7a0ac2d7f65cb8f9ebfffc3bdcf3da741e0f9cbddc7585fed7196dff86acbe7dcc6a39dc65550de4ac9f84c8c067a00c1bde77ff07cdc803801c2f3f8b10601f71e7d62dff32f5ef44e7ef0e2d6e3878fa6d9f221103dac4f7e586df92d2f9ecd96efe2c52d022756ff106ef99e9a2de32681164ed3199f7115f957bbca55683e9f6939b8e16cf9f7fef5184785ceb2da32baca3769b6fc4dcf9a0a3acb44690d82fbdbf7bbd3b20410f20b3e4802ca2362fb1697911659a03c142ae46d9a08c7420b2128ef6a7fff0488fbdbdfdff403a477ff2402f7ef5f7d0201e99dfc70ffeae8454f7a4a7f1eb31d74d496a0550b90a03cf9b2e52cd1933f511d9c4c7f33d519431acc3005cab3fa9b32332a9aaabf1962fa9b2b0f12ac48420cca9bac2dab3862451428ef9b373896c083d0fb268ebdf4f7547f249ffac35b7a3394b5238a0bf6a2cd0e8b8917b0e009314c3001064df0b025a0ba2042ebb3a3112268810858282125dd734e777f7fb95dfb905bca1dacb64b52ca3ccdaf1155e6e33dbf1a7bceebe336d5b866c0273d98b6ff7fae4f78d8527f76cfff5c9fe6699e26dd29be825d010554f0c2f60985261fc974f95facd98101430089408c68d811bb648eb9f29d143057e2147212609e628ddf5f8d1dff84c35c21a97ed8ecefb7951fe56a06dbb7c0396baeccd374d63cc9b746c2235bca1cf3c5a55c817b8c31004f1849020609122448f61422912049b93e5aec4fac5ec0dcf6eb9fdcdddddddd6dc57e8a1d529e77e51855b6bbe3489f49b498a261af69458a40b24f3b1629c289dd79cfcbc7b43b3dcf6d0be8bce7b5cff5481c253207ff18e3db1b6fc41d7f8b37ea735ff2d81092a4d90e78f4993cc99fdc27534b6ddb51fa131393ec2592b962f29ded85a69d9cc5068c50d7755d289aba2e14bad99de95f768f85bee67f9df53777e8734c6c76ddd4d84b8b0b7d09cea752e260537622297a8c769a47e8aba42fc2f4d43ee60e7d9cf327dd13d33c429f0f89648b3e4e96d3d422516807ff18534a3d317dd2d970162160f0207fcea753f49f44b2e997b267dbf13fb7cf9f2cb1bbed90cf03fbd7248665f9760ad95aa80b8542a150a743a23765fa31f2e8737829c72d3a394b8cf707697f1bce12430bf1e97e62150b3d36b1da3d86851e0b2271883e1bc417c40de2d24ef3d018cc1689e2d680f998fee40ece42c21fe3e7c3b7ec74484f7d127afaa217c27fbe08eb68f7a2b7db0eec7974ba62bf43375ff4f847394615dff3452f83544d5e3b8449199a33db1266664f270bc955fcb38f4876dc443fe5e835cb633e8cf7f8a4277d24cfc813a1ded1c813abbd43bc31df9f87384d722465e9bdc872ce3969f01723cef61d24f01760c00f14a8c05cc9ac49cefe458e5b24fa2e7f2fbbdb21936c4a2985d9f4a928846121d1e7f02e9fbc2867afd12bca71bfc8729b783bb8e633cf8d6d12e07ef4718b00f725ba457241e595fc090070bc1600e0781608f8f1bc1403a9818411b0f6dd616a8ab7a852a408223b1a915162d3d8b1081133d83bc41b72fbf310596ad0a47460e4053eb0620c5edd18c9c6ffc974d3f111bd2612fd8eb845fa9e01dbfd49215bf4b108112ed82f7b8af2373f9441212df3cb9e3e7c83b4cce19febb97c6d3be6962f698e3d3f39b3670522639688468a1cf10531575bce7cdd05cc4d1f02d38baef229604f10a8761073b5a91242ccd38cad3d25ca3b599e8236e5b623638560cfcd07fc22c5b0e9e6836df1245bbe5f615f9b0fd996910637b34c22d1a00ac1ae9b0f255b461af26316db6e3ed40fc83fd9d9e6c3b5a5e67ac8cd811ea6245b7eed6277361f4020b7a6619746e9a5d9b5f6dab47bddf371607baed65a6bd25897f44783f4755dd7755d94524a291522e248d627a1106515521409c28e2f99882c42502a552d8bc22029e653271939c3d5d4961024b032dea43f4cd21e14714a1147c660cfb7d1b21ecc914c8f4bdd26436aa01a37ae017c47b6378b3189f4587f5fea74a741516dd5566dd5566de598b5d65a6bcdb22ccbb2cc43d05ad08216b4a0053b3d333333333373e3e2b832075f2208902cfc9f9c9132f8e41112059204f2c78edf81c822672eeffe8bad1dbf8873ba7916c9665b8b3189f47f3ad590335e42c19eefd11f3e62cfe7f44792c19e6fd272e6de40ce3cd69f7cc29eaf1de05e22d85a8c49a4ffaea4ff53f9686f71359c145c0d57c3d570355c8db5d65a6b3b9d4ea7d3e99834d6250dd29d4ea552a9548a255992255992255992b5278e6b807b896cdb0ecef4324aaf6ddc5355bc21faf99489c8926536e8eff309e9cfc4a406fde55ca23f1595fd5115558964682bb5d5b4ddb4f568cb696bd29fc525fdd120dde9b94aa552a954ca8baf1de0ca1c0cfacfc68e01f8ff54f27f59ff6782f2df67c7cf224bcac7b733e52c29fafe882af35132ab3f389b90744ea97c746ad79846b2dde98bba44c09f55a1e66aaee66aaee66aae34035c99833df456e56aa8eaa2acaad3b1aa8e5575acaa63551dabea58cf5e547651d9456517955d547651d65aaab25465a9ca7235b5723595aba95c4de56a2a5753b91686d516565b586d61b5d5baaed6d5ba5a57eb6a5d2d6b312691fe4fa71a0ebab5189348ffa7538dcfc13d3b998d34b08f8e91c655d2712be91869b88d5bb3e36b51da987994803faafaaceaa35665f7f7e210b0a6dcd97898fbeb40f69a5fea01fb1abdd7072a0fd7fe5ab08d076c7f20b8361eeafe5c348b594fe94b9fc7c0c8dfb439c9df9479913f79a322e52fb66258924517b5e787f267bbfcd120ecb9c59effc9df75832b8b8d1df16155ec4a82af16d180dc9f55798c955fe563b2b56348550070c15edce57a295d571a8e68d13b54e0f9de59029e2f52e2d062ca178a1102fe6ecc8d992b42260b9d2af3a711f074163cb1163599b127cd156d5a6f71d826080a6eed16016b737ea7f39cf67ce7adfe7e7f1fe7bd5b66b93bf973160ecd7796b3bcabccbf54a39fb736bd68f6546f1263190ec755e6df9c7066477f36f677635e7c3786522c033ce463d342607a99e66e5c65be5d01fe702a4603747f38b5e763256c6a0cfba34a6cea7fe5540bb8af8ae5efd241786b536d431d1ab826ef47a7a86de53b0eb6d2dabf9ea224a76f6cb2f4f0671af7b6a369195bfcf6b9d72cfe0c5b0e89a3b6a45beb024e866fae904596e3ee441ab693e7e632922b646173dc19bea91efb56b3bcca8a992b9b90b982531489b9626f19b07dee31d6125b4cc57df750ecb2dbe9db1d377adf5a1c9b9b1b5759591b56ca460d8a3aed56cb5524f7d94f7f366bdbb5d842c4b1bd7cb771967ae337f146e8e57b17e68a0646a01795bc749bad41b9e44319db9effbce8b55af225f21a7d8ed41b6799385bde60e12c11c826947d8b62a4311acd2d3ae24df02a4259ee518ebb4404d2433a2d7a918e914628c7ddd97ee32cf5e53b8eb3742f75976d66b62dca59802c117a2cfaf9150d734503a09f5fcf106f7000572e228eede75354bcf179ad6aa12cfa4fc636e896018bb0a8444b2cfa8ea8440443de4fbe688cb34c6dde4fa65b1480ef7188f4c91e22f5704181e6c639ee50f77d3e718bbaafdfc305b5437a48a735ac7a3028636d33b7bbb650ce323feb6cb9623bb5298dc954086a7e6d39cb85c258abad3dbfb3048c5d77ab1767cf6f997a7ef3bcc7c379acb5d7b3e9cf7ef63a1cfb8e96d876b2dd59a643ead3cdad8dd15ce4cb75c558c2867bc61bfef13319332d5ed775e5b061c38de0fad8f680ccbbdeddbdc6e9846118f6a45843da61aed4ac7eb6e9909f09a9f50a2c83a82b9b9aa76963e669be46ffc5d3349aafb73902f42fdd825d65d6d510aa2d5f6e43ac13709d2fabfc88644bcda37e44b225a532b1e6a3129051620706442cb2eb52d46c9198a7f9f20b383e0136b1affd591a245473e5b334db89b912a9d8f3adcc5c894f80307bbe55c236b1e777f7d2ae2c3d8d66110b92dc78293454cc78327a700695a7d14bb38c23658891510513284fc32ecd04e84112663c1d5a00849a2e0c37b0f19e0b213899045b849ed6b934839868d978dabd57a61ecd35fc5862e569f7d20c3a4109581e288915d03c38a4c6d3b84bf3bfe00c294ffb5c9aaf77b99ae08219efd2207d0422569ed6d5902a428da785ee95dda359061559809e26c21ed32d2e980dc23004e5b5b8d06f7121001550ded5e2427100061a8f6a171cab1b909021c878da288e46d3a3b9a40533e369a2924bf38442083db8f144200417c88420fcb10a810f84007ada0b24645a9e76722409222b4f8341c51626b0f15cea4d13d260d3f2b4d2119821d4782d2e231a2f4e1d5cb815a948175acc78da5351c4082d4fcb426a6a3c4d3fa10222339e86422384d08b4c88c206319e26430545dc78320910245a9e66c3a5791251021aac3ced84851095a7a95c9a651126b8c2c6d3665c9abd09d8fe490ff5b3cf340fbb6fb834c72241a8428da7e15052220a75a00fc6c1e408684882a6445641a385cc680747a0f134d2a55902214286d0d34c2ecd52c8cd10623ced050d4e80f2e2113065138f90052222125a47ac3cadc4041ddcc49ca229763c39664d9804d0f31c738b34220d33083d17ec0a29ef1e090315319e4be7870cf6d763ba254271850f40cfa53231e3d1234ee841e8b9605aa008500308dd228f70448be5b5b898643cec5db22d561efd4b9f0071bd06c5ca0832f506e10910ba45a2408b31a4bc96eb5d302d501e7d4db7c42359fca0c66bb9b40bb7f2301cb67c172c0c3753872f8463093c083daaa94ab7602308d2f25cea8db7845b81e5bf789244f2331c81734dec1530507d01a6c633a58934a601aa5064e5514d55ae32ffc5f329f0c9f5aca3d226e6c956edd97bf641b77d9aab912ba0bc16fa2e520a5d58794b74fec5d3720c738da7fa5fbc1c5e730f19bd1ebeada634aa2af0178454ed4e206ce23c424c77777797d6624c22fd77200f67c29dc5a43fc9009970e903eadcdddddddd4917f41be8e3163f206ce28490d472265cda64486d93dae64971daa7dce110619127a208c310e545ea4aa552a954ca0808822088655996655996d2312e089bb819cfb4bb896c08d55022cab22ccbb20c044110046fce5fc9a227e06aadb5d69a65599665d9e6b1d65a6bed755dd7755d94524a2975777777d3c556abd56a15ad0a04411004c1d2cdb22ccbb2ac66201b9b8eeee5068adbe793e3be4444b7e4ba147105d3c4d3fc0f0f618a1ae189e6553bc618e72a664707fd07175b6c218b1d7f4221b2d469236367b08a34697e86a71a5fd96c1eeea3bf13487f39ecf9b4036d1ece84419265350b2467666666663a217070dcdddddddd43b761839aaedb99eaedeced4c9aed786c441af30b70c300a41b3ec5a2d8088b3c11451886611882200982c080200882a0e88eb44f099b246bb65820168bc562cd13b4b63fd5900132e1d294322cc6dbff29fb7c4c4c720695304afd8a3f26ceb3499604b1582c168b35c3b02b496deb4010044110e43e209d3bddd2396795d73a0505622e3f1014dd6ab5728e1e8cb9a236846a289914abd9bdd65a6bad3da5846eadb5d65a10044110047366caa7110dc3300cc3306badb5d676345a6badb5560cc3300cc3dcddddc3300cc33004411004c10b044110b4d65a6b6dadb5d65adf5a6badb558c91d91361d5d4a6edd9b802f56521409c26462de60c79f32882c72266253e6c6e2e01669a226789a313566cac6ddddddc3300cc330fccc1c210397dae6017d38130824b5cd934aa552a954576bede40e5db26416d20a1209eb8341a7e9e1d41ecfc7f3f978729c5250c2224f78147305a384e1294c09c310457b714f723c256ce2e66aae3813f6e86f2699d6624c22fd779c0977a01236a574252dc7c4cd959c2ba96d5fd2ab9964cf97b6c3a4077152db3c9c49635dd21f0dd2f4f3f1e0fcd741a758cdee0d43100441100431ac669debe16232c7300cc330ccdddd3d0cc3300c4319340cc330c4300cc330ecbaaeebbaae945b6badb5d6cbdddddd4f2e8c1be382b089f3cc546ccd94877b93fe48a6c7da4b5a82328ffe3e1f4e7f262626ad1700c2b8fbfceb3fc5b8539bfef38cd759e573fed7e8ed50beabb7bbeee71bde34c362b5633b9eb98a34e6cf2a220d2b3e791ef90f2e81a1bbbbbbbbbb7b383993263b50099b7e7628574bb92d5009cb10499c9b2fb26ce28aab0945a18c300c4330c8ee834b527f6f4f1ecdc99c21522013f70f44bf5f50d6da5a4dc3300cc330acd56ab55ad67235b5e5eeee9a8c2b736ab8eead568b0ee9aeebbaaeebaae1621886611846afebbaaeebfa4b55f9823e25cee3607450060e04db6ab55aad1b251e481c9a9a74974d9dc9d475260f238df95ec49ff028ba0f97046e0abb3ff6f3f1540c5473240e937e20f98b9049bc7f9b3227c51fdf8b384a1f5f017105f451a250d50d32e7f3f97886e880075a6e48814cdc494ea7fa5150a297673c55a5a0d8709d5e98b51d4a69ac663b1eabbaaeebbaaecb29a594524a29a594cab8374a1fdf0311c7e7e3b7c415d09ffe933128ffffc954ca7f121559d65a1c4f3bc698a577332e95287e3b941c3d99b17ddd2e5f5bc3347b25d6a155c33a1eaa8abb94291391c6fc4fa63c9039cc07658a7283ce1f5c02fd3cfdbfa6377de2f447b23b3a8bfe64cfe73ce33fabbc3623474f45e55ed48c7cc37b4eb908179477c3ab6893de538e9e27635bd3cbd3b939dff09f1b9eabe1569d2b6ab5e3c91169743370099472038abea8fb23dee07efe2542e230fdfc0b64ae60151b4a2669a3869c3745d38bd98b4a31e192ca09456ba74b29a594d279ba9f1d9f8851d0f82fdaa8fcff17593352fe8b2b6badb59abc39e3f0da27cb7d51b37b0d876b5576d3fbc9756bd7c534ec7ef2f5791c5e0587d7b2fba95aed78b6b7aa7803f4f32d13f1868c9f6f79207134a11fc87ffeef6f10e9cfa2e88b7295edd1c838e4e82a9ce953b2a673f4665c90e9e37f9d1defa90899c4cb0f24e5ffff23ed486355ae32b51a2e28476fd5960db7bb4454ee2592c38d5b88594428c4df9145b2b049552c1b4225fd7d09eb0439abbcf62a02b82a9555559be98e56ef6f1c67c2a5930a8a4eb9a80b76b4bba5a4bcc67d3e2a32a4b6e51c9146f737a4783297bfc842c9386757fb1cbd0ccad6c35d14fcb9df89443a47ef94a3f7c97153956ac3b8137525a492172fc2300cc31494aee47e2eb92627f74d6094eea3640d0305e5b5ff3fe5e8a5a098c08061ca269da26ba835586badb5b6d65a6bad18866118865dd7755dd765d25a860d324e334e38541c729665599665d65a6badadb5d65a2b866118866136aeebba2e199b0e6dc6cdbafba972738e9ea6dd40e3a26800d4b81a2563f6ea3c036546bc8938031840adb5d65a310cc3300c53c03c793bd2e87e46ee5e25771f6fb800a8715372f432000230809bf38c143de35166bc16809494d774d0a107b74b8f92a3a767aad65a6bad188661188645bbb348a37b53eec81cbac7f9ce53f72ab9fb19b9fb94dcbd2680fb0109e06aa06cb736800bca756b3a5c9da39792a397b1fd397a9a5f50beb6b6a2d9f0ad7311a62429b9082e49922e509ecadc3a17a15fbb713fab3c28cb9d731142a8c8ec4eceecee3f4b8323eb787a70fbf33947ef5372f41c04411004b32ccbb22cb3d65a6b6dadb5d65a2d263d66ca2df3d43dce1e9039745fca1d8834ba5749edee4f397af72839ba8ace1da594524a6dd8b061c3868d3d5fd3e182b2dc5d969be586116786355313059304f307175b6c21b2d8f0eb4665697048aaf9d5c9c659eeeeee6e63d3366cd828d978acbfa8853ddfd3655445555445551d08822008829b0ca981b86d0173b5ea6acb3353de722ebce52d6f79cb5b188661188681200882a0b536a2daa8946e961435ca14a211000000005317000028100a8643b2388f2439c30f14800b6986585e48320e8986c128c77115430629438000808080c8c8ccc40902ec7a292216d937b34ef0c70a37493035e0f43e2e40018f44d3f5482e11fcc385f7f69d1fa6b94bed491bf5eb5eff8779a09c1e7e8a00a2df7e2ab5d4142af5c927d1104537a6dc9ca603fb6c74b12ba059bfd434691e5963252fc06082ec6678e285e35a28af82e051596449a66690b76b829fa9fbcf713794c929f746f63004b71d40ba00e8ca77b496ace688909d60e925d4676860e861e860e90ef6222a9b8bce2d5652451211ac347d21389a2f15d488fa8bf53262502671b86ef2095f806fd74d1b552153b5239061b6017b21c49ad32219cc2015c945f812c3dd98125e91457835f2a2578d3c88f992b9d404b4e69b0e10c2f83bbe34c700f5a6fa781250936375127f6c6a58bf2e08fb933030fee1fdeaff8dafd442817010ee4030a048c80a9c558754b86b6aff8a3ac5653276c92f19959d7f34a03670304bb07d50185053c62fd0f80d918a397ca87f75b0e860d40f134fafd189e055f28ec60f2b55cba9a89b0239eadec2917a5496f9538243649bc92b1d5b1612952476f8f1f4a86fc6a5b553babc81027e8daf7f5d67cb2930621f02accbbe865fd7f9c2d9d8e49d1dd2a501351c77891e4737d7ac3a2c111e372e589376118443e31c2c82d2dc4473c8065feed7a879e300c55d25ee2a534aaf2e731fd7cacef4a8aa455440a45f7cc5b9ee12f26847f0967020102b226f7849901481415973f225580668925aaf2b64f4e00530a02cff5174c171a31b71da3b0b0509869c9d0eb69f56952888b4ee55db401e25d19c6add34e7874acd2185494855fe351db811e5e6468791d0a6694bfaf7e66d8e5422e152257ecf9cec96b0b0ce3593718bf0e7c047830ef2bed061af890ef4d9e8604f930eb90586117f6a90fe3483e8af3a88f31884d07238bc31cc578a5e7e407ee0d4e15c033b58e231dcedcd28d64397147932d96552eea0449c0939459f50a47b8d1dda4de859951552b450151d42280194b877bda42d4fe4136d31625a5221a928e353ff22def425d514e28b11dceac2297c46d59dcbf3b8faa2ec72d13d3de48d9925dfd2ac2ccb9c455918b107c00e67934df944153b058a19872700c4da617f463fbd082173aa888022e3d634b473b093288b115bdc34aa952a4f48e1bff993abf21d7b796ef74fe62b45cef810843b6a30337ba110cc60e88f95180aa6e9792531a6d612b7194aa942b4b08ca365f3ab896625d59e47bacd4f733e4d4900e2c693b865f953cf2a4f3511e1772308c1b265c65676cfdb7a17aabb3f61bbaedaf4149be03e5855f848d13c123f52dffe33381e9376eeb3b6e79fdc12e9e08da5af8f3c18a7f33ebc2fe9229110607a90b8c51934c591554512e897e9693661d6fad3d78a8b488ecd0b90ebe81ca3c4a7357fe29d197a7ff617722750ab95ceb666f18c4a0a8dbb60b1e94f0c87bc4b4a54ba84e2892f89024d0c31dd8c5b2992bd2bc857d0dabed4955eb376669a17e41749434cbc1037a45de18003fd48671eddc87546cbe8827e03a3ebbfd029679b68982f7d05b10f5cece3b73d02ec6b3a45390873fc77a2881e7870bff32c37f30aa873cbf8e924b5b88acb94bcbc5e939dd7b3387d51fc66898118cd01f53f61e8c923c32f857dc956ec12d8d06170d22e3378e6359af715beb4ef9cf0fa4aebe90b4488af9a98986961da75dd5bba37f52ee49e46146ada98080395d1bb40d1d4678e0efb932281f49f3e4862664cf7b52753aef77cd04769c395eb3161b2bc6fd6a7b99c9bc4447b53185a7c69d040a4016dcabecfeab77aa6d46bb1c70a4ec865c249c0379c1994af2af4e52870dac5a1f6030a506d54f07eccce1aa790d177fd96294364dfc6f089a2517d0d099cfc404424dcfad1ca6d48f2c000600097ffb98efc1de4a4fae0247154b1b6ca20b664903d5911c2faad50e38f863a147ac8e1486de7b90d3b04c00adfe7c3a2322b79b11e45a0528f90a7af7b2079aea573da3fb6eec81529cc30834ef07fd8c6c3cc7d7be28a72a201d0e156d6455cd22740448eadc93c8e1441681c5b92dde7a85860070a6258fe6b17b51d3602153f6e1273ba2d415bb8094d73511212298badb0f56f92929c1b4113d34509ede190b3dcc4a692fa882d6f959c80954cffac6924285f5c9a046ae93e21461764173d44fc1f7bb1eb991a321e072e661c2e089e1ab1a373e046031357c5e45ef8f4815ae05febe9de9d25a786ac638156e9797cef1a634683fa6e0a14e0079d5c3bcafccdec82f8b7bbebf16d3b9d296ef749ea7699076fb7f9ff7625c5e0ee66c21357438a742dfe1d05d683d7214ddc4bf05a0be874daa91dc3ba74eb74bb68eaa84c6c836c98c3ef508a2e3f30d47c81d8ca3602e160dbbee4d68574926bae692745984553f7dfd996fce83203fd370f38dd9aeac77c6db7835aee4a3b287d3a82c92a634f8ca98a27f1f759bf1a5e0f84cee5a0ed1ff77fadd1ba43eb38b3ce2f72b9e3dd630640c1b86ef30af9243616c340cacbc6a7f8d413495483aa1ca3feb2b731731d65a0b71f96d24bc856fb083f9296c3fe45756b1ac5188379d4a4d40d99f1d2066116ae4bc935a6fd890a281ac922bf261b340de064c6cd6fb8a2e31ba9347a832917deb04babe8f4a2901f5c994089d0413b7ce5800b08087bfc21042bd937f21c42ddb66e649a3476d81ac481fe069596ceb67d3dbfaf7b141f94451f9b08558701afd657df7a3fb722e55888eaf69eb4dfba4875233b8061161fc62f84bccd4bd2cd68d0a72ced77bc523852b7d11904a5c250da184c0cf079e287f6dd1161fb065940bd3e28db427cd56bec4cd6ca96ac566771ca9d47b9c3a75f87ce73d7711790a77847978407204c35f4824b066482d94c7950a69b24350ae2116f7ffb63494ccaac71c4711bfbfb54db010e8e140b2456fa258024a639f1bbef0cfea22d84683987c0a504d80aa166abb9dafcb118dc3f5145373e4dbc1d2f5dbeee1a2ea6af0713f1b134261e29750c34a5fa67543ac704fa6090ad9eb03453f6d29ca32842d9832083d3a9453690d58a020c0d03fc99121423ecc03807d40a4ffc57317a0e708ea200a1a5ab427569e980147f8f6d71764ebbf42ad3695fa692e0268951cac9f818ca7d3d92e36253be33b4b32a4fe92241a80cbc392c65b3f8b32778d3d4270196a4e61ca6e17f7625fbbe79fb8da6a00bf9b3aa810842dc0dfcb66800c2fb63e7325ca6ac0344d3d6f17fdd7530d77f1d28d0c38e23cc83710c79477a473e63c0ea830f83eb3555ad492be11a147229c7f010045e8cc4205994f72220d583e62bfdc3412bb15e130f78b2a8ffc3e6e5f8dab9dbd30e4d5f150880382d2c2c41fe492f987d50179257d219790fcd684b0eba3aa1e083adfebea69cb827f093a0edb8790894b12635882d44d49825851a2e399ab576a3644de18b4fb197f701bb796fd03062a1a1538844f86c620d6fec25b81d8d04137446308b92fe7b5d318c2b963387c6771038dae56efce5d081ee892c5ce94448989c884ee0262283dd4b99d586681e40b09c73e79697b9c04a1002a78ad5b8a539fc888722ae62b9e7a9b2c7a3fe3e78fb0b8e99c3c1ab5cf10ee10c5ed63e0c4016bc87ff3c392ff932676d8688eb174c2a2b861ce157d02ed661f7bb487d928e41dba907e7ca785c8c2224e3947d2a0122f16e821f77b8c78e7213c7af86a8dc94607d75aa5eefc01a0f254d1c63ccba140ee7f53fc2f01a4cb13f353f4f752ea7888f050d0cf9b11f0cacb2ab977ccef2aa2c993a589c25d153725c1814a7d5b8ae5185b59a152513f07dff094abf8c69002d7b5c0e6f2f8c45fcb766e3576105d31f4e2de4aad483404247ccd8d84e9fc74e214d8ba270a66d499fd34995eb11c6899e1e00f0f079ab990a5ddb78902d8d0845a1dfd975c6d2ba9dad95a71b4b5cc8ab14066f1028f854beef06a110ecf29ccf8f7033e5e903bef6f037146992b9b7c542cd00769e8392a6736cf991552129c21d9faeb0415a87352bc0742e47873d5c4dccfba484218836dc49325dc1931c28176375a92c73c2c41ecfc976db1255dba1e53a91741d94b0519e14eed1fe41ac187ea7b06b7c3947ce9362bf3f05e485b6d77c60b292f43d49d6921732544fdd675cebd3e31e3cb6174d09162073f5cd2cf1a46f1d1a726015a1fe59ef31882bfebcc4a37f554f007c1e48e15548ec527d6045b2fc002b95ff0599a3f1a474fdbc3f958046f603c5568559de557787107aea45d53dde4de7c4b9a009f4f454c6a6bd15fc9049cd395c43c240cf18a49cf446c9b5cc7df6108166d9dc3e30ec261fffcee449b2c8964c5c27de690694b7144099f94aa8b061354eaf400ef14ae6d2ae484ef75d4413fc080e6214d11501d940fcc3b572e3660344d717e28fd69bb4cf4ae3387b95d495960a6d105719cef6966fa55cd2cd41a4ddbe823891d606e39f3088699893d1f11d23d3aa644c8eeee8462da370cf4b5cbe0dc9b592674b7ac489ac474cc48e3ee8ac03e71c505cbbb204d1d4a0ca67381e2da4705de96cc2a21ae0c3b52316576cf7a4b4b9a443f985637a9ba88acea962e0c3efab0420cc56c9e501ab12a6584a9504cf389558081546360f687e3cb7e1c28400bd0b17dfba721de231fb873a46ad10818545a59a04f58854fa8287e486bcb7ccdec9fd45e4898ee2f048b25ecec7916fef910c139bf0c501346ae40502ae5b218e5db58b81f98faf6cdf77dfd8ebd51d9cdee8bd4e25313ce0a1bcac63ac60291cd2dbe430ebdb4200116f6782ed32025bf51b8b774c2027527fbf5d3ab15142fc63849daccc0a9b34d27971a6b71115413ff2d5f017f02db57db88f3fc6151cdfe7839544dd44e27865f0876c4bd4f3003fc5265cbd2e81ed8f8e480b611de5553d24d8e5b83bd2bceba353acb1adf93e76c5360de91ef000fb77958280f31e19f8fb42c143951cdc91c01bebe83c3a4c0fdcb43aa63c08abd644b320fe515e60592dc886fc01f0b887b65926c4dbf6a2332db222460fd324a46b1cf62dacb697322e340cd2b39a360bd0517d570a335cdacace168f5682dec53eb1d6292faf3f70cd6ab51f652b9b8dd34712b8970d81ed407ed6626fdc943b890eb085e32a2b38219bd8b9dbf3c0abadc3ef642451340a97aed999c1d9496fae05735b07490f00e9b843a6bdaa73d01e528a84b402ca9e255fb876c5d29801b16da8c24778d465ca45640b954a8363dc8445553932a2ac7fdbe43f5aa9b0a42dd129fecdbf89abf43dfdfb7e1ffcd526757f0b76f08fb00b948c66e56db93b1a6b8886fe6fc73f3977b181cbc68eb6c9b05ac41a088aa7ccf6a34c31c13a769941c68d10c77a7348680459951d2dca0801d08156c7d36ea3497682cbad6e51526d9ffb78191cad2146bec5f026e38fb754464160032ed4376eecd9d8115f0eb08dc81db697e159739b8402ec10c1f6646dcf703c66bf9e6bed10c78fc201c61cb3f6ea9785192f178e590f0006872cabd01ce96c70a030c070361c0e281c6137b63f3a4c5548e7921ee970244b3af10f938ede8fd2a1b9d68d2b4052b8962824c4fb6d29322f6807e5a6e78cf3b29e0f3c0d276197331de70ed88667be4128da8d62a07b09ecafcc0010967fcc2c10471cc6d48080a40ea1071446447fb83c43c891affc5498fd1119d5ebe50678dc982ee88f9b21e2a849dbf2964891367642a295470c770828f1bf2bb15dbd2974fa19d91fce19ccbb470c38273e8cbb5201d166ea4d22260b5d5862eaea22b60df2df0b24178952215b9bad9fd29de4598bbef0bef4c56752b393687da8d8e20f9c510c32cf1b10a537e24dc69480fd34661e6ee43e6225c37dfc8847a745a8431dc2166210ab07fc10e1f1f09f1ef881bc5bff2cf74c811cd0524f6a0f91892c9fde5e92bc33767662e285daf829ac88caa325fe71ad6c101b6549201cc8665403d94030c06c56f58499dd7647a8593238d236868b6b93b3199f2716c9cff87641157b3139cb88f72391357cd8418963a592502982f51fbd5eda0d89339b3a9d0238a9cf2a2172df03b616531490d820e4ea38f6a24342ca014d09f939ff8caa04bea9e74139cb174d4499e471cfa985dce45651870d1a555590cd911d96986dbc40794ed56fc1edb33fc50c29f35352138dadf42f54dce4c179828723efa87b788c797de74833778bc5d16e0034e7f2f498a56d64fe41821981e09b8051a559aa36be174aa34a18ce08eede665b559f8c7bc54cfa50f41f527be3f8aa7e84e88fa2de14eb91a802eab3ae77d955770dd2ef12cf4512498b98878e5f9396040ee1d6d6c335f68343f10899556b1c60a03f387e26e947c2b7fdb91985f946185cbd82e763c38db0609e49086f199c53fb2cf0dd2a8213c4a9b339c3936780d6167f3095713663869104110ed00eb6186897908bc3209cde38cb3e20523065612e368383fe9b972d43fc362833b3e2a008b5556b7c48736f275f6d0ef6097bdcd9dfe5da9b9fc7bc68dbcc484fdc7c6323fb0354b4cb7d89be2424dc3e90eb7664f435f897b511f63f9a307a9f86addff2130e3a28c1d47ef78d45e2f58968a8580afcf056c0bb0909966feba0527099c38184521cbf03324494ebb4bae39e7d4632846774d538da3ca3064f54ef6f54aab597674e643b1b7ab6fe68c606ac435addac0789e78d277f40dad76ab67729e5d088b906e204fdc97fc3a013d27490c6f43435966fe35c85c202d8aa202df180319facb00ebd233668b33c57f7128e2ddacd0a88254091e2b5d0db122192279332ac77bc438ec65c34c3848fa2a55b28265d349a7a16a98b403ac08c8b06bdb127cf6305118a2d749a28ff29c398b73b3281a93db4dc0a2c87824c885221e9f285beaf7e708aab207c5cdb6c73883318b06b2e4a09df9fd2184a056bd4a4cccb9419365bd2894dbe4a244f6c9a408191ba0bd6822abe564dd3b70fbea1fba2ae7349ecd7f9164ca0fdcd24b2a3581728fdd661efe8d68dcf3693c7ad56a7591ebee5e839588c9962bec7a25a9c30e71159c419c552b10009c45042b8134c717af00ae7bcb2624ae5846bf77849334f5fe4a5388d45b2542bbbd285ebb63091c11e6801f54b606eccd111b68b7e69cc1aa45044b37bbfcbc27c406f54573fa97df0a287b4bb30c22323c1e0c3e1145366fa6c63f9d7abaff603ad223b04b3fe582b818f52f59ad84631835d580409303ce4d507f0688901b3967492284f1548a346d0a9e35bceadd40a9be0f2f23edadb8dbd67de0cc99eba6ae6858455d91682650eae87494c872265a84a71dfbd87abfe1c8d2cb890cd21dcc858407b81d94eff9a292c3d603c3097432ac3ce71737a958bcc8d4338c43b1fc9e2c9f6c79370fde21d30059543995469ecb59252f80f7b6a5af2e9e28ace36f4243980fab113f62182c12801b2100f1f5eaa2add43c37bfa3d4458675b16b1e01e0f7236e1494ed94c12ec17bb9f8fbc047c204ad36c23a1816e86fcf80c8ba82d155572853310323f92f1f43e6475b8edc06c7d452c28496d1fccc327c73468c0d3aee12109e64441aaa591015286a38adccec9898d9fa278cda50c6692c1cedd5270c75a94b17e29a878fa0ec4dea036a17a30945941aa4328c501679a6a3a0a642ec46d5fbc84d98417d88c04d121cd8ed9cd32f4e8dc14059533a13ef20545ac16a9195dbcc32fcff8b926f009ec6c9e96fcd9fd21da99549be6b599b9a91eb9b4488f2e8471388a45aecbda1240b7ec9dce6a39e25d9d97f57014a6895cee1b0f6db888e7fc35189c822e57a1f81a7d4e49d11f1d931651306fa74821f0202da220403e4e62b02eae9ee758bbe8e57b604e72d6d3f9a0c8bda7287af47f29ac3af5eccd81fdf0b7468c10ed6042178a0426b203a1fbc7f908198092acd25a857d00bfe466fb251e6e72ea7dadafd87d188ccf3906acb0886074cb0579c1e14359ec8e2e5d53eecd1b8a1423948409044d7b60f6d1eff56ca1cf6fe28fc61a6a7f928649a50349e96f30c21723a4784c8e29a2361cb249318e1363bd28549b7af41d2dd9fe63d337f4f5ef4a7c08bebe449d7869e0c7714415853238652ae81876d4a964d03fd290f8333c8478c85ffe6a7a60b36885f59d8cfb1121c9cf4c95103523cad763bab3de4fdab5f4337d521c06a761f4422321c4717324c4f26ef538c1d26f1030d57b35c071e1c350c960ad8c80b36c9b2cb96a0004eaaa77d181ee955cacc5ebdc832372ed2d68a68ac9e66ffe0ec21e76d82f9f2e4fde41a3329e0270824cbd1cfcf70a2a88862d78344bfc4792ae9603454a2887df3c8e5ac9d913f8edd23fa44c2e55380015009cd96b26336b36d47423299f2705b77aa964b664c91ac15826770dffe36eb18c5d71e4c389ee20a02b512b1400c9e789f964d9940a68e56e27e4a526b2b136c8561f3d3b6925412bf36bd2d82455625929a3aed8c8ca89782235f4bceff25fb194bd37210e4bd87e981bb6233b4a0e3b29ee66b294abcf8fdc4a6589ef672b93de26c5c295bc184ee6ff1a2440fac593000a2e22e1323d7d4a2b2cfdd597f1c258b59c581729fd93e5ed13f84dccaf6f1537993f7cd85546e88f0d307f7df147d8aa040bf6f1adccd21e4c46581d916ae2d52178967dc7f901ca6267e394e6f762a5964dae4a12fee64284abe2676aa183a3fc51c1fbfbfe203010d19762977acb89c2852c6e8a0ba8f4fdd44ccfd6dc4aa90a9b555d830d0896e16340a7027033207e076808528a05d80a2f7305801cedb1f624f58f5e079efb5207264a909710054e78104319a6a5b254f24f900cd2929e62a8459718c8043a2e4d4954ec68586ad4cbcb61932fa452b626147149cc059187e937b51d1b3b0a0a750a40aec2d7be421f6681c34cb98ebdbc4537ffb2d127b2f7bc8e7e9172b308c5a69c03d9cef77d10ab1f5364112e732d78dde274c95cc37d818b11537ab01b01d9842e217a63a3646434cb2c8f8c7d6ba52cf6166c25efa521daf83beb4746be0fce737e4d0440fa66e0ab4900506e370ee4e122a197add318e24a0cd00b705b32d1906af99826d372ececc193c5584d8c6fdf52be80888dfb4faab749dfc3a8b6c8bd8a14ea544e16af850a2249174a45497b6135ca4645ca5933dd9e12395ea723fc4f63681a6bf6fe086a475d7ecba742de48e9c978d396cf0131f7996f242684e1e549c467a9794a8a3c2181d3caad1b3d4be1f0fe1d577c649e9d6d86426397ff38ea95d3d895973cf52769ed56234ffd209a66c220ca9be353c3cfd0c3c16012943e5bce216ba4c7699ab589a2b55c5c6b87b4359b95bbffd3239ff40491b06f65581a432c070eb06c9ae66ac36ae3fc9f2f56f31ff81d3dc8ca7c4066f11bffc4f05619923675156d3567ea6baff39d35dc54e911e225f67405b9e5d43ec0afb4022939be3a54a004618545b1cbdaad43316930c65e84c89e27342c0dceae51c9c3a6ca786c2686879d1452e2780b400054e63fd0d001b99420085bce200f50ef073c1f432c79647acf2074a031dd314a4b264aa98706536eac1091e5ce02b369652485a8a9235aa72ed705982c4a8fd8a2acc72e32be7dd1f2491865758d11646a1874f034b335ba921d3fe487eeb1e207e5e764297e3c778eb0e287cccd7d297e10674ec622d2090cfca680c066a749fb7349020d46c8ed721f283726bb1372156b666cec43b1e669913f12071c3eac272ccd6b9a61194aae10cb2589aff4772841cdb8964843e32036f36b15b49e844102227b1e86a5cc37a18bc686f81f1d37b65c5dbe1e15373a474d4c8da7c637cd021e57ca00c1bce901e56e49cad30322ce96458e593235ec892ea7b0aafd2c1412134fc88fc17b00f0d1cacfd045316acc5c164fa0faf50ce5afbea52f47299684fe02b8fba1216ea9672bc282e5b2514338bb76de7446c5115588189d649f6e1df777cebf08ec954aca95ee7506c0169d9bc224a77084fa93d8685e077b89c60937057926b829ecfd969ad96db7c4b634706658a955f3a81229d231cd5b3ad2990d09261d9398f655021729bd705bb9a06ee11213aa395800bc60be668a8d04c943e09336d099f038a72913a50c1602eefe9557c84d83442b8c600923b01c5be236737352eb6debe7f02ab85344c75a71734d27adc96d591d6eccbd8843330146eaba4e041496d0408cd59095431715c518d885470233a4683467235ef04967fab492192f78956b7af641a1d6b694377d9ba814cb2d678424290f47d60d2909bb9ce24f312d395909ff3f42a5749514a068d295a1994b7722fe085236a0e12f8e5a4c4630616e61a4e0696c066277a9ed2d008fa5ce5c9d33c59c49280fc7a06b52b3d40e3971508a5207e6a446739e05173dedbf392eef769c20a3607b3c60b8c5cea0dc3fce7f7fdb84c713b42667c38eb89a13d56bbc2559a395997be1ef8cfef716265b0b9e311ee1327c2109bac4c4df06b59118a27768169a86dfde4f7d34cbfc0538d5e1a61014ead2a23c65cb42a29f25a9f8da94b945aadde7bd2d8a50ca4ba966af282923edf70b01056a9318af343275a9496ab04283220897e28c7859d1afb2622f2b3d018d69bd42563c83b35e088f335aec8514688671f996bd6296c28c1c5321899611781472eefbc0aac08f0e122a4761406ec99e2c94218a749665df14c9206aea886ab8e549d57b6f50ebfa8cda8f627989ec72118fcbaccb9ea5521db685baccaee058306cf32ab618d71369219d49ec221511ead929a52a2627a7f0c8f62bd2e7bde3f20817751492d02ebc5bdefdc9e3dd9d3a9d3d89bf8d3ea5064a0c9f52f669ce84f70cba9879ba1968777eddf33a19e0cfe9ede41e0a19a1958ab83773e25c09d166b6c295506be65ae6c19166b6220f05178855032fbaca488644398c094bcf45d93c9720c9a6bf0449012de955475a704a900ca4878e2aaa4597144a1095e599ba60995bcec351e4469e80635c6ebd781f997b8b58eb3abcb8b032337e904404a25e80bec4386c18c55b6303ebeb324d9549902d6b2ab170f4f3d97a1a7ab7981751ae31f8d5c5428471a43e0d77dcf160ca8464f44af436f3b60ffa4e69efe47502bb01408825983f711580ae7645f7eb3a55414f39e28b8483c24811b9a34302a5284ad2b8b2198edaca71889324fbcc910c51434f29aa46878065102ded4f29a3cc383d578eaad516da120f60e751ebeac48b8d193728dab0de53de919c4f938a1b07e78e11fd720535409f30236e6df3d146c9fd11638a9d9a3ca9dcb3897bd28160f23b96464b120c3d5098b23061cdeda15eef8ea489da4e0b4af38f29a605408515d9b04c9a6d29e0b98185c472e481ffd3a52c26ec9de3794abbd36d66f3947004b50f050a6bc6c366b13e8433f03380a30c502162133672b719c807d36a78eb83ebac609273f8c42850ce19421f7f6a69f95315e9017f303ed81fb82f81e3b318a1bdbf3c660ce0f2933d2e390ac41ec39f9dd69f4a0a5a69140cf00b996182c1caa4db8c6f438a14bfbf64b53adeec4cf0c8a26bc9aa72c1d4f7dc6eb8c42faf3e118459c47d14b40c9c9d7d40b4ae46071694dbb1e99a89d231424db4113fae302e8d0cf7bbba71867e187fde72b707e520fc789ff7b6a17e914d09429c3a0e7ddf180b93fb47e52a2e3eec30d4b020410842b7a37d9c8e19aa13362b5d585c87ef8570f05ed89cacc3567b27f7640a4606847a892efa08bad221b9e83ab58c0eebbd726b6938872986523b59b74b2846d2b9335295e285614060569bcde6bf5494adbb59c472f7a4524b4aaedc8ef7e2b5dae5102a4d9201786d0974b08472a814fc904344379ee20903e69fd6a8d7ff29f229125539acaac5f299ccaa9a54aa1017ed24bb215e40860d166e1ce5f331fbabf846e4611cf5710790181992d0d8202a36cda1fbb21936f33a35d352db9789e64cccfd59bf4ada442af3b4c57abbf5e66af62cae2984fdafc7294c4760ac47e56c8d481e5f9fe1cd04b03b9a7fa5c59ad17676b48514d240a7371ca93f3d13404b8c864287cf50fae9e182bab304eb9ad6d0f54b65199bd005f4a8e67a37073af5f10553a4003261d88610661ac8a722ef05b107bcdc63aae2b852ee0ff862567e9187a2c553b47949a5ba6ae53788bb1b89fb18e8877141659c3ad3d25758b1dc58bee1c3b6259440fc556f852a5cf9480d2c06015a8fb70e8b6c6fdbac07b4d5b67b47393864e6bab6a7a9de1a689d698164815c10f6b3a386ab5f0258a262a0415ea68037db7deb0c7068fc7b33edb3f50d3a2f7b760a335e9eb16dc3e283a9b4b4f4fa531252439ad2ce7761089f6a59fe16533cfce98aefbc4df83fc61cdca2e2c5ac4fb3dfb813593b35d6eb49f37138f81be1a26051b72b320d61f067f13f88d06df8c6b0c32607e128e89e28435bf8a09a2c5891257db05616c9a287e3135c438e7f435f761e4d470dc43f2b99263790163b6138707326ccc81d0183ead630522de0f30d1c23d7d13dc8c8d8552241e699a740b9a269a942ea102ed05c93abe145b44ff1f2c337855d3664904fe77c3a60068d76a8d6f1539e4e38983316ca4e3b1c40d22180c903c4f241be3a9eba14be6fb2e917894301f0f82b9352e9d2ac10e6873fa18190b5d016f63f5753c9bde70da00e84a2e04dd14487d4414d348f3d0740511d8425dad644a5816ab0797cd7d0d0ad4114dcada96f2bd5044d0fba9d28295fe232b19e8139767ad4fc17acb58cfc2700b6a20eb17fdc9746cd37cce60910e2399c3c3bf761cde1ec1d61087ef3f1c143d011a36f112c55ff1d17d12ab6fdcac4e36fc6fd08fe8eba1133ebfe64b501c6974e79b19ad1d7a517d3e385d2529a4ee912f0485d41cdad884be8f4736b0ec23226d9b26845a8b05de7efed9dd079f8ff0eb23acb80e14bf36b84bd6e956955c5c821b7b4577773c27282dd158e728b4812b7c16be050d736ef5d081124530ad1545475bc0fba7cb27dfc9a71d6e03d172d52aa1be0389b36921f3e36054b3571e57f73e22dfb088887ae019b89d3778ab0907fb3a3108d1d4e63521f746cc0945749e712c5d7e514b6d9b43681cd459484a4746c715608e1119b83549fa754c193308f450a0eef8b4bd83717a9ab861b2073e0634560b768deadfdc69a06632f3f6c6d51d0c222276b0aac9b656e7353de2a033da3b0a95ac92a99aa3b05e7849775529757691dba208a589b25b63443ac6f0fa48bb8e5fec2082a4311cd828dfba440da2f9cf141fdfe0685b0ae37a127e7508282d67bf1e89720985050a3753611f7669e2a976791538db803444bb9461ed18e892825f497eccee70628839964022856f44490c73c18163311e58e1a0dbce731f234154876d02e56d2057abee794bbad1a3ebb2d57be2d40dff95c30f7091c5491226ca5c8b6e6600a22dbb69fdf452d3be4eb5baee02880d9e644add2c76fa6a3e9c9e5fad4602c8d9c305909b91603351487973ddbe86676177a8f6f610b61a9ea5ad7711020f5965264f10dcd973eac6af98fb80aa2666c37f3c5f3723d613207a066087b134965e5136ff12bc8673cd57b8ac1a177230356f05582132da5040b75dc57a828dce26926f742f124fe53477bf4c5253b132414a22c2c04d4434b243e2fbadbc52f46d30feee6b13d7e0d859c405bdf24c3b8aff304824d59a780ea4dac27724c962eb61d8c48da43326e0a5e99d43dca6c22bf0308d5de3d06d81f19475e70d047abe4fe002426586bb6c0612061cfb5d76c4c7645662aaa7889e28258ea58e28ae5751a8766d73278449e472e79318676668a7ee39e3028a59f4309e76adb7ad47a50e9b04d3005e9e546f78f1165a12deb570f61dd7d2cc88737883e22c84e1429c5a5b7df1f6cc49d0fe3e0a33d0ff011232c3affa8f492624960b1f680f5b38362e026f2facfc2f1749a8944d5e789e3b6ecd161aaf76445897484eb2601431ca147c928e5113b84f2db602c61592c32f82591b1891587993b7c75ac02c400ba2498a6d91ac6c2f22d30d8b8f70a4b14575eaf41debc8c40d5b519813f292966167b90ccc8556ed370ea496b1099224396c1c18b4f6c1aab71fb8226c37949396d6db0acff7c86df0b2c7fe6c265c683f234750ba696ac9ee05491b34a91ecddff8f73984b9e879330c2d0d918d91c46188bfdb3c9429d97e6cd2bbb2cef93f0938f7471dbd8c53fec6ddfbc3b229d5b38d71e1f5b4a82c45a5121218eac026fbafcd0baa32e3755bdfa1a79941935e1054baefb04881c2caa6ddfa59feba253462245c77a09856c1f9f78a3b9c608fa09aa792133d4803bcd74b47bacecd129c2b9171bcb9b6612531cbf5e27bf12b10e03ea23d1aba92f832c52abd07c9402bc2c0e77e0de71e8e3bac20632c23ab492183a9fc51567dbcba171ff37234045d5e981255ef23bce8daebdccf0466cffff3101e4f7745fe434fb87257711f138ddc6280d21de18971327b5e4549c211157d22c30b52718de675a862f0521d81fa5b2842576ec12b7f2c1abc070e042bd32187a2f1a42d313fa228829f42c9d3269c32aaa57d83e5ce9088b09f50e1f2c1633f494395f510d15fdac435b587d9fc37183385dad9015e18cf266683a87d319e01e569f72ecc1db51fce47213e171018cd6e584bacfd00057d28242d0be42fea03350acf413ad4150e5c34a1a00701d5434f3736f74e903a5e97f749524c500f1e6661a916c63d95c2d95d91d8025cca1c81a4fbe16d3596d9098156847e8edf8b263fd95cf68dbc79af06bbec2b9ce0c22256ea28f983140882383848b4d8acff719e4241362f55305413e29423814622bf8d1db6f2c6ef5814f9a9b2463747d4da066952c97b52e94bd75f37a48ceb9303df919e29a1cf5b000fb088e9fa541cd5a3c9c9b9f0e97f7c13d41f3f05ad122fb46cfdf902b890313955a319ed8deb0e30c846a01617b2a7bf4d2f4671edd295507c8d05475681c23d70619d4042c78f983bce002dd1712aacd1a360e134fe0d11ec846cb9b1eb1903e9026d44e1a956de33f1cc6573671b9c66051eab5a76e3bbebd7954e44afdb79dd2af4f76125cc8fc4a401b942e60c5802f4e9f089a2e5f38e51f06259b4a33851eb9bbea5b9d64a705a4e3c7c084cfabf72da7e4fd8bc55e737b394f745c8f4eba29c24c4dc92965fdbfc7dad8948edafd553426b3143dfce62791530a7aa981505c0d49d5726f91eb7e754598a41a632e89c54f543a2776d426e6c7d9c6977fb48db1a56b38ffe9aebf1d8c4639b2ed94313df47881d3d5ab9caa2bf206c227ddcf43fce02fa8bd53af45d0044581a713122324317b45c47b7c3f2adfa195dc5d3c6fa80ee7b16ea67b76938a253fe94ef14510864cdb538c5fb6491fdba42d82dd2dc2de7f19dc8d6e6311154e80f27a7301e53c754dfad417c880b5f236eefe8a124bdc19e25469a87dcbd404efd8148063171cb39e4368e6b7628a63c2c61297d299d57962e3118610b0e3628d35133f6451f3559796f8c2727d13a63bb8b915a93b10c9e2c69899637703888ce939657ca3ac20e30536d73067f45b781f62f7d358e4af41a1b1ef139a4fc276554aa30ec27cc960039bb632ea30e26c1644356c569af394440dc1718367d4930d207b7e488e60dde1a2c8035ff621368625fa4f208711027e8120e083fd7bf7661995c60bbbc4970fe38a65edf5271053e221194087ab64952057506ce86dcea6fee1745d1aefea166dcebd2459d83498ee71bec665d0f36157488dd6d3af237644d9d25272285775abb87c82cec77bd605c02ad7874c4f4d897fb4475959146e1b53d2dc106396ed718ea5371707072018dab3d836d37b9644be0d9d347b6e34acdf0ff84dd240ed38f09d57109a35f0157173d5dbe64247a8fcef8e6fcb6074794688c223acfe5037ea3830818f7f946d6c511448d4c7d96370c02a9cdfdb2edbe88e0a5ad232885f29ecfa741e6065a9983395212c3daddad2d1b50d1639a987113293cd6c7e066fd3dc384a706179861ce8059697df18a3246b6138a6ba006dcd1ff4589e331c348e9314ce7196b1cec67b694a2f00961d434bd6ffd31cf4ea55a3968aa1cf7a4f2305e6a939f0b1b8c3c1057de56e40b7378b0a8da8f016d775d46bd4f04d0b437f5df8840ac5cee3bd624ca97d9e6f8fa469562e568183d0de685b4a0fcf7741299a8971a418fc323a5a240e14f020850a2afac2d966074daee9f1b7104eca0a0ef344bb3d2183bc2ce693a81a9acb804498b1dc8469df25199132d62825b91265a9d353eafaaeb2ae30a626d153cada29c344fce52d44e766636dbf0bcacd2c4b9ae6f31e37784320ba3fb7e2ae6f9fc1584473947080a4a16c9edd6c5bf1d4dac1194a89ccd6590da35d8b77255374374bb03b4b67aa9892cef64ea41e65e098758cb45c16e7a4d529026a12a65a8538779622e9ab1a6491b76969446c9808a17c836dfe018ebe6f0417f55fd67d6f562aac286b9d1810db0bb06df95559a6216d4739f68b47e36dacc549ecf364c465d63e0327e9cc2fa545630594391ddb716ea91b7d29eb64482e5c7b9f173bd2c917fee0b422ab818b07b7772b0cad4c7863ebe7b0d8f8db3a4b53a09ddc20907a8c6079f734e0ecbfaf2c9e6430bb30fc0d9ced86c6036ac50f4b15011142519908867d82b0a0242d2c01c683d0bfa071e18e27b4ad80c085a500f27a595b9c3614a709550807193c055a135d28f4ca2bbc74ab2032785f5f30ee3bd6e2c45b58a171dcb48a622e91c06e49b996b524a3d8805fb4b5d1df6f3e7cdbfd0f0641a5023d01919a4d4ccb8a593dbe86d481a0b65c11306570ceea9de879f85cbc48a0b3a2d609c72671033e0906428c56a941a691ea7b050f8cbf4544cc3f61fb65663025aa9d77015f290cf5cc0b4a971203d5176a95ac17b7eafaddbf350d1aed26cf3162fd2e718d11cd2af2d613c6882c390c40147f194506a8aa8619bc61c9f07088823711eceee155133f25f175e7c7a680be75c4883372588f0b08b09e8e0ca0c2889c46f89a16114913c6b8339b306fbe43f701208c576987cb1e760a5e81b549c43c4ae79e5be1077506e9ca0040dcebab656b1f5fa5b94dc450c2a72914af2f07b7fe0bd16a666ff480fac5166e35cb86fcb0119cf11ee23ac1d1645c1df32815d136b1a3217689bf4a58c805ba033874c4ad84283ab0ddd2693eef96462dd902a94826ea4097f61972dbc08d57c4e843b941749250a20b069df99dde32dacb1bd7bef7899b1e1cfae9ff130f59c140913ab9391539f409c0a6af1332dace4e48a7f00c113aceb50aa78991aee989b711253add09a13a43eb5c1fa52bffb7a9def60fbad8e0859b70296682eeec2c4421f990bacf05fa0538d5848818990d20eb3a6185cd971c221870a8ea71124e14e057e3a346cc17f0ac8187aaff97f4443cc398934ed2fd59faf8e8df11d02e48abf77566d72defea17ac10d910b03676c56e18d09938338aba8d9996bf3e0a2594846703850b8eaf715030cbb25405fa74aaf030676e81fd858c32c8e653c2b77d78c5a567bee016e26dd166a75454cc03ebe97c199f267ece51ac69ac9024183ba0c701d569ae9987d7f2f5be9140ea92f491d2f6056c0e4a5d2b1bd683c14d12b819eae547024f925146fe6681cf767686eedd8e42fdc71009b9987c9dc1a1c556b7c85689f253682143f0a6cc908861f10b2a2668e3a81c49c9bd944e23429f639db15e918a4fa93fbfa59005e38badf10ce47d1106ca978ab779841e78c4d267296bd7ab5e04a133e92b43c3685aead8c944502c67c00420b1d2d01e30fbf64bdc1d21fac30f40ed8019b823468ebc463f9a298047bd3c93e5ba417614dfbbbbc3e7483f012cbf886bde1bc3bf2df3bc8ba05857c0af00b2602cb7a3f07a385faa5180892fde8123891deb7e3c5ccf7c9efe0a55bbda82a944151c319aac45e4cf6c0ef1875f008f6dcc8616d8e23e891f1e21f7e67d3c54009925c590fc4e04005d3b02430b9487220d71e02a04e4eb7e84cff15608679d233e3c4a10c785d3694198fdea34c78eb189c1930c9b2b6c70a828a367fb9cfdee343eb745c29c3057a1d0831c39ee03903767541948e9dccf7a6677f1a123104b9e50d948f69f4775529882b8c3235ecb8ddfc37f32dd7cb34c62e643cbf739b766103a45ada3cd2a66b5c9a1c5063626a4f231bae2c6dd90f4390b91469470ce7ae16c5956bbfab3b4406d0d5dda81c566b8cfbbd13d1c7a83561f2bf0ea66db82e5c3ba21b3cdd5ba24560983594aff86692cca17959a5756d2ddfa382f30e0d229548c721ea6a8c6ffbc4059270054b675a4b9c1809c7db54228a8f431fac587958d277e05ccab6a39169ea1c36665ce444e1b88391f178c3c68b4237b524e0e44d46101dd83da8043264044b810a1232779a7901f1ea0cf717b607de9a4b074cf52b5ed6488a7df5719a2e2c11663692e4332ae6541a970b13007ab392a5731c297c07b5e0b1b6ca4f92fb75356e8f7ba223f7e55c6ad09fe1ea31c23c41aa9e9c2ea3d40148bb50e85e05262d75b4873a0e061dccbbc2c177909f9e6455abd89652ac4e44f0438702181ef25e554c8f1fb16034013a77c3a67995b390e99bb9a91c0e0abe14d6894f894479e18dc6eef03c3a2b615f95887ff275ef8835d63d8f767558997701ea116188ef81a5ca97ab116f569ca9c53bd597847f198a5a3d078c99aceda7b29b535191af995da6ef9c30f33da3ec9452fdbb36734a9e7bc5bce186665768e4ce35644e062f47e63441d010fa6c002da87fa27076b0e91fa1f498f59305836b30f50a7a8d5f5138369b549770a02bae10b2179a36b676330b649a829856e000be938653c4bb86fc37374983929856cf300afa740475a7884c19bd6c40c84369558fcc1a010d9276f0cba37ac2b00063b308aba822e019d3f1db85e1dde1792e3daa6706c16c7e74b03cd2af8df53c4db2aa1ad99cd136846ef33183222ecd1ebc6de24c472036c2d217e88495b3c703ada54a021a2e9eddd4a4bf6d27b027099b869b8ae46743f07d1838c48508d2d8be6735a9ab0f105a40acc3901bd917b8acfa1d570f7e30859e1d4fda0ff531992c0b2bd6a7c31244ff11dc3dfccb4cf324cabded7f34a8447ead15d47476953aa38ff96ebebf76d612a323e002d9d4a12ccfc014d4006fbcbb9bb11184e18209a28691f357a19c48d72c63a0a6cd223f125d101ea1fddf92fdb9d107bd468706227526fb91c22902f8bda86e3573220d3f7d40110d8f74f132fa154b8286421aeec02dc54b421948cede215ea709efa60aa88f1b437771d05cd4e370d44d63ce679c8050637704f4e448bc80ee32c01a588449e9583c3f0f75f7b600c7eec665a11f7620576b8c380d843c31a1be3653b54a07fdbda685e7e97e134adf56e36bb2b079e263139652eb0305d2beea732995185fbd90b10e2e547525c612897f0fc3f426b09d9106527af7a0d1674f224d5ae16653553956e6c2175b83c208de0634f6c93f0832b3cbb933de5f2614d71b1e10dc80a141b1d829626cb02672073814e59c04d01b074486b31f8cc3324aa88bf176daabd40a971b385a67e1a55c34129d1a00f076a36f3db3a999a05a1a00b47315b3756a9d3657d66c2d95aa0ebe9aa0cdee312ce9159e89796171e143ff7a08f8dd499de5a234f833d87d3e2e7b7516ef5c05973381bdaea1e276d2c7614788179653397cd8a6a29296443eb72eae7de3ed287e8403713e87abc8a1e4af48dac344f92790b931a946d839b655f03db419615c490fd464d31d0f07e46e07da6adcdefad28ff0c9e4738052b9e95cfd81053d9a9855153e6a9b9985a9d534daa1bb28aa5e0a22fc22d09437ec524ef898126b6cdbb07593145fdc4df09a04149289bf21ca5bd92b1b27dfb1df8f766ccf1afb2b8f42a074af233ee19615facc18ab2ee548ba02eda6347e50ac27c4871e90678282ce072c9059866b651666866d6db0e0412394bf509c8d9ed4c3bc636a1d1cbf50cad798612e5be2887769e25faf124d5c2aec77f3789ad3840c43628e707ebbe3f21e7f1fd731d8546210c231d14330252cb9077dd361033eb46419f6bc212b21723a9dac45a29cc6a01822f243bf4621e379d4e826be7ba01994b8d4dd02923b673819e0eae71cc423274d63c812dedf200f42cb3059a60d21e4810b24844f66e27b195218bae6333c27eef52251c4c1d0ac1b9f8b0ed4f356dd4d4e745bb23c32535fdcdb116ae774ef0f8870aa0e4297fcea43b9dbc17a8dcb34c04e2ce0b33c31d3cee0ed3931e01c8ca6fbe4210b495b438b9df893cc4922cf8b2576801048ad127aca9d4beee9eb11e18ec30bf72c60743db0affd5182058bff0b0bad4c04c7d1548af84a5d987e515b5f526fff3cf3f2910134353158d53079c5801b455dd170840a9ad0336815753ead38b5a486d7bd94a6f7ce3a234f563f9a4dbc2d3626392b54733db137cc16db63fa09d18b6edabf801e13f4e9a612cb3970029237b32e03e55863f9925467679d81dda8239a7356e416534ea57ecf2b5d03498a076ce2f24cf02dcbe14b24ced40c609bb166640cffd4fc08b85c93aaf67064be83479d204abd11630b15ee5623247a661d5759ce4afa8bc4c04f6321060cb054888703619ca80a7a4389462f040f7e836b9b9c9de5bfa689bc826162789cdc57362cf0d3f3a0006027b947534c3d019f4e77ee71f3a80cba1577260c4d8e97635b7d90d82adb85d03d96ecad02705fb071050ca1d569be593a70893cd30b7d2c9c300ac75fe2a840b04aa7db039d0e89e99ca2a485ac092c7e9072104b9f5a0d371118b45e0ca1a2a19a52466e1c9ea64cdadf0eef6a62b2a99212ace9b984dee4e1269176d3e34e946fd4ee0fb63edb0e07ffb5ed24e56e36d167b45f02b69055a69517101e01db5aca3cd13872bdabbde3f349a972ad0792c5ce224aa4fe50a1131acee621f32091dd23dec1862840684146d749eddbe161948566a04afb30962c5d0e0b90413468519ea22c8ee254cc55adf86f3bcd232a933ee127a9181f3c3ac51ec09cbe19201bdaed8dfeca06e63dbeb1ae8d2a5cd5964d08429b93c86e67357187e5a72d50141c4eeef4170fd40915c6127ecdb700aa3ad3ca6990f67101f9f9d2c9632db8c6f0995c52421eff44ae36745c31cf1aaadb1c5573b8320119017c54a5e3aca06ae2778679ed33415a16a89ec3d09f2c8283b46f1ff06e43deff2677c090156eb94cbfe3e42bf5a44721840fe231268a58daf96208475e998d60f523877c89bc21a963b9e8d39848efce1b0c0a3e0e05ccca148571991718327c40ae417b4e5c46c0ae30812352c6a11c88c479e65f8128966ea26caa3acab2cc827192d62e7053337a9ec12c9d1a928fa4a37a6eef299c5d8de600df805d95dad7b1ba9157074487b2ad2029f5266bcdd7f538d25059caa5af1fcef5446e84047bd9c62381f85a7a8bb0fe0bc4ad617c5e268e916d6b91e6c22866ff69575cf23b18382edbc1443a4af740ff4e72e60d107948765e90437c9a89b3c3c0ea2a12cabcedd28f0c091752757cdc2969e37025cd203e3091da2f1c7b536fb247270b13772e343016d80482da46fdca55001f6b2bf0a8f9ab52b4583a403933a3609370aa855899a89e74d9a95e00e02255a8df919c6308afdccf99704f471a9392ef38725baa8ffa88b3899939125e8e8681adbac91757c1ba49454ea6a3aad875d2cd8d2e34015005a9aa2771e08d4cdae393faf907f9c404addc39e8e9e67e344b1739426ec1dfff54e43302813a9fe9f2d4465dc2661869c918821d732c3ff84bb0bab4942a7f906755995fc3a92ac1b650b8eff2b30c77dc589a48f6ccffc879d15b34f2c0a5a0f96eeb75c4e0148fae882901699b48f8db04a6d614bcc0821285cd3325c3842178a844a9e745e23a93fab580d6a161dfc4e196d22e8bb5cabfc7e9fb83a6a9dc149ae85855dcecbdcfe3f095774457c66d26d7affef91e9612c5a6a143f2f088359c1eba26a167beec78de7f3c7044da721643c0bc0062a59362abf119001d8f1a59a0855b3a56cb418e9d792f8ac25056ca035cafff40c4283abbab16f819ea18d0e69bc482d5f0335cca0a7727ccf144d7832950793c0f0454856350542ad4b79948f34ab779f6c2c1b08871d3e9b4307e5314b32bef574373322fe9177be9c5b1ed5a2a0d411b8ac64c0616dc056f5135d29b42d0d019aa339fae3a9d68f7dabf0b0e8857638db9ea3b6c4e50dd3c16697a18872aba78c399e6da21de9817006f64436f1242194cdcf6aef0bb9b4b13d8f58ed28f45ec2bab6eb4dabdda69e3512124596b72b2d03bd6e31896f6f0b27cf6a373829feef31da9290e8b7375a010e4e651d3516bd33fce799efa4e116a3f3f244b518dd0e1a8259b3b006f65514bce98dda109a9e787eabc3cbc8d77bdb08f69e4adde84f54d513940f6061ba423a6262c7e84ca58e313cc3808d0e8a4243614fa8895276c9bd1d39603741cfa9c7602fe6ac6ce311272396816ba3f0cba259721087354cd78e1af2db1ca3c9ad89e96d5d52a3f83b39db7f54e6d314b4d8ed35b48de53ecca231d4f0243322766783e4fcd61e496493f48a38e00ce0a00c24a4a589986b0153204e59c15579714989c85b006750c6779458cd4e886c72b800417a890717b422420d03cc470c4c9a1e122645604f56fcaae168ece361d05a7e75834d1be80428799d99d8eaaddf4f84308ac71875ca57e98539e001458298cd4a4b876421cdb2240b82c53a4a4cff9bd6543ca8eed1a26391def16f19733682f8c310019244e5dbbc62adf6c2e4f19b55a12e7a681f647e868186cf0853df10e223d6e716e66d5624473108786c820a15e7b16dd1755588114dac2ff6e38362c3147518b1b23c665f965fde0b102b3fef7398913e7bc9207c80a74f8a558b2acffdc4122bd8c3ffbba0a8e2edcf198e2009aedf579d14cf1565bd5a9f8de3ff9a633bedf4329539e2ad5ecd454f767fe1ec3bde20158986e70db005b212783fc55ddbb215f0c5a4169bd060bccd8cfb421ca8a48e9e741e735323da23c7d2a74ec445a89f50f5bf21f7256199131821ca2f271ed7afc365880674f000771de36f7c32ced0ea88f984b9af2df0a0661ff2fee17c62b33b82a0902bfde21ec8ec32bd231026fa32a67c9ad3e64ffded12e57563ad19e8a5b2016a7544564446715d1051a0a0e4ef43cf2603824c26b623111041365fc7a15dd2ef2bd926d45169d7576524f27b1f0f1a172424097c325e2b7c6751b8fcd28c7e304cbc3f2166ada89df2f1fa4a9afd3ae881e890bd2b6c1bb7fb9872f2e329f5ae303059de42ed750095fbdaab806e581cdc144d6d325e8ab76b31058b9bc9efe84546b35700bbddfc66df77b1987e79fabec95318f1771f5646958b174c04bd173052a121afc6f221cff52b4729875ef1626f600a54d8247fdc49e3c2a0bff7a45b15f708908c0270b4252cd9ffc659b694b5e676581891b17bd5ca2d2edb861acd87822d2eca618d649b087fa713c3ec30e715fb7852125f0be672f4e435408213b56c741999215f235171b2209cb3c289675fe0d97ad6db2d8203b1e316297f124f1ebb2ae4ed1c1837d9eedfb6f381c43b6170db958c78a392002faba0e50c7c8711e28dca0bfd8ad81483dfa03fc027017a28c295f32d0aad759efc69bf341c3b61e9a0d83a2355df2be4f11271f732c7e0aa4af05d73c7c12d534b462f1cc5a44ab0eacea035f0399096b94b4ef47d641b5cb1fb6ba887083434d36113944403040581c241b018881b278854766b2fadc195d7aede115443b26fdb218e2927122cfa957636663e300450a5ca33fe7b3fd39b5606c68b063f362cdf0e60b04b52c2107c8b706094a47cdec7c35ebcdec08c194ad741c36e99564b5e18434d301c0dca6ccda83b2b09a8471b028c02240c2c00fb874e1d7c17e9b84149912ee5b0208525b8a916c8a9761ca5a46f2db547ed1e1660be12478999adbe77eed76dd1a4a6b9f9f8edebb0f21384cd08fd2dc37fc44265e086d0f85b36cc47e04c43877521acb8e36a0e8bd8a07d10718fe5cfaba07bbc4a917732a3edbe268b18f1c990f637d77f331ec9f12cee3a9ad7ffbc55e0ab8e961c70d7b5f9aacc0c6904ecd9649f846cb0751117572508f2bbc355fc3158787047f288c388dadd682284ff29c71018f9e0383ed3950fae48d17a103ede16c8675ac032c9e474f98a0978b3b91f41a42d00443a4f9401d1de4710f2d1ecd5181537f378b890470d0da2213489ede720ad72326d8a265150033e5cf0524333794dcc0ba99911fbbef7b76e39991388a2797ba9ce56e0583ee054e431c36dc3ab11b9ad6757621bb0a4bac9dbf0cfbcb8f1baebdf25806d9cc0095be168f361b4489fb4187e56dcc0362b733dc0c747d6a036cbce0ea6b9a826da6c83fe23ed9dbb1f3cc3f246911fbe968d29dbe4f88d7b315c6a3faa292a0a1a31bb93f9f61fdb9e39596dceac341f3f5ffd4fbe7457f1034e79457a543ec5198b8fab3ed231dd5a4354336fc7a5fc0529806fe92138c95f57db86d739c3bbecbeae1407437980344614d41cb6eb8f83c8a179d83af9b60edbc7c9fc797009a4399d069a1786bcbd888862e871f8383bb1bd3108b33896f21c7e2610d0a70e64690723528af7e1e1e0bb1bde64b7209e08cbc1c8503974186f194d845174ecb0d2865b7ff68ed79d0ba0210bfa74bbec4999470bf7e39d89493981056e922085048513b22b2b46a33295419385b0ba977b92344cce7ea942ca630e98dea2db2502b0bfbc3f65f9a92bda3c2bf2162fe6c6a1e8100207c9c0d5cbf27dca49a419b89f33767e85a3a52d43cef601e99a4dc3e77bd7062c6ccf25cdd8208c91667eba1cab0e07ae3b087cca685f073009e1e2e117b7886d73a1593744c364c676d260dd59ef05c30f3d885f7d01f3b562730f143cfd031d2edd71568af50fa7bc93eb830a86652a12bcd70383680b73205a017b3b34dd3b4362c11217426c5529deaac60bf3bc24131d6acc6af71f005bcecaa7ba5f035fda23d785b534719bf18c48740611ae096b7c5aeae4bca81b6ae445449aef6231c6785ab63c1acd43e9b11e4e5191089695e4a02baa20ed2ce4ac1803b0aa2207820a38e89a244b6da21439c24d0786e9e0a5939209d0c9d013ec00c42f761c92b249d8087e75108bb8a8465a3738197872fc80236dd0163239cf50ba8766655eb55c801f9a96081aedaa09b18307c7122e2616c101751441442a2414d03df74efa832633567e8074cef8ff9e9cc3382a934c7417c8129a9cf827a41c02cef47aea582e80aa59febc5ccf3eaeff725792d3eec1ae4ec4147f3a714510c13aa052860f8139ea3d57195420ffe85bcb4a458e0d2149ad026bb8dc6565d307c64f160cc003f0da8d06e077c4bec767036387f384433d8454574874e0a24fedf21be6918c5c49227a5c6a7e482bf418ba689e1332ec681206b3639787882776c48c5caccaa8aeeceafe67f5ebb821e198af74b318f56e5868b422d620482e3c2687dfb1f1e739a94a62b3eeb555719450c1f5db60f039040b6943587186b2fe9ad563abfe79808b63da723216b826b8b51fd491115cb13542632d09224706582051196da5b9db76e37815fb715b03cdbbe154ae12f768e52b48b5a5a4b80a87f4c2029a0b7a6658301a16a5033d71da33244c95ec6e7f832c5f2ce967f95a2a126372c76c239025b743ab6b69517a0378f8f2a885737bde0211d63f731400424e6f739f9a63eb357479abd99b023d69dcd4da3e9184ec2d37915bca94924c0176068f058f06ef3b93f1f514e87b79aa9d945292415f8bf8e1c0630002e0d118f4bd14e8fb6b1383644495929330b593524a9b171a496a41a1efbbad4a270308c09381fc7cc427b3cf2fe1c678b37014766b28d0f73a8ea05fb5ee88006a7c4eb41b241b2c2b2b2a2c2f278574d15129a48932cc655e21f9db536da86b6d918300f0189a9f10a24f067a3d3f555d3c4eda8dee489534506c1723d960f115959594ca3f59303e82ee926cf0bacbca11d47ba31b33d24aa25286cd2b94033b8212c1b59f406e1f87d195bacf09dc987d7eee27f4bd94c1460d732ee6dc7e5bbdde3ee3cdbdc61aeb23f43dc4abfbde440c40ba94dc61d04e567ebbdbfb5bfd25b78c3246cb3118dfb32411ed04fabe9b405fca8892e49352aa686eb160fef249b8d67e471b185c592957ca58e459329b8536fc46637c0495cc47bcefc74750af7c047d95bddbbb9ddb6194a16b629968f476d4391f914c812673dfdb65eef687a4eefbee2e842ebf9c65f1c0c186158dae68f4ba78ec4f1b76310ccbb24c24128d4623121d89b2142c655ea1941469a5bcbd71da26cf88fa38df98186812ba7c922af014501434ce094c500212d06ec571a8b46216e3a33cbc2aad1fd4927d2bb3799c1f415d4a190a5dd7ee9c18866159962de442998d8f80cac5f8f5452736278661d8a345342ccb44a2d1882ee991a4a83b52b9cc06c356b2cc66335166b3321a8d7629a5241289a664369b92b260d47d1b78ecd855515159c96c56329be5565858586cd8b071e3c60daa691a476d4a190f5c77635a442d2d2d2d2dd09b5bdeb288ba2315b3b008bd317e22918b1796b084154da398a43c4ca0efb10cc8a8ee53d57d5950ec047363801ffa2544deb7d05b1b04fc439c1119e3bf4cc92aa1e32b62ad587216b0b887da8679bc2451d781ba1bf37e63687f3f3c50e0d4aecb03c4b35d982622fdfede9c89887f7ff73b6722c245ce442446ae23132bf4a020b784df8811510448d84139b764df088b8b3256a8e6963c23e07b3a73a9f7d0f776988f5bf782be19488457e87f81c7a406732ec6430524eaf248a1892bd4e52143a76e36e457bef32ee40d68376a326aa2aa369ee5b19ba6f9c76c405ffed21181ef2404bea30ff84e73c077df80ef4e350be22d9cada9e1f9e36a6b6878fe98da1a023c0f11fd200242b400111111037e9786ee1ce03b991ebe3b21e0bbf7e13b2d01df51057c27ebe82194add9f1fc50676b6476f84ec6e6bb1390ef9e87efb42042be939547c3f0d31cbe93d1e1bbd38fefbe7ea7a1bea3956480df25bdff6ccd0cffcfef3b5b63c3f3f84ea6c777a79a52f3ddd7141fdf69350587ef684d29c06f0acd773233df9d6ef8ee65f84e0bc077b4aaa840f9ee424a4a356dfeeeec64ea7cc984de4480de4080de3c80de3880de34e02608ba2319c0759212e13aaa2d80ebb40782ebfe87215c27a300ae9309e03aea03d76908e0baaf3d70dde9005c27d35208d7c9203c70406cb81db84ea662a069ac20037028ae723f381db81cb84e46a7001c0e3e6a7a703cb84e060a0dd7c9cc70dde9068e0b00a76393e139f5f2927a49bda45e522fa997ef645e36ec7fb350bc6a2929cd3efbec3b992ac366a9364686ad867fd9b2ff2da21a4724c211e188704438221cd1773255868d867fd944ff1b44b56a34528d5423d54835528dbe93a9326c04f8976df4bf39aa839a9f366ddab469d3ef6464d876fccb46ffb746594124d2939ef4a4277d2723c326f32f1be97f63d4a849f3a78c9aa47ccaa77c4a8a0cdb0cffb2a5fc6f0f85dda8b0accaaaac8a4c55f94e26240a800c9b0ddccba6f23ab6abd6b059381bc34fc31609b0c5d4c6f0efd820948de197d9a0cec6f0cfb0f9cfc6f06f8bd2f153c786e3e7c3746c2e3f19d3b1997e36a6636bf9e9988eadf413623a36ed67c4746c36ac9521510038d7b1dd08015d9e317eea0b4795206b2b4995068f9f14fa32122d5b9665599615141414141414a452a9542a954a3e3933518a0e1d2a2a29a3179a83241ae9e8eeee6e15d5155864a152a92696d9a4fccc48a41c3954b6e65051054d528eed558a91b010dcec895f55454fd151b413bd44ddef152c0ddd919d847b180afbfc04f54de3e830d95171777777ab542a954aa5c2c1c1c1c1c1c1119154728854a89652da3618984e51b12ccbb258be4cb4835319bdd01c3c786cd3f0e0f12aa48d4b51e1f08bca8b8acacb3e7626e548c1c1c1c1c1c1c9b1bd145ef18a9df0170c8668341fb3aa5782f8d11c2f23514677487427a33b22ba33a23b2f7487eed02a54fec896658d46aa2bb0c842a552a9542a1cca612b2934cd23187477b77737fc7f8174e4dd0da5e5edde6f4ffb5d7733eceddddeedddb62c254008bd238c10c2860ea14b612ecf3414bfa1afbbbbbbbbd9dbbbbdb7773b0893a1373343070164e61e330f2dcbdcccddfc9899f979175c48f213f41343564ec3d084de53fe81f7133b76c7b5d690dddd1ea384229b61b777777777508cd0e3f6aec70806e8dec46f22c7081d72fdf3d6a0efe38bdc688b2da47cd0d87e1bd3edddd093348c6cc769988596777ba4dd1ddd9ba1777bb7c3eef6766feff6d8ddb0dddddd1bb6777b84dded0f6e6ff7663ef08217b8df93674408238c314608a315a154430d35c0f09a5499461a69a81ca7f6bbf5e2760da56b28bb1bb7dfef37b700ceab57fe01fa3e8620740bb61523b47c7bb777b777bb5fef766ff75401d759ab67aadd7bef3dd952bbf7de8b52ea33b477a376efbd076d4429a594d25ae928effd0c61efbd0f50fed07bc242b9a1ac826129d36a729126e61da4aaefa2b59352ca33d618bd97499f9bd0d5e49a9ca876524a29c2da875a3bf5fd73b206e5bfa494328a9ca1d06c2852b6cf2461d77b292115ec39914e283f2796b3602f3f243b8a6419bab64eab4fb619cf09e5efb0c7f5cbed7de00dac7d285f7ff519524a7975940e03e50f7d47a1fc57d31d256e7967507ef9ec626a2969376cb88876631ed759bf6f75f25fcc9858ed767dd7a14f779f2b4608238c314608a3156194918372f6637e1816638cd2dda10f7cd83efbddae472bc60bf3b87137621d37eec6ed28ad6193330cc618a168034cac1518f6b333a247f728ca305126f28f4c83e6dc2b869c38794e9e93f55d8f987b9434d6bbbfd6300bddbb4ec61e5720ee6f63f6618c113a84104208bfae5bbf0b1dba432a2d0e49081dbac3cb033e9efa82a7ea3b84103a7487fe1990ab3ad7902910daa57bbbe5eeeeeeedeeeddeedd0bdddddbddddbbdddddbddbdbbddbd95d53c2917808422b6fb777bbbbbb617777c38edddedddddddeed2b2b2adddeed515aebee6eef6eeff6dddeedde7ea127a8543c4eac4ab0fae8967316580f7594ae6c6b2bf261e7b5c80aaff3e9c977d903c567c8d2a621cbe23aebdd72cb0a7170c773429f94d2b276e9c2ecb39680692e599098e672c5f76d3f6e42fc1747a22e092584d6c5b56f10863808a10588e0ea9c4addac07192ae49470a0fd218470bb1fdcef208470bb1fdcef208470bb398e46bc23cf7d0b5e0842e30cf7755f67cc084e7781bedf4da3cdf0776ff7e682bbf7167cdd9ba99840404040404040404040404040404040404040404040404040404040400ea3254397bc1c464b86ac900fe7f4388c968cd261b4a015f498f8c0e831a839a87fd87f967977432f74823997bdfdedb70f7fbf9701e97d61e6377acc16158c58f53c2612980db71b68c787b063e4f8b580ebc0e4efe05b50c27d6bebe737d0e7fb7ec41fc7c0238431c6087d9f50e6f82f5b9979991fcfdcddee3a21e6cb711273b7669907ab6e47f83d265a0ba621fe5b89f00d0afb19b77e6b1312bfe3740c723812c58536a404e3e6fb06e1d661a0c6b7bedbbfb80ded86acb85f43dde59498a23f07a0cf78f3fb8b317e7c2782ab12ffcd4ccb0d811f39201605b92074686ea1117c841d2661aeaca8f8e31a420821840ea1f783bb103e840f61c38d4ca82882bd9d47c5ebc1db793b4f50116b7c08638416d78542d76ea83322c4c917ad8f9bbff54ae01ba8eb21df76436bc9f82adcda1b09befb514aea0e3b5aad8f5c27a5942e16d769756561f6dda1fb478c4f6b410eca4e32616e0ccb49a779142ff326bbe3ef76e4d1d613def1423bae78452c4963612b02b11569612d3934812abf77b9e8c34bb580bf240256e82ceeb2dd35ad9b93dd32ae0d2943d61527f4ec69a11ca1ab3b0a7ddf7262bd592f87c55d111475938df191bc027ddf94a4f1c90af4fdca2b83bea7ed43df7b15e87bbf5e2e6c7986e6fa6e57d2ccdd4d36ccfeb56db5ebee5eaca94003f455242378d412ec97648f64890c4d1b6ccd0fea0d7626073b77b034cfc7b5f3649a6950fb81307f9b5b343f8a29a0c42a6a7fccb976e267157e97d58e53dd4543d9866dda6603e4bd1d38754a5910d61b99e10755facd8694b86f18cd0774073e735ab68f14240935a6ce4e275155c8e9b4c655610149f1905af90eed9ecff3f1e1a109285241523e78fd82949666ea7c0c4ba3fdfe0096c6fa19397350fbb58dc160987e8b9fd4c7f18a573da01da7e2130bd3f10639429e8ba9e5bbafa71d2e26295b282d69daff7b3ea5dfe7d334256e1be6691ce73ca01dafe213b51f86511fd7c1fa7ee34106712aa8ce74b234738aedd7caa062744da89dfdaec442746261fa43245a8a391bb3038a7119d7954853278814b21629881248f049c80130c62e52102590f0692b7680d903b6513284102e9f8a683d743bb6a5b1dee2620ee446a3b7714ed3cc2816a6bfe7143ab567cc41edcf9101b9eae35c07b4e314a7b809ce310076f5dcf88db9914366733dd90163d9b6b27cbd7a6e1859d9764f3772c87c681d32215d6ffcdc0c88232f60f2012e24a1c512254401b50cc3f22bdb0daec3bcae7cb6fdc86cb21f6d6353627db615c1ea8bc230fd2b5b67a48ebe6636a39ff3876732ae595ef20ce959b637da9ecf1434fb1f4c6261217dc3b070570f10595199105949ffa357fe073f1f9e197dff8bc2332cdfff7eb2ec716441b6b2b8a98795cf3ee32e8055d20a87d54c32a1ddd5a3b2c93d8dfeea197d7744d4ecfb53b6dd13e96b064456218cd4ec6be643d794bf9ef04c0ad719a9d993b87ebaed9e46dcd5c3a77ed14fedaf9910af19773d416536300a9ffa4d3e7ceaf71cd0eeeaa9dd7ff55c4faec7b64b0d3ef5ef90d93cee0a8242431fbfbb826a7f90ea4302b06d9a45390e1692de3faf9a8653a9204a34c1a7ad3c06ed7f3d34d6e5b90249dd1aaf3da5e0939382241185099ffa1f3775ea62c102242a1f4165ed624eedef664ed35852308d44f567b22660262013c27546b131ef3de66eaa6a4f26b5753666ce395ff269fe663a5bb3b5a79ca20a9dad797594a48e90a8f38bea845621f915f07e0ec17609eda6ce086774022154ff8eabddd4a9fd338afea9b335fcfd5b6857d49e55d49e53d4de1a4a93b1bddc94585cc745e8292c47a811ef883ba74005b31f4208210bf1d6d07e5d0a1a6be43aed06b47b3bebc3c4661f69059e20d750f8c4bf461de271308783cc48620612ec8977218df71e331a38f28c207787308d2cdc007ea10b395d50420a27e8429226dd5f98ae042b021450a45c83811a4f04354f880ba024f0008d81b39bedbe67468f195fbcf798cdf831a397c023052f240f1a523c3476c03a8fdb99f0820c49299928a36a7c62660e85a410672471cdebe26942c7af154f135ac41823864d2048296596d160c74752bc4d06233a1a41d173c516642469e20418288952ab89c480482924121523452525c57710e4437996e0426545454587878924dc8787891f545e22082b2c2b2b3e86dfb88fb6840d586cb0b0fcfcf0bca008ee23799688818d1b366cbcc004f5358144d5f8a4a2a2a272e346906ce28817a8516a299530c993aa028f125eb4985a5a7e4275b550f244a52e8f1255985c4c26ec06a37579523fd2891f2c780054aacba3448e0b0e171c7069d0048b284bd46e1b3ca84d031c9e256eaa4ce1c88103c74e16b4f0319e470924395e72e4802235eb5ed14409bda2098ea351353efdcb4b6603fdaa7bc5163f3b68a073451465501e27562926ac50353ee1c08103c7bf8d24bcbcbcbc6c1b4b5d1e2684c061dbb66d1ca7c39344106600a389da61953b6b55c45a552e76767a40450f7676eaf3d9416247fcde6366778f3f3126f1247edc8cbabf3f43a4182dd85dedbdc7ccddedee4f63fbc4c8ef2ef0692e2c4b0849bc259658820a73ae124a28e182100b90a0ef31f3482e9f20843146cdb22c26ac95b4a494dec5caf7deafbb43083d7a2a460ff878ca53af05d4a5bc241a8bcddddd856ec30b76d427b553e55e7617cc39f7bbb75f77c3dde67edf7508a1435fe87137d8fbef04f5bdb8f97b9fbb0bbb77bd9b1f4a31e7e6784cd688d58f66ae0013b67d30a4245cb004478276b27a0b68272bf733e9ac15c558f45eb0057dcf9d0bea7479287741f908bf1a7ea5db9f22dd4a7d2e619195caedef4f7dbf6c82e92ca0dd7af1b2f881816ee93f56406dc062978626fe22c19128f8210b7e681b010f945b9665921c4541292d4e09fc1ffd83e1364c06e8b62f99deccccfd9cc0d6223ec8dedddddcddddddd01b7643e7938761eef22e6b376cc0ef9865c33033afa8a490e8489461f30a492b426fe6e55d66e6963ccaa0f05f7c32ef278f1e3e307ecba95205ca19ff3e1411edadb7b43f82921072534749e99d0a5409cea34aff5e2365368fe70c0393faba6b676766bde869c52b6d3af0fdd5c33390736a06394e5d3b97153c03b9f7c3a72950eb55b045c51d32341a1e4fe0d1a347cd18353ea4407de02006c5a100500a904314680e3a4041871f4fa0d6336abe7ffc1ff549e88aaefde4d1238c1e354ea8f1d1046af9c0a10787023081c22f400e4ba0f073d041093ac49c1f60fc58ad56abd5aaae56ab98e349a0da5b4f7b00c007bc729e0fc85d378fb91bbe9e9051af268471810048cfc678edae1eff82aa316faea0a9b335f0fbd9c9d25c410dd3df84aa8219c5c64c1bbca9821f3c986eea004e9d8d81dca5ba763875edf0124bf3ca783e9c7a3e3ebcf22995302d8b5fc25a329bf8da765d21359e8feb0a85a1f64f1c4266d4fece2504b4a77ec8c3551f774d774261edae9ceb72c2d258dc948261faa715397552e184761dc2ab63beca38b5313a5504eddb9ecf7c3e623ecda378dbc078ef07092bbe82521bd3d9b533c4e3d59c39338504da3d9fd4f3e19968822dac20466d307aae9da0a6a102a7462b92d421844c6e88352d7edc33395e5d3b8b83f6fd57154b737de0dab96eea75d3341a17ba70faba292366bcda018d392e4c6a0c3befbba8aafd10c53e0dd37f85b1a72b8c9db9beb0a7be82f834c19816a7be10c4b59baa1d1e0a04414c92a08c8854e8a096a46cfc08990fb03ec84ca68e8e50135b03835da6014b51fb633002b55e7b2e28ac4378cd76541e525fe4ae9badc88e3a392fe8a29ecaf4b8b7b363d3049ffa39874ffdde05e5d5c638b134ec6461fa358d1480374fd809bb82b278c28a2b876766157bea9f5edcd47ee7825a7548087458638d355016f6059ea6c7c51c54848261fa7d8b11c8c0f45660ec3ce153f730793d1da722143c6312021ff7c8e0537f3f28911424093260ed38f5a034b1f5f5d06b8b2a7c76b0a151a769b40f81124aa5d276d78e539cda533f15b4eb6432a9709e814faaab05929d4a12e38bd41749d62ac3b25e16e86ae12449e5aa85139c3a77a615b55f009910ae4152aa186c0058cc0f2194f63f98574da37d6ff6c385d2b898d3847653e75283692c9e596cc6700c16da28fdd00a338410c2f9bc15599954704bc32b01d447437d35f5fdb6355b5f57aaaf2385eafbf71ed75ddb8573dd5c318721c6a914e4302ee6441dbe211567c0bc0834d6211cbe378f58f185e713337ade8a6c16f57ac991a9fc65059f3ad5bd9b6a9a45a152bc721e7aa9ae1d3ef56b41bb6ba787c799e0ef00329bf973a988c1f01171bce213f7f00dddc3330bb797c3272872164ac62beb53389f4a9a33d8cf90d9609c3f2ef43f3a8464a19036c9ab8eca605e04dab5bb7aae9e1d5868738ac33317c73345368beb864f174e16f47d77ddd44672e1f08908b4bb6e4c4f67eb93020bfa7478502312cf84f02b5e0fc5ea6af1011ed4ab2ecf154c883ba8e8173187577149d4b1e1ba0ff398c32b1a306d8b5044299e8fe8c4caf4131bd3df7175b169f952500dd8527f1a329bcb06ec019936d450c30d7bc32c692d6f7d10a52fbdc515b18488c67d11a6c79986580fc4a2acd7dee28a30b224088d2ba2f4d617b18448e92dee08aa8896d79e88f5dabfd738234b3823385e7b2339de5a54cb2f6abe6c08217a78d5f443d8c01f62facd4aa55fd45c1a4d1b346306997eb0bef441585ffa224cef5bbef4d607d1f2a50fc2e54deff2a6d73e4628f8a46d93098e1c2e2da692d6b22dca655b54695b94c90a1a75624e4f505008088eddd9e1819760277070aaf42def711a905586b219ecfb27cfd628317dfff4c1d268df7308b53ffb19c427a2927883a5e155cc79c24e4fdc811040b8cee757af6ed17ce6b8ae562bd3fb966dfbcd1e18adddf331719b9833fd60bdcb07a1bd892bc2f4dabb70452c21627a4dfb2274bcc599f81765fda270f8f492f4106837751e4e56570b1040a9b22ecf1539e8b195b66d98968d4766b3d9d41102a5c13c08b4e3158fcc460813ff0f71f99709114d3a3e88d7451560a04cbfd9e38058940b8704490c8f24c72301c023d91ec9cbe3100288452141627de99168dff2913331374407770465e24c8f33fd60bdcb13b1de8533b2e4bd91d25bff38229a9196d7fe08caf4def48bb236d37b975f54cb667aaffda24a9b0935716c9349c3f4e7d8b6615eb66d986f52fbb755ede77a6a3f00a0d4fe18a64f0c2f8bc2613364ea344cbf69889125444c5f7a23d6bb705b89bc2eaa5002aac419d1dec4b915f4fd381068c7ab2f40c04960267018bc7a3eae1bcee1317af4e8d1a3a6a60687c5e1e646c81546ed2fedccd5b3a7fe2be8f9f83c9f2bc8e7fd44260f8d98f3839c95a874cd59e4b474664600000000008316000018100c0a85a2013dcd82d6fc1400115d7c4a645a38120824d15810c4300c62180a30c620620c40041985a8468a0008a5404ee7e9fbf778161c25a3b31eb41ece4fb5fc4246f9c6cf553c9819f1bfffddb507c54636eb10a50955acaf145662ffbc2308747e6a5923736e6ff8784aba00d302dfeb04d4ca5956256099e0aead3c0f631a45b2cb62a421018216022960460991cc672176d41cea05ac6a6a6d142f5cd97537da51cf90f3a99508117f2b3a1530d5497436f0e5865d726d98a311610b1e0f20ed698c56e0464d715e6a58854dd53213688fb91184c661f087080b1a7611757ebf7573972fbc6a5e8a3f94bdc756b3b571929490fc6a864f42c7956474a1b8f42b8707c9b4cdd7859760f24d0f0c14cab2203e7499bc6aca6f203058670559b876eaff08c6a61b3bfd656951c3eebfd1704bbe9b2d10c18c2d567230d73d6ad32e6ea83bf64ab32873a50b83dd26874e6e26f1d28d25839eef9161ee4a19bf2c23181a1b7a0416c8f6e22b255fc6ebddb465bf9ac4f62575b4e8ec4b69d63a2f3b0ff3d6f2d558ec448fe966da1dcd6e4c9ba3d14d9ad6af111b58e560be7b5193468e612baeb2ace033ddbae92c625d51c4d422fa7d711839b25b5248af5556a0c33bd624511dee040c62c048daaea0fe8a29b1fef41a521a54ab0aa40337a0f805dbefafd0e5c116d82017ce10f81a41d4d3ecf52f868f255e153fe21280f15055bd86564c34b39fc194de4906e985a024a4d09601363ce764d2d92164c50b3dedefed2bd3616f2a5cabd77cd0ef31f1c1adb2c1a1382212f11ecba8ab92adfcc7de13588442adf372ca9c20b43754e180cf6c8c97a4d09ce853a3579bb1a720028b392c65d67dfe1d9c90773e31bd2de327aa080349fd733623b9234764f280aa9400d123bffdbd41b93aa33e862b6a90c40e6963ab200ef9194a149e66fd471028791a6232fcb394cb312f885c6080477cddbcea68b59958d812dc0be91109a0d3e829c30b3e10541cb1c99dc9ec19fa252e70ef315c5e138de8b86c76dba7ca6b88515471042b2b009416d170520266400d691edf73e74f8a71bc69b7b37381f50db83b48da0afa1dc12cda27d743b8911930919043c624e7260cf68f8e18c25347e45b806a00fbc8912ef97320d63046019c5d3200c11d886202d8935f1c361c83fa4c162be9ab79d4e9f7fc5d1b217ac9edb8cc98c879e819fe7a902bf03210008d4a7294551738a83732dcb1c7c67222cd96b7a55e53780a9715b3b5ba67dc202ee798fe53d679c565e62bb5cb7869e4ec0110b83f705fa8e0f4e0075a5b211fb6a08e044a2610cb072f5402b4e3b770ecd93c1b80d98b31a20728b0cbeec2d8af4c6e2dfb35c1e2f3efb27bce91dc872f1625bffb287516d9fd8fb404e97e8515cb7b08b0c6ea03c2ba4519ea89a989485db97c0a95c91c42f09b4ca83a335283e789014683d4cb1382f810f50ee7ef1258a38ffefdd811c62fbd738a34316d1a6881ea6bce641191b7c675c03e476e7a694986e400f4290a94ded64553fa449c3fd1db3f5ed37a3e1b8c42925bc490b02bf5074009fee3f05ba4c9615c04c49310f0fb02029392620534951d5ce026dc649e6975d622203c80ef8e77ee350b4e2ff583edb8ac610ec5a9963695e96e0c48d5577f77431b53a8eb0e2698a9313901a1a8da16a348858dc17bf277bfb4670397f5d2e3e95125ad121ca34668e61e7f7711701b2a3975fe7e65ead70f19bcb87775e24548abc1b412f8d87c96394f5ed7b20d4e86ac089985979dd6be03d1a03e43f245da4383b194c4c7bb28842cc02dc7f81f34b137abf814b015b124829941e41ea83e1e462d6f29ddc566619b2c84821f4feb418101ec04578a8634f8e7f499c8dccae09d5bdd10a7651a2ead719e33aa3c2e5833a00cf46234ddc58d347e7dd57c2a5c4160e3685aed508111f609a9fb57bad073404e772907be94ee741a6772c025912aaefacf33088c3120428903210d5d102e60e0e2f952dfd96df7097979ad461087f2bdfa3dfba08f0554b0101ad18891dc0b3a6af15755000b5b7196bd14002ee02fdcdbd6d04460d22ad75f121874a4a58cf6220291627d2b6a97b3ad1c9efd7544bfa61aaf406f1156ae48afed831ef655a1bbc6551dcea0030293c8965bb986e272a82786b7a8e3773d3a0c4a6bda0cd87f49e0ef6753e058934561776df5d6e5053b33c8d65d61f8ed659e0fea314d84509868847b6ca0132b7996e5c0e14a757b8735afc9c8307f1b5943e54cae235080c54ca04c7ede4572c50c1fea2016f43d0690641ae1f055c067e30cececd45322ecc7d25ffd47c60159a1259fc87428728a76e96910a32aaf88112f1b7b403b0280ff77b8f03cdc070cdcddff14dbf7c364e62555dc85e45916371b0ee0d910b657c8cb5a8c8745ff1a70f18e3bd074f16784ef0f79ce35f72e389fbaf56744c71376a3abccfe3eaa31f149aa93034bfc54e4349c12b60fc3caa9a2a23291c608b185315dd1639cf396e7172e4057e700660fae3d8511f89b3c2b5ad1ab8a85b18a7348c1b992c13cce7f6d21c24fafc2ff8bae1e8fd165b3744c74a64c3b35a405d6d7e34e37081c898d8ebd2fb5fdaf147f2e144324501eaf6d2ced3f381e5a4547c70c7f2c6044905a834eb7178d22744ca683ec199a0b02c0f9f1191cbc1aa8e51ac5692856c4d48325286f2050d7194f0821e76be0b97ed32629a362770b08ab071949717ed4bc477155ce9bf5e2d178a5a9f7da2a8bdcea8d512bbf8f96314cc2c5185f7c4147df86fb9593b56fe908d01db1f032c8a581b32ad27142707bb542757842275cecf13ffc626e2667274e4341e056d404b3d6009804e2968164f05865fa7a834ff902915e963583acd010d203ac6e24d0b2ed21920a46d6f52f275742d06d488bd81d80f0e1f90657001351ba103191c391e6b0766cf419556287d19240b296ba11c865c5dd717efe189405294bac23cc89df632f5a407d8bf216da60a6d7cfe400a2b8a0036b8bd5c0693e16efe89a9c5fd4fc3ca26b898005c522faffd3ddd359a075e8ba30097ae37599faa0f97d114d0e3cfcc11405eb4a159d4ecd98c9689ae6c848df211e5ef4a50f0c7a5e20476d241a3aac4b0d55d1bfef204f857ae8e8b64b69611cbe635bfa88fc380e2e788abf4032e1db274ff74706f7813e3cb90ffd58a236c42cfc6a066e3acde1e60b6478259606feaeb4885ef3f4801187a6fd4ba1c5e32bf3075d2aeffe55797b552435f3e785eb14ced20b0aa364c9c10d556ef72e5681d4a2aede5e600f55faf626c073066fea36aebff2f38c104ebe4dfe8834c3e30cee6783fd5a49a1439343394a68a18e14f2ff0c52700581a65cc35f8972b6a1a82ec2b2e2c66ce7b7d6e1184952e00f7b9cb8fbc2aa79a2191caadbc2322c920d03ac7bd6ec0320bd676953f332e74eb9aa513fd1afef755631ef85dbd2b46bc57b4155a1e2b7377aa06440b8885d43716cef100192d3d4fdc7977d83847555b985d229391252ddcb401e5f0e12161ecb2199439c95211a3d3ecc4c407a817876c7132201aa47d2ed2d4194e53f9e6be9b491a234e1b78388c44d6bbf4b7bf38dcb984e8d0115e0d6de7d0f055d29f8e3befb791e575e82fc82aaed6538aba5d4c3250ccc4430ad94638ae173448b6931b31f1f10cc0a858b9f1aee8ed047ce9a09b120305d812113e8034af8446c6cbf129586ffa57eeb6791358fc15fdff4b3501eb880d936eae0bbb5a23e7cbdc95e34704ea6902cb3a663d9cbdee05190ddf96b6b7998e316e1934e29fd71420f362053fe3d18ee2ebc0819b87fd5e453d908b9525ba85fdea6a595829ee6d470564f88599dd1c834e9805e0da9703b83748e8823854d6b2130db0d37b18b4c119f63ddb65d897ae610f988ff052302f9260a25b8fec7d69649693b6170b1a0b262b7364d3d9fceb6d18058e1f5d39a841377871020df5596f55dda13161b236bbd74ae33e98a80b769f728cf802a891ce7b728827ec54565cd6085f7ea985e827869d4ce17ea8d9a1dc6fd0f9a4b98548838534726ce1757ccfa15023e0540cbacfb5a9dc4829841ae83acdcf51dfe953d17d2c4dfc44ec8cf382f7945681ab2a7154e4bf8303e0c841876a86a6572dd52a95f261360ebe67a3a8977782d9e742a437bbccfcf2e496083bccecb534708b8d7b5e27ec5cc628bcfa9309c753120900bc50d19cc853b49424c2e81f07a4b5ef3574767bf7429f5272479a469b98c6f46bea7e7523fb11f2459af1218252bfefe391c1f410758ff45cc04ed9d43575118264718da0b0406047db545aca037c4cf2f3cc70d81d0a1dbb2cddf0253c8888120b65ac4aa7a12755bff24e6f211175daa11f65798d7d1e96cea5166ffc132e27a063575a644dd7227f388760091b2b3ff6d592c6eaab63ae442f393229be5785178dfd36b8910cbb132d113c6f2e08f48fa09feec771ec1c30ad6f1d2f1b55f25fcf0001f6a85e7d347c3e601cc08624fe6f69126ec058ad0e56eef65bb5907b30e38f802ad80ea33234058e4e363ad5ac537e9af971018c7185ff0b8ac10847446bc946588ee3d250ab5ebb6956a28d2eae9ced23b7dc4bc68757bc9581036f7b818eb9bfdaf601c17cd7836262412da810bcf224a509e1a3b29c20984d4d17e8166c125e8a74a5f04480064bc63174cb50d4107902f718f25e7a8b1a310a8987b21ca7a1dc9700735e310bfdcca1d6d8c10e5170e5df7f771bc23addce22aaa6537586f6ea6d15dfdd00435ea6538dd5cba55d12a4eb263951e4be1b642095325d119b1f0be12c7e555e04649f7f04f03ac80abf57db43ac40bd12b9d5843bdc621205a8c872e6dd05bf437aebc34e05f078e0cd8b10df9a17e0920554635dac8005e3eb159d54f8d62e320f20d9f136ad2d3f36ceb3a00e1426f9b6ace6d5ecf60ec64e73f4f2df9ad829a1e7992cd6b2a564919cd71c1c0a558e895d7158eb1662b0fc8dba85419247082266ca7c90eef12b9727bf89626529c461c186899ad92ce47aae2611dec2c7f484d89da07a30f7749e520bd4abe879cbae0f5ff8fc8dd4c275414420bf22c8102cbf87e50498b23e9ca105e8f39d26990612620a049641e29c71570bcad3fc6dbc74e0cd92634f6334c0c55ea7d716a44d4e0d08e7d9586a860813530d9f72af592d8e7526706bd6d1fe67f8bbcc44590dc83abf11bcf1ace96b951067c884580a29f76d6477f5c91953952fec19cb813058c4f380ed03ede42472f8440dc51e0acadc5f1bc4780a0167f5e9c23d04b79ec75ee289bb35770ee4eb20beda9f42f189e7d9c28bc8426a0d0eb72ba030732617358cd016d36d43f8640a26c25f8c507ce5dc47a0642dbe4667681893c9fb86763a1294f9c6391a8f5e0b16bfd3545f1328476a38229b7c6760e8d0da9bd4b6668312df4c2bb16c9c518e2a8c4a216d04df70714952eb6f8a8f7f089d119e6af8bfe04d2d4cc1f833f6850b7bd1185379117113ecdf9975ec8384d4d0a7719c1dcd63b087a49ddcd8856c8dd8f0d1225221ef37b5c711cd21032dc882dbfabaa0f52c4496be71fd9759ac6776e582720d8106f429ac6b601ddfa19f20b556c57c2c04559354d6f02e78614db1e091a9618422a84a09029cb706fdcf00b5820e1adae8ce8188fe4c01a62d947ed57ce993640501daea239cf5d07c7c03eb2a6278bae3b208ab0d1af1cc12b6b95420294604efbda8ab5dae5c3b1107ca92e8a9981c962b73f2f57b21e9d3d934854da7166bc976d664c1fa492042e9a12e37ee8137c55086fb915a3023c1fcdce6f149f5747a4c98a4de71df36800860ea51e39b88ddeaec3a1b189fe4d6840063009f79eec49795298fdcbe34fc72dffb45217ae62815869d62f52705c958a1b32967011576e372cfd31f5fecdadf2fb6eb0877a5ce437baec5b0a7e92c84a1a06b4db22169ad07b259d34e5206ecb3e12f2aa3c1d9e7a7d988dccc2a9fd862f11b929fe240e6056acaa43dada773fe92fa8549a907d64e84fa2c468dd4b5064491a5401c55a3dd0dc8ba34e35b75fbd3772307ddcced47a58aca5700dbd090e15bab432c2e094027f9231eb25d06946f559a80a2a6b2938699cf50a7072e3febab799dcc40f2c9beb1a268e5bf1896f32fb0cd28bbe6b0b846ce32607980b1c6f91195351d971f82e3825b4b4774f1e33ddaa9555d9834fc8daa40f6fd0a6855eb1cdc831d51e244bf0351c70bfec8d7da41f14a2828bbf17e87ac742196f4dd7bb0dfc44356abb42f02b78ef3578c9191944bf99e5af2d5ff4edf5af2daa401a010a0c154d20430a3d21323701b374ff516a397b99a70ed137709fec89c705958e23b7c32b52edeb6411786840c94cb63ee5469917504e81433de73d0a42494386d22b25aa26a2ef8bd1a2c5b52b021190629fffcea4e2d80fc1c8c7288f3cfb8917a4c20820b4e22851d6a9f10a1fc0e85155042cba0c4214402f43042c76fc73189fd0b8d3b4d84982418d4518fee525883540ea8d5d7c25790a07a593b7de3065e621e1886025311d920d3ab4008471dd85703cca36a395b21620beb5be5d226ba1d51b2907e90c1f2535be57865997804e99503bf727f37e8cd472973927c61a101d84ba71113f93b81ffb18b9342c9ecfbf7900aacc4340497401aef3fc0bc1e0380f8c74fc0fd2551dec0e826eb9d815bfab831a2def961a56e61c8382be8890fa534923221e2f6f95cb17e4c9a59cd32516c5e56bc49f8f5e111e0f39d3c85190e76df3877abc0021b2a4bcef3d995db1f9ffbff8a301e172024c0305dd28fc735a3527632a2a9e4fff8f6e5581617e68dc0883ab25b9c0cf2d22a79150ba7a47743ccc34a7cdcbaf3e11b721a3517e56a7037021266391553f4d3166de82c7093bd69a01137a167e39819110ddffb1366a1c08cef237901a8173bbc905f97bba70a1d8a91c7cd67359b6fda852314b12dfee4117cf573ff529a7f011c90c828b4a358f1a058e2e9fce8c21221e73ce52d4e994917253d60026bda8503ad416110b7aacdaa8f1b5a0996ea6e8beffc17b77505641f057c29caeeb45c07f08776937909ae3a88cb00bde25a9947bdfa3bcd4554370973c4c7411a0f2975a4a8a6591ac24a600ec6f7a5ed1d3f3872cd8d205dc462363af96198ff21f297407aae04789d9352216175a2fc4ac3b00a74c386aa8f48c855bef19e4c9ac2be63a1b60dd83eaafc0a7f2f048860ee596f972eb879b3b350c91c5593c468021c312f8bed4e1afeddbda02a77294402ceffe866793b4c57278389c5c2490bbbf39b5dfae52c7ba3fbe4f906cc93a2fc7ca99a3cd46bdd2c89e34e4d08d250596cd01b1d00377e86cb8e87fd0d7a51c8f71950d0f7a46073f9e19f3381f58497766cd1e3fcfa46018d519e8ce1d294f624bb276eaa472da022dd82d0a6f255019d6349c2070f3e0c63e507d9237b684b00f60f40e142a1ced23327eafb48f85401c5136e1e6e765ecce71d2a8fdc43051b079e0dbf5c190a7b3072092e56a07365a1b733842510a7a1251f35e505d1c18f106dae059dc3f14ad131a65aa4ea97697329269ede820c77cda75edc4c09ef808008f080ea9ff02860574eb19fce93aa0bde1a27000e1df6f08e2177bbfc9405bb755ee8add902217f0392b1edc67bdfe936f937b29504fb2a32679288b4b9d8b4719bf5daa0e651b9163b809b367329cf502a1b95341b9448fd84be73700706470710a692418884f9c5e1ebe71cb31ee3372cb4f817d511a1974c2c687172f168223767cf0836095149456954a0cb2232725e3a184be553f8b4c9801eb33ebc5e1bd326061da8be6ab460ce5977badf37781726ff559d1387c719b43fe562a6af69242134ea5df0db082a7cf73314a1b947ef43856208faf1ce8a6b78bd116b54e10cf1e730d96d8aca445accd91e51a9c65c44eaaa05ed7dfeb5c3f482ad5e7d39232e0286e988ae15446a697137be5c38262c4ddcfd1acde0ed0a67fd995b3c2e850e836485c379226306c20d7c591919b38bd7e64ad86602b4b1e9ed8a1c865ac6d23758df0ddd0f97681f0e865a7d4b984693c7b4bd3daa2ba631bd5cd9cc7f6c57d0a3ae4d4009e05a2e1a10a6eb6e0f0f55ad40e39256a38b5a992c12fce52c5b0d506406b7d77a1c9f04456d4f908b699c861e615667c4f41f63ca97e58f8c921f9324eea417e6a76419cd891539c744d01dce0144e3815d866aff847e519bf041c007184402f5396200ec6c86ae108fd63f7487ad56bc63f55e1a457ae7247ce1f0fcaaa1980c367935f87745e4006decdc04cab26d9da36e0f638b3710f98f853c501afd01d0ac36a2b469ac804fdf7912a431dc57e8bc93cc2b137af28a592bdef2605828531f0ed2191f962a7818813c29a72c71f471a0d4acb56769340ede364f8076c76cf842d6ef573fa09780958a0d14101fe3421eeb54b990b19f5d32814ac471beda1114e9918ae36a9272cdfce547d18f30949d1c4f9a6ff452ffc50a18b48c7409156321b5f280c872265c84d9441184ea841f05e1e358fa6436240c24e984e5d4fd506ceb70187a9f5c68057281289005f547af5446df45bb0f5e3944c6d4e1ade77ee64a5c7f46f8fd9edcdd7fb3372876dfe804eef940b73ff98e561e504500f351b85479b7250d2290eeb68e33ce3faac259c0d83b1e085b8084bf27f67499209e3d55936c5095fabb56ceb8e92c4437d74a4243fb571e5f440e0961ebe4f64348c8555f2baa5cc89339b667625551aef428e6d61601d1dfae59957cc66743412a352c9635e825ce6258dd17a237fc4bca0ba29d1846aeb1830afc834f13b7ad47c31c2bca259aa89a9343054ae8fb7892b9757df6552340da4e09b957ae82254551ebcf3c285dd394670dbb65067926d404c848710b7cfc07f98e92622acb130b1076c585818b4a586bca1bfce95ed5eb9f112e3cef5c77f99c601867ab22bb95c7d024eaaf5b0f488bb9fe61ff255c09ecd23f6e50d4b61e01f2cab2ecfff45e659560c6e2f9db968ebc449f13626b95fadf1d8155aa96dd8541975e326536b8972b3c32f9674bfa91258b5885cdd7c2a911acbb999b5ffb44ffe613ffca37dda4fffb08ff6693eec837fda0fff6cfb9982812c00d50003d51882a712001ebe511f05bacb7595b6aeb4aa2fdd9ae1e581e47e2b73b090693f4c8a4492f23b007885a50f40be53035bdd13a1d45e359e6cb3ef1bffff334431a7b8fc44d3f3186fc053b89912b884f5d094e1739adb601642b9ce5ba25719af3f4908c22217906b712793892fbb819a483bb42edc23660d9c0ded715b5161e89e380d5bedbf96ba5db66177df63f0c99c9f3771c344ef9176e29cef4eb0c057673ec28b8b7cadf4f4a9bbf38924efc2b81f4811566a4d598423a65cbf0d38829d605b83f58a7dd4d84868a6a6a3c2a274322308fe0e96770dd2667dce331450e592cec057374017a907fa04e522f98af830c00964a3fe60a58a36eb8fb57227a3e9787c1c81dd5557154745bc09415a7da731974aa623d20aa733be8dc6b5d9c1cb11481aa0197857949d5120fcb1738ebb918b6f02ff965128a845a3a0f982735cf08481260ea7736db1f016afd152f8558debf1bb715dbe0946234a04f4f0d4fff6acf829ea0f83668a3e51180447f597f9f9a671ca4077599b7c8dd5b939bc41af5fa74f117260bef5cdb41fa82bf5be9b137ee58f5366238c23e60efdc49a65fff3fbf424174875e7d97d0d1ebd39f44dcbc453ff19943447d189a1c03e7b277992df0da58b424e11e771f63d5a6a456baf353dc1b3e4d40088e0d94656bb88d37bf41deb9f39c6d791994ec14850285f80567c030aaf322ed70178e371898ce56b6ba114c317f1023881b25ce5768664292af0c8d0c7578ac95aba14b8779f8cf9e65d17e7ecf664b458e237ebc334c9b8c093216603adca71a444c992d8f3c35b9530cff631a2c00e36b633f5fae30225bd732e81d0ae4913e8792cc957e8ac9b129685eaf6db7947b859b68266a1dd174db3859c447b32126137ca4f3c3624dc49b0e6190728ecd18ed88bf4c93cccdc0cd083a161cfbdbe4e252c62066e86b7cd53a5fcb7912a089002c65a28ed7ae550703edeced8f4e26c3a9a919118a2b4508c56b48b7319af0b8429af70af3bec7fcecc8bf93097e236911509c9cbd892954b59178ce1d0e2ac8a359d74504cd2373f4c4e66f1a29740e03c52089137a53153e01fd9d0323dfab5e95cfe85060a56a02aa9cdb68c807494d5ecef7bad3f7c923d06eec4f704e5cf7f0ec8c815bc93944dc229ef0a804e7a6171a7bbd35f04e3d658fc22cc48a359cc41b3beb581d154aceaecfac308a8806902a720a7b6ad8444478491e606e88b77949eff35479c984be82bec508bdd446b62af98f7fefc04cad1367a1e7d54b381a63993c2a2cafc185c2cba2b5867a9e91fbd90f1023c2ed7972c3635113b540807de3d4bb0fd3b60b54f8f4a3391678f667af53bf9f1839d6f7666955add71e6356bb1320117ff0138fc4d985229e7d7e2d672af14f44ade3abd7fa480700f3cf23f4a9629734fe14f7543bd5e26581dea4406cbb62f0fe44b3081556e51fe212a74c20ed67332815b0f096f6dd8218639ddf8758003945511868f100ee9308dbd98df55cc9f5dc41e5916c3a87a0c4717f13d29eb5eb17c9a2d9181b6ea39f2e5b615d5aa53a799ca3af3e1bbb0d5eb7649da9e4566fc781a766518aa9e1a796f4767baa475e709c78b245293f9c4ba3dc1404f0a1523e0021015bd0122ca0c30a560f5fe9d49ffed6532e4dab61a73b29672d557d1b67cf7da8c549cd92655029146300e924b55e8d51a6ba97d9a536f60fdf2b2c44f18be71d2946127a029b6f2660855f10733cc772ff7b64411f4a130ba5593a28a8c24a5a6de285d5ef3de84f73bbff057df0489f16087ebf68498a808fddf54e97eb203391f5a02d283cf9046124986ff437ef08e48fea1253ca972b0c79cd7ce1c6e78879c4c0d65645b6c5c24aa516384798360ca2f7a5c2d8b7954bf8b140388e6d1b0c19188be60f873919602a692b04c693741e4193f6b4882b8d4bbca34496d5d9d00bd65e8737720ba56ebd02d363531d91200edc2b19df9fc6d7da0116833d17c9e20620f2305f41aad92e067ff2f4e71d17c54d36db7db73f484195d1a5ca2d967c37f9060c72edd03ba30523878cd5f79a750b90587c28837cc2fad11d49859a0c52326e6fcbda901756ebd630b29384a8734904ae2043d53c9b2034119df6fca258c2bb8034799cefa1708bc05cb18906abb4b694664ed685b99cad90e75816338dea5167af3becc3af9a87ea90291462578d244e0064965c752102379a484898b5c1c20bd66a694dd625ecdb67753ec7d24901fc3099a775f494c16eebd0ecc236a0004b9de9b244a1504a134017f64501a1f11a58985846b88175b00adb11b8c2efcef9e16a344108df48becdb3d9f50c54d49616b8ffe4940876eea581deb7e673ed20869e608397419c15b43cd785d605aa6ab74fa88aa6a363f8c714dc07a4ad232e2befa161ae241d12bd8c8573c2cc952173f15e9a7c1d42bb4878715005d2f24ec167333e4ba63d732366c20eafbc92ade0b544de2da06eeaabbea7186ce3b83207ec49f41818cd4048c3eb1bc66c6886a43ea46832ca4b6f905fccee56beb658212069de50c9407cc37d741a0c37f7400a5427d549d3dd61326c5bdc2c16e7ddf98f67a2387e67c388e7325d7f2046af534e0cdb9dd08570e35924ee5c22f0c1581f6ece8df28817ebfcf121729f16315695c786284ea9f44f601ec38dd12c2ed2e93d19b431a2a29564690a51b6374841526b8fc05a4875324f756050d23aa54fa4ec76221056765d001f882eaa2aae27e6ec4c97e4734236a01956da8163a3ac6cdda2a9b869bf1ebdd00ad53b4f154eb45105e8d2344332f85c155f907017b8715e8722a7b25ee4ff3bcfd05027af68fb4d4a24b923d33c6807145b86880809d6abf9b684974ca5beb69426a45e6b2ef336a357c748ee5666514f510e134dda51ddbd090b9eadab91d7269dca7652dade2a4b10625821324fead12d5090916abfafbb4e482061198d94618bfc06b33c340e01145438cfd046e38d821443f63867428a922c8942cff073909be1646e3e0246a9d68c47af1d214edd235a49af3786dbbf15823ae111fa76ef0d5d0fa6f51149f7608497dd5205e04ed2b1d55d9306616bf09575273b71843481b4ec62153a1428974a4e955823ae166eaa0c857abb355be09152112c26cff888453aa5f3c1b322752db012fe2a7c3780802dab155a8f1927239e867c685b444cb66275f77c4beb1314824a6e8f3c1402cc56d398899120d1c608d02b7ee52ffe90557c402f804d610f87e8a46b8239ab3218dd83eb4aefb3226eebc5168d5abaae94fcb0f03857cbb35f731a1eedadbe57da8d1a89c6900ee086449b1bd7b103f1ed0d4582b64c5f7fed585f8289ef5a6fa28a07a5a4f981c7f51b8ff50726c3e61100b435f82504834e55d13c666c082a5e8cf4e846efd59958fe8520100b41af37be08f1184f0d90cf53af80b531024948e722ae401b6840f00089f2c65bec2d04f61ee6ac10979370675eb944bdc55b26d5910ba50d9696de2f0729dba3b26f7ea6362c93b4e140d18afc5b2a5d0ea274edf20f0614d724ebabfc300844d02eaf2397921faa897ccbc72958856716180381be179a6f0e50ce6b7e89bcfc57e5c3cdc04aabd4232d964a81d0846ccfe737260c4e04e8e82ad1dc8992abfd9c74ad4be18e99af9425a3b90eba6fbf4f66d252bc044517a95ddeed3318cccafb5acc69cd8cf862b3443e0bb0469d5c205453478fb668798a7cc03f8d5da96f2eae40ea4302b03ba5814b230f7925b6a9fe6158ef14a2a0c35a66d3d5ca812a36fa62da99ea9ad38f4966d350dfec5805626eed0220af305bba8020ade511f7492e157c2d8227a0427b804c1f57944f57b2ebe2c4109ba98cd76b5ad19fdc74b07e30d5a0061e34466ee9e4768675354de3b35a13d42c7276dde1bc5f562895c487646494b15cd4b1ca7fb2c822863960c2c82908b7061fea3d63b6b9ef0da8428862839993981e65d741d9b4b8ec907a7c8cb17a5e851569400db53288a7e30cf8f46892f7d4985684622665202cba500f64a09f13bd33666efd7090d7899dbe0acf16e1be765a78093b0b907b4d1fa369acc46df1a2b56912742a5efe6c8b252df0028ba9441037c3aedb98fb2b45de6b339e20812516d6c6820474a9da7c06181bc4c48660c45f468f1fbec337e175d54a327c294fedb07bc0c5e57b309475d7a299450192301002ec867dd1d6823fab4378ad59ba3324295f02aefac7a821680d330852c9a945a1d12810079bdcb1baa13a9b3491c2840ba355bfa26286ce9dd3db3386842373d687e4c989f0c861a6bd0ef0fc46dc392552351ffbab90ac0597154b30eff6bd35e284106ba6d0c16fae0d733592bc2c8ec0e45244debbd384c15f9b58ba00c054f698af5b831c159fed11253d5a50ff985c2d4295930629474ed597781933cee37ed3683fc287e6b20f23c62e33333f39c810a9e9c1ae16d9d924fe51ca3cc5086a51200fa474c9399e604a677c6e21092a1ab45921f8f366a36a93127dba861e2c07d152d3eb3d54a99c796f4d69e337d5136587cda6c24a43db96c157c23cfbb7890d59e362b3e33d09bf32c27b32d080cb8a8f8f0ca58290500ac8e1b0e3c599e149fb90a40213ddf3b1e13c0311cdb43be9973b453cc8512365db2477c66f9b3b75e47111b1c0f7fa18b945987139f79e6b5a4e3283c831dc4fff153a6d335c5a716981e44634ef2e013af38abb3f4f80c4a7c44bffe15eb9f4a414958295770a3d34e0484030fa030ac297c16dee52a4d85584db00f012b2c27a6cd539ebff5898174d9b2e93390e03992b42ce5d8e1302d57464fe93cc03db279da6717dd883720bd138ce9e7fa4a1efebc175e8cba1442ef3d0a30e1e3b6290739fd2e5711651d579aa82ea3931642948396c1eaa98b6a04f3c40b411e38773500d3c833692a79c721254384a13adc3733d9d25d584dc61dc4f76c2f0c805e80239ac36134c860f841dcdf30e6b11d35b0486b88c97ac4edf9c870572997e6702a58007c68271fe1ab9c130c50d7932318a3a592ffb6fd864e22756b8c259ab4a572a42bda77e862a5adac88bfa875185efdfba971e74f5e02071bec76516230647a5113fab45e454be8877a67574f9e9a9912d6d2c7114f3179242e9dfe915cab01e927c57e2ba9c0dd5ee59300a49711d58df5a160187c808546d8749b2e3c597af03ee83b51f20190c063212b478431b14eec8335e929aaba40329bcdb237c78a41903eeb8342ec7b931704496c505b101e59af84cfea72e2c8598073065c914f0ab6933f8bdfed267ad0c57eb2537534a620d1ff4ea02c9158bc88e40c12195373379f064858424e67ac6ea8fb1d405152f3b1c541e7037549d59a5a3e224dcbac8852b43a3086354d559c5664aa22bfb397aa397fc3946021f5eae30327558ec07b8b7923a98208ac227a2f90586b39d4c3d50b2cd3c67ac44aa96de74d4350db5e0e73801f5b792eaa76b85e7b8b8e58028196dc098a9b757242ca622f8bdc5bb56949706d3844efb3147e3b03396becb4a18d299ed3fd77a8d39ef84df512706c7d2c0e90558e9a549d895927540126e313b79f5b4edaedfe84ec82a505fa3f34c368baced64a4c103928f70fc7b903ee249c3ac02179741bb95b7b257253c5f7cd8d5b5af238f7ad628f781c713ea70f98b41611953925eac508654aa7322f06177bc0e9ce0d3924bce64e7fcf50edcd4be955a51f1bf513bc36b11c60f8cf1dd4e7d7e959b2474d95232b3c82f8b649744408599e0d32a8b70a868c3466de35bce74fd7a85759e279a869d5b81b1c446d0f0d7fa76a604e219c8a040f6338ca334054ea519965c11db33ab5cf7c58b70b84a1161a6474ab5cae3294ee2353fc8509d8f64b9a1ea0e42d3ae22bd05c4e27365854735078b2cd8a06eb1f5f1fd0b08e5ed07ad630bfe17620e094c69ff3e8ffdae53476a5d4c48b5dcebf9475202b6596a3888804b01a57aeb85eeefb5f3e83ee333af598b00882313b7b4a052c8547b8ab19efa65264f779a319cd0f174e1bbf421d06973d8a32a4ce952cba6210eb6c1e0da4c547f0f3bbd8a73f492d62605a7492d8905fe804ee626c95f9b341cd692061707d47055a6ea4263e4b476163276dbd593ae64c2e0a15679414a2c7b242a5f34c85bd58efc2d666236b70ad77f9b16f514da75ab5497cc9388663ed39508474b938d5389aeb5e0cf553594c89d0fbaee1c61c42169cdc68ce76d4435e2645784ce623318ceddda65c719ae02723d6880289e85b8e59af060518b1d08eaa911d89433873fd0f2828d5e42c0fec0492deaa1cac217bc269ec5cd62400b79072953fe5233d4acd84ad303a5a57084c1a0a084319f470262817cfdbe616129c7dd11ae542dfec9a2302377310a9f359234b7dc75cc230eb8a4b3fd2d6bbf1a20c19dd4b0ce213e7ce35150f1b79dd1bbca0a539f43f180e54954bb0466c894b54b08482e1d2a926b3a96bf84089f830e868a330d7c9685939b0c085782478d261a76dbc891636a86340a322ca389b667c4c512c9777e2a3c509bbe16593f3d8e489686d2e6f542f9266fdcf7f110315ea4510f19177da856085df06f0ee49ff6e93efaedc245a0362cad1ef5a84471dfca56585b3198fd46797344eb00a3ce9518c0e7f7e9079735dbf393cd9612c8c1d8f24c8fd99be39731a8b9371448488a627996427add2c9190bc8931ef462e8526dc214b09f78982ee9a66bba9005180d969843b040a1ab44cc6c4dba3414060e03893aa8deae962497d36a3a011ef02276bda3d7db7f313311834a732a0b619794eee73da91ee6143757e28508d1ec7001396372db52c9f955e019ffba699ad698f5fc7364291f43198b0ce6c2ea69c64aed3237c033353ac06b0f3a9b5ca026c5574ee5effc03a9f5602fe965fd9f0b198529cfae9c6bf90a382a09d32e826c533d8dd523352e0816adb718bc093253f9c5f7c82780c5f515b6de164835120ab902f84247bc3ba4012963ece7d180aa8731e827188c067c620e504699df3be423efd2ff53b32af05476d2b87ad5a743c07d1395bb1ac631767f227740618a5eeaea0958aa27a0a6870a4965c00f6d4b965885e71957cb707642c4d51bb1dc62386678b2410583e288e4581502decdcfe1b5dab99918ae33efa9c6891c137cd129a20450697488c4f047b53fee115c4abf69d00015a5fd250c4dbcb6e1ff0245ec85a3e89839bcdbf2f9f009e45f3a2681ae737181e9303ab5cd57546ffc80df6c212f2384c972a982f39a274fb9dc8667d86224f5463f4e1d4ca876bb3ce7f99957af31cf5cbf3c68971103422a44b00ef8e7bd0e0a0cc481f1ec08784cea6a919a5e14960c03c360ec229639dfa884e05017e6e602221a86351223fad71ebddea5668546da738e195f4cf2af569fb5f60ea51c55d30b1f9fe972bd2e1fd9643126201af561cfedd23a486af9a9839c77c4d1826824a3d2acc6047a6cf910b06f97419c1a8d7cc701c1cd02a4ec09e2ba3ca20f9aab05699e1635e9b3472e32f86cc04879caced6fed094c1c7fbd5ae0c5338aa9f858dde86752a464a6612c3e2b6835fd108d386bcb7df83abbdcd021c03592f28057a0370e04d026a78306fa511af24287b1a29956976d439f5379d73f1503ed71b0b28dcd294de9803c069a3ba9c1bf9076f147980501cd12ada5a05b7a6e4be1c2255452a31d315670498892a45bad2c3c912a32c76848ba41d430100fb5773a1d6a8816d36443a101cd5667ada060d927faaeddf7a27a600950afb889df289e0623ad2cf219e518a4be11686befb2db31342619945615df4a1448e3ea9e8e4c235f5f8279f46ab568ae74bdad1875c2bb8173fbd467443829ff201b563f8e9875f1f03119f305a4499357ca9c941d67a3ecd2b0bce711da6d681f51e2a86e0843a1f1623c45c41efcd970d36b2452cf08b3dad1007cbb854dcb15584e2625874b31cb3c6104cd80983c8c5a5d38d9c0b28bcf67156d026ea167ef22ad63ae09b5c0c12f5e17e22d384595971577146d31d22613919759d28b23f6b04503fe94b8f116e5bda0f3000012a162e62d718efad2cb96c4de35fa8293c772dd606f0cc80496a3b9d0c75ea86680ac3f032c2d11db58dcc37740dd4b77406e04896c5086d758b95cd854c630825ede8b54494ec0771c49177cf7b7050f051ddf0aa509ca85f0e92b52ec3deabe22c5906fc4b972d0ae59102324aebbffd16f126f0e946cac326a49522ea3fef4e3c88ebb3848fa43518232c82a0d40a90274768627d6376f504280b7d6572a60886f2696032a19c2cd70051f86bc24820bde283ec4dd01c3ab05dc5ef33f727a97e1cc6d4aedcb1bc85445a879c89d0bc37257f6987fbe9a1ad643902334279a1aa29e09f21c730afaac7b07a57dd86071c24614c0786f630327a767b5521c6a121278c21b54de96ca564a5077bbc75950b23c065fb0515f21195391a5f15f8d9eaba20153454948f59301f19d740528e4d81c87d501d3a621054bbf00c472cb6d03734ae8cc5385dbc9bee4636a7359fc85170089a3ca299d65ec5cdb10b34b4480bd265916afb25afe720ddcdc4a2b1e3e5c435eb00d48476c46908609f750f0c9c7624e85c1c395ad0301bcb813a302b76aaa5750818ea88fc37d50ba0332863d177a2c355de4003f1a7e8dec23ccd18c7b7428e4dbc46176e7a6386ae55fc5ba12924ea472d9bc4047d258943ef5a9c1bdf15203ebffe53a92974cc824a15264bc9c0fdc13ce105908fe169a945a5ccb813970010aa82f98e66e8c3be7146bb1491d6dbeb898a23afc7b3be15c610a2d32c8c9606b45b5bbf006b8a0c7d76c5a339e125c8a4ab4f9d9d7ce4b09736ee47819daff7106dff0752ee23dd96a72b30612a9204ba78646317b200b50aba235fddf444df48c988334dd727f320e488022470d5a845ce0e74ba37d30480e963dcf87528272ad1074eac00dcef837499d9abf80c90b9e30198c0264e9988a01e9dd389221e8fa83c10287743a014d71d4faa99cb94f64c0959c9889994ae525feb0fb53d6049f5827d085241ce2f68360933e0d2bc3179438020fa335200ee1f45d0a3a91e447ac3a18c300e781da598d17feae6846109cc2474823adef769ca4d874fc5e0180e390a8057b8025cf0718a56f6d22b66750fc38362fabe65ea2c5fa8744e5793861011e07d4ef4469c646c2a14e5cca567283157c0cb6be51e881e23b79376047918c24a3bacdc2af1b14842e95ed779808cb7e3dbb7ecf85c058d73274c4bcd2cfb4aa16e1f9ab04e99b62cdc3d57259ad796488cf5ebca609cd7f85b4a66e07733061b1bf450afc6c2cd6eb86412c96cf5d56de7bb4a2e5f259f29122ebfe8d65e1e166d41775f48d5c070c5a88e0c4639ca03025491b92db6c054130aee5873cd84a81423d95e58b24001ba6dc04091260d375ef06a3b504e54c2faca6c22a362014660dc5f048bc0c3ac122f3c083e07a17e4ece08e69fd9877314d3ffcc3e19c9108a2fc0bb0fabdbdf13452f5ac0c969ae5e55582c7c00201ff2a10164096b9e380247ae763936fb55f80536cdcee27bf2286283a70d9b679b3c70aad10a9ee79473e1886dfd4fdecff24a6e7049e9b0df35d2e65014bdc52c48543f07d979592fc3f5c2dd8ddb8930fc7ca1fb21b71e859b8322ff115ab31dfad46d060331d2bb94d3a97f15a72b32e7fcc2f14ab70ccc260fe8ab6b738f247ca293a75acf0c52a62f9dd930b7c789d1793f8cc05756f51c9e1cd97d477062e00c4089a0466411a49364936d6592cdca82ac43285ddd5df95bf8d0d24f84ea75204153b1d8b7bc841f00c943bd925139d40c6614fa4056bebc3dadede29d24c6a52024ff9a62589271ba7954e4d1b424db3fd637c2339356a4f57e413ab4e4c36b9902343db0afcbd45677c2ca994573f6def7cb1e113e528f8324feca99f46cd842528056da5fabe38a4166cb5baef509f5f74350a3c58cf37eac78c65091520a2b90fbdf2fb90ed4bc271c56eb83471c9ce08dbc6058ba675262d16aa13a5a352d810b8bb8b384d601806b1cb6be4190d4170293d8cd74eb9a8d41dad870422261189ac0e0a4a6e7f35157b031466074b70ba76616feaec9e5dbcdc101f1e7c2ed5392b070272d3050f631b748d47208e862e5e49611ba77b1272397dc3f3a329c8d58c3ed5eae035bb4fe5d146c7abb55df05f4a0fbc37f8a4ff24a89a257b4a42e7c68f7c2934bf533ba23d84d8816630ba4106d049e0de5e5271d827c97b8a570a75b7d424537070c78f74f4439f0b5002b548571ebc7db838eb4ca98991f2e7c661e3eedfdec3c8efade670a415b5c6d686021173e8209621ea07787221364676009eba27cc5cf8e058b2a81cf7c08d857bdeaa5a6fbb474f8dbe2d14eac366374111c6b0fbf305ffba4ae17f7b1c8b4a7b16fd343d35ca5fe90d1546a10db741e54d13e6de6b26a5db86dcdd2953517f01862bbcd68d98c032c2a9af18a6e10320bfab0d42204863fb5d709bf7dcc65aa1e5c832dae9730feea39612c19ec854692ef90f75d00e5ef051216897791281479b109d2ab8d635d226ae507e94af0d08a7af3534e8d696e457f44e10b5773fffbafd431daa5969739f6feb5a8e801f832b68148a95f93ef1765446fe5b000bffe66491207e3236d54ee01dc87524f70fba91a648cc3526dcdc03cbf6a1ea5fbac41b753d14006a10d94a3d7117e71265600568acb58aaaa8cd7cdff11e2269e22eb60aff64279dd01c31209205897214e5b5e821a30d9acaf92d32ba03dcb7fd87356920f9363bcf9d680838d0d40a2ce21bfcc0ae5346d0b651f0064f11ce5214a6d079f055ffaee5abe01e7faeeb2c7cc2021c3d1cb312ddaaf8d03dd5abecc518ee4d39c6ff0227ffd535407e64ef7b16f403d7bc9b77623a9f2285d1ee4b60861ad2eed86346ab3abf101c564447302fac6935a1857843edca484628749104b4e70fa67dfbb92b24c1d9eab43c800144d44c3834586034628aa749502547fbf2687f9dfb290cf9f5db2cbb11d8cdde0150c5b9d8c3b98c9e80e381b7907e969570127ad4248e4a6012a6db2487dc03d93a606d38c06a91d7d130c244d42aa6f19b1c9b361b2a36c867d04945169942aae72046810e6c0abf54aa7e873e512cfe2655cdb1a5e9aa6f5e0e5894314fbce1128e2e44256588288437fa0c80676556cac2e9d58d95d7465de71a9070049adc4f59bffaf8d89b8d0daff3591b7c00b5ad38914a9cbdcfdcc7488b9c80e03b03c757750dc175266ce05176b0268f40969d15894dceabb2df6b991323c1f39f464bb04ff74115646e2176dc1c669823fd23eb8b079a3351fec86831df2a2910000013373db98ccba6d964ea1f80a7526a20f1b17c292496e133c58668fd102b41c7257f3eb183a3b45d28234558e9c12c3d026cc80a12fb447dbbe52fc977852ff2ff88e6cfcf03dd06f0102e921d8f4bb6d580c782a7ab24b59ac79bf8e4a1ed122aa30ee06df0152886d5f04a00c673d12807c2d7a2800591a7358006ad626bc111a72f311a66f6b2dd0169cd60c729cc7ceab3ba63c2ca92766eb13416dc26666ee7872b02865f80d1759e7386c4fcd61474a50daa817e739006804f7245dc54e5677d5bce012db02c74e0843f9bc4cc1f0bfaa96c53201a8f0d4d5b6cb5a429bfc7b79c9ea27b37f1d68d76f857c39591a5d8a314d7c563eabf6e656e09ed37594901876b2cebf4bd44280492bf776a6c4f7abe7daba22471c0d758c4a1e7b4897489cd730b1843e1967066ba884350f6152e480fb7b4b52f788fd8d544b00eb7d228dad3968efc40a5f1b5cb185146eb0db2dace1f3f58003cbd198250c3edb13b5d698d8e73f8aced95a5325dd40f247997873c07c426bc0b2244570d04dc48d6b239e5c2bf2e108aabcd3cb091f6f772b023bbea507a10f4467ba4007a30b54173d00ba967e8a5c5106850ae6acf1bda732239f41974aeab87249352832a9296a93d21148fc81924cb3091a24888b5760ed54caa3d4d12eb0162b164add6cd4df341bbc8a01081b056ff62928d6f3c1915ab4d41a9a9b94c8f5d6034c0285a58267d2f1a214b11baa4455a9904216ee860654170001c33fe5e5e495df28a68faad9925973552b070013f9dd88cd301dc2aedef58fe8b4134eee284a8a3f0eaf4fef896f50bf1f908752112a8b6bd72fee5de708bf16e5b69fee0f7991124ce581bc41108be8df4e4230f5f05bc278d88a089a850cb7dde60b678af98d5372a88f163016ef26fbe9396a8a8208e8e36e3f01de61bab10076ccf96b91c13d7d41f879067ced15e0b8b47fc15d737e52a58560a01582992b5b361eddba20b26d02becf2622f61ffd7b8e1a7b441c8cd70902d693cd39ec99f7cb06143ed99388be50f5af00ef5bc98d9d0065a3f16804ae8b4ef54771d101a69356e03a6800a3833e1585255642068e98f019c84d800bec0982cf0d05190849619ccd09a72a08977c16ab451b2ad8585484022ef3dff7bebb7aa972d21ec37c5dfdf1e25083f53a5fc261bf05acccc6457df267380f781983c097d10b475176fcde9f3875a764204101d4802f3f29a200533728e231fe0cfd34f862a4bf845707fec8d68a4cdaa580f34026906b89829ffdabe0ec4d0b744bb132abf03f88e520293b11c08c65e7b3453f9ac70a55d0c972202f46b1ade26bba1dfe180205eed9142309d4a4d909606a394fd08977a8a02585942d9cb150cfac40e97aca83f261ab966b1385d9094f35288053d26926d175c5eea93485e2e3eaac927565bbb26963fdc30f896b1818f0f2c42c316f5f5f5b3b4ea86ffa62e275ffa15184b0f0dfc0739967a67edc23146feed15a81e05c14555324cc9173a0e3a3f8c43d8cca3dc9d03d765cf7c0bbe924d42eca390db9551f9807d2c7c1375eb137ceb1d449aa6c6943fbfe3d3c983fb5f1f3cfa2693d16fc2659d60199767b6eb30c48ddf3be6f0d7b44ab683e356bdb91f3ead7ff9b9af2494a92cff0edf03bd4a0c5a7de76c5e32dd64a991f9de1d58a34247551e83ba304033aeb93b8c055e4a1205d767c39cd765b77ef81e2446ff8a4f7c02b6776ec3657653ad5755e7d799ae5cd0c2b7544c2c44c86a5ce9207d24b9211681e6964ed221da506918775ca0ddb73057aef51a87b3a7c57b7cb2ba7eee90e8466fc5a4f9e14e83cc9662ccfc5038a7a441a7584234f3872edd6d0c48ea45c64a11fa0ae53f47624f43521296746c6ef1ee1607ecf08f0c247ac31c647d0d8e42392d3067aecbc4c8a5e8d60a6f200f54bc0c4183a2029387b79c46dfb34c1f0620f54c2adb06cf32033cb9130355bbd28d2d86db3d58f7095b1560565e9e535a2ff60ec0356a65ec3bcf16d5ec399352574dda7ff46c9da903b25c8a0f0a1815acb495efcca1fb25c4b640c8981fc5ad1274c150624fc246206c684ae38100158ab5326574eeedc6a8569e1a4173bf2f740cc1c0c2c8005de0fc5dc0f54205c554d3a493bb1e6238d37a6583092b0a4e7677d1ad804f30d19492ce416cb301b56f7c00fc0f11251950b0a4818436be773ce4bcd3e1d3ed7e96a8672fd8917eb5e428f0bae7afddf964823d208217b6fb977fb0f360f990f1805be6f2fef5d14f8ef1e0ccc439b3b1488818839cc77c47c3007bf03e6e0f79cfce150883d8987cc35de6570690ed6c34256fed80d51f30e07a9f98783d87877212b1e16b2926b30b5f17bda0591bdfbec7ad8c0e1869398b94fe31d0e23a6184e62e6d469bc3b05a44ef3d82920c5a56eb844a6919797f6cc34e76449eb8208bb7706b23704cd340a08bbcb8749cc9cc2210ea944733bd3284062eae190c6939899a6060e73320dae711ae77a5e4e736bbc5e1ab9c66dba069e2f326f9ad3384773391f1a97eb9981a579c8f5d00082e636fd923de69c1c62cb32effbf29a1b0ac935b4bb79a171cdfb9efa6cf74198eff00e835732789953f3ef4a99dbf47765eeefb153efd787432da73e53a781e5513dbc7fdf91fa8773bacbefe8522fbf97ad009965709097c7f478c131b79935d7dea800529679e907d898f73f1ce6e4efde0d57b2776bc11bfbebbac796120606dbdf83200ebd5f213975ef7e770432cb5c763d3acbe020fd98771744f69818cff3ba98dbe36849e6c6c45ce686327b3919658ffa0e3e275b8c82b9cc737277ede5edfacadc1ddde5616e0ff0eeb0effedd1e165f764078afb9cd7c0953e75e73c325720cca3baa47f7ef3bba0fe764cffb8e10480eef5358c84a8e59c9fdfb9c1c23f3cb8d39e6bedc66bedcec354440be27dd5048be94a6bb3996b6f44b332dd11148172a776b22037bef3634038bea2143d4046a2541cd22138afebeece136b4636b22a7c8afadefbd174bdbf7d22c5baeb090488943142734d404a3b82422a039882b2773b2447395810db99ea35ac4865ccf572449ab62e47cbe87dc0f6724875c8b890c88e4d824472645820e34d43d41f4e5bb1ba4eb80f06e2f7b7838ec8f40e6ee337ff1eebef0f007864f76372fbeabb67ff3b3a755207d1ff1ccdc7ed1caf3d8b16721cbee71a85faf9316f1c69fc89305797693a2c8dfe2c6b8bbaf4c0ffbb28b703d1d96dddddec3963d53b4b82dc9776b637753e336dd47fdeaef3506b6c6bd0a03fbe12d497f36497f9cc42108b21d325bde246816010de271366ae050e61a4779a8e130099a6bdcc6b91ab76ddc2e7ac2768ddb34b79a469a87e124e88efe11310f0aa0f9cb6ddac6a5b92f2a8897f71b07a1f9cbbdf76d27fd75d8eb4ebb9b28506edc2137cef94c70ca9b4a5dd2dc50669a6f40a6cfb9327da61c7d5a9ee0c353fec0ef8b0265e6b1bb8179ec6e62bcc3bce63387519a83f50e83fbe5dddb4feec5f46b13ea1898873197391773fb48e6f6cb9389b9317bdd8d4cc9fb7c1fcd5cae8833e10d688240544fc15c50e783eb4183ed775f3de4a4d8603ead952edb98c6616ebad5451521801b17c04f7363ae61e3e00d5b8b3c4fe386b3489eb717099ac3f62ef71a3bb8a76ed3369cc4b08df2bc0d9a671234bf7c763b5e5e4a3682d85a496edcda2380bf5c11d0dc3808f7d46d5c9a39d5eda22e6a55b809b513d58d116c8d2be29c7045a91b2641057051f2a66f42db14adfacfd011728f4e14789043cd091b6e40291cb3a70ef9348995f8c66bbe5e9f77d4f7d9dc4fe6cf3cd25b4c2279f6d1ec993ed388f536a0edc8ec38d9afd7abc7f3f6e435b99fa933947bbab7a1b98a31c6e885f43dc04071453c7c7ac1e2e2a17cb7f2505ecea7bf1eae872ba25239d7137b389fd9c386dcb53777fa9b9ddc9ac8ed555f60c36de828cb6f4344527e6bd2df94f3ddbd5df7ad49bffa83f93c7d0f6dd7e110066f4443fdcd701beabed9b3454e4776d10e17b697945c4fa8f5bc26d7f33d3c0c0e531e0e71e4b05ff7ff4a6dc27a0771a87d38bce57a3aae07077da2f405ae88776ff8d9dd745248296b3247dbddafa0dcbdbf1d6daf563d6915e9922b32ad7099f0aba7906753916717b27dd857c41c2df7613e6c29c478d84bb84e9267d84af2fd3f37ce4983f3432f86ba0d0813d5c891490a8ce47eb50a893e1249682d4fc266ef13fccc3f00f537b72301000000c0b9b560b6d606b4016d47405082208c4ddb1b00976f475ae5b2b56a7777bb006dad564517dcdd4d00dedd0d00de97fb817312b38833f33077c625beec6e665c7637f87d37dadd7c381c92bf7346361ee2a079980abf87a7540df83ead98d4e1bd7128e487dcfde596337ab95c9174822be29c34cc6370a8c5c87c06cf9c0687a7b90d1c7eb9c6ed2771669ec66d39c49979eff61c64cd7ceaf651cded2d7e260d0ebf991f19fc13038343edf50298f78dc41c0d73b7a3262c38e3f27efd42ea6e5eb0b4f2e5d28c45613ad62df1030b499372cbed1dc499790e2b795ace4a5c1167d4aad80100800bed3a29a5149e10b1620e6c18aa228b17b9e00544a668a2054860cdcb27332ed6ee4f4b224794358fb6577fdbab0708082866318323497002c8891b702074440b3a5b08210b3a29907db3ccd152cb4de72161cfdd1b238d5f5bdc8376f78821d9e2be794aa02352220937a00da855520570a0430d5e37d8420a39c400065760220d3a433fad1f4ec8018b1cf0600c3da843019ca8220e403500431ca460cdcbedc8d05c6daf6d686bae677bd172638eb1bd668c2bc89c4ede8ef26baefaa7b7578fe7eefda3591c6afd7ad12d37ca58d39771e7a571a646b0dfb20217433c77786b6d40fd63a493b42ae48af24fffcc6e714eb822ae28a7c70d4e0c01084b8ee0063394dad0043abca1065a1889030ecab006298844e1043c50a1811cf4a00b4c7a84a00528a4a088007264b27345ee57ab20cbaeb99d29708e4c76806af63eb989baa7f87987715be2e7bd87fbf8793fdd95f8797f716dfcbcb3dc52fcbcbbb85afcbcaf5c1a3fef2a37c6cffbec8078ee5a72775ab12520b46cdf1d10345b7c84bc54053976de7374f14049e67eb922fd4dccf9703dfde67a5ad5cfddb567fb26c6197bf9b2b89f743d31468042c70812da400738c435ac410a1cf480065228028624fd62828222b9e120575c8f04b38839b6a1383373703e7540c14e8e4c7e767cc8910a464bb21273d54f1a9cef2d56804525622393223eb92bd2d32f174c31545b606350644e1d27272547767c767a6ca3fc4888fee6c3de224f943381c11c32d7571ee572451a9c3dfd455665817d779982bbd9af8982b9124d62a5fcd4e9c9d3ddb124e3f4fa36ddf88899b7579ce9da08aaf111fdeedbd08e98fba8be3c176d67258e71a6bb4d47dc4ffa9b8d1b8848176955d82f23ade27a5a255fb327cfbf7ef2dc9a6cafe8326124e13694875af58aabd9852b54c1051d2466a08235df4771955364480c423048c21198b085b8cab9410eb4c04313159c00083960cd4f9eb86a400bb270848818c0c0843ab0e6fbb64f7f9dd6f54b9ec0865ccf51d83d73d52faee749af226bf258d24b2775372425e6ea4783f357e838e18958e4f90905cbc3e7c7e72776385cc96174b5ec10e254b283ed6ed3ede0e103e403347d8ef0f0016a553fe6d8f1f001f201e2e1f3c3c3a7d54719a857fd9ae0f431c244074d72188f98e8c0490ee3d1bbd5e1f63ccfbbd73e497c8ef818f1f9f1f9f181a25f3c7c8c94ee8d6bd35f7fbb4268fdecf6b18e3e3ffdc56ca369d69e4efff74d15d83ec193dcaf56452627c022cff793a93377fa3575e4ab5faf16f4ab5f793eec17f7ba4b740993475c6865294b730a369eebeeae28fdb9d27ada88961a9d190eeb351c9e349f39b19b44cd3d8db3a28c680536d47a5a4655f6b0359ffe7af2e723b1d6d39fd47a72bdd6e3d3aa58874ce78f3d23ea2fbb620a363c658cdaf08efcb141c63009479c11cd9564650fb326596659508e0f4fb973467f6a9594b9459ec70f17f9281fdec8e1716429a7c892874f10bd3c66e0e2318325465a11294b35eba819e94f6a3ffdc94cfbc9f21916adbaa6d329d822871a4ff6ca5e59f627a3609fed37e7496aad8e09d7974ceabb4b5b0a0c19572dc17e943d29a5b335124a0f9136d6b267cf9eddda741267a44b5fc1459750d3c95405963ed25bf3a6bda6e0524a8c87949aacd5a5023c640c87b1a8d6aae1fac3a09aed2ffb8368d8e2527f5d55da394dd334ad0706398c45da7968b60b42883b73ec6e78f4d73b368c42407a68a707398c453c8eb094a41d45c24074265de67e77777777f749987679cc6009029a5e0322767b31cec8dcf5dec0ddfdd3d4414119340d082d3ac1167278e2d1d44ebc235f2dc83a18d78252899352b68e4eceb08c5f3541eecbec8e204b196bea8c39eb14303356694e6e28f46a077bac486876794a074b1f23ab5e99b18e47a4b8d4aa428c31c618638c31ae808b8f2e933bdd1d31cb3823e59c73ced93d70721a8538c787302198e5e966294392e6a4bf7867d10de57cf144e1899e1c99fc14c957c8518a1bb4b2ad3e79126989e0944325747474badc0f55ba58d30f514a39ea888ff5a169c699f95a3373fdc4b273d90db1ce316735c43ecf61f7ca2db21ca49ef6d7f59c2ce5fa1a7354497bcea6126b7df9da022eba8429b27d5010bff9b045a73714f4d010d743434413d3b02376e610fb31757723a3ddb63cbbafe86e3825aefe261774a475c40691ede494cbdb6cb09109148ee49003026a15ca37a156d9cf73dc10e7a4552b9fe78c620e179fe7d410756c3f916bc22551c2b9b82579e3011bf2ec2b4a1bd751232cfaeb24cbbbbb6139e7c9ad09a14b86f150c6462e460c3c04c787c3c0418213e33de47ca9ef8ba8c7781132def21832300e8cfbd012e33d1cc90f18f7c1a6e5f270b962bc87fff0e13062bc8717e1c361c8784ecb7fa0de72f99696cbc0437064fc848304a7e5590e10238888885042c9ffa8cb78112d3fc6f95b2e03e320f9718c73ba8cb7e02143705a9e1dc98fd3651c855120b84a4c701e7589708392ffd1f2ec3f64fcf4d8a12426a2e5d98b90f15365c2e5f7f3e165a300f0902372c11cd0047df0e1317eee5ec99a53468cb7c838d746454b38659ddc42e7087bd5b1a1968f5a73151343ee2573ce05f390137a79c80d7d2d0fb9a21c80879ccccd1e734f87b93d1cbc30de32e30170f9cbfd871f3b9b96b99115f372232b0037b25a8c5e4746731559f2c5e1ad68234a0922e2b81523ad9278236a17dc0de237bf11adc04ab911c51c5b1eecf6a6c20abe20314657603d105f3908e9253a042b5fda8842ec67333a5234054b7be826049d9ad026534701630b0a8adf3cf613412c8aa048f160c3ed482bc599f993146020aa42f7d08fdcb0faed862fb88b84cc21f6132651b996de8864dd88e66a3bea8d48d6a3b9924678db69288c24f6e106f1e37cfa9b2f021a66f0622d51dda07383a8da7a103f9f566d53e388b0de5c1bbd83954164d876fa4371f77872e8f1d4bbb9fadb82b6b040f3746592564b4e8ac3d38771a849798dbb1bcf1296e34847a42d485b64d2519e1c9ee142d360659779d2543fc9862c8de2370fc2c4c4c1481ca098021c944c010e495e4a5d678e4689da21cb1a255a07a01c6a3f366e68614d97bf893342023812808a0eaad51c867c8480914ada555d57b1e9a0fd864e438f6185430eb6bbf6128e013cb1f4dcb71c71b03974c041c70f593414047859eda447b1511577c2a08029012342bd00a0582900595efb64b81b0278836d1fac091811a2ea0871959d84410113025d9d2e00951b6c0f0fdba77b693bc20d3a8a2884b8ca9e83a443fb6c25e4a9f520cfd3d5e93d70aa551bece93b627e149951c801f9481d51d684346339903a361aeb0a0716963bd5b62ccf5d5943654a9d00546cb0aad51a2cf755182e3e83804c50ead877f726577a2861dcbe8beda65befdd957757e5a59b72eea23c76360dc3dec8e280c422203d601b168c030790b942c51b3157a84822619cecf2248c83041571486f8c8a8facfac89a4ac8bf3807669fe5f1468d42c12a21f18e1c7a81a38de740c4d43666c146f94577d3010e4427d8f89b2350a73f043253965396d317dbfb3bf5f22c1875c23e4818c59291fea34f1ab2bdcf827fc8934ec243eae545b15c3e87d517c582cf726279184fa717e7809025795efa4823bd526925d1aac884073d7227cfccb3335b4140c8a59f1a1c2187128ad30b1620ad8a4c96a024cf4f004504e9fd1fa4371e8284e51c1ea2fdc82ef110ec190ef6faede220f9816114cb2b8e86512c1845441f7b11f2f518bd0c882c17e7b05b7abddc49577b76b7af5cef2ab77bcab547b9a6c7ce870bbcb363b56fb7e96c02fd4d8d2b75d3742718591c98e034024824aadfd18e7df3416ae96f726082f3da05c104e7334cf2e0537fda0f5d0225a7a91503175dac247ddabfeeeeeeee6e9296b9b0240babd736edd9f2b95f72d2e055ea8f4a1d514a11d4520bb965155a2ae9cf2583aa8e95a70ce408895247eb84f1c5611a8771dc16f1e07ac26d58d564506e4c49aba214762092fbd2483ee99564a2482e69558c421349726722e90a6511d723050b88e45062219be4be8661a52875cc96ed61241cfe9501214692557f9aabc8526229b6da2bc719736273e0a24ba8fdc8a8f960ada7ead8782073255912281f49622f70d2c26691a5bca81e39995e1e1192304a74b05128c79c814c504eda041b5f078c6258c52a95328c2e3a85f608cacb879f4d04a58de08d9f3c76b548e3274f5d99a632b5b9e223409029105aae151f3124534ae3c0451a3b5de67c96691a86c3e7ec15c361a645fa1cebc566c723865af7a30d53bf11461c3fe4b6e96977a88ea6d939e30b0662c873626a69132eba845b2b63e7e61312083b983588436d84bd326171ccd5ca2ae5d8413057a44b1ff973a3532cb2c721812cc6421ca74894431cd839d295ac36c28c48dddd2a244db3f674fa81e67f3a613dc878714261e15cc8b8a4f770557eba30fee2a2ce7977612a9da57bec6c5ac68d2c14ae6729d21213366c9d8c9dd348a4ed1ac6d1be69df30aa71b693481a772d499b7d27d8f62143a23ebbd15c2169c1304efa0eea2a9b760c890f3804b275e66ae5d825d15ca9fc855155fb0fd2b5d76b2ae77258a13c6a9e870dc43dec16f663b1732b57b252aed15c6946b3e536bd72238ba3496c6711b1c698c8586b91b114adb3358692fe30970fafaf3ab68d5c8e619f3a333e7beee35cc93800ae76979bf219d7c5f15d39ca4559191765cff27b5f3c769185323457ad8c1deb21ac8932e603ae1d2475344fc6ce65cf2816f626d2cebd08d2378cb39d740ee320f9b19d84518dc35dc3a88eacf7879d74bf09622085820ddb2863dd4dcbe56d2c6677d36a8833d863d7467106934eb0f208548c10c823ea6dbdfd112eae558c8a81391414ac246f07b59225197b07d51fd816ec1c8751f5dc86b9ffd0cee121486ac53f526a46f9e0b6b7dc9abb3b22089963bcbb9b9677e703e5db4555eea22afea17d7badf847ca65e0212b4ff91017d76c6d4992b1c708ca5895d8eb0f6ce796db59fbf62252cec5d88c5c544bcf76512d38b2a812bb01c5c0dbcff693311fdb1910591b46c5f8f61c560c8c2282f4ed3f48dff01024313e04c6498f817fa80c415de539ac964bf3ec5044a09cf41f2827e121485a3e841ee52df807e92a78c83ce9724fb9db4917e52a97440477ed4570d7300e921ff3db71e8399517b13d05e3cc6fb8e5cebc7251f691b572171765710fdf79f11d1757f9cee93b2cdf5979ca23cbc549da5148476d8771516fc280c8423997a2b2e282e5c5a9871e5edcc862b991e5e246d60a2b05e5eeec98bed37d873be93bde774adfd9ae59dc12bb6c72fb3541eca48b7dd3c1def964ecde4f9e4019f358a51b59dc8daced46561b4d109344fd61cfb01cea0fc34e9b601b7bdc5a39ce5802e372e4125a4e6b3e14758c95621806278e1733fcbe9ab8ca9eca0f0d901fae561996690cc70643955cf17c88ca33c6181ff12c8a38babf3cbb25fee2908f59e3d01767e67d60676327c85c797ecb348945891a98e7cdb3077a8a528f25aeb70a393c652933976ca2d9b41ab1b43f6dbe92e0a24bca0a653047263280227391c65a9bee06013db049fa9b4037be7a68b3bc5745c8cabdbc4256728642bd879fce8414dd258cb516e6864b64db9d6739efa6acec3af9eef6fb6d2fb3d7ddfb76b3489e4bb24d77979bdd4d2b91e5bba5779b9e45a4ac324e0ffcc0fe776b640ed3751fe8cd783804c1cbf9703de041ef9db7247bffe214d9c3611275067cd85d06fb741df64050a6eb8ec832182e913b1ce6e4cec6c4ae8b19a286acb1ff9e92359e5743d678ffec3925c0739cbdb3487ff6880cfcbe1be3dd3bccadb9bdcdf5d43c763735f7bacfaeeb5c724df7a9d3755dd7c9bce66e2da0fe8ed0f80c0e7fc8339f5dc90ef635573d4470e673e63233afa191674e13bb539c9939285343032353430303f39898981a35700d5903731817879999498129181818989973b20482b846c80ff9c56756b7f2c0a25a505e77208f432039ac17b292714ec6180097dd8d0ffdf2d495b9c6532e2761345ee24eeacb70defddeb78379df9a206a0e7399213c100471282483e7fad21ce6cadcbb3439303db63f76d6c2d0dc6eff2ff3cd7b63191a181c0ac932cfc91d0f5993ba4cbd461feb0fbcbc27f37ddfbf73d6da98989898980e06c67b5f4af39ad7d05829a5f576c8da0941e3fddaf1f80e805bf3da2d20ecd7e0d21c6c63212b0078ec86a0f10e07a1f1c64130f062212b99c6870581dfc75cb08d370e4b98723889996bdc468da752af914a615a8994c2c94aa9948dd40b7eb98de3c39cebae4763981beda9fb72d2b5f1ee86e8fcf23e6ad50b9e1a4edd3e223d915d8f2d7643e4d41f2b71286bd7a30f2364a5afcc12e65a7777c7c4d4ae4256328c262f31ed82c08781f9aeddeff682e7badb61adb5768898cbb4ecbaced677e0ed77802ded6733b5205a9fe3ba2bfbdd757fc7d7ed88b9cc67d723e63252c65ce6323128203ccfab5de72e27d392bc30d76e04ad166a1705c4f7eedd777c384a8e96663704f8987b41808f790cfe1ebb0ea380e8defd1d1db671e67b631b6762d7f577d84fc3e11219e6f58d85ace4e486b9daf1533766d2a519c60d85e40a002cad0f8fdd8d0f34b70fbd8231de886a3c06872b39e65cd5818539781aadea7352e23035039b7aec2f25c3d51cd89843a67637e00d6506a3ccbd542a891ca42fa494651e96b2bd0684fd0d4bddfbde3753e7644946667bc95c76c581fd2e739ad6c9343d51d8c9354fe4762483b7d7f7dd50e6afcbdd381452cadf65f0f6e4366d7f792df692c87d9b190ec932787b0929e50f6f4750d870d36404fff2486deadfb9d4dd88bebb0d35196ceae136d4a71bc7791c56aadd8d8d3332c7ba1ed825ee3ceb79ff52f76eea3729bc0dd9b81dcc392dca9e9e0d0cc2dc3087c6a5fdc53cca98fb974b33792691fe66bd81ad36b028d74e70bee56afd75cf1f39e470f2d460985b73f06e47faabf19a4b295e329d8ccca5cb6afdc1fce5a88ba239ea329f2e8ae6a7a7ced9b8e0fba6fedd7003ea6ead81fda6c9a4b8c4685ac931afb96958cc8d398d1be6641a97dd0d8d733308fbee395976570fe68037899a2bae216b62685c178fb92cb72c3f40301c14adfa0edec68d20786e5a7bef3bacf79c6cffd590356006c1dbcc98bb0181b7e99a1bae6498d35c246e500fe2f414a6fdc1dc66c2dcbb9df24bbf90a0197563ae7143212b39fbfd76a4b9959b7ec9939ed7758fd749aea77decca59eec2e536cd492e7634381c9269de5d8cdda6e71133d3b0d0a49e7a67adb5600da923d5653085c39c9c3a7825084a093e75b18739b2bb91dda5719aeb028732bba07196a768d0f82cd22a96d338a9bba181a59d4b324bae216bba50e695302e097fc81277328f7305f31a524728738906c71ab2a6fb6baeaa0d5c0387276f2749ee2147a11d9fcccd5205a246e64f4331535247cc12cf22fd35ccb1590408b97a0a4a48e33430ef15e67a6ca06010c709c6f8f2186b3cc69a733d2fd8060eb51a38856b70cde5bbee3237f57e4d0dc4384ca266f032ff707802df9de696e66069e0246a8e799844bd91ed69621e621d96b9ec7604e94e730c0e023e26899abbd33c4ca2e6ef3438bcf1b215cb3c84c14974fe2e83435a73bf86d401e220df636edf5d1031365583c39c0f07e95ef3ec86a8b9c335644de322399435648d74717959cecd928b1b5fec65b7c3bbdd866a6870a88138b4127fb7d7d364623859929930af797797e5bb9d652eccadb9e14b0da923669667b3484e061f23435303c3f50dd2ef1c5efc1d9452ca09e49ca0dc7537e6df8d30d6a6fba793b5f6a64b6b6870f8721998fe4b8e1097ecc91c7343971cbe5c884b26ddbb614e26917eb241aa21f31a191a97a15173991a34f61d730973793904f8d02577d75d77dd7507caee1ef362692c4d9f93b73726660212a3602effbdef5d14ccc17b1d0cee11fb030fe27002d9fb87c30964896962ced1d0d470c91e16e292696afc855443a66a9eaab94ccd656a6464646a649e929149c9d090c1349eb271994be3f5a668d090b161659e3a27939249c9dca66d90fe9d93f6ddb521697763e35cea610b8d872b35de5df3ee5ccd9543d03cf61703f39a2b1f733d19ed46ff905b055ed29c477fb3e6cadcafff74ea3ada60570387da69744fe1f034040d16e2926dfce51607b1f1cfc6e7dd686d74df3b181ce6641830a61fd392bb25d3bce6f83437f61783c353ccc395540ad3bce6c6fe68700c0d0df897c7c4d84cf08613c831f72e8cb53848f78ff4affb2765d75d72b464ef177e0f414e96b7376c7b7b1cb411c61c75f0864be42f2728872f8fc1425cf227c4a5b361e336d3c625a16e985324bf1cdf7002f945e6c6cc6da7ec94b99000703b8f74bfbbdc98bfcbc8212f979923dd3087eba181953bb822f67302b993898101afec7a3c836067bb7bf7cb7d3b67000421f377995fe66397f2cb63872bf9a525bfbc9cbe3ceb6e5efae57d4e20f763cc2bc2bc62cc5cf776322417356e970fb7ac9cfa9b7fe9724efa9bdf8072cc9b50aba6d882ba756890c3cd75c395dc195e6daf15972c71cc696e2824d31ce68632c3d4c89cebcb61980f043f9adb1b83c43c6b191999f0bec6ca5ccac4dcbe361326ccc9d9696ed8bfefae47e7ec9fdd4d4916915d772e3ec076b73194699e3a1759360aa9c09569dee78290b9c669aecc9f07414e62e620a9d33cd4f2761bef9a6b3548277bc0bcc1f7e58e9cfcbdb3d24afb61943daa07f8ef3bc0afc777fb1d5f8eec0e731350f3ef0be82effeeca04212364880edad48ce82f7b3bc9d92b15566291b3cb4bcab1db519f01e92f7b86218bb09a051b365016b12c6259c4b2d7296cff9345facbaeddac5ea1a885e64a9b60764db3364e5994659f473c11c1ec35c8d977903320e4ecb1933d712613ca99d0a6a31991e6d448e17b44d279c41c5223655128ec219348ff5c752769f67423487a89a47128db3389442291488f2ea427a82b6f593663ccb06049d8ebe9fb1722fb761e3147ccdb7bc41cdab7edb4b56dff5c79df34bbe11bc1eddbf650cb1bde708c603880bc3d768f33dba3d0f6edd165c341a8abb19e1c5bb5a9b0344b1c5da2aa3e3a91923a4a4c907297acecc69c1357dd0a922b904e7037b294982b0844905e7b289d2043a6e70e3457a7222dbe9ee4eda27e70db39ec5d14dc6db8cb23b268108e309e5665cfb2ecb58320579f20108e2830a18dd0ddafdd4d03f5d747ba45d4ad29ac0c3fa43ffa2bb81a88ba828866c82588203d131a0b327d68e5134ac419a08cf5d42e7581f4d3fd2aec9459c495f6146d9d4ca516993e3b8eb9d2b034aa38328d33d268ae6e8a0e9912d12c6d8239763eb29150e3c8d228939ae2808b2ea14927570cc3302ca262cc84b2236da7575a51d62428573ae4aacfa66855740dc1956b66946be7720de10c39ccb6c83523ca357392eba38675697b7c2ca1c4fe82ac3d9dfeaf35c1fa784e49de6e64752b4ecd0b3868b1866c5f42ba8188100b09fdbedf5a2e6a9a16856890246f57b2baa569d69e4ebf16390ceb6e304d9b5558ec3613bb3d5f35ed9ee679dec9ce154ef721a81f29df9e825390c37aadef21aefa8908d65779b403a05c49f74e93d8ee0e59e2893804b1ba635826543f04e5db7358b2634064c923948b2a02e5294fc1cd33c17a142c8d265875265833a18af9e47aaca755a6576bada6699af6d8596bb23729c9a667dd8dc93eeb6e2c969666ed58a70099b19efe6acd70e45abd978ea3551d10a6ec61db8dacee8aa0095ee061957004d12e5b19ebdb1a7d164b283c68509f493c640c4b2f5893ce12b262262ab69e19638c311af5974a8139a4aebca2564490bea96b8214f563bba822e8372a3441fa20507a34e537b9a23d13943a5a0708c3c8f451d2944cb5384335adbbbb4f3d4054c3a1cdd829d37b3bcb0791a75be8b44a4a4cce170e49b8ea607ad41fb5597ed53a3a3a3a3060d12622183302de908208c6943c5f7345b588203d139962f3d5d1a3384331a04ae9b71eacb7297af23c273bb9559bcd2a6c562a65380877adbb2ce338cc71dcb3db4cae74ab15b4130d59c2480c5a2cef1cf7528905acf9eda27e6cb7b77888fd247d763724d9cad94b9f55d8302bf5f5806ce520a5c78ce37d08ea07cab7a3e014e4b0ecb7d3249612cd1589351fbb00280fe9933c2916795227f9c86a27abf2d3ebaf09cedb45134415618f72143c7570174d70f6d104a7108260434af49a730a1bca5677d96a95e9f3480ee9fcec803065d3124399bbcdf4ee08ae68b5585bee642b4876d9cadc0d658bbbb5bf0c0b91ad5c1fbb10845c31121bd22a58f99012957a64866d34a0420eb0b091e369441df47fa4420eb6c8510a28004246550c449665628e9b9aa9c9f156eaa0b88b353d717fd2818b2e61495616c42a5934aeb4b9229d3211575a75692ca835c8f4894cb54c6b50a61528d3daca5a9c5e149206b15e641ad41f9598b62608051b59f221356a654a872648872e2d9a203d3da25bb42a32c1c14ea6af403549af5c0cd59d56452650609169ab1639aa3e99ca179339942187f527d36d08074572588fb0429bb1daad56853882865cad0a6951a6a7a7495a15b9b0851c522de4902ed1893964a6c7418be64a9e9e0e4d3a24d32a296c488f327d6324680ebf4c437a84a3bf1a048b4ddca5d66c92a6699af69a655956b1ac6a5957acba3a16697d1f33c43124dfff718202713b66ce8632a179348d8c62a5820d65388db2a1252a3a25ae16c192e24a9d82adaf2d1be515b96224685d39d925764b79bd529e4cf94e71c51cf2f395083d71667e72384e70563cb326294e344cd3663de7532ff7435f2f5ff13ce9f51ce9723f720bce878382a3dd4dcd3429399f9f50c32946294429432945fdcd9427fd4defc8c7dba255269db0947d6ac529af149f231ba64cf1ca33f48e525e79ce942725ef48a6bc525eadeacbd6b9411972f859993245ab8ebc234bbda309ced03bcad3aa70434869e5598b605140e44ee2cc25050bc307cb4ca25604cbe578d93180c4f28cf24c6925818b5be6b098b7750651d6561379befac8895a8565398be615fdc926ad9a93a8bfa22858f94994e92711d7433454b34cca8a433b0319d44f4ec6d8b1b923799e9b5eb05148367439a0febe2fc75a043b73c5e129039ae0c47006345799d00467269409499109e5f989279dcf88f29c44dcc4563003084d5a7aa5664312850d304359e37ebc577db4535ec14a4b258d315e21b116c166747b65ad6e57e67a65ce5c364c19c247337898d859051b723d5aa916c162a5193b98e1d32a2c6b335ca72564ad08590b5158c610575a1aec1bb28659e890b5572858d2490f5988588824e67eb2562a4d267632a94fb045b034c7384127d81086110ca3c3c0a2ae588822a8bdd6674da24abe3e238af55951565f59c01057f8081f99216baf9c0bbbccba26addab22257ca90e92773f509da67178575820d67f064ed33785a25af7d0611ed306014657995d65c49164b2568ae224b9ee5157374599ee509cbd10b9d563961da4196598e2b184611d4be6579d34fcca192250c36c4d50c9f096ad760c4216baf4aec0c9dfeb4e3a3193eb50956862bd7201ba60ce120cdc5f1c419edb16340b398808fb2f6193e30284f0e6118a50c65ed594744b364b826a8bd2ec186269d1a64ebbd577fda371c4d3a732559da4d3c291a146c682292b57bafa96dafac1d862661184d50dbb4cfee0686517fda39184652c66bae344969e6cada5bca78b110bd8820b164bc26a83d94f1ca1a0ca3ac91ae6924cc423441ed5509369ce193b5872c44599be10333d42e45b727bbb04c63b462047118a908b67edb5a3546927c6300f54781a839a5c7c551126c8c9eb94ad1e9c9f4306200d152b4734e4cabb54a6c4e26760e31b193c9260510a0c8d548abc2149d9e1f1f2341ad0a63f4fcb42aecc115a348abe250aba214405b64fa18477ad52c1a4349a659c8610c2814405378b6d36741e65a9f0de5edf56136942b4ed1414298a293b2e1149efe84c21844c835898d52f8e027872e8e60842e8e327d3d824dd1c9f4284731877ce8b5b622a170334a29e293319cd2d39f11600c6158e693a96b825e2b0ecd5576cac4d2d7225852c700122b8b011403688254e61845769b9e45564c2dacbc56157218032806d05c65a7d784bcd6ac422cc270e831b1626ac16b651af6e0caf4d94de999206dd9300650fe2bced0bb20aa44b0f4710ac51c31d35a5dbcfaa3293f991ec32e4fbd4800b1436679a4bf22fdc508ca54c600aa43b0a1cd610c5beb45a273180328d323d1394ce9d9b1230610e20cbdc4294f5019a787c5008a33f4184ee98933f4f9f260188661b536c9b5c600923a62a658a4f4b8144d152f74b75a3d57add39140775ad54fc2459790f66cb922d1ac3d4da37a032bf1ed4c7b9010b99edce79e2751cc2183241639cc5cb933a08e02d0bc4d6b7335df134fa209760694fb1910d723bb9de0a24ba8e2caf495e678c4d65c8fd899e3e37cbfe77358a1cd3cadaa99bed4c35322d21f2df59478a60faa3341fa2a043b1f967860c028cdc1cea31c6a3a2196433ab3a6d35f14a4d720486da73fca71259e1211fa52107d69097da908359269a927d31250a6a556a6252599729bd6aa903b2ad1129106698908f46149275442c3340dd397745a454b3a3b94275fbad31ff6a3566dd12a0c6b3cf56a3a40d029f1947832bd8a2bab02276592202c5bfdd587b26524cbba24ab598649610722b24787c8932c659546962cc9317774513548a10e434d0835d184032c54ce0e71a8113944c3e08008f6e312215776252f25d9660c27c172cd1c98601bc9a19ea2486258ad35ab533eab73665372c1865148081f970d6456bb8344ce63ef29310cff60d36348a6c7d1aa5ae7c4613371a8f94821872fc278b21b33113c5a352319a21533f53b58ecf3218edc40b2ca237b67f4d8fb071b1cfdf5e91696c774613e7210ec4234b0e34cadb8f4d7b7426359bd4252f9346dd6d545694f8e08bb761a8f48d5e46d186b92a5dd18412dce49399ac45e801e88a4923eaa21532212d6554bcf459b9282b51e95db571d4be98d982b1829f9837a7cf570d4c50e43fbe9665fb9a8eae2a22acb45d5171755dfd9342a4581327d8823d314c591a90af6d11fbdc53c56d8c3928e1168b9fe9463bda9fe28cf736aae50f6261c7385b218454496611cd349f74c2761148af70ca350228b3e5a7b0ed853abf268530e84628a72e37629142c07482f9403a198daccbede094000489ca191282b6129a66a5fedeb11d8b5ef905029d88787512c134659fc03bba71dbbc53f48f7eee12159ea4683f4d8a5a938435f7f60edc354a62822b07b2f8274d32d0a45d947967751166b2858eba1ef0e458477ed3fbc6b780812fb21f3de2dfe617a8687f44ddeb36b3a76b3ecd88bc88e611c243ffada71e6338caad74ec2387d0da3aa4da3aa77513b3ba4673b2cd28dfee88d98f4da2bd393e837ae44df6140264871f4475f71aa3f4a4f9be06367be4fb51cbac496d3d4640599755a86450c0332012933209f642925912c31ad790821bb2b04027c640d7fb9edec6b73d5bd7df07804fbdd8d1104d2251c89b85abb9bec15011c76653784cda11119bb101fb9d6acb54c6221a9dcd77210f503a98cd59d2af49041fe943abb22a6e6ec69a3f3935f7018a2c21443b4ce2674326dc248a62ee6a4957e52da9d511c6462b472b5e91b07999f39083da5746a326b6c564aebc43a932433f4c4288655acd2fe2a903db54c8dba8459d16a634929a5941911cf3c7a8dc266456488af58bd93b492f1734e21c4883f196d76eae382fd6efcd0aae6316ffc247b6ab0841c5e8b01155af01272b282f5a415c3b22371495c32052eba70ab946b9d56fba85a895a75054fab8a48273e4fb29547add3442ad697c70c96489f56855f8642bbcd4388fea4103c1090e303cb154c8ddc8f3247ee9495ca6ae5fd1b7374efaf5c252628af72e3044b4f99f12ea30e5944d6c86f0f67ee6eecfae86f89c51e46212180cc95f4099245a40ed944d6c89fc293b525d9a488cc324836d92e3bc8ca96441394d734229f2ccf7557664954ba8c51c87942ae3f9dac8d92283f73f73a7c55251c620e871520555578735ba0763d9e49241b04d44bd2b9ac1bdb2020a7bba9614ee62144abb2cbfbe0babbd1a490b884a282e80fc425b9e2e8b24140ab6ef427bf5378f95385d63307a54b6a905d339965588665b9d2bd05173f65bc9da594524a29a59458a52e2bfd49a961b2e930ffe22726b8f779284b76c2a1f4e1f0f602879a56719c200b8e46384e9062c9e2c0d4347bea233a4fc9823c2513796a21bba33ff427848ffee64f98c7595e75ac11072608e62a31ce84353b2e1d1775713a1969c3b8d2109109ee8d1f5243ea116a2b7ef3b1c8479c995b6712899ba9d46694e998a07882054c9cb230c1a8aea356a18290ef4b5c8f92b004b52adc8c481c4fe5d98c48242e7b6d254a445f291a7145a5a0ae548e39b56d25ec94624af26c4924641ab2471467601045e1c5a14c47531267e6a5d41eb2b478786a5e2f6c2b65a4d40d6fa852af8aac9298d229a8d4765ca082c82e2f63d6565aaaa49cba2c0b4f6d833ddd7098e270f8bdf40e8727ef2c7827bbc09917c5b082431bd1702ae130bae17350c1e117f190537098922aa83c95a7495a86d594a88bba620e29329e2a644e0c5197169e15d10445cbf4040b98c8429a7e4c40797aaf2e3cbfd6993ee6cad38267855734860d888ffe3c2294bccb73503ee33f503ee3f23366dc050fa99f91c39a07e2c35e1c9747168e7dc8c2934d37b25caebdc987e90c882c139e713d14cb9a81eac15d5ee6642cac863bcc6084fd14d71747f66e1cadeaf68622781ca91bd953377084a0bbe92370cc2c45e52a2d2eba1b157ceabaae95bd54eabaae2ba5ac5cdb5f0a0e6ad53c8c1a545b31673f4a1806020924935db0fd4da5bbd9baae54c2309b3eb55cd34020532e6f574a4f4901c1b661dfce21d1dd6c20e878c4cd2563b7faf437efe256286efdb9a91b17878ffb03487fad6c43161e1fad22b50a8a3ea2bb9191942315607086dcc9005cb3a7bb5457f53215c855007011129c07807ca872e9873433b4870140c91ecab0384a107bc892c34cc784a3cc61a6c3440e4d4432774d45486dc3a167594e190e653c001e8df48654398c4338521e8b118e105994c0d284787a86132d92429ee76894a2cd4ea3bbc16e83de2851170b0f0f0b0f0b0fd1e919485a86a94a9d6d5aa5ea6e6a92fee66b506df52b1b6c585b39a8f6f0ae3af60552c7fdbc6d22e6c0f6f3910e76e70471c60d27182622b43c341d41c6435316623c3471e10f4d6ff0e1a1290e7547d6ccb338318da1aa20ce4c1d280c21cecc87a621549eb9da8ca60e34cd8713119c57753b7ce24cdc6e6752e7c263a9b7d7f4d3f50ee3b21c75bbb75c1797714b8f7157fecbe1fbe2d5270525875a66e1992055226b28d104e92422a2ae2984ac994f4db0b6664d75dbed5c7d384ea5545a21bdeb5c644aa40e1eb266de0a4fc8d3c7f3585a7355792a4fcbda26e2ccfcb52f30bd217ef33e5c531ce267a24304a7d461c242d69cc00d79de544504e7f390e777f2fc189ce47919d79485f8cdc7b8262ec46fbee59a8e10bf79d43511217ef3550558c83b5287690a59336f524204a7e9886419826908190aa618c46ffe744d4ec46fde5eef3541efc84483589d58419e7365d299e03419c9f3619775a069d6f680e9d1abbf9479211ea94395c821cbcf26b23c0f1d94d0204a44142404a5291ea954144ac13c96ac73412aad684f54aefc0b9f9ba3ba7494aa8b94292191324ceba124548800a568fb04e86eb24cc7a6bbf9d1dfccd660559e72ef0b5a2e79459e132cfe9aabbac3d3aa2ce67822e6e83ea53657d4253cad44cbc2b2425db0e88dac14951415ec0df5e70d1520257b4a12dd4d23618052a66323532e82ee4686c0c3487d0096569c99676979448d61a46dc348f795692e9aa70ad5a195214ad1661fa2bbe1309656ccd13dbce3986e8f438f22c274fb1f26ece11fd6c56377e362db224f6ea7bf95cb6344f190931cae78428b65c22b4760c08a2c24f34fc41c9d27e69e8833f32a18487ff329d8471ae2d002642b53123d16225e6901a47bd8bb938054c760b71cb2b46c64eddecdde274177d322d0aaaba4611be936a02473e9367d0410d101a51f1a66e1910f59781c5062e1312931f2e2a1e9487e682a0214a1a9065147f59135f30f4d37a8aef007d3135e4a6d911e7a76c03496561118a813a51da9a3fabca1e482a8ea3e5f5a4154713fe11214251a64165c52810b1c6a74c8b3e3b6c8f35c1a22c786a84a712275d496acc90293a8225d212e913a2a8fac992f613460cc5541851f72b819492a445d2ae7b80ef3bc94526ba4adfa442da8218b5cf0c9f3d5555bd555d3aa3cad56e55129792937e2506ce280521d83a53964693da0c4d2e2329247066f8b4b5dfd4d8d844f59c3a7ce1b52831d8264483dc5dbd1b98c25bb5ed1f548d7c3c27b5d6f68821e51e64c37b2b2e869518d2c4b09b3a4c166d7300e392331cc747eb42aa4ae0c44ea489d0d793e4630e4f9308e21cfc72fe4f9eac46298a58785273b044ada6d08743b2240226d58e6435d5d5d1946da284081d20428e01145cec9054a17281991e968dc054a998e2cf9a0b433b3913893611696567ff259489a390c686003a5ec460d8461182406c9b6084b2c3c31470bf13106db398c9e07628e8db228f68a261887e969919a2bcfc87b69150d56c335a8b6fa9b67b0ad232cad23b266b2384148a98ec14eee88238e402222a14191e7c338b419756e2271664a7a457562691125ea6f562296232c4e603992612c2821f14a5f46a753b8195557cc214f6ab01e1918405d5c89a5455dad96c671a5ec0428c85690b920ae5878321da923256ba64a3c1749a4adbaaa8ba585c33593e5e7145aae56cd3c0b4faacb210b0f0b4faacb485b9ce16a240a814c2204498ca044374dc31b169b91196c8c433a9b11038cd080074415e9f31288abeaf22175b0b486cc90e73912947a04dd8eced9391294b42b3152a693e9b45a795ebb9db70c2395a0542fbd3a472ca193e55f489ced7437994e19accc99ce9064694175552a5c2528459bbd04dd0df6127026284596acae4a45a543aa14b1667e4a21cecc17950c76330aabcbd38215de90b706364455f6f9ed0d51857d7e8bc3662475b0f03461b4d921cf7338a568b30fe96eb02fc12d81d3dd64c7c989393d3d6d6e46db1158785878f2b4a6254a2f585a73454404e7ad0822832b4716a115d422cb5392b7b38f175d867d784351d87033c2489b6c41a9debaa4c1795aa7c8f392a70362cb95ab63b0980bba1d9db53711cf0a6f0b2f0b0f0bcf09c7e5926d22e6d86e7ae81d9586381c7a45d933e238ca518e0b59903a38bc847b681a82111de4f9828726251001d3c08918e4596513dad0e9661429de8c84e28c345529e2cad302297b434d94ea18ac96c3ea7aa24493584f8be85911bda156959e20b2d3de16ade3d9214f2f8b3c3d357864c8f3550c9674138f49c7ce7b43445ed15ccdfa69c2c23485d4e1614ab4f3d09407131d1e9adc80824d4eb0690cb88a3c7168c2421cdec0852ce4693a429e2622e479d311a98312c99ab9ca9a58922714e8178650244f8c43131479c3262399ce04e7439312f2bc371467e6c3383454df498fc81b0a83253df4865e508a36bb7c414fc91573b413a5ea8a39649e19a6f998ab4d0d46daa605c744de8ce2ccbc37e40de5f94c87683691e9e4c9655286d514cb10ca123387b444e748ac8160032eba84deabd64c8ab8f28e3d0b6a1597b1674a628e986756858c9d748c67ae3c9c054d103b0987dac4a1e995b167417355b38820764c8749c6b4c8184634416c6882585058873256b960b52a44e99c730d7215a334923a5ae7d4279075c8d8a3c46ac4b86f252bb178bd5e91b932a1150ce389333cad4282b2410db1063b760c3b663429a6721cef2bc7315de57d1eac64ade9382bf78ea372d37be5de8b50f1bc224c5759c13012a52828294f99a55312a96626cfc8cb843286613c3844b9f2a820ba201d4669a90a5b4f3b12ce5cd77433a10962f76e7751a4c75cc25910182c876dfac3be611cfd61276197189609611487a78c499c05f567d39a8665412d00ec2a382b73b500b087a73c896c9805e5a0cca51565ecb3cb826ea6a43fec750b96be3f251694b17bafced1a829061cd74dbbeac4eeb23b75cd15b58224946d16e893fe6877b78cc92b6fe09038857577cb467060aebc9b28519ca11c256a15129d8d38434f23d65cd1ab1ba90ea770b49b8e43baf7d002218a39b66ca3a4e398ae911e5ad3b51761ba46d26e7a11da4d26922948e9dcb939d850488e925cba0c22cfcd901265ca7152e6d895ec50b2833522cb872e466c2720fdd163981ed157a43115ab4ee750aa09f5647a231a073136924c1b09995e8621ca3b507945ccd12719d82632d528a56dc8f40c990ec93224a4948214b1861ee9955ce2dab21173258110f4864c8b9029c5301b1cafaf57d850129d885ed36803c519497de6ca3bfde976b8e20c3da5c274ef38dded714cf7e8a3108523d9003946418a3564d9c973de4dc7b1ef8ee39dda772fc2bbe936ddddbe88ee160f41f2c3de7b11a67b78c8090e53b88210cbe2ed096430c28a2c24f254fa4c90debb9125313dfd606f8432594a975ee120e26446254f103e64ecd8953d5734484f5b28259aa7130e526c8d522a89c0604b58ea28f1051b9e32b52b51b046242c89a486b5aacd1c8164ecf2ce5326d2346b4f922873c9527b4624e4d32e4a9e66f41851f682b5c138faa3380640b590298e38434f44d4436a94250ce5ac36b15893aebde992feb209642765240d487f1915c2d4d55ff62cb3d90a99bdb32ccbb22ccb9e6537c51cf3744876b3a1d5c4d61c1f8f4a10c15a924e88391a073871959a4a0c8939a40efa503ee184048b444bc920d5442a05b20a0101e6c0e72b51fdbc40ae114a0c9958893843858dacd31ca2708316b0427b24ab4bccd197a75fee4e62524789fe52d50a5b1f9a723d8d931455481d99628e7eabe2818b2eaea642084d50d25c29e6d15f5fe2da05dbdddd465db12a7b4c58f264c7a28ba7b3638f9ae91249a422e6984dc495e5211273d03885e8848884930f240eac0c72adb7e1e163ae54be72d3b95a5239779c956fc75139473ad6dd901e79240b222879b8ab1c67fbca71b8ab1c45c4cab717a1728e88ed2b2f62fb0a1e82e4c7ca551e27c85d65059b6e0a439093515e92d79ad8263688bc3d27514c2693c98463673299bec3bb29c56432752928a66ba5cb1bb3e996eedd23641e90a035031db1884fe2163cae8f09d66fb72240bb365eb019c6918a2e6be7ea0211ac57839685d522d71bc1138b783457a52417773344cafa5a6b25b2a46b51588b250f8f66794e4031c796eb6912db48628ef9da4dc4159036c4d5694a238945cc314f3e681cc8e0d429b07738c92157bb7d2c24fdee6e36ad16c07258a936b14071a6be36b17d0e2b5197c541f2c31ee538a6a71cc71ee51228e600425c4935906cee80d87263691467ea29151607c90f94dbe3a4dc741c94db87a70ed52fc2f49417d1a11a139172d38b30e121487e986e5f040a963e13acb778c8290b1eac218865c2da046bd5416b0bacc842d29a66edbf4bc95385e54ea4bf5ab9c72e88205ecd12db418f1dc311c3b0bbc4990cc3a81d3163b8f4f0cb8d43f911c81ceef2dd3d42e601099aa5d15c494db3f674727177b5e450ba640f4fabb6d74b22bd925834585f5b5a56563a2cd12c97b4cb49cc31b529ba495f91eb25cf5c5156f5913c5bbd172c094b9dfeea35ac447ff5b50b363ce55a0fe47f7dc48143c3214f7325a588607d15342de46a45ae2ed2cfd6760d5e51aeb589cdb222c415f6fa0ca8555caecf8ed46c09b93e1ecd15863320dcf5a828d74a86fa5242cd5ab956a109d6ea9a6005aa2e490414d6a35c5fb960e76bbdfc825cc50812491dad0307b9865c1f6528cb90ab9459862b06aac2d2772767272fbb0ca8bf7a79b3235bb0f37d2b22584f064d0db93e0b491467ea8f50ab57846d3a39e3a8b0940a2b678c314b92b3cf26da10571f15b1857a8a98634e19c48983387df0cd147c77f8e4703a830d43ceb2572d58ec75c866a72ecb6382d9bb3bc20079e02a1536adc5a814ec93b6c1a2854cd18c0804000000b313003030140c89c50222995452e4b07d14000f92b05078589c46494e296490318688000008000040200040025b2161d1380e1038fb09c9640ba5aad777837e73739c09ce6c3894e01018db409501a8eec5d8c1b0e6da3c9d67ddfabae7ee31525e0bccd2b51dc7a680f58a468cc047982b2f57c849c2909ab0eaf78cc92913730cad8d59eee1e1882101bbe6d2daff5370e655ddc9bee6ed85458d4ff00d3a03838edc20dd01dc5eb2cb2778c5837c2a8e3a281406382131a2b1d54cb31224a78a6251a85039714158047ce0ecef86aa8e233fc704dd36a99ee6c8281dcd4c1cec30f495b2781d5148691fd108139b8e8ec8bd7b9b7f75d1801d30c33ad1f4b83bff4de4a910724b61970e0e3c6d37122a33ffe8f174b6bb7e260a36c76c24db816ad6ea87579132b8a1a270c3d5d9a3b47bd6e71416b8bd19a2724f81165b0575a9a13377a3ec17417e069f12187eaa929ee7418011a71fc3025209b8b8194307db97a094761313128b6994ce3877e9d8fd25c7bd7cc60259e5ac5908c59f727c8828409279404f9b5ba5457be96111371c76b54a8dfd4b88fca5403164f76c5bde6f53143c8d7341898d68297ae89e2bc46046d7d46ab6c397d3d29469c1bd02793d9a4f17619945b6ad6782694597d2f0ba94e23d0212ef36de3b32fd6f06f31874c2ece0535fd70366d305b9685e12adb01031d0a84abccb440c9a1804da02cc13ffdebbf2212d1d4c450bc6baf2a3031da924a4d3795a1403eb29218eb7c20808f21714b89fcd567cc8050e52f94d3e952ce8650d509665bbacad33b6a31515c79c2f1f30a04bed69096249b4fa272891ff844820ea1b59f609aca796935884771f5f409dbd4dc792219e5ed9e8055f0a9d72c4925c232dedf8bc654c85029bfd8f09faf76119003a947b7312379521f929d1826be9fb8c5982fc21cbb46f2ca31eadf0c61c9d18028adc5363e5f4e81a19372aefeedb214a3fa5def1936b190552120075c475672cefe03567ad0adaf41eb4bf2a6de9ff82854009dc9dcbcafd9d823bb520301f00e576961a99e41c00a584a2ab5404e64475522b93824dbc5cc08a271f00f7a53994472ffe420541db2dc0a97f0064344e4a83ce834dcc70901cc97086a815eead80f689d96860f2aeaf11a45c1c0d2c27000bf14b60c8a221102fcb214030ef6d421e191a7c3f5eb2eacf551c861bb4a08969162a633c4ba2e924a1775afec97195bb606daf33b1565699cb73cb6a5dd24d0955fcaea01e18bc2192665ec0ed4be513fe463b1e1172530e417e0777d6a0431d178e58c9d66dde23e90d8c150852585cf74b9e4bbb8548c0caa8e76b332553710eba31d32be5313a7bafdcebf89af0a2a2cd90791ab41ae74eb503dc650a5e05ef657862b5671451335924dd1e75c466d44571dc5e6a674cc0f2a5fdb241f2b2fd78fd4b1a3ee99c723283154072d919432156d5cd978898f600d1aee83e23469a758ca4fe634b444dc19558d20253c43aa3a4408c33926d65b81702b675366bdd090d104d3f1f6cc7c2070c964ee63ce8947473030233ef08d6d3d862f88bbc136b44393b88a0d1fd0ae0b79c98d36d2163785d127800763152112a9ba768ef8bcd26052d758bd3017c82a74309097c4577480aa1adf48b51f8e67397a8990c8731d0c255ce9394561349c0dd195feb8701d76f67ebe1414ddba1f822823ca0c5cb33cb740bdd281296afbfbd7eeb2e75e5c308eb8e22fdf06f3c8c55cca5692ea6709cbd138247adcd31c347be2e22bef6106a42f9dad49650b973155be2d67a6c36bfbbc89a00fa8ee6a801f3861d9ce654ff186ee7ab344e202477818501542ec7f94cacb757d57b03b4c3a0bef4d67c9d35416f45b812841938faddded2eac8807df7919b17693b9397a109c057f012c0f255a8f1f5c44a633601dd9530128c78bf89f4f5b3e6238f375a8e9670b962051b3889521937fd231129895bb8670490aa3cee65087847c040ccbb9a78345929c62df87379f49799eeccc1e18315a69fb147f745931ea22d4dff7769a7691c6f309fdf94fd8e07bb0615cb97c5eb2b5139d2789ded61e9c70fcf76b332d7d90e00736a7c541f5c84a52017fe79d085323694f8feadba489ca8d93480560eddb33d2f4edafb675d6daa87462f3c4914a481789dbe676499c79a540913e6425cbc52e934d6b074eaadd1fa23ef98accc280e7c5806485c0a1f2ee8d72fd93ef4871a55279fa0f268cb8373dec71d5ffa4b40956314c97d45e93cd83645a6fbd7173293b188a0bedbce89b14d3509c9d7d44ccd53e4c8923b892342bbda03c48e8a8841aaa94e2dc22c9281449860d3f6a1a218a8a25a1db79206dc486192aa2a0757654565bbf4a8e2a59686f26769c829645a641a2332065b64ab859d95e88cddedc4a9c2a41c95b946644f14543d29b0a730e6cd0d7d1dcfea66f72149b3f211b8708ae30f2c3e23c8d31628920c95bf02a4abe5b52634b7a55db0ae44f67898efc47f37220689fcbe315a7e00051cf683d0bcb9fc47d5244d8e7a4257248e224fb05f2b1b7d6c3e86871f599d22e4129deba44fc7b50145dd589e994281a79cdc6576341df38301fde60858b273f18171b2f9e34f9dda9a521495053909c43079fa77bb2b249fbf216fe178cfcdf3fd74eb9554bab3ead67dd868558959f117786261751b47e0a2dc73bb55099b572ae71412ef5a6b08b2f006965a355485f88f8b4e272189e38ad21aeb6314871e361a8bda21810927b6d5fa4a948e41dab4acbca3ffeda4e239dfd4a224ccd96182b6f574a53f3d0570189a8d131412780d123eeb3664407e1495fcd42a5e0ecea5d2a9f6a2c2d30abc880ac154b8743022a1598a5a4cab538440616b52dd4f11a027186d11eccc605c150337d1b7363bea09f36943795381e1aebe08f1f1306282a43c83fb9804cbe5a0f3a7d8096a1f68e403a66e932a02b069fd25b31f58248537f00faec58080fe4b004a5f2acc557e11b460b83e1416887f009cf00232b0d3d0aa8cd8684ebac4ee5a46894adfdaa69fe9c1fd1a9e5ab643061a22b7726720443baf0f47c27c1febd084c29f0bf98fa9d1086e0b1516a0ae12b38e987b401124ac8f1135ea830bc8df839252abd291f1acf9e31f091e3f46bbb5712b6497cea19491009951876910955c08c860c53c7fbf1631f7f08282010a99ad267c48cc451b4cbb2309f1f763d87fd68cfbab49628334885eeee6e3aedd8a68283ad85a64d5b39ce1686afd486174d1698f3072734a6b574745888751b9401869b7ce2f3777ad913d8ba8295b3a800799c9af1601a3980790e091322a13800ceb907931f45cd804b38e59d488e84e6d255ef2cb63f3d7dc38f6db4e378025aa58138e8824c2b278ff53b07fdc1dc7299b87a7793a56137130c4640cee4fd596ab0102487134fd2e7a991001ca0f18bb6b23820cde1e176e81823c05c22177351c8b7c8ee385277868920cacd5608cef8f097ff7f2e81621e7ffa8df834893321b9de208db78d154f4c28d48c80e4fa8e468dbba5a54992346f209156547240cc32cf07c823a09c09641976b1340203d48c459909156b446c2fd8199bd50ba9cdd32f31f4a386e51257f151329863c2a7e0902dd12e768577422b0b7f719acf46f4d33d0d73f322ed00afd9fb21ad3952189e9da7ce4a663ccc3a24297d26480b87dc14ad606f9f862f4e32e93df01cb7eff4a2b1d52eb358425f1a1040a591fecb9ad32ba7e8f5f03323293099b088a3c7333704bfb3a8b2f7e0e6fea9689146cd8047c55573073e65036e599e8fd7c5c1d4086caf4866c0458e9e7cf85bf9ea3e8576df3e6fecafb71ce7bc878ce79c097d29798b708ad7d2223279880980994627c7eb02a5c72c7cd44c9730164d4eadcb8f3bc8fd20dc833a5c15e22b6e47078e1bc7d76f4dba9093061e28df5b10c205664215237c302b0e46b6aaaf3dc86bcbec718cd0d71852bd92c9d8778824ea2184106d6e78a3f5244a602297b2a689a83e5dbe57705c5ec340acd27f6ec090ca3909be65c5588410c0f131231f22c0a406ef98a6966ce01d94a9d76ef70d2aad50bbb17e18246851ca9bec7a96a005d6824c6c675d4f633a9d0f885806c84711f97ced4605b4901e55145e0cdd886e4873540d11c04b0e105b742e6b9a7c50d20dbd847f2173013c2c68a47a46db7db483741072e33d3d603b779b4eeeb37ce4bd2473c215f12e6c2f3701970f0d0f8136350749e00d665000873f322be603ac833dec80ec45237d843fd0237c224d89e0dac6f35d026f4938d3bfd4fa482a232fd2d0cc44b9cdf0ca5aca463bf79550c2334f341be02f2b772f0bb0d7c82cfcd0d878fd39ed93c784d7aca9be1e299b9f2ecb172d579929f97da867b75d6be59ac14d0a22c5985dcea620708110365be4ba5188381892c940a89be78d98f2697744ba1050a498871038d29189afcf748584c7afccbb985d5ec57ba206d598490215dcc74b9091514b200ea11635a7c3ec3af09907e47419699745678c7724a84bd84d56d2f06415f05f21da1c1998b74ab7e1a6122885551560d70bf55ac1318b8a9585dc46b01fe13c24b26e13b777e26c1acdbce714f7b23e610b037f0feca2f380074c4b0cb6cd3615be424a7d7cf1b518e0f5e01fd4674fd255e69c8db612604fc29d1d08c84fb30112d00670098f2c30815692abdc76eeb4d661de4f1c0388e45c88ee2fb7f8683e7baea7810152019f8746345a85558393cd5f1fbdc3da4b3fa2c3e331a78b7fadc3061784b698cca8b34189d17d92f857f3f7d88991d0fd0c4491ab7e710ffb84e54ae642efec964afdc7dfbbf90f464e4d901bfac59fb35f530376cbc8ca6fce0ce41a3e0e77f76dd0af8ba853833c4ef583c8592504789fde84a934161b57405a40b6c254a621c42ad077c84c5f876e19e4f4c74da4a167390888f4edf8b7151b029d10cc95903d06c56e614f626ec6a7e29bfdf6282d2a55d419709633acbc5d23e3b13ff251d9468b80e37ae524bda85472941cb081fafdc930b8c4601f91b2cd23e82f39f878af7bb702c81e10d3069879cd79b15f14344d291fbd00d75edf34c3ca24a3a3e040301d4099e8e2f1733ea39b1580a5470b355616126a6c5d7020c7c044d170650537eb13cecde0364ee8dc608e9bc7c1f70d03d96fd49b9a67d165745a4030b78121ec3bf205573abc0f7d5e490baf1358143ec33bc48ecfc6ab7cee83ab7bb49bd8b132336b868d025e2d8f8f623513097d9d88154d078656122d5263dbe1c41fb8c86a0508e2c5cf02c822ead042bd582952db6b35910e242673d367411252e11e5a22ee02f5ef988880f8b422410f904e885584634cb07fb00e9b3238b06c21285fb030c078f9716015bc083f8934df7e1c90c48cdc0fdbf011668d018064f64e393a9c66af87f095a313c5705814e58e2372ae4d7c434cf3f49ab6398aa802d466d70a51df4455ae39e94916f35740b37c33099404cca0c8bd9f5337e77c1c11f4965c935fc8a9d8dd1c9b09941efdda7229987f1828276287440613890ddd4ee013be092b322c34a0ad779a35b1c939c2256742ac3fb738bff301fb1037581fea6123966d26cae24c8716fa1dfbddf2ec4046bdc53fb2831c36faf34814f98a2a85e696e781da28920ed78909a671e412da8248604f6a1cf1fc6a0cf70160affba98c7975076f7dafcc7825904f26c0328598894708d8ebc9e4cc56fde30e5aaa48bb713a8e173cf510f89c98527444a15ddb5d4e2993353919930403163b25685678903b19e5fdfb723caa702fd49c2c6899e7808a0aafbd8bd79d59d432b92523a00dfeab1f4391d16579df6bf7b72d880be313d2d012156fa336c6d84358384016c430f58c54fd0c5685bfaead348eb2737604814d228a6a397f02130524f9b022804fb425ee23a585b3c0bc22bd0f8fb7a73b042d8ccc28c8641c54d3cb0e00fbc20706b403d6b85efe73074827a92c5d11c6dccbf7d861e0c8176804ae04c39f5054531915ce8c388781362671c32df00f12e10b7d6b62719fb20acb7651651f9b4ae308455699d505310160a59c2bedf48ea3f30bf310f5e6106014ec0471b8b3547af6f737227886023d4c2a42a5260836de121899c02f3456a61ad9632302e554e84482922b5821f25d0f23012a2c6083d767b69e6f24c007cf10ec1727cf34d6ec59ed9e01c690017e31d9fddb4207a593f288f8955e76ee6b4644240b2b75801fd287a119c97aead3a716f1cf3736a805fa09b40f25f15092e01f7f53df31c830a61ddd6bc6876d27c15b1ea6a4f0db21e889428d825a3a856a1fb80f0a233e2c8d86d7fa440fe5ba4f34fbc77b3c9e15a40868bfd50aced44321b8e113f489fbd167d14b4a849b481910240888185a802a30d41c9a8244f01b77797e71fa93dafc5a3156311e6c0810388dfaa4e5bc224373ba0a2a53999f8cd46ba816e155ea27c23b0eaca0dca071556be722c0433057c14a844a1469aec86adfb1d806243cfbd18f33f31d5e0f2fcab4a436acd895825d20eac09e0fd8bf76c374e29f58d2f1847d9c26073638469d014c80ddf868cd7bb3e7a64fd0da1a803fe47096d18a281e0076ac837e6948c0a6e8bb052769dc55842771d37cc8a7af573b263ec37b2b0c787a9ae0a8955d1f21b48c71bace435ad03e71131c0198e47bfd7297400a298b6a350686c6ecfae95919457242022a87b4200ff53a3480e9b2dca7faa57a0a8156a4b740d66a0b37a08f11db0dcd7056002bdf5ea9ebdae99c612d715f87d5de6b23359489f35ec3053f575d15360777c61013d9deadef530e053d4bd2c29a09e8b8e9e378ed106d04736a32328be2e3d7cd3cf63d1676ab73bbdb06792c6b57e8401380daae873c740e15b603d5d84ab50d34711a064a1e59146126805d310083db202a0def5e83cf7fb595f6e549a502a02d99543368d3e5153a4a9fca5901c387673d91cd84a5303c1e1a4abe31acdb470e2c1793a066d8df67a1e8b80c5744daec8fdbabd4b47475b6631e3b6f98a439718c8d8326ee15c7d317a789c3d09700376f6797e28c5388376cfa0efa71f67c1fe90449eebdd80782f8daf79c1f0056a78b268c43052f54b837f186d08a3c189057f92e9020aced4ec09b4df4e89eb770bb8fd098e46accdf52ec87082df6e0fdf8e66412c8854377e3c63be409a83eb2b3538493bd9a5ba4771922e16a365eee8f68e1ef44509510935e9516dea9444eee4e0ec8e6d065e3698503af37ccf813a0b0e91bc366e829c8acbe734a138dd7ad32e41640ecbae113b10dd237b498676b0fc0febf226d29e4379e27bdb87980ab589ffd79d7f82e0614adc89225909f7484d18075ae1d9be7e754c431fc4d5e13f3e554af47bd5c4c6a706c5ec01201fa909d5665b59caf654c89448bd2f9a80006bc22a0d55bc4c8e6429213a26cb08abf051f08cc5bac7b5b87b60acbd691580e03a82df14253bb4ba02f6f603bc037000ea2701a4ca2300ce503cf29e8dac9117242f8cf530b133fd26e923d0b9a0ebd142e7a2b806e05ce87d9b24ad9fc6b1b86ca810058ffccc9283b847860f0872888dc72c27a7213c0a907063527a0f29e4beade8d00e4e8d2296d76d0ca4821321c24040d063549a850e1bc6596e50a04d34f4f0dfadeba10635896120a8df4e27b4b1f01db4691e8ed1afdd716319294f272fdd8dd5f0c914baab09f06c98db326954a18f52200b6ff86bd293bd36c3555e83a399c0ca197afbdfb5a0473c0a3f987971b07646d0f84462e3b748fb6afa782d26be74b89808e064d010c5fe45ff09440834ee3b9c9bb991c8c5c72e7a190942f4c51d1f7fde3ef1460ab0cfa5562884a112bdfe60cc31926ac078b7f47b25517eb16b12fa0fc274606b0c8f0651931c8e05b12dfd0a11554c402d2d6823b2221e659f0a41aa0f78a3c79ffcf86cf8ed615a939ff69e68385932ef0d2b28b894930829dbe0824d1e96f85d70d1e8125cc67488ee0a0c2f2345c54710fce6b7d0e437c1afce210f6f217064d86170caca8c5c2fca6549b2cad037d2a733b4599cfa7b7d29d8015f283ac3eed3f5ea1e17a94424abe64ebeb18312b470c8e0bda010f0ac93aba3f8a2223ada6e96e55833720986d696d54bd44a0e0791dd69e5f76dbf7633afa7a4f97ed4f6fe92c1fb2e09b0485541b0d24effbd32d3b01221ccc95d30047c850652bd2be5abde3ca249a733a1c6f2cbd6337a3c99f0d94590ae0a2c2cc08462cae9690aee17d871fd1dbaf3158e3a7512e4b4d4dd747c097ca22303e27ba7bea5d520d08c1618502f3d2251caf6430d0914b2dad5b962320a753c07148e7cd3cac8fa3040e81bb9729e84138d30a4fd4e148c1844326ca812d5a832a52663335632d60d7309467efcfecaa6131daffc14040364c259a28b55f62fdc0759564fa3395692d7f63b4ef9d3c02bf2786111e6dc9bd395beb257a86ef93066d332479e7e098e82a3165ed676e2cc94fb8bed2d10ee6f9d2a6b2f895530c3798a6a8271b80a857e36be79d36194d4ed9fbaaffb4792576854574b8c395e2bef66cd698c914e51aeaa4631b2962a86958b42c1c0a35b72f2717460c8fe19bf7280c6a203a160b060bc91e896f3347a2cc0cc19e8e6cf8a2f40987c48c9f5792cc6cdddb0f3cc723555c0b4c8625c6f16bec32f1c90729519e1950e63b00aa5d1dd5bad0c91403ebc67b720971d5207cc35e0c7fa16f2025a43acba1d83b0242c63a867d6cdc4d8c3e5cfb5035f521766f44986d3b802524d3a25680ade51343c6c72e1920c9a450ac8bba81d0ba8b81aacdec3a56e3c9fb53dc958e7e834d9edf0a27640060ec43e8043ca46a8ab52750b42e6e504ce03218321c6ca32963d4cc9ea9b0c44737972e34402ea14f8d8921136bf08a6a0e952616583ea841cc805d19ccec60d60f4e3cb6ce69263063318a9af55da902b387df92a7e5219029c3478a66f5b5bbf8723287c165072571c6a876072725db94a09ff35cba24d8060be7bc0989fb19da47b20700e6414c88bd2153034089c224fb86e0920e35ef57b19e4377eefe6d61bf60f555cf72a6550002b70dd2fccf51a6244dda4da936be8447ed58efc35a833ce9e593ba462b450dbb71b797c8ac0bf98e0e176bae9bc37d06aa6cc2389ce5edebd3cd86113cc5a8f74665bdd72690b05c4308eb82182663a6e6f68603590bab88e1de3245a5b47eacdd388338c6fc9d5601bba0590639f0f8adee0c323708f5c5c5e96863381f94c82240df13356badcf1f05434c1434c04fb301341530556ba958c052dda5211c37fe39e08360fc1090c8b358e8be96a49ed5d62839f88b4a69cf54bd47ec0529d306418a59d2964bae0170b133252b5a517b822a346e493c7cd6066d7ab610bb1cd93a82dda196296950afec4260c70a12c0702d6339f3e43fda10932616d307386082732d3b99d35b2641321a5a5c036726f0631bd17a718ed24834fcb551c78a852b49ed3961c8480fe8719a1b568106bbd1196e3c1aedc5c77ead391f70b27b55d6722ed5041d92fc1bc3c477b7134295ec0114fa32f0a9deda1307a6447dd88073265fb30fde348f92828c8a0e4c971437d025263f0b7e7e639d0a1865df8bf0d5ce9d64f8cb3f0002a853b1504312b21fe3493f7f41f17415534b0409e43b6c43e888d3601981d56a22a7efa410b2bdb41858f5b37eb23ad82226cdf9b3a88fbb89f170b5bbea4975b51721fc3ba572052a4d17626676fb16618238947064030f8b2361e357b5c63ccbe9d58c6c35dbb8f2da3f63e7882e6809d6219357148da08079258f68e58e0f9628918509c1d2ead31196c75531280071d3efc79701ec1d803ebb4c19b99ee67f81c27e6e56bebe4ce17044e44fbb42af35402dcc2e600174705a505b00345963099fa3db26611b59c0ab1711844e0a5e150893e19324e7fd0c7f82936946f03b0276746789f19f7874e9c26f370bc2e70f019e43c20d80e3c78c8e0b8ce78d91ad174fc1475174b74f313d597d5e2f840baaf44445c2e6e385b057a6d334ff169bb5bad8e20d99002550ebbb883fee667b1873aab0542465c78449f8104a2686a6e0b9d5129cb0b6f68f7f4546711dd0d077b6a5f71d05af107573bb97f357d5447a10f678c62368f604bee0c5adf03d44f01a140c6d23bc0358b2d741f00c2bd89bdad7ac9f9e988744cede115953f949750cfab2a62bcbf2683b90860a0bcc002de0bc9edc172b0a12c25b5631f5fea3ccbd677c1bd48cef3cfd97db8b06964612208eb1108e789c80ff73e3bba2fcb90df299adb90ec37ce4c1fe1eff80725ea9b8f2a4d4cb8c8251cb72623ee8e448b224c2dd364c4b44d35788a922490f82f7a4d610162a698a9005d507b9b0127a402d76f1949235ce7754686b5edb916c25cb2473253923e45f20fb1a9f8da064296d61b0a520c22982a783fb7d2bd270ce850752f8fad84057059bf1c10476797d82c6c69a61608e3e5b437b63119a9c9355e05efddda38052d7a2cdc5c63223e557c5fae504371f85241ca51d107159f14cc985b85078c200583ba74f677e2fbfcadf6328371632881c9f3aeefd4cc2f89624139251021da75c3c59446a18b6a220bb2560b0b6ab82afdf11acbf5a816d49bf8dd2191698cdd6041d7043f86cae8e19a0bf99354a633e43e8c5ccd339235a183cd361efd55058cdd4c8853e4050497b9fa4ae899e4fa4021e8d9fabc186f2e9d4b525c0fdb3012c0cb365a8378a4c81b3c702b8552ce3474092fcc13090f6fa7596ea005ab628fefcfec49e40e72867b4b67c78546c40ecca88595bcb726f0e24ecf96efffd888879d9f801152fd402996049d1fcd06b9a1c1e5302676e1562557d82d5af723a71e579993fa74f5fa57b4f6300bdf2e3a7e1132971336a50efa37ad186227e9a5dc94ba912e903a4b65f21733b3bc136307249a43d85a11e0163497f13a08a3c77479086b0415be5f50166339838e499654efc8cacd2d93cdffeff27b52ee368a7a9a92e7fd8117b92e258ec4799c295b5767b0908954fa7eacf79f043054f0ad4d39437640b985b0f8bd5d99e2bc007dbffc4001693933ff6b86d44745d5c84fc1239dd874bc2aa3d995b472d53c6ab525b3741aa2da52db9188b7827b873312505a4b1a5906251b8c2cf151a07a321e8c881b22c672e3de630a7c9c965f2f9c6522c85777357a3bf2b9f9456dc60f5afb465acabc9ac4c126103ed801a71f9f0fec4fe4f1eb1c66abef5098174f585c157e137150ddc2bec2f2374449360da2bdc67122e9f09347ed4e580809d38bb78b9af0c93bda3ec006a5378d936926e19c87c0bc3422b0877e1d224481954cd714b9a130849eca6e5e85f08bb0fc893e081c44b4c7579146acf27751f6e721fd6a76e64f75fff817e0ee2f4fc8743d887afd84d2064d4faaba5f1116ecd0f4179a75d5304fa450dc12239644f38763d284b583e1bfa3872c47d5055d9dc78185266c4eb1219c96dc7ed2dc9967b058cf54aaff9531a54759df661e22ce694aa827e2529f50ab9d31ac2d56873de457665de242255b1ec5ccdf038671c2554a0d8cc7c377d062f35c747d06dd7e95bae4e817165424be8651f3fc9bcab59855b995e223344e80853a068104631f77a04afccb1c896c7802548ee2b332a91a0ed81b324398385f635c7d0fb8a378886373d16e7d1f343b0131581849347aac30ea4ac82ef1c2165dc6b9183495d245b219f1a631e3a121669d70d10e54213a450191b0ae258d4c4da68f4766018777f3f50c0db76969747f0c5be5d7238a834fb00abbcde4d0cbcd4d7b61b837100ea1896a706055e4350afa6dafd528426776de887aa93c08d3a19ef43a6eab2837a879de4e3080344c427768353164e7025b92350e6f0640e30644ee47375ee1fec80118dceeb70724e9244b8639de51439b1ef22b06253e445d498070a31606892514a79720f41be4c9fc1fdb477620e5b8248ba9f9ab88f151c653e09496c0b70c079b41743f3891e5e5f963d8fb128a10a64f1e7577b73cbae421c3dcec4c4e88336bb69e6c8589c02e02eab13f4e70c1e21aeb924525ed3fa9a687998fbcdbceaf9abb07ae1c7aacfc8175c3eb7e2e3ec9612496d5ea00eb54b454de3705455339135be670384c4411739dba8ab3831504e9b205a8208ddd5f1101a609840228e18411183e86227ac3c083515bcc72340702da9e8107893151c184162fac0d08aed84ce8b109a28a854033e2fd1f3cc0cfc71814708678e447862cfa47638dcba2f37e286a326c113cadf1d35082de3f25749d5b90981d258e42ef158caad7f6b49dde3941b074e391cb4e1816253fb4972c5d27b612322660498a68d92ebfb8fe173555038f2da0d55094f47683898d484cb8f58d8912f19c12c5123ec56015d52394b5896e070df3426a9a6f907450d05596dac5911919533080c4ecf05e2b0a0cb8c581b3c418454ac46e28e6c217407fa6d234b4a7124904cade88522034acddb708045b650c2683ef56f548ea18067da90385f72b1df1192ec93c8bbfe94bc64df424aa2770f76ceaf17e7df2f6012ebd5fa66b3f7da78251a41fe6992d38b7600f309b88f9f95f4c3be256b792b3602ee3f9f6413f87eaab8db132ba13e676ceeebd44682c24995162f60d081780671fe0d05cea068d8ad2a5ccc6aa5c73d3e4f45ff566b838b7c40be78f5e7289032a10b1466d4099986c07bc884a41735217e9e6d752b29f78a81d64edbc0dd1ee7ba0aebcb9d8020465c318647cb098d8bf361299cdcb529f9ff8cdd65bbcecd6a197624e1d94bea71246154d634f1b2af3ac3aec2bf7303a87cdf8515fd1e9fa0b8ea24223c157993565ed3ea5f5a4b803bc7b741f6ac9a4c71d8eb94cc128048006001600ff7074384916c07c60b0f1cc8d48fff8ceaf77fae25e449d189c5a98488d936f07e31d32409f461befb389c47ec720c3047f4656308408e618099d4bd113f10dbed69d69201556da4d6d7234f4567b532b14b8f147185b8ed4e76e6b75935f27f58551819bfa477481cd0ad87cb7456909cb5d73fc7dcb71d1b87a58dc3a3bfed4110db6714fafc9b04f1a50903dfd2dea859d51dedd420f567241367ed3782432c3eef8d198c5e686abf18460a0bb33af3bc00a7711a18673bfecfbd10cfb52a81486f7cf68f127b3dbda3ca966c0720f989dae1255a3bc185d309c258425f8b090cd2a4e0c3f9d8d1dce178f7127423a791a3aa2e41fe11e3a08c08283269e8ea1facb0cc7052040deaa15e7510a58161a8cfc8b66358412a467f47c1f4a52219246d1796882c57d6e7dcf67905fc966e78a7135e7603c4d158f9c3534d2db518c685c71cacae364052fef007de4b7b83375d7228ee197fab80b14d026725395610dc087686331303fc10f08359db47b73dae91cd7af5e0374a568eda544f05fbdec08c062b6f895f698e339be7350b4f79529964044e3e530d148a9482540bd2a36221290d9f367819277265d8c780e971b6ecfcf29a6b6fad2f863558b790eb7746859d69ad502d757b8ef62b133e1e82cb2c182968a57161f2b3fdc3d560e3c6aa038e05b2c772368cbb79582ca56aad2dd654b2b0112a11cde04b15504cfd7475232a814c1da5067a6adbee8595f9a02dc7783971e7a82dd8da5d95028273ecf99ce646705fd258f3a90658e25b330e7f95622fe1d23d9acdc97b66285da352388d022eedc6f22c1eac1263b0107b83b9896cf6a2999b826ca7a0886c550d3ec063dd9d9f0e0b7bd6c29fb8d7e7e46c9742fd028b98684224444debbc0a831a5e0a31731a4626567fce8972c9987b8711b3bfd615714a94c68c730422cbdf93b019718b3a0bd611ae4becd113196a80e77d39992fcdafc6044df4aae3c05d76117e608525ff48667b715cff272cbfb26997d1d71a660c0f8a06f2a27550cb9f043eccf5a2e913ea6620056125490465cd40872eae4019ba02001611606b816df2cc3f07c539910881e994ef8c7331a7ebef0e32191a21f4e41e5d4e50cef249935fe43236d0331bd9362f00a0997e8b6903dc2a08eb1e65ebfd4cee5ccdba7f0c9174de764f4b24f8044c9c14d96aab5e3763aec976a5c09ac1fe77fc146422f0d9c2702eb41347a1a180f755eac0211e828213369ce32394f822546f8fe835e53bf638e0b0bac69edbb71e750d11bdfad7ce35799d34c664dc0a086c77eb7b9a2eae3d70f9894427ac2fea87e8c1f9a1dc1156ae801820cd66c933b1a5165622da3875214bd394efb4766ce6535e8d27fd0e1f4288caed116c7d0a660de398a4221a5d63d475d76a1e47d6837e8f0db5c8eb0983505ddb69c2f8ca811610647b5178c3f8c010745d56a54d28a3ffce8f525adbe0097c21882278a458c499caccb1d7727108e0095a3ea7aba9cf3be242f6a979fe3896f47c394b4e24645e13cbbb9f19a7e3472ab98ac6bd7a332341df6139647a9eaf2b076b0e9cb6a2f71689fcbe00ec4b0a706eec776b016b9e2fc6050b51a00dc77306707c90d89d98711199ccf07d5dde27ae3e15f4483bb3dc3088379ec38f1d9b62e15247f714214e8ca41185f46c3727c6c108749c8f1bf34f72c8f93eb0cea4283cf9d5a7d3f11be6fd8cb8996b15e1786ee2360ee538a787e15c08faf2ea225fc42048da898e814977cb5a68df2bc2d81fb70c3937f392425c38be63e58954a4506385e70df4c48712ffd65598b1af6f1b32c69bf349432c9c9b6e1e417be3c7f0631628280846aa6aad35ba4e0cd67460ae1a12136b02f55f8fa3f7ed3e9b49381beadc2db5870ee6c40f5c8894514657d6ff249437536e841996a4cd79a45db2f70c388e409458294ec439ad84d573a7a96598f24e33a983e4beddc4c8ebd650352df3af45f4ec0ff0591f92201f806e0f84929f8f8ee650098b3fce90dffea6b592215449d46838d3f4efed8199eb1dff17e6ea2fbe8ac596a87191bfdc3c6fbde5b6f07b13134194834ca89caebdb2a94a71c51180c201e3aad922357f2515f741030f3042185a71f032925265f0fd10b1a56ff71354b786ef12b8dc2305e453321ad17313cdf1db5f8a794402d0650f14d208dd328c7a5af7ce80549a9285ebf05e4f4a3dd6268e17ebab09ecdd76e5f8a34e778192e2a15eb2075d083d63220f4b95aed8139c0c9dc8569d3c7e777c0fa9c9854d8f31c80b713ee35bc01c1662113560303f3c8095779cdd730a2096fab7885eddc07db58abb8d8ea0b43004754c27921f27d418bb4cd30f18577fa41bff080d9a40126c016c0a018e95801a53912d14e8977b49258cb16da2168f016bea33047475e2e37899dcf09cf413adbc703df8ba2f3d38d721960f813ebdbd5977b40967ae292ae05f3bff0096e688e752b3fa0372e911611e279b001ec3618a4ce45227304291a4fe5da2ec8c4132d9f16410487ff873cbb2b1b242a4808bb547bfdf451080969bce36eb7049e0bd465127a2612ac7f64327a016bc1da2da58cc228f109e41bfc477c0122474ec5e40ee2798478562c38a82ea05520517a2f504774484f1b109e280ccf981967ee1238783c260eae4b38b7028cec710c658b86402b2e49a0535e0f5f6a0b1c5d91fbda06ed9ec05c23053729173c6838739a79b01e1bb9fdd16f93b7db46c28d0d377f94d1118a20f210c7af8af209199765795949efcfc782b6541193179b0ea2303a127b0eefdf638017aaaa94d73b133400eb1b4eb03db9762e57e5b3541871f5f871a7d5454424f7482921cd1878e47e7e9bf583c9cde3fba00704e2a3a11fcfb08038e49044129cdbacbec1d4efb779f707178243fe581f0e68391ac51f0f155d5ba1d9144095d39e6a2ceb71f5345c950d67c2eef508bc7dd1836a42bf2f21d17a7245f956e56ffe88a3d538249a4cc5facb596fb47d82b67d53a2b8c2d00a1640b882ca2246abd0489dc19226bddeb1b0b78e11a2887f9c6b8d1cfb6666e6e44d74346475f18c79495aa1ea02db4e6f17ae7a7da8db471866b691eba51fcf4eb6a1f5b163d0d64289e38c44e5f445088022dddc2334937dd06a26e76625f82050bd510d160b744ea91284a2ef4281ffd406842950049da9c56a43169390341ad26972cdaf69def88411550009a362f42177769f209d33892d5d649e4d840a6df21ecd86c2fffa00c62473b72e8929564ff78ec999bc7f33c3a34369d8443e6665fd86134880d30cc8f5ae073e24766d11420421655c7998d180f682bd5ff27dfae54cd2be586d07308770570b2eab2129abc261d04b298269c9e042d2dfcd3bf971459bb0f9b434cdecc1850023125b674dca1bcac6b348fac6cbc0844d264962335df39c0ad892b4e192d5dbe2c81049902b1a764c19c09e40902b21d3ebd80352558457dc137a166eb6c411faeb82de156db491fa38422249ec1c1ea82f1f61d01a7671bcbc350b744b5eb3b343747ca91c2ca1856567b7d9851a3c35159e65099dd10996bbf339f4cd97528648ec8cde2f4a2a23031bbad275a9b2e28d3d90494497460e23ce7ec3179c9369b74afd77967f8cca9a1f232a6184a35be64d44f35ea5475c3c264820ada42dbb223b0904d8e3b3b9366008d4f3efa2a0b3e68033ffca729e8550b1442c30fed9036335232b794d0f15a025f1e6edf65a4d692ad154b044a0193497cc96fec70bd7d6ff14daf542aec6b1280a5010eee2b30b29af7949b2eccec1d1550e91052aa1fb8c077ec1322bc7ce1e746165a5f0843d393bfa7ed32731abeb98af35cb53d91166f778d466742e7bd5aa088ab9c7e5d981e5697f7d8c90cbb5a43dc392d11f6c04f085cc05b0a74091b31428e6d0041c200b014538daff0fe5eaa59f01f6870d50f25fd4a59850a23cd053c6ca3254ffbeec02dbedea084d6cc73aa16baef4f5702f144b0c456225e6404b205c959bd404d60b4c05b899427e3dd656ffa5a42618cd508d6bb05078e119850b8ad460f080a4fea5d5f04475dfa241fc65dd0fef86e835b19f67510c9c359e726fb6c70704fcc50aa7f3006c44e45e17c843708493983940da5c5a5a4a3f5d88c06c9b05e392d677563d6f44101a19db028334205b83a6c2ec481aa28192d65f644682af7512f705c3ca264f91bd61e419025661c1a812ebea836b0a0602d81dd0a44e2962daafa9b377b0198f0a5bd7659e463f57bc32436511daa0368ec4bcc91f43b10eb47545924c647f20530a529d6e2aa652bb2fc514beb23bac1e332a939a8c78a3b9577bd04e76c2c2313673414daa7a6dba5b3e4780c421e654c71ca1e00c592e23b7388ef054f925cc0fca08d66a79cc97fe95f5ddbb20827116b5a9a8146e87eead01e7905da2bb00e60c9c16f8413096402b1c213cca7f81be1e6870a8dbb2667c5e58c6e116b9e9e2a3a1f18d4858f9f75b93071ec0e5e5774af736d5ce22dd6d4f062e414746226d7ebee03bbf42d5687f22422f1238b876b8c00bc618b8025b7b1767a1b697192e6ae48242671c70c7754180514dee474c7016d4cfb888a622dabb324554546c66d8109859832f487f3d75b5512a34da7c655034545b8efea95d1184d97d57f1fcda1336b6d5a09f88e9d521991ee16d4f5f0c7b5cc3f53170626dd5e432fd92233042d096181164e4bf998ea81afcfd769f0acbdab9c0b4352aff62e3b0234a06a127f4e40006617b8b2801e5b344b5dabff8037e9c8ed4410259fcda9700573ac3c33374fc11f0769b1f6229ac8b78b7bfa270d9c1421f4fce4d999e46b9339094629d8fc817b66d4303f3250b8f8ce90ad88a8b5a1b1709c80d23839eae95dcc273d1c78bddeec07ce81cfa85a576a109740b1bcf4f41c6b1d9665b4780e7dcdcbbc503f0c24708caaa1b2a968cf409e3826c5b26820270c45fb3596dcb5cd8bd5697e3ae9e89239e580703931b50635a31e0ff5ca0003b0526b522906622a7ab13c02d3998700263919726ad5c0aa62c3ebbc46ed2ddde822612dda9d135a7fcccceb068fd910932b0ef74bc3246dc00e12ff2c8ca372d8d2b13deee62a68398201aa6aa5374f191e3c1137a8d78f59293020e10e0aff06b51dd32b77ba3abcffa666632bfe6c0dc1d30941ce193fcfd1a00b25d3601c6ed3f5affea6989f61f9fe068127455bdca7fb842f389eb5ec3f0025db1efa37b66d7d100ace725e718e8228f39439f477baa90d5ff4056d1154dad1ca2195385c2d4257a4e82d02381759d9d46d1c522535a42d6bc76f443471afeb26773f224d13c8ae4bd889cbcb09070105416b8d84a8e5ab195bd277955128f58f525b1dce7c3c922567d9fc9d7a7a15e01c37999f1b2d564c70b92156817f57ecc1b26c1fe853ba742a33ec39d18676f38b85829855e1e0063f8d83bed8900579db2cafcf9da2f0a9ffe0424e8decf4b2f113669b4975f9c819f8f267c5428e9c04dec7fc7126ca2c66a5959cbacfbbccd1429576ad38e2cf321ca0e8971528fab1eb62de9a2538dd56dbdf5fb32500a5a04608ec89a298594b2a8818a56a0276eea9e2706bcd0699f73088bd460bce564b66ab134479d45c2ba90926d1855acbad2e6837976d8498289f3e798c49b36178b411a76ca0bbb78217531c630ff7ddd0f7ad0acb35577806b7fc906d7b313267334365c18d3de57f3f9feffda66268ec591a85a5e84cbab29e969e668e5779642b594cea6e6ac5e8be847b2a7c4d4c0608a86f28bde1f50a7d9f048466671f715c39f7d29cf2daa577f525df30039a78ad9908ed670ce218a1702399d4b94c1229d9354c8c4cbe68c3f3f3112631877604d01a795f24cf80951b2235662fcaf9730decf9231e8a0b212f30e0973b90f17ee0b84ebf60471c140175453a37a58d84cb0b5b60a7af210da7ca5eeb6f2f233c4d03d42006f0c5068183d4126c64d4a57891eb63a7a1104db054711e7ac323ba76b953a9695fe653c3dc46163d439b42c6c10def4cc361f5d01bf628dd8f5d70b8441362683636349cbc98c9acfab4236c4af24dc73c4ca5d5fd0bab04f684ba87d0f91a54ed0b34584b2c50e0acf5fe0c4e2f7ed2826245b04834e75c816aca4359b4096df181b3c98e1a8e151ac5b81f1571842c11427914ad9083ab33a256237eea5d10a69cdad96140295964fd7acfe0fe85e29e8f632d4856d7695591dac74d9c42f0b86d6ed062050b8d77f3571f9cd2aedb58fbe9a44beb28e5e3099454d1f262a6f4b69c5a3674281b83985b9eb296c2b51070959d1dcad035779b60f23617b753985bebb7caa1b28ec7721791aea729c54bb17d5fea2b091fed1f00fc8c3e4b8f9df097f03b97c28053901bf6554a1fbea5108799e07e161e7a1871d47db0ede80a66f212689d2164e01bf8672a115e1886c028393577930708521cab90c23d7292a6f3e2d2707586098d39abca2dc52aeee2e4c86b6cbaa37c74680ae00a8c1179c5eac21b4f90fe32f5cfd8f0b0059870709328f6780e846631137d6909d12de520e26204170b99692da01c7a5af353cd3dd953fa27c03df8a85bcd448bc57743840a01da6a67cfe8dffd4bff03032e4abfb19ec939c9eada458d66da0c306b7999c3d4512a2064dc0d714ee1dbcd1019c38c35a6c74c4be6c3f548d55345e654cb3b152a30379556fda9e9d0e908354bb364bb4c108539032bfb48c570362c2a7de67541987986ebf0cf8c353774b101ce45cde3d24c573763e1f2ae0b526170f39cc35284d076124f15de28a7803ffaadb8a094788219423ea5c72d1d29107611ac219f6cc42549c67855942742e160abfb825c9d7fa5511f16370eee0fd5b9d317f10ea1e77e817f1165423ecc607d480814cfe58c3df99e228e7b18cf8bb1f3e411d5f29947f106ad1ecd13ba5eaf95a4a11e12a4808db9983e27e3e98c318270464bcfbf092210b487b180bd2906117ea0525a9606383d0921302535aa4e5098939a6260c80955aa8038cb0bbec9e97422e457135f1c208e4f93cbec7abc0c0c6f3276ba175a6dbc0e3c9adfa991d7433776b939a0a2a850279064f793315a2ef6a508c68c4ac1e4284f47c9989bba02042840f5f8d5b4409472f59be86ff6589915108ac47beafcae6b03448133e42d6759bb3a72c84433c141983678fc4d02ab5a1f56aedfe20b614423e74c070e821897ab4542f98e3eef1a9b6fb1b93c227ac92e492f2093adea45efe695e5faf6e95a003d1b284007deaf06098c53b28bf5df59055f56aacac3b2234e81c6c487f55fdfd818854d0384192ffd248ae6a19735c82c72d33d690a35a28235dc41ebf266d5b9eac1d4dd04f7db49b888c104e4f6b95b794059316f737096abaa32513a28d623422b80c2bcefc6a42960a3b251e2674a879c9304c818b90ae6fcc1751afef3d0eaf381f02d670deeb1774a811473bf8cfaf1f631a3eda7d45996a8c9ea5ec02dc258f5eefbfc6a1753834181c090620c1002818060586848221d03002f39650b18a724038157530f08c098d14c9e34b96fa688db1c767de860c64ded0dadb33db335001b95729ee4210484a909c86f04109dd1adc81172b392df5042671e6e9c324c583cdfc5e43568a89171c72760fbd4dc3da8525298bb4c1c1516567701ba9793c77314c9257358103690404014320351e2295fc329e7b6b401b80953a2834c1808fdcfc9839ab0761a12c266a8e41ddaadcaff2e2499c2161f97cb20ef936aaac8f5735890f24458a4b050b51cec44f6baf12b6af8a27db0b411e5348ff8a8a32f4a5eaf1798ca601a7324f72f8ff31c38cf6df98d5df908c23f995c2c269cc2d24f4a35dc1a55bd03563c0c2890219e704f82d1f4b11ec5e217f04f79328faff38081d21819a44e0ab864bdd496e414d2caa577f09587d80015f1ff0a869939743c1e25a3b84c6105ee8970018ca9122c22fbc64c06b25b07d9200a12301f2514a902f01bce77bdcbff1f7d88e5d6237b17f1e5d1cf63ce626701ea1be8cf577f0c5ea0fed7fa8fe10ba5af09de434a1121dc828ab646bd740dcaa4e3cfd838475e94e3175d5e9a400e005ffe349d9cff1494e706816896f993f61948ba939a9cc4e95a6b4635d6ed3d0f4f1cff6dfcb8cec0cad524de3b1a255ef5ec82afa27e71cb47f972289534f60470bcc5a155aaa3cb87934cdb77d15dae5db8b295dc66bb6d0cd1d901fbd3bcfdad6a3d4040bd4e69f13fa50a819d870550f9531b44355c99502fb425e1f6afc7c8206b3f14ac9b44a3ba2974f90b5a6dd850b5b96e5d0a4745f928abac394947788f1907061143d2ce894e9f1e728b15f6bc90f55360990a4cfd0b5c107465978be0df80b33d24519ed44c0678d2534f7f0b9c28d41454f5566e632b48805c956deb462c4e69eef1596f2e7c9fd07fe496c5e1d123c88d3c827f3151c1331527b8bfd61c2024196e09eca01e9045806504d6ff8762429a20eed141d50a781ba2b54100e524a7fdf91d0a2a3cd774ebe70d9bfdc35a6e7abe1decff8e44c911646e35e3f9fedd949dc082a9c524700a0b222c63044525957fdd998b9d62947225edb8ba741b680caf9a55fe1632f0dd296f183ed5b22f7127f9186f02c121e986b67d70fd3305d3f9024095102eb5a297d7204f8c28e84a349246016282c2b325127cef1fc6fa5c541c248bb1de42b6fcc3ce7cc5964f1bd0de23d6279603449fc34da6adf59365049bde69bf3b4194f531ce1613b3931c3e7cd0c3284c7dff24d3864f0fda215a08ac743ba121ed94b2079b86572829c473bd45db7582f97de80678130f0f2093d072f2406022d0ba6749eb41db2500f4dc3635d6350c06540199406ed7c81380bea6cb34794a60a98a2202647a28f76f6dd23d1c8a0a30ffeb2f5b625d7a29b745542b02c224278917f5aa57f680b2e73fa9f9bd72ed7c8439ca8852296d06a6ae03b77ac686704e9d1ad4dc0e0407a8f29ea65de3cd06096ecd0cbf8d47744f04002703f08d6e9aabf5b63a28f892ba2a05627dc055f34430469053b754e8c1c0dbf003bcc39004fa44346d3a9c049d3e87489fff7ac3afe2356a9b01f66b4b50697b0ecc284134f8039a00391803ad9484bf8eeb0a1b87dd71baae07038a4ec85c7cf30cf497165e9c6ffaa5459138c804d416077c4c14142da450380b86033498c817fc2201c8dee0dd7a8731bb80981f7b8341867420e46ea80f11e0f4d27ea309afd863df165e90a4a1552deb0cbe2bfb3274f1376cdab004bb2aa25ae96576a0862ce5bf2c9ce6dce21d3772f514bd4e483466b870a1fae75861ced195258057a68ccfc008276b7243c211e55b05ad666e9e2b405ac3301834f122dd091825ef63dccd38a778448344adb89b5be6ba776388eaa17d24a344c57498df1cefefe47080ce3e6e99c23bfc15a937144a4dd26161c088846e47bc7dc759a33b1d842254720013296f8398fdf735f2eb3c324a60726802e07448b85490a109ce34a736f97ef61313fb86683b62d5d1f8719141ec2a2383b9f547136b62793db4b89272cb0e4a76dc710bb5cb2ce79d89e7035288ccb8431230eae174a50b88e768f1a96160257871cd6ec4ae782c59894f31cab49721bf467cfab1e336c201e43ff855cd19adc63fd1c7409c9775a3d4d66a2bb026ffbdc1400ca2984dec317c2a9a1086f7553852b796289bb66b7cc9206022885c6ffe2289b5704b6bbbfb0511594823b3e6f13f545c0b024d3739f7028371b9a9274f956a54b73fd341239893813e9de8c28afc13209e21ab779b6909e244c407d95c0eb0a2ae5c0cdebebdaf249d6f3cb08a1050c3807cf869a58c8886983a4a9922cef63de2a265a894c0e5b5749da661d3129d01162c15092dfbb69347558a8db232916b4e9fc5bf347ef0d6d6dbc75ead139f0813c5142d0d9ae3e09a4d787920d04028fa69aa9513ff0aa655bde6f2bc567f17a9839819c63d3bed74ba6e414044b7b9c35e386ce531ac43055b59b78a69c39e9aee01972c420628d39f65e1a352f2a22f2b0fac14b9c76187d79859a83a823a96abeec23a596b8ebd78cec1ca1ef841c1ab87cbf96d8afcd49b239ffae5202556316b2187b097c67561286cb535651f3337f1c0a4083d2f2ff5d6730b3479b800c6581c59a4f9f9fd546d65a7581ad2ed5b16a6bcd0e2ae8191533cd2808c4c4994175e101dc0a0d758bdad22e8afb8c8ca1e1b21b04fb0fb0416fd9195540f7dafbd867528e30ab3acd17020283a2a668ce35e8ec4f269640281b68de98c5bfaac795c40dc79819831d6786410fa82d9a83009a0a2a141a5633c3796b6ec05d9f002a009f22d42aadadb22fca2420774ced22207965f408b9b305345af0505f05bcdf18f3a217d22069680271e1045e15c03a3473160260959b49257380f8005d110afe41beedd46d8c8e6003eec1092a80b6f88058e0c0ecba930444de1ca579e2395c19de35b2108cdaca8833c5240b70d72265b0c81bdcab7325a0291bd66d8b53a8aa44247549d3d85d35ac29c5d1932cb44ed585de9a279b38469c766b480d1de0c7b3a034921ff4df887002708fef6171da79412063eda48d2408ffc9c2d52bbea0d83cbd4e15d865f454f989392514c35a141a7d95f3373193703bf8e8f0c16eb40ccd4a8d43baf941ed6327a9bbf17095b3834a43cd919e39ef07ea1552612470f81803e12ed15619c65d5211b7d4370722971bb7304f5962a27dce7a110c2d356da3d98bcbd6754e69b59bda262bd71a776b2328390cae2499f6f338d4d9fee3b43fd14aca8b5401363d7878138cbe4f556cbc78cc255d5610ced57fe4062428458ce46a375916fbd70abd70c1b1b535a6a0f3f0c4061659cd602466c5dc1a36b10510665b81d19916ff673e2c8195f2da059fd2d18339c44aaca84b1db4a19e2b006e836eafe12b53bfc57810668805a78ca8a0c9f0dec60546ee201c46c359e2a43eacb7d815b2447260cb565a68d11ddfd44c041c0a8c92326f99d72e02c51ddd00916d5b710f49a1210a3056bc059e331169133b031e4f5b15ef482bf34ceefa177aa5e9553018e3f80187785fc1d075f036df902516948d810cb2b5528371c03227e8d97368c5f70a056181ed0775777d383d2b1508032a28eb62173e0a28f57ae5f299a1a6516787d0d35c5a11ff29636ceaf76135f3820678c9c223306e21ada3ad8e15bd0ca4e4435430a48ccf85da6578c8a8e5fd3e4323abe36ad3e689bf129b1ddea8095a4603ca397d790f93e57d9f823ad2812b56d155dcdc595fa2c244e7671ceee34bfc0e1c2c1f39b3e0b50a84e1c378be82c5a07abb18a2f4864e9071132829c9a214ca0269487a0a0b88c84274fb51e5c496656961c748bdd84cb84f797a7be679d52e813ab1cdbd1f61751500fe62944821427459fb619e5af91d7bbd07705640746a1903b14bd80bf12ceccb980a00059c613d3207c6bd89dbe3ab9ed37e59deb1c4626db634a50f765d3574889eea47801a7f79e903383521b26f7f19bb766f906abd1500dd636ee8f04c76a22d73f2da394fae3133e8d2cf6e6d9780218d219cad0fb0abe9c5840062c231055dbfa733bf995301ee5a8d75bd1a5cc30d8e6227a1460cf81e013cab381d21e82c22d1be07054a54d66df2005f68b12ef2273afb3eab44fd3c46c47458005f36748a9602e8dd91b439493ee29cac7c2c1d83813c74fc2887084f53d371023e0c55ce38c0de8fc5af6a22a67b0a5bad7208d79e281477d171863eedf72c9a57b1779e57f8371b8ffbbfb6056a3f3d3c4af8010b56ef6efeeca73e83a5c319dceddf9b82bd5bd302749a57b0998a4797dab905f32bcff560fb30577f935708f3f39b55bc8baa221a7b019f93237a364f733cae42b452951253c6839e1940ce544b58869d44749cf2c94c3011197f9583c979b5fedc0aa51d8efbac012e8d69f07baaba17937efdce1b90ab77b7c45bab6201b1a55ba70f08523892317129911d0a3721f2bd921baae0a15f37338606e55f29bceea17dd20f279b546af17e36bd4e34b1380663bdf38533fe9101fb898cced76b96e9750604d670fceac10fa83b1369d680deb121422c0a186c51a8a3df5206577e5f1763a8e325fb13909383b65558955de8180334da871f1624ae7ce2625e46efef1c7b13922fdcbc0c46671e95a1025572c799f83316f715c9a9cba0b42e0cf79acf208560ea0fa9094f6bc5aa9984f27e492c06d8880b251ebafaa616a8847bf9f5b7e0ad88a842df0e92ba25c513b290c0823b431f09e862d52e72f15a135889d2b7542719fd4f68109cfb93f50fbb6b83889ae6a310527e953fcbcd810caef30a85ec6530a237ed0003a6f6400b0abc9eaf0d9e16518c14636851234500886a3000ab5fcb338788224e7c2fce5bef1991efd6b730e172d03080c06bfc34783a96cf20d7701981c1c54d9c8e5c399c360e0931caa6049dcac46fd7c4cfbe4acfcc75301768a087a7c4f0149226828ac98633d654bd91960572aada26b64607a8dbda7854fe6e5e7acd3dc37c29e8f104428e4726d2910e1299fadfb2f3f31b160b180314962b462e53c2d5b3e923a1cfdbef03996446307a1de847473bd974f8fcacbe9dd0e879a6fa8a66bf971fd570810b6348970495811e2c0a38d5de4c0fa43ef1015ef3a3e01608bb5caaf5ee34ce4fc519518844421092a19eee21cfefed5ff8603c74f1c765f634038153bdf6ff43b92e340cc83c6ab43193cc1b4c7c018098e82de81347c3630917131b451d319c627b01d2917111ee12c95fc95427c54c15209857bdb60384298ddc8a83554753720572c32a113996e5fc6f0ba79e21c15ee00a09206a4ae93a68016ac12e0667321717178ca7e7bea59602fa127858aaf0ba432e0d91469652b36fce690374516f506eba0275d3fbac2254c27427ba99941c72f51bec57490e99e50cfa5ee04a4d9d4d73220f361eef2643c60fba319852b52141cd0b781398438c2697f4c8c1f09af322ad89a82d34c29cec2b2cf11feaa021e2649169a972224096a8b262420675277ad55fe8c7c95628901f269b6c87aee31adeb1b7cbb3ed1364c17f5e1366e95ab8ab3a1db921770f1a501311271452c95b7602825ebb6140d1d728fa8eef4a3ff81357116696d016a0301514f990a71db3f32f345b3fa83e521e4e8448a298b26035d7ca27f174b0032dcd69d4df5bfec74ed8c2f06c37a210ae445039897df1560e6aa99507f7e0ed3478897e8cd67a65d66b750d090610ba9a1ccd0a4c7a4cd6d9a37862a2743509abac49e77c95b1bccc873c9cf626844dc01fc56a508e0281640df2ade7619b538261d1ac733a22d83f0f647a6723d906ba303d6abf13c0d8bd61a5e4fc24c040dba90ce6ee908d4b9f44656f51ab82d12aa5975c9d543057db8577f05f0835aafa0b5293a2d85c98edb31ceef01df745642e13466dcd87c95ce33a2c18503577ee10f3844045ae2c690f51a99ce71121a081c6ec2978fb58ec20f07613119317a9a97bb855647c0bb183ac5eed2e8ddbad80dda219f05eb6ebf2ec443fd5b16e6303a0881944a560d72c85d4d9abe1503f3880676a6fbf565b2957e586d16e03bc57c0c9ae48c05cba1d5c7406cc365ed9656f7fcf25c4033c98145522957d9d5d7ecdc8ba7ea15b45e50050bf94cf31b1d12560232e1c5cc0e05120a1c568bd2d049f1a46874d82ca861564e4348782cf2a8d5df0e1c121b66d92ae96ae42a9463edf196b18713d6cd9d1fe83e526b8aef4edf4e09bb1f60347e2d11de60c555b116a2cd720c15af7cc4390747e432caaaf6729163687cc981f839ba0b574fd386aff9bd32c30e8d9f355c7a94491f3e58dc2c0ec042377edd89eaf4b31c5a19de6ab1fdfb4874308aa53d2757edab1f9dcba7e44e7b3765d54c83903cc9658f16e7aab996bf3beca354b6140100fe8692b3db01e22a5bb321aa3470b6fab63b0af4de889c0ab6317792e8a93875e73b5746c489e1fbf58d20627239c828f582d5d4555b3b562b1b245ae9e60ff44ec693ae064bd45d07387072642ecd1438fa349c676244c5a5e01c115f78ad43109e5ee80440237ac9594c4353f11b727cf50440419bc852682fa8e45868517c3001b9e0dc62c91cafc6d858527c8604d9744d6e86a0ac397fdf0c960031902b43043b72547ab4a2531dbb17663dc30d0d74ac4df44fd4108404565e28f92afd774757e34be09242687db682bdba425e2ca707dec4d970ca5ccd2d806246d94e59f0ebdb68e7f57d4e71dd6b8118299cec5b69838ec20351f16b04a186a79e5d442be6c2eaba2c24169f48affd6f61cc1bdcce9c6c64afbfa00924e16c23c66dd6b489da874a9ebcc14ce00d1d55dd2c903c59ab65cbdb65c7f457039d789c5965985a8eae4c84b0174ae7c29c767069cac33ecd28379463ec832654f615b690cde1fdcb6e46a5c54afb0aa502791c4f91c4d405a399ee16ba5f5a2021ccc37d2df48e48c644884f007ed47c225e0d21c4480eb6aea3d9a91ef36e8139a5fb50f2c14c5465c0b2e7a2a0c13d3e5bbdb57db0376e808a8e7a3cffccf6964c231fef0be2143cdb176f72b8651f06dbf2f93dcaff2e5c25be9e93e8e36cb206e34fb1dd859426d8034da2e609c568a37c1235fa0d04fc616fa7ede94af68cccac905625adb584b5aac560034c1a400bb957f69ecce78033f3e95651596ee5f2690c4ef5f4225283bc5420a88e50af01a30a0fb120ea4b65a2c35e765ecf7af801dfce3db65067ea288219d2ae0cc8dd5b47a8220aa0b3318b2bb492622cadbd337993a17b97690293b90c962f6059b41d78ffdabad42aca1416ed67f30282c2cdac6472484d249637d59e10881cfa08e21d015b3f8038113a7faf7de1f2567463d38fa6ae66df0d76317351f0085c7e743b25808fa2b1f6a5ab04751b61ad9d91e847975b67f7167352dd69001e38f1018025a92dde99ceff2af2c9b020778d4414a80e74783cd40eac3055c7ebc8fcd40f8ba77e10e821b64e539f42bcb4293fb5b971c17abceb9a8368bad5b76671afadc393636032138b2eaccc7dd173aedb144f3bf31412dc5559c12d9300d23b3418a273345dce5985219288f607620c1eba26989650e4c7b8355e0e5ab517dce11979954911ebe8c7d71f4caca50c5cf1978222df695d47abd4b434403de3e49ec9681bee75c6aa21e9df7fa8dc50476cbda050b74bf1c1d642112f0f1d907b8c0ad8a776781116101a9602b00dc83be6b5109c02f04111ad39ebc201d344025c6c895205c110b823829f474aa1c8108debff8fce36af885f23da6a23ee394bc5bf4be79941b4326d85c099867822310ddaaf691a52ed9c9bb5d7a6bbc413a284b056028a5e386e6f7b896190c31a947e06cbe06194c97596003a3699c2bdf38ca4ad5dd185e5433825c55fe3a852ca9ef1dc2b7ad86efdf99ad6886787c78b6fb131fc24edce2fa08a358aa98794d36c2d24a4fd58d1995ade51319efbed0ce489379419ea3dbe2959e59dbe435d87acf4c1c150d40165a842e608d2403184cd1dc7c1145fd0e2460968ce7fc477d7d6ee1a5a0bd6416e19729f7114a22bc0c8a8db81afba96cd9b38649e6e57ec679acb867a5c22cae20c9170663d4842570358232b0a329a1524aa1a5ca6abce1c5d63cd5a9c6eaa5c0e4af180cafdf61c3b84c4ec63e7f114db8d760b9459d502bdb9a9cd328642fb6312a3e14d01e884fbff2ddd45935d94b0e8901787d2fbd5bd0fd5ba3f0f4524136ab5a9102c2026e572fd97e32c1406ebf688cd3a701cc39f5e64654d73d9200b1b91ca5740206ad592f251b843ea8f635daec4d84572f967b58d5ae3f972efefcfc8e3ce5d6143da9893ca16ba7ba608b81b3f1212f8aeba52a94b3314dd8ac7abc18fe6a47c8f2225ec864b014a568d5870bc3b09b28add1196cd21d8ca6886b6ddc5744fdbc20eda86cbb87b6d9e0950265267ded2cca5aa93a3753bf3d5c6dbfb945c9ecddb5b334bbe75fc987a815ceebba1bafd8de9311653cbb454aa067b5c5f1676082b2ab421e9d3408bbb218420b8812da2b50957d6aa86af24b03420caa52881063505fdaf5be39f06f678998ac3a4736f5c26909fc30867f92b56a806717be2b8402496c131286b39688da00b040496ad583ebb4e2507ee90c244629d8932631f9e8263779a1027f263cf10a03bfb13f5f8bc880f5376c7fe87300543f19580722a8e815638c90f23539ce7adb2f9c5dfed0c7189c19449e990b4b244d952f05d710501696af2e4ada13a36e5e86681ff9d2978f647c96c61cdcfdc3703a68502250f18d737b16172c51d88d6365a9e0e083861fc18b9314164b08493a0d36e98e3ab8623c7b0fa179e8c81d2398a382e8792cbfe36de50856a0ab8f25f7f3936996618581929ec2a9c0b897efd399d691af0008f199bc9229a9016d980d8453280aa91c752842f1f183b74e99e620d883d73a5861cbd20d1b1b64656e8b2426d62904890384c035988c7a0d80d112f7ef5dc06432c28b87c7d62586ba3a2f44686cf6254d85e6a72a53acc42ce3f04288ee568a7c9e7f35a18c4117989e2fae9168b13327022aee65fe89308e78a420d12fc478e8840782363be94adfa82917b9021df0d043355157e175ec74153ae3d4d69db5eaee73efc9d45f1e12256aa1fd9b689702e5870f4d3089a7d8c702ebdf875828e761fd9b6a2330b660a0fe55ea5fc2430626f9c914ef91151e833bac7ff90705b4e4fe45c3c033f357882212f9fd189f7ab51b8797ad8e8ab95e977d285678e74e3a1424273fd789246ee110b6d0c16757b750ae03b11006e5f6858b8011b74fcb8dc62f8140c0600178ab73009c8e6f72e63a53cafd00e3d480dab896ac14824370a018d61d5c49b812bcfc61da051a9403baa229686b753e6cddba875d744ee5bc27e356994e34b6e7c3c3c75afbbcdd60da40afc6bc3cf43399189b6049c062b4be03c644e259e20752117554917f12dbb37077a472a7f675ae67673fd237ca19ba3646e6ad90e1d715a14249e8a6402803502225d72f65a2a39afbff2181f026328688e0c92cc2bbcbbe95740dc84a117699b3498c15aedc1b9bc7553e9af2f01c1170b86ddbe621aa520f6cc764ba36483c015e8c25856b8062230a878201f05c2d7a4bf50782a5d0327d28559ad0b9aaec8f89632e00ce1bd0963d98d1043e9d4878601e4193f5d16229b86bd71f0ce610ec951875bf0f58936a18ea656864c06df17c8ef3407180e12f57513a772bc6d7eddd405d09d10b1634dd99b3e4552ddd4586b0f24c043a4e13a526cee573b830f0f9ee642cdf822e69b631bff700c7e72c24b678e77398fed4a4463e1f6a403cbd126449f97c1ef5651b9978c6eb0d4a84037ba7cc8a98fa12e0522cba10211d3503946bb78f7b2b99a0a276ab97ff25d0ee9051824c53a03401150c14ccfe5c026c1362b3454ec7da3c3010be9884f5cdf800ba8fec84287f3d23aaae385eefa9e46352776692079a532c2606c0145169c94d4cda4c3c4541b1a3b893daf5333871644b588bec16c2e29763253dd7e5e83fe9f1e233e99b4861d91ca0584df049aa82efa8f8f31647dbeb1ddd0cdc29ea23b5fd435d4234cd068e046ce706e5898c998df1dcf1ca0343e7f2943b63780a76b373804ede7f54703da8655999a679ef6ba80c7360592c282cd890bef80f90fcd3c2324f129609ddbe83f278dfad00bce0c7e024aa9058101ac2a8fcbf47fe41cbdac51e607577a629b4523c01e2c06bfb20df3bc461986310939babc6c4d2064cf8b1ef3738c0e5a1fc2b20b5c3b4f12c11d94b05a11503f2edac8b4c54a54df567a65dda77bec4adf5491c094ca45684bfea89569f48c6c305be24a33cb2b3248a8a4bfb7ee9150783dfb4ed615628c15be9be87eef83b88811b6965c55139fa173639135d1c72dc0dcb84fa39892af38461b12630f341eff19ce98a9bdba4cc47f44717f079c66453af6e2ebd48eb3f2ded6d38cccb05f2bda05446f25cc4c9a89255992e09521a79fb4fa3a49a096006742b57fee3d4e3ee28a06184c96db2526cbfad217b227a99c3396745f124c2dfdc1342a7424482a7c96d9d09c7447de99297721fe0dec98afddf31b8c86d88101366130609f07f07f64c33704b109bd5231061f31f49135066571144b1fc32c8f6bc0f90ae363aa600070c95730a7c312b0c4ff421026cfe324ecda396d3ccefcb34fdac12497b044174d8055055afd46590a75b7a8d800bc3abd5a614841e46aa2347000de899db09697a8412e25ae748173d1e1cdc9fc5762d7aa12cedf61e0dc47a4ba28238252b557478c63127d8b1425ec971210fa46d18fc3288fabda2683b1580a2a288acaf98a040ab49b50dd86ade33f462c7827d9dd500be4995c79575561c82cb35e14fcc126f07229c8577f724309b2487854806cbca114baf61f15550078edf35d6ebc814b30fd0c98b449402194e124801d569fbfc071fb29ef6351845fc0e1af7d50b7f93c3f658fc9b267e0041de621503721a5ef6fc82d63298c5f9ce5ea5158767d47e97809a36d003035f744a62f60e29cc4226c61e349569fff2ce3c8b295e6cbedbd6ddb041303443e944aada4a2da59cab71e56e60e78c73a81a8a2bfba0c7479cff98b19e39226c223068b8485a3b32ad4890ee963eda1d57e6693c547b6693183151f569211a53999084095412cb90788643961348072022d0799c8cbf246cac79ea5b005d032e0b273e5e8d6fbff1eea43ebd3fd125b0cc9d9e974533d7cbe7163f3c0030d5bfb732aea3a900d040d0405b79626db572ad45b0795aed5e4dbb713cd8b1ad1ec11f46b1a144cbcf81634eccc5d595ca212158983af620425ec7be8684910225032be6331ed6561a813aa756c78f17c35844ffd809394049005a18e21a023f321615a83d8fe9549bb3329ef167f9156366d42f8dfe55bdace05e7e19e13d8890991b2bc9daf6b5bc52ecafdf03ca37fc85fdb868e81557bc48ef5b3e1e2c7b192bc64ca3f3a6f61e4b14411e15c761e1dc3271cc7ad16828c70685323a00067b7441704ae2d63f55eb93834afa09b05122d3f43746a8a71c69dca2cd39c2b61cc5e48b29104c1060971352650e10b1c3c2e4e0f181c786025ac40bdcd5b592403e476df05d378a3c74a0c5e0b7f56c7607e39a562b98e42ec53ce6fd9ee88bc5f880c84655199383bc5c2b19c31608cd9b3c7465b28af72c9b529895789a94a61494320de2d056279e503645fa9b12cb69d9383c0308f792880551b8d3823fcbd817512bea07e4051b0ad4dece376033b4f465bb4ff078e74352e6710aba8ea4ea5fc63688966ab401a6e39aa494fbe637c890fd9811b950a45a7d095d4c1a9fcbd0cc084e5af300fd8f08f6e306c629125dc86f8460bca0d967d5f3daa0e040ca8351696094d17cded48bde8fd06cee8fe4b794252e16fc6e459865c9df64d6e7975aa1b10f51a6c5544f5693f2aeb5bf07d1e3343c3a6fb35fda00f5f84c474c58306573bf948a00e2cce361ee8ccaaa987cff6b059c7a19b381286c78e2d982309d1d09fa7c46a57a1f551efc73a2c0c23db5d19db2b24030cbb4bd761cf6a49a8aeef9eb82d90aa9654fc9402c2fb86397a76855686566b475b4421933c0e30ac4b8e823e0c7eb411c2815b3b1d884dc4624ea01c3bc3777070b00e6c883a1d29cc2a1931e5a4421919eca18cbddb3ed7dc9c330ff1b01f114bffa5940c5c18805a4cc40967f4d4ce02fe9bf3c0ec113be4a1fc18925e865b8ed56d11d0a6f5bfe1060dd8904e86604fe0edb36ae1ff02b13d793c210bd9cc1ced8c65c67cd8d730cf8e7338b748a8d6bf30ef9dc2a98bb6bcb82317c4104004cf685cb679aa8822c9a3ed45d74bf282821e56165fd8944c56703a963a03e4146d6366790d85f64d6cfa6ed31cfb50780cfc17540a612481332e1035952e58625525232cec5184024162960be9ea6a9cdd37f024ac26ef331d2fcc9ec9a8d8717ba453768e24485908fbd0a915683c97b45531f25d13f6c74887e426d94562c7fb2e43fa3a13aca7d29e46def204aada4836ce009c4117f4f52673b301e87acb42e20e7e0684860694160e1c81322bcf77b8f1860350e92d2205a8ccd125d39839356234f23b6a67f251b8e3d2f61909e74288924585f690adf34f93f872602984098040173be1f0b621b388f94e45562119a1e10ec4062e7b83714e3a3bdde3a2a97337c625ac84ad135009a359d1a16b0d6703e27b1563723a4a4d67bd9636120942a719e63eace6343684e3e0319489e220ef3faa9797448e48b5401313da4e5b2eb7b01a8f404ef6df277311694380dd01048798db24c3815aad8e7af5b16741c44b7216a26c94dc3ee629a7eeb36b9e2a473e2bc01650c90738503eca8b5b5717d0a1c745f9cac77549338a96b7e034271c6b471c8e79bb773f8993bf103852ff64a4de7077f7639e1f501b7d69af184788400ce61303a77895aab03a0d38f9e0ba1edaddd7f55dbee22f170309b48de7504c0d5463c4e1ea5d0b0454b9040be01993f20488ea2e0be0af37830bde4087a28877b80204b39f7bdd4114d47f7eef6e4ffc221b4b42cf9a2c4bdc42d75b5483ecbb583ab6c3f74137104f277a717e3a60e32d6b7b3700776e99520881f6164b4d7b54d6721c444af60101844c2da0ca0ac0121695b6a0ca3899fd0205badc639c88c7c831a9de76525ccc4419a3b942428790e33e2ccca9a578febbab74ef86b47b16421c0144e2080fa0f3571a48ef07a3d4ce3a2b99dee07840a78929f0860bf49088177875e48859fb3e0e43f727a5e9119d8b285c99d24574e63db858e5aa002e83782180852583453fbe4f96c8c52773dfcf113acac2286c21c5100fabc7f10851ed4735fe6193e44e4103333f244bc8b18a882899ed117404b575f9db74d98f9d64d5a757167e0d5751284a6c0e7b2a4ed5b01d497fc17a2fee5d4340fd747421553494fa92b03ff29af0c37672aad1f65c43f9ba7165d8c80d60ca205d86f9298c40f1c86687a3df98032b4ba7adf4fd6541d508dee5090eac50e62a4e69c542bf98d81742ecc0c5222d6a63bae9721738963278b472f5008d36f4d434436e3a23156268ba8b4d961f0ae1908368f7542892f288317c045729e67df718ad812508b210eecb95a6daa48223bfcbe87c82e9c94c460c45fcb38556ceaf27801a978b2a116bb6b79830402e106fb08a89023e8d860589903d260984a361edaab935468e8f5a52bc2b5715596eca83bb2b32be783dc208f84e097f3574ece3ce39e3ec7d4a1220330c4c0a706f56ab48e926d64944200ea0dfc0150d26a29204e0755b271d1b7cdade6d28907467c23a0168375474e2970cce1b6659210fcfafded110e82a4e41496c6a9c6a48a02e28e9648519b2e460e27625c368f67ff6ee8b13d239606839fce69e242889c38b3c820cd3d734ed3a44bddd933a9bb5d786ef39c140188fa0a8425d347ce73248ce7dad94812151ca7edc12cf7261bba6aa95bd1df5124403647748252c1a27e2438d4e2ab8738ade55ee83f937bae67935c2d9a2e2dc8464e0fc2c0fc79d06d98778fe492337adb3995b7feb2a3eb09a239d0e9753f1532627474831b03a3b0b9a1f5001f3e8a2ca9b74438fe885950c8c62ecad94cfef3529f8454fb5a25dd8c9cd541e8ac7a01889cff7deca545cbe568204113e4920c4e1e48937c9303a2f88c58189c750938246b704c3e124871026f4dda7723d7a83e1bfdbbc98390eb574265a7def22745d77a7737e5629ef055580f5a074c1f845a01230a4df89c0494d994525ba9b42fa3aed8465947e56bcc4e6f6a432c6e6f4990b78ab7c3aadc4670a21ce25e39e54e6a1c25a0322da0feb046c01b88aad36d8fe7f0a510e4a967e228165a56f0edd20ffae349a35843cd0d42612b12ad128c4d876862c56b5c56fedea59b76233c6f7922e818ea3e7e8a7d19014a3ef981ae97e09661c9060d025e5585f6aaa4ad629d125d0acda60f57db36af6b0902c5c6aed209e255d3f9f2620bca942d636c04e9b80aa1dad843d3442a95ae24be129104d95237ef0837955fb800e196ae6b8aa9bc0df6ad0f9006ea1d8ec66f06df74c582ddda68ce99c2f6d6779f4157016458a442670fd76314176d5f201a5ac472634221d170a6e6d5de8311df3a81e3305e8a350864fc860855a4287912863bd6bd83c0fd7571c8e5a58e31841f369aeff0d08ae188fff846c57fd424fe7637869bc9dc8a7273ccf21af199cb9cf2a6e31564afdb4554e62f975680d138fae14e607e6bcd1e11eddd345e7213b2e0d06af3abc4415c697e4f6a3c157de7bf374590e330eef63a6fc68e2e3281abe0f07c5650e3b3dc98d595b3c54d369dc889ec54786544bd50bcbaa6488530c3ab621e78fe958fdc09ad8b0300bd7fb5473a6d5fe77ae940fa08fd41703a968dfba198befaef91f4babf64630a6f733295527beda7d4ec78d60016b1ad25cd642093251471b29ff8c5763dd7d639e7345cfdf5250aa6e23655a250f0c3f3270783842334ca0946831a07b6310e9d23b096de8d059060d7309b11b994a6ae9f2d16c9b9ebec361a57ff0e7e0f18cf785f3bbaa3f2249c012730beb831dd1673c6fda38d97365ead8a267d9ca1ea5ad93ae397e6800bb77d983076ea808090fd02574c7a0e071fba75a546180f8fc578c6edc3221db253a29bad2ac261c4414f83e2acff1108581c7c05834427baf76b0ec6d38a0dc60b1979dcabd8d4e5ab6c4d09732f2fa07074a80dbd278f57f9242198a7510a329870cc713c2760b5bec5ce6683f18ef1bf2fc889de3c996ce79118c07d57cab1ac496d31fdd49eba8bbf318f830faa1d70656bc951be241a2b10386b22e3ab6b6a1355a0ff052c87888876cae5281a54691868529afeb2aed14906d48070ecf5ee69d116b9eade0b396f0f57333a85692419fda189b2ecc9810efbef01a4c9710f754391db430ebb930ae685072e539cca3da4c764809229ad61eb8f922607ca400edeae4a8ae699eea122c12fe5913578d29f5eb8b5ec5f4106420f49356036ef53715427c80cffa38da688556f858ebd7c30983936305be7238cbe6c86ab00199415ae32862c3ea7d3b40ce699ee4f4af755a642761244eeb631a371ce992e37b9dfa599226898285da247f847729f6aca1690f79a21f04462b03bc5a75ab09bfd187e8db3fbdbb6b475d795fc76e8b7278b6e043446a650a909e00e31c50c2d68c08ea5c18733122f2edf433604eafa66d7c73eb4fb9b37e2e3f65530a490078ce9680663a5e06b27b3cab8d240ca4abec0ee51fb9169487f15ac5a0f4d18eea1bbeb196b62ec79db9bc80a02c9ca8c422a0ba2967bd272d1a068923b6c5d6b1da11b450e0ecab4f8c84c0581257f3e6f0591d46eed2bfa15d03f3e38d4018a4e04f58b20e27c6c07583ea65c23f73c0b8d294f0de67a060584cfd2efead04a5c2a39d47a4cbbe7482b3d981adcaa0a14d1719c8e81b63c664ab5f3110162a267ec875e4e1a9864ac7bd1dac1c1f0ceee9377031a17337a3175d7559421563177dd65191a31829f468ddf000f0537c742173cb17dc293608d9b8587e73b05deab934d5c34ee1a22c807df60ab0532c241eb4714a3ed7253d8fbd7c13546ec805a46dd9ef5a77ddbae9fe3feeb494d5c1d3a522741e73ed7d5dfaf4ada60aa8f4e0a7ae2bb0ca812135d7360f9e5bb3ea9c8720baf354fd458576db281bab1c9cfdb372f5007ce3b974261a0932fef42e691f2f1c315b86a065a00c2394b7d2d01b08200ada91202428c24deab4af4c50abcf4a5502c69966b603c73b84c10af85589458dff445e26d5f8a04615bb76cfc83c084e525c2d25240449fd758b5942dc6730f5c0a30752e9faa7737e04f65a61850cdb55791960183524b42e795415c43e00fa27388a59b6be414acd7b84cd55cf0dce2c6908b698257c88e21a24da3e32290f750603ee926403484d1bf1ad2906d0d2cc17aae6aa874d31c6df9c1dbf8a33a623820e340c267fcaea1c365d21574173e0fd1c4aa43df9c9526b9bbd1abe466d53b93a2aaa61bf66271145578b40ef5ece553c156013638aa3a2e3b39df56ee00d21568f5d8ef999afadba3f91384a9a89af3f09b83a0dfcde2487c4610573008be5010616a55f91aaaa1d91b550d8e01b4a3a0a70718e90f81b7388ac1a6e5fff33dbbc8631be27568682857b7a5624ddd0903b27993f0d0fb1e80baaff9e49e9460fc0462f1d44dc2985ddf40965644c22c0d47b81135754771d00db7b3a41b64ac6e5c74779d70bc8b279b33b054bea38021a2bfa5875fbf1497e5ed0d1e1594ede6c13f4897690a2ecf60ee82babb529d1961e3b9f38654f8bdb84bba6962b031c789eb23b3266cf46615cba0f68d9f3cc23d65b0e4a5cb2a4574f43a5448cdb560485730b7e10bf6c97973529544d0dbdebf150cf8c783b045e6b5f52a6991f8d0b46402b6e774042bb505a8caaa8b90302635a32734feeadab5fd11eff6a462d5771d3285607b3b40d5b9edb05fb3ba4d466d3c968d6e225a6466aba75dab2f2041d5446904b2f5a30a50304d66df2d99cba8c60febf06e20fd6cc3bf8334ba22a68cb0ddf6025e3c4eab87e91dbaf70c78e1caba76c4b26c24c37bb4f73a7a765ca722b486cf20ceadf3512174628fdd0e7576958b0b5d5709ca6e2f67582b57a661736f7acc1c0a7021004bccdfd9449a8c8d2cb610bc7adbf0da6eacc0f220ae29321a36c9f1f48dab9d627d05c6c7766b70f3d6cff22feda362001a81515a2cca7f1aaaa7ba6baf79cb630220eb6df669190d5086cdbb6357106f46499576b49375c877f1064b71a3142ac2ec33b24df799e200afabe38b74a6ff54600053076dd21e4e203376a3e5c6ea27d16bb6bb2b36e27efc565c6cbe7a7878bea98efdcc200b420dcf5f53f2cbc91bae480969498ee8c24a88a5d8f5b3375cba09ee476de8565796847f3b6290c27b7741aaf6a5b3af02a1a93fc1b5958c09c3ab9b88d90e71c235469f3a8b3d93224e789321306d8be21026da3414f25b47b1308edcf65cb1b2acabfb1b6a50dcb48cfa2f5fe1d4586d5a34d3b4e906409e4c3625f1d801bacdc6801c96bdee97da7fe99d2f8d3f5c266c4ea1e29d1b43e06d2ccfe5ba5f5b3cd2cddc9ef9ab375e5f56afa3fbb216be51aa45807ff74d0a0a1c32aa1cee522a890cc059030e1cf128549a2e2f38ca72d064251b8bc860262c7ddf1a534a90baa96ba8ed0d6c7a747ffbc1f265939f92f1e96496c772588bb4a3153994fe0d2d26124673342175fb8243e1ca473b41cf3c2ec45db783aad523a25ede668dd047ac842507cd8231eec11c28ff85fcf9690fdb58f7f5d4030b83df749c0c59b71960d8098be930f7ac8555d02b9d9e7e8051790cfec97987ebc5d967cb2bd01ff2b34af04c304c17e847785ea1ce1cfade00a994bf5130b2490af497a7de1bba6d09b29e038c9642da883b50a37c045e286a600bc60091954a5ddc462eb9852b527b0da09372c83f259b8b8d398492197f25c59735be51666ff7be0d3a6f4ecff06b3670e7f36fad194920fd24e7c0fadde53840b973447c49b8408fc0de74e311e070abe859e2fa864dc3ac2d348a9fa0794aee507440f3d9059bb782f1f53d5bdadef8356087cbb31d4a988a424761cfb684b6650bc31ffa763f601059c9e252c34e78064278aa83a81826c2c20cf06d6a1a7ee58f9c40491e5bbaa381c3946e4d1442ba06a8d101892a12f85faa80a513080921e17faf19d580a3fe2dee45bf73fe077992d29d38334140186d6bf6a6e7fe079891d20202b98f688e7b55134a02c02e9fb5f5a85afa050f683983b961b5144640e5a73c02230abba23ae417537125baa2d240b862c72a7d46d64565dd0a76d3bd253f991305f33a472651942c798f6b7a09b1cd838aa112233130501eff73701f4a96299cbe1dc22680ab08e6445b2487973c8957f174822704979e788197389ccb674e2e62de46b13ddfc0603ac9f288c09ec4517d08fdd8c207fdbc153a71bc3d51044b28d421262e9fa3c360f1a678870fecec321183c23110f2f1758ebcfe23c3c33504bfb11aece8747500242c08c08f02a40407101e131e25ae10d9fe9f029c754919d87bfbb4d1be246e7ed928de443e1ddf74591c631474c13e4e96328758668d2618eeebd741376a13d52ae8ad720a1eca82303aed904a0a45f161929fe6109ced48b50e19ee8edb172065e8e69c0758a5376fd7e3e45a95d54e923740c58ec691a5d2fb374859c93bc42ac9955978f907f3b6a697e4e786bf4834daaec3e8e9dab608530d9132e8699a52258a2d11717cffcaed2c6509ec638f9be97008bb4ac7c399b045c81e37765d46d649a66bbeb1707468fb52eae6c58d3fbfaa41931cfeb816ee4e631202facc8441b513a1c41517815f414a6ebf43df03efbc9f0557837407380da09ad74da3752c035d9bc0118837c3b79de515e54175fe2d206e4b139a90465e720d0b51db5198731d91a08af6fe8a1e2c2c818413db3b15f9b2b931f47484e3212a0534746f46f669b102c3b676f908a8940a545a4c1e1b472764bc0e5f87d215a24853a71f7f4b0f49811fae02ec34b843831c0f98ba30d7e63b709fbb4b0e9445f3228cecf1675e4e8d4980c8783dd93594607c40b5f44d9febbcde7c6ba56ee4d9afc9b2cbfd2163eadeee69d49b1682af9e19af0521485187956bb0e4f39310203abb5cdc56dcbfb5a1b99218fc12a6bd93ae873e37123c6c93b55e5b6d42805fae83aaaf2dfaeab78bc0c659bacfbda33d10d577918eed207493ae38d4c9088c5fd090b06948e1a90ed34f91d0dc59b94440590b613902669efd4e4b8c301f1c7e4f874e3079528123ca4e32b3e55eb5b398ad752a62a01de56ac375b55470dfcc233b033a23b676892b9db942ac4845678f5e951f7c7d3cc77b7d8d42a79b6c0da944befccdc8c6fb896810df9244337cd9c75804edef2e928800dc241ef7bfbaec45c96349f065e218080264293283fd1f0033e7be6b0fd0c78927446b45fc1f07ff3b5a109781cfedb06bf71ad64e13e11576ff40976559d43634a4df9c7008949faee2618b825da2a1ff03c53ba17b01d8f87567620fef8e3bd25470737ab31f363d70d9acf70c89cd56a54b226066bd811e26bd36e81da63757768fa033a8370015a87e1891896187c0a3bf32da1160f9cc8d9738bc572a0d44c7de1ac2dd1a702556515f6108704a3faeb00c1d837a499d203d4b62e9a9d106ebfde54eaf0c3976267a4b644d4f67619bc8a057d053a39741af003d67e27ae98d33f380cbdf8e4581c3a231f9180d72737515d760255ea180a2fefeebb1d52663b5a7ed8aeeeaecb65fda17a6c21f6ff18eacde583356604a8971a8ac1154219859bd95e72830ced500c134e88236d0e2a67f56ec403828158bd2205ea54c3b941ca71a0c9294aea35ea44c5f8ad7fb174f700f682191df8a4f4839d204008b2d5dba4bba788a1f8b4b631e44edd4282fc4bdce20a641ad423aa5a0812a74a6d72183610110ef62dcc5f3eaa7a4434952beed321cea95dd2f4fe96f446f53ef4396a51e07ae3bc8cdf91bd541af2a61a9fe5833d815d6f82c3eda02792c7f7922a248ca058bb988767cee660f1388bd5d3f7e01b18535c982fdc09f15187c0a9c8576ba1cbb207e91ae0a2d637ae10ad01bfd74a717935bea95fe9d5e3c7e012cd2048e7304720e571040ea6ad20148a4795bb7a32010b8c7b052f1bf93a3d17b5ee7ade000e931177f9bc4439ae83c9c0e5ce5ba84601942c83c23603c781df883eb3fffc30a778365e31b3d627bf998fc81543a4fd62c516b441a215bca1d940eb00daa0e3d6ad8445fab44ea7ac124518aa689e254ec1d15ab4dc5b3d3bd3344a448370fd56ca748ec81eb9a8c09bff556c8c5889157d21c33735dc62feac3b16ce315a3c4315d9b3df65c8ec4611c3ffb9d39a3118eba9628d5b459a6693349db5615bb903f2c098c536ae69ac6ba619cfd157b38c3304b22304e518891212e0b3b1f3639e198c09e3bcdc0a356eb358621cdec47536ae674a4ba26adceab8b97179288f5f9570ab88826ba61c51bbc847811f182e225023bff0af3f24255868a0c15151a00815de2f5245f46d8c981d70578007300c171c4895162d4878b3a9a37f903d20e694431d61aefb931da50f13834c77368f81d94e632ea3a0f0a3b8bd67cde6033669e4b4e1cc54039272756629a20388e39393f2de8c379f3e672c1fa16d2c0c145fc8581e6f9cb14c51cb14fe62d0cd4ba327de64b06767eacbab55ee38fda4cfbcc9381c664031c7374cc217b67eed5c5cb8b1714f225022919e8be52605f54c8571806d20008ec3c993276eea02f225e4248dacb08e9c381d705ec7c7961a079318e255eafa71c78b0f33854bc8114dd9034d0837ac13127e7f5a6e2a618153464af1835a45367d3646ada52d7661cc54e4e4afc859558e9ca165925abe0b0f3e06c6cbd62628e9d9086c705ab39d29aaf3935a5b408918849400ec187db895de129e414d3020b033bdf34985c48fe70573edcd5bc5d5d2961b213636a190fa6becd469e9d585227113d37a8c4d9d8862c43f442d462f6ae92446cfb0dcb67d868810b6c93d1568c869d9763c8908da16692449c4409ce339e074feddab8c68d3b5ff24a8a7dc94b495b9e3361ea2658870e7b9b89e97342fecc2f4c37c1451f18099405d4984f0aa70f87859de2ab18f5e16657aeae640becfc6c047762364e62b1310cc51608ba7648109ff0d52f5f9120f2d5cb69be96ecbc2fa6571076822e1107b2887fc538ecc459d9295ed929b62156915174858166687f45316633367664a4145cc44a4fd20ad98504bb2d6c8eaa34029a7a4126ec7c7561ec7c6744b781ee0b175de9729071c80e0739e168d5db360376bebccc6ae7430ea619e67efd726e4619045d3b33b1158b8d3c3feacf09560a9b70571a8703aab2b9b5e8bcbd7862632b1477401714d173630c4be02b28225f854daede11b5b8d2b4c9f32b4681b1da3b3c3b3b558c521aafacfa15a3c428397d78ce53774c338debdaed2bab704d4e73f6cbb9d99b274787a78a5e1c23063a6089088d90e10664d8c445f3d64578c0ce87514439ee3cca2b69e751a688f295a4994a123553edecc4787073e2ae746dd645cc766263952ae209555af24b0a620a220a61d36fd894821836852189b893a2ad578391a7765333e560e4df66ca22eacb750108c0954ff2d8410091af08c082d885195976ce7ec531fc798324622f3bcc5451cd704c4c37a519e5fe8c1ee08bea5aec3b773d8cd12feac3c57ebf2fcc517b3818efccf1c3a639246b9d5e22b5aa2c4a8ff7bc4a3dad35d0d7f7d41aaaac751fe78254437d8f2a6b55590a3deee3547adec15befa06e816a552a3deea36ef97b4824f053aa87e646fafa1a7e7a518cfaeb25520df4bf5885fef5522452ad557e4a255ac99f1b8c3b55366d36a36348b3b49dfd0bd3b59994ed84357476878a61e4cf3c0d4d437800f1c3cd2f6af6a30e119000b1995a101b1786b1cc4e8dc3b594d3c8336b41f4dc185b0122e72491183934c5cc5c2ec7b9308644295eb66b2f3bff97d2cb66a7d88628035b86f4c24e510b3befe160bc8d9bb99d7a7366ad9d16d325b853ef687956bb5b5689513377464e0d51aadfe82a492443366cef78cd1b72beaa0f273e217fe6797cb89903cb84695a4735ae69b8db150b00d142c866e2a2c9d4b7dec0bd174b8e73544c5454636cc6b3d30091675f140e8ef17eb82feac3bd2032657e75e164653cff25d29439997dfcec5212c921e450e7a68ca7caa2d0f778955adfa3d60045e5af75d6504fab9c3eb34ba4191598a95089963aa2d6d7c64d330d10c3a62f9268f6f9b00839f481913e518449e49698d50f377b77560c8106ac15b236d6402e9a4e0c34cb98b2b3ca4e8f5fb3ab2f924a8cc2dd84523718771ebb8e5792b69d991a8c5cf9e6346f5ddb994362941317cd1c5351b51835a57849118338a33dc6f052d2a10ce26c1c41183ecbc3577cc5579ce3dc391793a26d6c876704b5880ea09af6b203c42caf247cd56ac821318aab1944be92442e8b44d3e63856be3adfb3c178f98a9d6e6f8c93a96953b47ae9204acda10f377de61cfae7c5dc97a312a568da1463553c33dec9641bc7b33397186852c0cecf9e0267859d5054e8ebb9d6bae5a775beca62f7e1c48494129244bad3cc9cc2793161cb754ee15431ca8da858edccc89f1a8cb3ca4b5e1ba312b3d1b47986af9af68569da1cc7346dde58ec632c369b1dbc6ada99d9fb97af667ca6952346c9d6fb618bf2196683af988daef119bea106e62b3ec3b5ce59fda29a36e987eb99e3abd8735d1bef5989451305ec6725992a4060af1835e2e650332d71d1448281e65f381a4439f29c8657d2ceec4c050191a9787876669f62a4cffcccc91f279ae9659999de4cb189849d1fe5cf8ecd07e68b82cf7c625ae9cba2976c625417316afae0782a14316ae6c4a899db898d135022ad449231518aaecd442ec432638af88a452089a668a666c6b3d384246a55297fc07a99065604d209599bd578b868a7f255bd6112388993e3ec9cc32b89e7bcb4d3b8d98c67e71fee3fea0f37873e731fee75e6c4a8ab31b633e3d981d7e02b0ae0d818af183571b2269b4212f1d891f3d9afa8868846934886187545313a7e5df68a51585c918c5416b0571417279028f8e2573423565938aeb802cb39069a4c45022b96404e2be424236b392ee2dcac82a75eaec2ce59bd6112763e87023bff61f191f9a42491f8f92f0b49147efe2301d75c2690445b4822f0f39f185963aaa6e1fa0bf33df1814012e57cfe834212e17cfe8b8ae29b4212d97cfe1b8124aaf9fc478524caf1f92f278968fe5dd138cfeb58545d1b6f6607de6187575277dea171e18c8e4d3c36756df6f9f14bd774ae02cbf32b62c1f58a5225b8e2094414885d5c118cda8713abb0571463e7c30f27896e3eff8191351d9f3dc7a61ebf346d8a2a10a3e4cffc0e15a3903ff3322a868069f33ca83802f933bf838a54c89fc9f303ce5aaef0301aa3238d3d07ada1790e95f2c7a6e61fae6b926939442cc2d8f92982518c4212ed7c5e0c018b2390443c3e2f522189767c5e8c1a9bbac6cfb94dbd62ceced7d42b8ac951af58859da7a9572463e76135cace8ff58a5990e0af7ac52dc47ac529918bbbea154fd0aa57440158af4865274fbd2218b37ac52ec677bd6209ac68859ddca55f497867369bcd66079b369b7d76f9e2690a93e09c943fdcd7a1534625d36edb3e0f96edefb0fd1c1c2ae5cf0db57d9b98edd7e4a0b17d9a1cb66f8dedc7706c1f46a5fc7951db3fa1ccf65db4d5d4f63f96d7499c9aab8fcb6c3613375d188fb5c392a4f5585aa7d3ac0fe785695ad79a2818c1f7c7de0ede122e4cd267a669f34b67fbf3a2ba766567f12c780fd7342f6a8dd1f36830b2ed5e226c6a8e39312539f6f7c5b2bd37525d6b925f744d8ac9011b375f3837c2a63e25393d1abbd5e480e25135cd05b07a52d5eb220c45f1a30c8bc148d5b526a74e147ba86bd2c2a86e0c77bd322960752c16ebf3aec65619b2be772e48b2aeb228ddbd43f5b7c4de552add3d2e486328ac0a46060c0dd855d362d28a6c5f9e54ee8b030dcb55ae4b2fa49838c8b0f3b02e1a4646d73c33f267be456f78b861ba2933d545d7c0b3580c5a8945d36daa69336cd6fb5eae69608551c1ba1002892e9a463b9a2eea5175cd332389caf450f709f6fb5e17b6ab5e4e360d04d9936ada64fbd99a366f7f97eadc77a9ae7dadeffb3c292fe78dc9f5bd319e54833929b07e4b4d9b9f52f7b1e0a1d3cb49ebe11727ac4feca84224ec0d2ee795842cea1e24101292a8cf543015f6baaca4681e9a07f9e33935356dcc7111583baa0e73b4cd4dc783b573b324897ea3c3cd0f9d19374d2eab31c08eaaabb2b3ca0c3b1f7a33e8605573a87badbb6a9a5577053bd3ad216973e963f5f8600fbc0e04ebcd12d577c387c30d05ac37462af7e5ac54d7247fe0751ece6b0ac31f2ba0621e6ec038e161e05e0c80bcee570f0a12048eb9d1e166878e0676feabea9a7c297159090509a56451b1358dc3b0c59ae778d822ec06277f5a20cb15dee0585a18d587c6552bf66ab1b4dd6a7b83bb017383c3c1bc77af617cec35180963e606274267459763f00677f4d93e1eecbc37e653b29f92fc99476e3c2454ac12af03695c04d61f3fc2253d2e69f3ec7d41c2ceffe0226f0809344f44083c844ed6e0123ccf846e8dee0a4ae771835d141775eda4e02ae58f141e0309529987a64d90ba2c5883e4cf3ca11b532548901551ce2146bae1a1bbf162e75d373014c0a66e9662f6def48481e2cd52d77aa925a487bae64203b6038729eb636515383cd91004d148bc09d343b02e9a061bc1c992940e866e055d0c3264b9b97180bc71e20601a20ca227c6c8da99899e1823ccde9b2590f5a903cb9c88e7b3b4b0a91b9c27c6e8d97bb3f4c1c071bc92e4ab593434cd6ab9421dc4d0d562b50cb49a3edd959446eabc178cae2b2b9715683d31c6570ff166e946879b251f3e5e491fe8cde0536aa479d81949f45db2ad6be0e769b4964108c82c21dd1b9ce5f162d26fda6f4eeb778cd9624a2c68d52b5f206770590370c7d81d06d8e00deec2a69cf040f4e095e442c375e5b27af7a0a2914192c8e5b29fd2b73487683e3b0869629024727d71f29a5a67353935b17a90459739e1bbeeaa960fcaae0325e7c626c72b3c48cf45630f12685ea7ded1073b2fab3c18ca9c393875dee8a8739e26a766586fd054ab7a511eeef5ebe1c6f13d6e8b9de63b5e5eeef53539c9a28c8fbdcaf858ad018a4af7d86bf03e56263b5f25769a5a43f758fd96a6cf573da6a5a6794b1e93b7e431794c4b1e0fde92b7d4b5e681a901afa45ec0d2646a8930d86161e8143a3535b95c6118baacc41ca2cbe5e4726a6a72a1e1620016d755d35c56d765d50a4398cb95a32664001651745d14b1b45a0c7825b5b0b4d82ee053fa6cdf12941c948a159755d33e979555d75e9f6d014d4e5558e191f14ac0459ecdfb2014955aaedc0dce46451456ca98749f57d2d56ad334d92c1ce459759434c746d69cb1bbce689323b9b312bc8d7cc96742d9f341317e5e9791d6b47f67c97f97afa7560d9a3e0d529647a4c7796e90f57bb0bac03a78bd4a24481ea44fadf7f450ebfdb7a890f6e99f16d4b4d661943507546294bfe39c60c6f9295f4ae45914ac57b42ccb3aea8a45b4b3825f46ef0662b358acceeb7e573b9644dcac83200bec6e77ee2a16d136c1628120e829f1e0358bad686585175dc1ca932b5c24becfe222aff57e4b12856208d22b4de3b33a3023f82ba956002550df756710294b0235b7151f8661f55810e85aac56586f045cadca56bac63a7f852b204b6489d66b279b9293d8609771e6e8b07a70426a24f9710e4912e4c460524292cf9943728aede77d1feb6379a2f4e9b7a80dd591e0c562bb9b05d7c50726dbd75e0518d7b0be2813c516b0342191658a6d574bccc45fc48f05a56b37884a6843a5697c16abc36e014bd3f89e08a354da475af96e8d65d1c8a202b0de4922d759f562b18162658cf1fb955354aa950270d1012410bf8c1660692fa42d3c691a97173a49c4fad7f485162e303616276d59b5933fdfbfd777d62be9f5bd582d607921cc32c319a6f79238ebaadd12a62de9da92a631ebcc8242a56bdfbb62b1691bcbe2254f88182142c4f228e4dd65ca5edac8641b71af76b53c16f85006f19932e2d015b17ef5f2cb89cbb6aad04b89ebe265d7bc56cb6bd1f54a6ad5ae695e1d9b2643d939ae43f3f113c5d64571268a5f93bd7f6b66c2cef79678d84ee5a99799bfef9fd7e2b2c50619d44d271760b7c1b2f8e9bd55a7d78930212eea3e675c5b20287a572358b3b4755517c4c37e3f2f3d61b755b3b4156321c8e299ded7effb1c3acab1e339adb72a33f3fc4e2fb6835517f8b0bfbaefb8a961af753bcb536fe7dd8556e579e8b55a8fb55af566f1d8e3f32475a1f87dfcc1825e4abcbb3e29efd0d767b463d1c5b2b74ec5394de521ab47d3a7cf6347bd3939f5e6e0541df58e6fd50ab298a6bae01d4623c445f38a10cb57b0df2c1ed75677b15e16625bbf125e8e975dfb2e9e5f24c0aa1003b50e529a2a03df0d5d993efd31376bebd313626f164f88ed3effc1ea592f13442bfeca6c2356adcf16e222b173d1ceb320cb82f701d6bbd75521069ad2f3c658afebda85c8a10b7574b481737c3235c24fca6b83655d2e96c5ed791eab597a7c96ece63765be17368badd7b5942c9ba565e9d1e9a5a594ddecf893ca988bc79e077a7a6c6ce63442a4bbbbbb6b504fd7ed792c569639c1a6c9f38f264f10c81301e5d114c1a0dafce6f942ba06ded575f547d3827ac0f952e21169daf45815ec8818f92d0a79d79385d634f6bc771d8bd5751deb9e0bac7b5ffd31763fa6f7c677f64056f7651656e5183a0b46cad93f844c5d2347f387ed8f534e350d61e514a2ebba96dc89773d6cb13bf43c2046175cf71e521a0d029b2632f953ec477d5fb0e15d74d22df350a64f43e95e30caaa48a45696ce8a550c635422b568674316bbf173d1782cf492272f6ce9b38d8a95d0e511e9dacd6955234debbb5cf7bc30f42e685b77d12c9d91f6e94f570873d523223f8cde2f11234fdaa74f73fdaebba57b31e9aceb47d3e3628918e95a78f94a6ab1cc893743675db5c7eb6c7f413f9ad65dc7aa63d3da02a3095e15b9738d20943d97e541f182200b043f6666666666fe58dc499af4a1c176306cb15dd7fcd93d11821d18d9661425f8b045599d053f0f04ab6c9a91b1cb40285fae7bf41ab11e10eb53f3bbc332f3575fbbb3faf3e6e48c34d661f445453a529ba6b1c079efeec062c4ce2e9c9ff4ea5377eea6ccbdba1c423965ec701dce765dd77508a0b217bc9a324a32407cb117bc648ea8b2f3e054c0ec39e79c73ce39e79c73ce393b26e69c13ec66066c2198f1c410d66ab55aa7699910dad68bd52d98b434b09025ce29b2bde1c7d61217d11c06a3f9f77af7ba8bc689cbbe2a53e0a504665daf24d8d8b4799ba6cde7788fbd0e7be87a25c1be16052d335de6e1a83be6ae3bf320856551d92d8dcc43c78f31eb87500649f98376c3b27318e5bdb3a763e3494fda4c5993c30369c64f4e3006c25a2f57288231f063d17435b41b291ccff33acfeb68facc18eb60de8be5f1cc117f842e518261277f48d63ca3d1c5c6a6e93256be69c61c9ee7795ee7b5d76759c51483f57d9df7c19457eda161258bb19ed7f9d83b673767074271774d93a7792cf003dd922cfa81fe3e963ef21eb304ff8532478262270158eb254e188cfcee5fb764e53d8fbdef8717ba5e2d4f4a0b695a8d5460ec63492f87ec660e469eb36a6c1de264c3fb70d32a47be6f44f003235f8e3c604e4b3cc872796127caee2430f219ecc0c8973b5cedbc999e37bb708a39af30267a9ee779defcbe392708ce0fd6975eccd311b644f0f5314b26ac98d7d148cd1c5492bb86a5a3057e2c974b145fa0f782c13836bbe31cfc123b1e3a521f76ebc124cb516c1a1f1a0835f2afc8e01223ff87a5fc995ee7791d0cd625bc81450c725ea6bc5cd1c01fcbeb9ac59ffc40cf04ac6f727fbae055b0765dd7759e3732970965cf65263b5af91e3b5fb2d74b6466666666e697788444e6481d79692347294a5076923669b3756ce7d88c625321af59736e0ec84c5e1539297be49cdff755597789e49a55d6b115295b4b78d268074e1f3e48ad7cad255042a4aecaa27c075f65ce83b3cabce9815f1011575010f8814a4a73880f2ecd2199c756786c7dc9ecc6eea818af94b232977498318a1c02a58f7cff8c31c0b01cc4557237d304ad0865d7a4643d640549708c81f4d367b41d58a70fffa3de901cfaeed5eeba779d3edc3d9c5dd73d99554ad9c989a469ec79b5ab47d586e6e2b537841496752941094ab0ebbaee2df04d6fb5dcb5648b5bfc05c3dfd1bbad96d76a893b722c7b52ec3e285b1294dd27df759dd7c931960526944123eb565eb11d08b2baa5c7593c3bc1c44228de597d500eb9def57a6f51cf8b5917bc832eca6f5519f2d4d9f3aba094af25b21b3b8cdb183db786db4be33a8c14f5af324affbf56a87e85e2db50346585442bd4ec8eeccdfa1388c9d413887993b449a7ec64ca63588a85eece7363f47867f6be75edce252b4663b2d32f53f541b11be4b1addfd1b65ab0ef885138d7781e9e310ca2d1fe9e57f2a76f2ef467bf7d268d040f65cbb9aec919bdd242d3caf0981e9a53938acb34941c774ff1f0f0b43c284d6b79312bb118e287564bb113232196e925d80ccffa3c3c9cc34a2c88706a272f3ce339bf99ba76932845d366c7e8ed2f6294a846676fd874c533fad63549b58424627ba6aeb597ae3512af8d9bd5ee8eeacfcef33b7be39ad651fcd9678feada6c67369bcdeaddf9ece10eeda8a6e19a16a6713ceb5bd62b69d6b8eed0a9693c346c6a1c8f9f544a629f5d28d9b9b49c337375d585218b402d24901949d4461861efcc7db139b00c5846feb4704556c158a0924460c82166a931ecdcc2ce1cd303f346c5b45e4c910ca9314c50d8d6b4dc1c6235de90b2b395ec165f7fdfd73af80b478521ceec1cc54573a999bc5b1519cc4ccdb4f3581b212fe0858b9a6836c44a5da1302f31613bfc42695884040a4123e4cf0e0e653c26b7c36366ac1962a7a6f1d0dab301271fa107b40fe867b3ca5720f0acbd845f42246c38444804d3c083638cea9ae4d90f0e4a2130f355cfce5741e8675026530b998d6136e0b0ac06af312d405db68aaaa9aa5c3cb5a1b0089b6132988a88aa887e66858b6675056986ca080aa07869da12338c9d5f818ba612d3039205763e1441bae08a91eda83bb10b333ad9d8509911abbae0d8c864ebe745f03ce06c68449a2ff24a9a5d358d5bb3566b4679369bb5ce57676cd1502b84d1d0fc7e389a9af37abd2ee75a67517cbd5eaf0f07cb0163a9198fdbba4baa693969e56b26b6ee7a48f44a72d566ae59fda23e5cf8a211c51c9dcf5e9fcd82b4662dd86c769e8543b30799cdc270e8951406a16c61946dcd4599aa8aaf988de6331f8e867e61bea8a6f5f97e5df9f6b128308e8ffdf21553b1991ae758ca0bf91a9efb6ba0eff11a6a8fd357f96b073e7c9cefa383baa5dec7b7d0ba654b0e0cdab05921d179f9d6b4534a2512a53f3d1ab3012726f943152699496245ae9bb534de99bb6cd180b1d95477416586fe3518773e7b3f3cb2f311767a27749a43b2ee0ec3b49a3b0cd34482767e83c430ad56d8d4ba446ad5f00909509088c238b0128ff9703b6fe698e5d9acde8e0c0b9691445de3315d8b752d46ff5909b13789c5ccf09cefc1312251355735adc794ea793d959ed7f3ab8ff7a85be87d7ccb43008851f42215ede5fdc5ce73335961eed9ac995410e543f0c3ddd8e985d4e28baa92f31b451bb199665f8fe8f3c10f53311b700c61a4234a9698f04189c239005889a11380c814b4ac8624e201ec104f19a9470ed1cf7a5643318ac72caa69b9a6512a4ad13ef3a763ac1885049a17451062c0cecb9e1aef879389dd09c6d78bdf718032960e3b3c3b17290f1d7f7ae6e1a152370cc3c3b3d3626e16fa607aa79966faa1992ae5972cca5fdfe37f951e7fdd22e7dc9213c71355d800e9f568fa5c993b95483c76d0537f1fafd2f30e6a0df53df751df5367aec7ffe5e437e6c3fd84309b5289f4959144ed756c74edce9ba55f1932ba367b67d5a1218171e74ad3a62b4956ed4822dea1b3188db534fef8114390af246e8cdf4b0993fc9967ca6159398c376cfaeb6b0f5ae5ccd19def481876623d3b0f0e0e0ff85397683d7cd8aae112401f10d02ba95527d02b69bed21e749a91440d43ab4e29d255631f830819d263953f43af2436c324895c458abc9262efc2e8b062145599190f6b02e30d9bbadc48ff5f1ddbf771391e3c38d610577df4784ff5764ecab9877a5b2aca99877a7b0aca79877a9bca843305eaedaa12ce3ad4db56249c97eaedab27e71ceaed334ece13a8772a353977a9772e3139dbea9d4c4bce38d43b9b949c2550ef744a72bea1de794b3a2bd53b7148cea5de1975e436d43b7348afa1de2965efb422b2df52ef9cb2775ad9fe2490be2783f4590ee108d0a779083c80062ae58f162ae5cf0c54ca1f0750297fb2c810c394edc34065fb2f3480010bc0e282029a6cbf850420e0002c18a00053b64f002adbbf32002bdb174000f88cedafa0420a4cb68f4293ed5b01c0cdf6abe06cff8428dba73245caf6a54cd97e142adb875265fb2658d97e097d65fb24f419db7fa264fb4e9a30d93e9326db5fe264fb4a6eb69f0467fb4951b68f844af973a48f44a5fcb154ca9fa31168df084787083c33231ef82802faf1b17da2a1214546108108992bc4d8fed0165a6461fbb52fbce0c2f68788110618b62fc48c32c6b0fd2069c8e00cdb1772a30d356c1f888c43e240be61fb413974b9c1f6817ce84107db0f4188207eb0fd1f238a18c2f67f3c257184ed83c0049412b6ff01144f80b17d1f2aa688c2f66964ae1063fb1e6ca14516b6dfc1175ef810230c306cbfc78c32c6b0fd1e69c8e00cdbaf6eb4a186ed538e8371c06fd8fe73e87283edf3f8d0830eb6bf2344103fd8fecc882286b07d9da7248eb07d1913504ad83e0f289e0063fb3ba898220adbcf21738518dbc7d9428b2c6cffe60b2fb8b07d1d62840186eddb9851c618b65f93860cceb0fd1c6eb4d171340efa0ddb1f73e87283edc77ce84188207eb0fd9711450c61fbe2531247d87ec8049412b6ef82e20930b6dfa2628a286c1f24738518dbffb6d0220bdb677de10517b6091cc9368111498c20778631e44e309640a459e5ec37e1f2001b8c70e18e71c0c0153b2c5181a80a4cbde06279dd6cb6e1b3de0446d0de4ed2d06834d9d56e1a914f4b0e7d40cb2102ad104dfecc2b5d07a59b20b841b2f468bcff680e052d11e24bd73cef41446e9015d2b4a0a3202144ba99e3f55408ecbd7770765e37df81720a2abcecb9b56a6c1adbf41ce1c278d82fd8b18e61c162c7039d81f89514abb18f2ec40e7bcc86b7bb637404edd8b43147068d616cf72e85af86b045694c13617ecac349a7d0f730ce9964567e459177dd7a191879943f35072ff4906e098f468945076c565a69853e44e817b4411ea40a51d9b42142433697560844a269af24a10a3a1dcd1609a3d0833c9c21e8d4356985285bcf8851e8425efb14723e8844083a09551089303849c4b2b3368770ae43c8e52b49d2982247825ce845aee449e771855ea42e11e42604b90b42b50611aafdd264382119ae6b4245ce457ee461117a840a1d91b6e69574a4f228749ad71269851eb2c8429742f5824934966b1a5f098d794a8c388fe570aaecc825128f5fca8ff0a0e0f461295fa45ed0ae7029f9ca027685cb51e8b29bd059a876234e95722154acc118e4425ee4618e575291ca63908faf25d206b97c25a9241cb9d08fba0865ebbd9c083d489539117a9007a92e1ca9420faf986e5158dca2780723755362e010234f80ebc0180eafba7663b9908dae4915583ec77293a70a392be2759c5f55bceba83554d307c7d64cc9a8b4aee33aea969aa9e9c36f9d0b528dd4f4610f8c35b42ed6489d49322d0e4e8df1ca6e43ac743485d0a1b764555c35847f25093d94dcc92047a26b4275e8422e5f49b2259ac632a1b315ba0d9509551c1c124e98f6e17b3a8c325cd3f842aaecd634f036d6aa6c9ad0e7afecd6c91fa12a9b46a4deced608516987d42bda1a2c9460c3eeb0724c1a392bbfe56b5de9e635b42e7ff3a36ebd699477bfa2c8b7eea2f2f205830c34505cf7aac62bbbc96e4f23ce0d678927b11a17d49051a3829a15d4705173821aa99a2c2411917184c1808046e84212d54a202688944445888441940708e5f1d234a12a9735752de87cd91714e6d50842bf9d1de13828904541cef3e8cc7148c0454270b04a4de3dbe388914538515c54eb7640bae45ab7d4343ed209bf42f6c6406024500818c80a0954820950ce9f572494600214122e54431c1c4e99aedd1a261c1cce95adb17c9c291caa3964eb9470b07c9c2a1c329cb0d06103968f83460fe54ce1485165f938b91aa6ae5dd9ada6a96bb70353e3a5e64b8d9497582e960322bc0aaf8efab3c0d8167492f20b3a5119aacd2b2baa08411445c0dc80689e213272be7c456124d9ed87b16dd784e5a750d5343e9223bf9d45729c12482222e7e394914445ce316062d5343e93e35421896ae7e358218986cec789421209391f27049268c8f938384924743e0e184914e4bc46931b481aff4eebe44cd3f84efe81ae0950e98bc167f5ad216b2010dfd577e6bbc1915a55844a4b84b28de52ccfabae814a0de4b7e3cf335d03977ade40d6c01da452d740a60681904b5d039b9ab683ac8144481abfe6d64ee06a445013d535b91a2b248d891c482d52e4458000010204c8e5ab4811204141414140800039eb9504a4e656e3440dae4604355127526f36a812d530597e6dc88a2535b925582841868d72117690b51a20248d6b989ac6e006248dc335248dc32b2a44a8ac04f2875f84cacac81f23239915b22a64219045217ff84254869381913ffc1a2036b08691f36b9888ce079d8ace0faf8cfc631a6ba470f603f6c96f2c17bb5d115a4386fce113a1352e903ffc215ab302f9c3afd11a15c81ffe105a7302f9c317426bb8d861048208a0aed5a4a4c1ce079b80ce0f85688d94fce107a13559c81f3ebf92fcf0a58b46e8322141707042426a92b642842ebb75cdb3d28a3367ec8d946c6a0ed9665505acb443b61793156f2c61873c2589c55293e5cba2e65023f1850411c2c1494575edd63c593e1f274cd770a4e89a04c3728d54cd544d17384c42946dcd53d788f0910411a63cca8fba3585469142ab5015e8059dd018ba09bd21137a6d90d03b4b81de6a845e5711bd3544f4ea18d1eb830abd1f40a131b409f48625d06b4302bdb313e8ad48f4ba2cbd3547f4ea8c40af0f14e8fd60098d8181680c7d439b3b7b426fb5b746caf257a077b45776dbc248accf5715f92fece7a05d2fdb1cb117baf75f9f8fd1d7737c76ab39bf65b72eba769fbce874b163e6a54c99ae350fb32f20fc08124cced729d3b56b86f611ced721a36b77de9e3fe3a16b77cc97aef978d1f93324ba76e72fc2f9321ed9ce7b69c6a4d304c29138219daf23d5b5fb24fb54d7eed38e5375ed3ed17e74be4e95d1128fcf3acb3de5bceb4caaa96bf7c9c78d9c63f5e927ba155982086e284c2daa6b978a145dbb5364b9ae5d29b2315dbb2ac8a8ba767bfcc9f932335dbbf54eaaba769b7c464546d76e94cfccc8ac869c2f4343c8f9b2ab20e7cbd8103a5f76a66bd78a0c8eae5d002875ed56b175ed9e7003b244100e280cec7c9da8ae5d284f3a5f478aae5d13bec2f93ab9aedd129ec2f93a63ba7649380ae7eb5875edf6f93a6874edea5c75edc6ced761a36b773cd3b5bbe4497586d381a36b57c957a8b3304a5dbb499e429d45d9ba76938e429d49319b9a435b3aa49ef32da53628a210a80deac90fb54135f9416d50483ea03628241f6a833af280daa08c3aa045c7a136282a537e436d5029ec541bd445e14ef9931b2a4f52b8b9918242bd299c4ad5324ea997cacd942752a2542d9f0a54051e273b4d769aa8b0b3c2a5ecd476c69d26287c2aa470146ea87c4ad502dea030f4dacd0af5d6eaad5d859bdae5e636a814ea7dda390a3c53786a979fdba086ea7dbaf950ede6b54bc19112e54f709cbc09ce932238442e05a776c179e2f913273c6f12c26d5045ea7dc27911223827721dd406650500b7a136a82a5274aa0dea46b94e8ec4e609122936364da2d42be54faa96d149bd4f6c9c2069c2c4e6043a65764427ca141d2a3a425174461da428364253a43c8acd933ba95a409b28412e642344a55ea17a853ec5a676b1b90d4a4abd4f3a8f327ba27327b3dae583dba082d4fb64f3204236177a131d4d981c898e2347d28164880e216fa2a376d1f1343b9223b323fdb80d6a48bd4f3a3e44888e0bb9486d50504c78486d502534d9516d5097c93df2a310c95193304462526f9323a95ac623f522098f1c21d9aae523813a918db0c3688791931d4f8eb403b663dc61c4e473d2e44c42243f52b5802113a0c3c227f5c2ea85dd4958bb84b74135a9f769c799c88ec86a170f6e8302aaf7293c102c3cec482292fd9138c28daa16f00888187424b176119f643fa223c86e446b179fdba080d4fb241e4890f8a0bba80d6a0955f216b5412541caa936a86b2f42d502de118e8c20b58c44b80dcad68bf4a3aa651ca1dea3d6084644a85abe247a8447b5415d115e94738b4e944374240749ce6873c61c22fb8d47906e5b471fa16a016d507684d8c716927ac77ac71f69d52eaddba090ea7dcab9e57194f31178d42ef436a858bd4fadc7c67ac71b552d9f7d1ac14804d03eb98a4e54b58036282344b7418de032aa5a445bbbb86e8312a1de271e3752b58cf6a983221e27aa5ac60e6a970e6e83ea7a9f5cef59efd3d2915c45880cd586080922042408081602edf90ffd7f5010ea1646eaf907f4f7a1b4baa5917aee01fd3ba03eea9689d4536d503dea6caa695cebac8ba6f1297d9d51f1f80ecdf92ce732caa3ce72d387bf83e6d499d4f4e1e350d76f68eb3aa8eb36b47591baeaac5567512e3b5216183790800d1ba35f099654d0849d740e7183d40c6c53d60e62aecab0357576a3d15018601f9b5eee8e7aa44adac240dbb2afce7c8d14061a5e8f51183edbbda7b3b26dd7cd6e5d9be1e6907817cfa4a6ec8cca8db195acb45776c3c14d1f7e28655b3851961fe2e0e6904c09e9c307131545ceb24c8ce55f1c298b839b4312292a872325bbc91f3e4ecee90613e0e070708d839349c96e2c2ac35159d4f4e17b448c5776cbc1c078c74ecc18c5b29bec26bbd5aa904bdb00e3f24d2e5d2b0058f09412f440e94939bb4e326d3d3cab32734bc93d4d63d1ba26a594f2f756bae4595256f12c9a8d95204bbe465665b1583d4dbbde6ff9c77b188b8dfc28658e951294fd2111de1a3b4f238b440672f508f2ac97c3cbbe23ecb35e2c16164e2a4bf27aebadf97aeb4a5ed5cb71578ee7685559121a9acf2ba1f96c61b1e162d9d2d04b918b2818ab6d5b944602c97b350f5db4fba8f750960476ef9e08bb7725b0bbeecd87dfc1cf9ceefb6a12d6e7654c589f57c2aaa3fc91e712b3d96c07efececec50190f1e07e9ed966cd4c8e3d745656507a9ce439e57924ee591c58367769e994c475679ecc8c181bdc4d0253b7559b983864d9776c3baba414135f4baae6834f4c2e8bdbd2eaa0bdacbba7ab1ae5c645c171b76de4563e8ba0f94b69fbcb75741246983c7a53d1b980b8e0dcca55d1d0831257a4d744add9224e2346c0cdce9f0b25cbf33200fe30dbf33b6ad42abcbbeb2b7b3575462d913367f458e35f39518229c8098f262e311396cd76c75e0c7627d1ed8b5a6ab4316e58be58230149790545cc28d99b30d4ea6d9349de66de2a272b7dbed76bbdd5e08baa259bd2a878ac83899a69aaa6e57443eaa2aabab3353692edd6eb7dbed767b81081122448834d55453d5ed8a48b3daa96fb8a89cd454535353535353d3ed76bbdd6eb717aedae9363dabab334abdd44cddd4d4d4d4d4d4d4c455b7dbed76bbddac7a46e5a4a6a8b80a541a977298de44736a6a6a6a6a6a6ae22aaee22aae62dc996ee2aaa5a6a6a6a6a6a6a633e038e6e4fc345a90ccf514eb6abce0d26406018ef06b62bc6018e35752e772afa40e87633939c5be26c6ef954465f9d2b6533b5959318e7167cec89ce5af891166c39894d2ca57922925c5a599a545d8fdf663d3ba59347088054eafa73b4f4a759ad67595f631470681008b0e94f112d5e3654c0b3b5c28d9ee5d98b1a301d7baa8a67dbf5d0d6cf7ee043cd4c2f4e96e77c653ea60d0b5c076973c743b15d8ee9d54c745d78298d6bd7b0b73a893ea6e17959353eb08de455b956d8e674764fa8094913cdab6456f903aa9390482f3b78b9242eaa2e61094e9d3bdeba26c37e915a94eaa8c2d48aab3eaae3a3858dc5d27ab84c8175a607b650ecd778732c58cb2efeba4ce78b61e9224a8eabae89ac4420933b6935664d8eeb2ebeceda66e0787edfeb1bca0ae75ef82b0744dae8084d94935ad0c08cedaa3ad93ea21dd540fe9660cc6db497552dd54d7a455ea3ae4004fc93c7b7ece2e86cec6d0d9feacf30c4b8df17e57b6ff5d7d6cf430f59eef93a0f4581eed0f0a0a0a62aa8202e138d28e4bd27c0eeb93e68c6b8c36077fafb058df591d97a4f9d1a66bacb7c7aa32afcee0d9ae7653054eb67f67d5d108bf130d960cc34a31bcdf398695655869c61c82c01f7069565e22564a79e59595f2729395f2f2cdcacb382be5e59c9597a7acbc4c65e5e52a2b2f5b59292f9fb1f2b6929552cadb4e56debe5929a594f236959552cadb67ac94772e5979279395773631b9f366e59d5156de99b3f24e292bef9c9abfadf9fb9abf31a3df1d56ceace411c187951e18f9b112a8e817889543ac1c22fa2d62a508568e50e4578ab1b288946488482dac945b0c0dc92f6ab226c51822874833844821328d2032887443480ac93880fcf20d5602919c43d02feb606590641f8082b05288107e79082b439046fcfcf21156fec8a71fbfac84953f241320fc32182b9fb0128a0f7e390a2ba7b0920a9f2bac2443fbe52caca4c92d3cf8652eacf4407ed1c12f83616507520c1fbf3c86953ea4193dbf7c86953d328d1e3da41b55561907fded1baca4b273f865fbc0c32385d8f9ed21acdc9146cc7efb082b67f2494747322193492878fc761456f29054ec903b24991c9923b7c0f96d2eacc4915fdcfc361856de483174e89066d8fcf61956dac8346a7e5b0d2b6ba41b39640e19078da4913387f177ea60e528a70f3119849542c0244c1af1922ff9244a513211fe4e305686120ad7ef8cc24a97a4a2f53bc558d99264c0df998595a0dcc2e8fb9d5c58f9c94f1eb4f6f6e8e8e8e860d38e2e5f162a029f0088d4d9a31f9d5f490cc53f6a6ba5f70d07a98d73708ee32d6a6338ce38b88bdad806e71b3ca4363e737ee322b5710dce6efc456dccc6b98dc3a88d69705ee3316ae3abb31a1fa98d67704ee334d4c6689c65f01cd4c63038c7e035d4c656e7336e436dfc82b319d7416d4cc6b98cdf501bb7e0ec82e3501b579dc7780eb5310bce627c07b5b1997318e7416dac82f30a2ea336a63a83711d6ae3149cbff88cdab88bb317dfa1363ec11905e7a1369e3a73f1531b9be0bcc529b57199b316afd4c6243897e03da88da5ce59bc87da188b3399fba0361e73bee21d501b5771b6e21e501be7ce624ea3361ec1998afb501b4b719ee21f501b87e02c8283406d1c758ee23fa80d84fff80fb5f9fc8387406d1e9c76206af3f10e1e446d3dde7320d4465f2f446d3cff8350dbec3b17426db2eb7c08b5ed388fd7a80de7391fa2361dbf39116aabb9cd8b501bcd739c88da621f5f446dafc36e84dac28b1781da5a77dd88dabe834f1c0220f803c29c0627aea589cf00e60ec03d0b1397e1038f01ea302cf1173cf00674e00c50e20bb81dcbd35de0c06f125700126f61034f80068e80237e00a7b360c40d908117a08813e0cbaf10f10160e00218e20168fa0a425c850b3c85208e82975b01e200b0c0abfcf013984ec5874fa9c0a5f4f0283c1cca0e3781022f418793b0f42739dcc904dea4cb99d8be04872b91c093dcf024252e3f42a5fcb1e17dc391b7d29123e738909c738084719074862329e97c8324671b2449727e43c9f98c12256737969c6bb064c9b90d266736983039afd1e44c83264dce6a38395f3971724ee3c979064f9e9c6540c2190d123806259c61504209e7334c385b9960c2d90c28e7174081722e23ca998c2851ce2e90726e811429e731a69caba64c398b41e5cc022a54ce619c703673c209e7155439aba04a953318003853010000e72fac9c5360c5cad90b14ce5da080c21905299c4f90420a672e54384fa9a0c2798b15ce26586185b316013897094000ce2510c099040210c0398b019ca506308033992b672cae5c395f4180f3180210e06c4501ce5514a00067310638e70c608033152c9c47c0020be7290e7096e20007388b804a390401e710200001e728a8944312708e4a4002fea38583d0420bff4001f75180024ebbf7e0de77e0c27db8e0c27bb0bc07162caf0b385dc0027e069c87010cf84e033e6b4003aef3c2652fbc701e307c070c303c2786e3c410c36f64b80e1964b84d96d764c9f21c0e388d031cf07186c76698e1302d7f69d17291868734d070d703de7ac0030e52298740e01f6559087416020fb9d01a6e03ddc245123df22414c995d0a42fa149ce842a7913bae44e28933fa14d4e0275f212e8939b404938145ac2a350132e8542f9141ae554a8949f40a7bc0aa57200d0136e8556390a14004f815ab90a1485af40537800a80a17005de103a001f8152a8013800ee005a0576e004a80b3400bf00350031c01948527801ee02d50045c013401bfb485bb4015702cf47e01d4853380627903e802fe0265c061a00d780cf485cb406178161ac31d4065f80c34cbb550079c063ac31f40b51c029486b312b5e17c03e572960065a5330e946f38db284be0dc85320ee70950b69d73a0dce5bc447902671d28e770a600e5a5f30e947538f3409902e71e28ef70ae00651ece3e50eee1cc44b902e71f28fb70b60065a63310947f387ba16c8173109481385f80b297b3109483383751bec07908ca429c3140b9e94c04e521ce5f2863e05c046522ce19a0fce56c04e522ce4e9433703e82b211670d50763a6f80f2116724286be09c04e50d9c39401989f313e524ce37ca1c382b41f9e9dc01cab7b307282b715e827207ce50943d70fe00e525ce4c50863ae3287fe00c863213e72628e3ce4e5006730e43b9893308283b71a6f30a8aa7efd38d36867c759e993e0d0595964140f98923d10f277ffa967e51f2a799b28d00959605c51343fadef74d31a40f017aa71a97a687f1da58ee9a065a297f583c8cd2f213dfd4bc6a5adb1fb5249ae227a89595d5f5b1775a5d2059e82d2203bdf2ca2b5fa05736805ec9007ae502e89558e8952ed0cb975ebedc02bd9c007a1901f4f201e86516e86503d0cb972f5fa1972f0b805ebebc02bdac02bd7dfbb6157afbf6eddb54e8eddb62ec9d56b7b3b0775adde6c2de69751b0c7ba7d5ed31ec9db7cfb8adc6ed379cd03b6fb0775adda983bdd3eace1fec9d56770e61efb4baf3087ba7d59d4ad83badee0463efb4ba330a7ba7d59d6218cab49a3290222c3d8d33a451278922f0febc92441068c3e877baa186343212e1578708bf38f30d69248291df99915f9e1ba49191a25f1f45bf1ee8208d8a887e7f887e817e904644457e8714f91d1a421a1521f22b0291df118e904644ae18fa9564949046435ad47ee51646352f86fcca2fa2904643c210f22bc510238d849411e4579a9185340a2203a15f990617d248a80d20bfd20d30a411101c04fdca38c69046415d807e398733a411500f21fcb20f6a48a31082f8f96521ba37a4d14f113f7ed9881ba4d18f2440f8e5271da41108501ffc32133f48a30f9ef0f965288690463e53d07e998a23a411ed0a0f7e998c12d2c8032d3af8e52dc048a30ebcf0f1cb5f44218d7c84d1f3cb628891463d65f4f86533b290463d64507f390d2ea4516d83feb21b6048238a83ff721c6348a377e1f9ed1cce90463c3decfcb60f6a48a39d2066bf2d84f786349a15a1f3db46dc208d749290fdf6930ed24806c5e3b799f8411af17862c76f43318434da3145ce6f53718434cab902e7b7c928218d70b4b8f9ed2dc048a31b2f74fcf6175148231d61d8fcb61862a4914d1935bf6d4616d2a84606397e3b0d2ea4518e36687edb0d30a4110d0ec6df8e630c69347689fdce1cce9046b11e60bfd30735a4112c88d7ef1482f586347a1521fe4e236e90466212e1ef7cd2411a8550aedfc9c40fd2c8f544eb77423184346a4d01fe4e2a8e9046e015dfef24a38434fab460fdce2dc04823d64558ba1746968290bcdff9c5178534f2fe8073987a471ace4ed49ba3e5dc44bd9fe10ca65e9a03ceb87a83b29c99a897880ce70fd42b73319ca1ea9552309c97a8574ebd70f640bd92aa01e70ed42bab187056a25e69b580f3ad5e7985e5fc54af3ce3c29903f5b2d23d27512f2f29e08c44bdccd4c27903f5725302ce1aa8979d10703ea25ebe1de0ec542fe358381b512f4719e09c817a3957807311f5b21401ce5feae5a92b6722ea65aa019c31502f5709e03c44bd6c15807353bd7cb5c259887af98c0ae70bd4db4a299c83a8b79750387ba9b799ac9c81a8b79b0070b640bded54e5fc43bd7d3be1cc546fe3a89c7da8b7a3a69c2b10aa35a854eb564b9349e9181a01100000001400a315002028140c87c482c190228871930f148011799e547a4e1b08d334c8510829848c210004040000000064360004e2261ad1736104e8452344449b7b0e742d4be0e7ff2d8725505b45d1b60cc44c81856547376ddd71d8c29f78a62755f5c4c7b70a88cd583b097c2afe06da0a6f9e00ac1fd8d0c80aa38e54697199fa0b09fe52b66e7cbf7ae7f4d5bc1c25b03cf6aaff44841042fc21044e1488cd37a38cec35822cd29c56f0d59a9c26ca3a8bb333f52368e370ea1fa3185ea943051fd83eb5fd8336ee9a335d9ba9df93d427951f4e438bbf69283e3ee83570b270fcdae62fcb5f257ec79d75ed9b1002dee2c563dd40a9e3ff7f8096c9d1c14f4e202d1076b292d936a4bd4e480963f51529d4cd000de93406fb596b9526d983db8ba7c16a5b4f818aec09d1868cf0fb5a413ec9f3b97f6de72e5b2220d8f8bb4f17c91b12f6f385cf94ca532acda9243f7a5dbeb611c83043953c55b354cf529949752695a953b57cd87f256274e556b66c1291b5a8f78153fd0f7eb4cbfe009992eef4fc68dbc1fa53ecebb5d2f7adcb0caa2d8048fff9d12eb3404cfae83ff087f334512dca4fab977fa70ffaa00ffaa06e3efc99fc688b977290d44703699ae83b8c4bd08675ca48bd63b1af213733ca212590124809a4045230599c0e4010a113d1cd2887144c16a7031044e84474336a8e179c803c980f9ff9f259fd1740940da8866ae3305ad5536d7c4365c522b860402d6d2011f524e4ae98880935c8548c80616203055dafebe3c0b254b7f12d25100f8cf007501462a688076bd9eb9f43629700954f9e970540f7870f70e690aeefb9a0de180fa7d63efbecb30732a26314221211898844442222111119968e4300a4e094706bc8454486a5e31000293825dc1a92db032ea01ee68b6f3e7c6612bd0a390582d05398053d4530d05378007516de2f0b5b0f63d3e9acc6031e6c544a20eb65d79823c49b10a0a3ad54f8a863435eb8b3236133bed167d1ae94f419e287f9811301fb1f77d47091e5068e0c8eefbbef7dff3ea7e4fc329f99cc4c662633974c8d170887fbeaa3cfbef8cb091fcf066087bee1752d75801ab7924121a6d6fbf0b96f9ffaf6b988a3e2a998f2a8e8d86778c3235fed1a7994f20e702c296f046791f206c068ba7553e774f4eea465adb4a56ae589b8623f8e7af8fab21c9d20adb85fe4339219c98c261dc20b94837cf1c5071f4a44facaa9405578c595132b08244231db6d2db064e218b3ddb02a93ba5991cd88ca69c00a03b571008953c49b93ae1a2d8a8f4f62e2a737cec089139c3811ee9acd18e1a1e3fd6b30d2d0041a8506081e5d1e8c34442622efb1cf9efbec9743e481cae4837b374d6d522e8170a31c280817951c24e538e2370d118456455bc441f03caed38f125fc4b3299113f1b73c07b58e267f4cc8d31136f9453f4b40b3700e8b80fecfa1c67767e4ce05bde99ec84be6b771d3045c506c44855db328e37a59963b96246f87a41e1dfdd08e9c2f45d68025f0366ec51777ed053ca24e0d89c766f6e86670076c7f867c242a6280485d6b4b1676f4d4db99aa923fb8752270ef90aa7f4a0b78b8d2924756cf8723bc856ee9be93bc7dc027005333b07618eca23c989b8c455ef5ab904cf45c568bdc3fc4b64c2bd15cdcb888f5a32f3abfcdc9d6265584e03bcbee6152972a13640402e9dce0b1554de3226ff7cdc6609e0c65fdd6b9486f8d64ead0dfa2106907c8732abd227f34520fca35ee9444e4f6e6d38537be3c31f7b9b32f7a4f4d681e14e88a605f80abeac8db079046089a84bf9d0d52fb313846c06614bacdc3524236861eb1c8bc6f4046d9d536e14bc4544028fdc6c21e2af10553042a222d52a5ba528933b0b2df1724d3cb4197649f165043b864475cd8fac437eed01469989a566b44b8674fb747589bc6b211358cbf9aa1feafad005b4b21ed12531b85432506adcd6d90163a21b3f0ad7568c91f9a120bfb4b3bf30888513dc2befd08dffb002df9dc07ce3cf8f5a9460143b5d85b424d58227242deabb017610f48b04f58e9d5ae5212218edaae564ec7b333376647048bac137f1d779f4ce94a55a9c9996dc7e9aaacb4062053759f0c8a0f8f2a337db5045910dbc128153866a593de9fbfd3c3dc753980bb2cbd734916b45163260d94aebdc1805f5417494f5f4facddb25f22e7a164880e1460984973f1b01aae6a7cbb93bdc0d683dec4f04cfe153bee5a8d5b4cb416c243dd5542e04722087890a494381ba7bf268e733c5de03adad8d9984803cdd94d75ce27865c4e5085a9848e0e1d80f46795ce0f5542f86aaf904653354424bc1c5bc122d312ee5642549976a492570985c5d746b19586f898e4f5f635fd343958eaba145b744434a507c2000e840ef05f990a9652f97e2e4d63db4e47126e96f6819aba97f7200d427b4bad0b6c08e0ac0b0c425a2a8d8c15f82df4f0ba58087920657c25324dbb25d90917af3a1e62375db774a8d66cbbe35775419985cb38484b072a588c33f362fe02713668861ce142a05f990b62bf7ececc9ad711b3506f282b0d6b19644b9c50180e884b9e39f0cd1df30ad3d9686724670e5aedffb18ae4e5f50903a450dc26a42043f3a22439a6783020233b5e3922d03130408ac17156242be19beaad7a2ea18ba4cf45aa0f65f967062b7416108b921a5f3014b6410065dc577b018b0bfb99aa00a43001908d3e61463e871405715557f91fd3f4b0ca4941e1d77a4bdae889f00412bf12f6ae25953b58afb9b9e3ecd523050561ea359d7a0a12250fd985852915141e23277b79e6dfc1a75a9361134760a9443169c67f85d6ec1bb3b83526a400e3d2d74179b8234443f2602411a0adc4e1aa9f5482320004dfeaf69a6f9cb3cba96b772af5ab7899b67678c861280083a1bf348ad3865a615eff9d30ac52179a9434ffda0c9b2b65a47cb1db36affce730bae444d9901693b2f469d28ce82868bd69bca3527a2a9957478e21348c385ac820ace652ad3462faec766f3b133bb88d0e00f21687deec67db99d718f6b46b55b27d847b9c22a45e3316770481d5693423a808a9d27a80976fe3ab3296a3c7383d8ed17e4b4e65e425b797ffd851144a136af35c695668ba4b8a663a8e669254167c1e8d19268d158e1901b9faed088c2681adfdba8a044b0c9ab9a299aedf02f74823876946437a90a79907f5c52535f5e7e9caaac9a8d1e3c89ad34e59a2b946a6583096c0a6fcd8585b21abcea613ae36cda23535cf6d2ee0434b7bdc48d4cd5ca11a238837478a6fbcffe61973153b1a1c8786f392194d8a28ced437cee08a9c09a49c0930677eb862dc37e71a7d8e63d1f9d5de45311d326440c1d4c150c1fb65ada35f61478776941d3011dece9db596aadd39cb6c03f61d0ac0b21ae1415c7def4d8b472b79943ad344328f9468a759d0731395a674a7e7e07a5c85e2f1b0f6782fef7983e1f353afa61da003441f2ff679a619604abecfd8989fb9b79ff9ce9f252bf7fd261d708ad06f25f4eed12987721d2354f30a15f08cc14289fe0b9dbba16ca5d38e3b74db10a5ec4e7739a2bb4e940aa40a069f82b6154da634f326b52a56d41cb8e833052495548b9fa17a96d1db94de0030b75bd434dc68dc6a5cf2975c83d42c7934c66a3cf24b96556ab6411a9f9a45c1aa746aaadf467abb5251977612f8d4e296f4d15211395215632865efa9982f55615da589531a85b5ade7acd4342d7d04294236ab62fc52b695ea337015b8649a68564a7daf9a394d9ff20adea8e91f6e7adb577af39be23da7b155c3149dada3e8d4243c7d02294216ade2ec5396958ab3ac158a829a60565eedb6daf3a13ef34a2d025751302afb4c954de50a8d484daef4160af6175457e42c351635fa1925f17d575b9b7a57a6a47af46a2b507d8e02180556e5cf579b29d5fb4a33376057197fc55955638bea5534b0f5bcea639662841056085a6585eadecb91d36a58eee62a85aaaf518e44b7c432e8ab942dd5e15d2c2c873551a5dd6e86f2702c5bc84a15d5089bd1bf87accd9bf501af7c89c9ca83b4b267aada5a59505c6bf24ae7d8fda22ccca2c7ad7119f553a8d9e286eba34a51329d15a3b9b2adfa81d215ec3f9be5bac658cd10d2a59d89d63df07a27566645d29ae67a7da680f57b96557b75adaf37571a9d701fe2a92dc9bf3ea00004c21ddc58cb25c152ae7a94c1f5fcae4d73c2c6d5d47f416c8be3b08f3245cbce560c13cb3653fd06db02076313654aad8b5b3374ec97692ee8d26effb2ea2d8c110cfa7cc004bb75aabf1d6884f7847a571d614d3341d0edc6423fe77d9ea1e3af1699dc27745944239019d826b82da210491bdc25bb2da012480dec92dd16d1114b0d6d925c165188a40676895d97d08924063789dc5224b21d8fdafb6b81319bf6945147f9e9ee3e508e4b68243a8a68aea79cb683688b5724399b0209b506987ccb81c8d28c3230aeb191ed20ae49de92ac09a63f66b1e4ed0426dc0660726c0590d50e4062360292682f2099b603486b1720399b0209b506987ccb81c8b7039cb00d81e4b40548969d00c4da004cc2de0032db0624cd6e0042ae146ba9c6cae0ab86ed71d12e051076174041360391bf07a008db02c8b90ba8042b81885f00509cf541042f0328899d00846e002cc19e0022b70194c36e1012570016672100155f632cad06b9c39cbc7bafb36e11de836baab506707d57fba89617d817dd70f9519a49fc881f5370c8c9cb60635a2d058343bcec746c58f4d695c8c06f2f1c0e9ede1ad71dcc911421535fb19512d5f509eea406ff33d16b3f71329fd999b0f90e87e006873f1ac32abfc1346498d078c314ddc06ea8c023e16d20c2b5e1e785f134010875052b48c3a43b1028314583d12d036650191401df9101b9696c0c4c2cc43cc320490ac310693360d8497f8173ea0bf0e40ce38f17ae72176e4b173e652ea0162e04fd16fc58b3054885b5b006eb2fab59182c596095b14058b0d02b5fa1b25ce12b5be13256f8820fcf1422ace0900bd1789539196d81e05dde57004f8f70aff854e4c455681e30b3caa9791207e536631dc2788ed1ca6dc436c6485b6941e94b8b9a6a0ff6c6392d69ab953ae0eb0765378f16ead55d4aef5f95cae3568aabcf5addbe978baeeda954f5435c3e289f7bbea9a9ae5174fcba40f1d94aadda89f1e0737160c44241f539f3fb9b72cd450dd5aa2ed0eb47e5e37737f5d5b5aa765f4b45636b0ad5f72d5edf94eb2eef5454d5002d3e966f3dbda9ab2eabbb7f5daa1d5551ac3e646bf65d61e0d041b54297e9fbbbb279bb91f2ca59a8d5c7f2a1b73bb5ea7e15b72f4a75c32b05d5678c2edfcb5d97ee545595e1ae1f97cfbedaa85717a9dd7f29f58f5828a83e677e7f53aeb9a8a15ad505f5fb63017ae38072e500c4e583f2b9e79b9aea1a459bafa5aea12b45d5c776efefcbb55795a74dd1722aedfab8f2e5cf13ce7a95595a74aff409b32a7ae4f64f2e2e25f15bc56e697ebe382ba95f14eba5fc53c4b164fdaed82cfd4f26ae25f1eb6279a97ca2782db9df14fba5ec53c5b1a47fb95829c5cf2abe25f3fb6259e9d3af1c14dfbcc433b63422875ec4cb24f831ebe3225d7f61e3eaf5c09c6511d3674da02b49115aa42a69237982b51a088a9c587dd9f2d383617f454659e5887e782f5d85fc4b5f214023df0c3324453ea235914a1664ad689e8cd5e7185bc306ab134877ce1790c0997e8baa19e26b92ac1cf6228e5bcc1cf5f14868bc47e88eb95d4de510dbecc37b0b1af42eff45ec45a37be03596ea7bc6cfacaa04ea16c068a7aca83c5aaa2a3b9e680364d10077d8d7a9f5a64edfb1a8da64b53f196b1ee6aaebec3b015d4d5be318d415da07f598abef895a801394618ca62afc9f0527508957e00aa013d836bc4fb00f8d17b837b80a7975857a3df98050343c29cdcf432c631b4b8f673732119d454d1a718fcc0cc73a581054063f4bc2da81a6b58e148e92a5d8fe3ec75049aec26d7bd2ccbb6626f9d6e2a2a27219b69e6f622e9bd7ba8f3a8a31f5ac7d52a71bb3e5845691cad1926c369f9fd8ded8dbe93bf5ddde267db8324b910d80a4d8f2fe8979edb8d63fd4a94caeb76c939a5cce96325a098e44834dd48f91da2c97cbd5a5b2c58c01d5c913780cb991960a6b45d5eaeefc66edff9fcdff038c357838a97fcce570331b053744f3df739bc6b3b41201f0811ee8873ee8871ec2bfee5b7515d0c5e8a3c9055012e451b5e531ed144e7877de27eb0b8db386d6899d7fdc631a18ee1ba4e5815754bedcc98921a267f1ef603ac6d66e45e7b867bda04be1cfa2efb00ee0a32e40866073074bb3ffa8cfd9add5110d600eeb488d9b2da24002fcb56015b7db3d3c692c56cd11a595044e5463afd4000a077550b2a9d29b74b1ed2a6afb9caa45a11bcb702ef285d19b6b007fbad2fd528e57789daeef80c1559b83313219f3175abdc1c6b79643aa5710daecb81d655d3da59258f66a417914de852276907b61454ade3f45e141f1fb93470c3cb7dc343494a0f833a83bc81b7ebd40f4c0ac53b48597ec99004e54590789ac46e851831b39db113d7839b61e3a6cd30530bd7ff22924dd90b80f0dc30ea87cd8d3d17159c31ac290f96c5e190770a5bf9f2bdd6c803196d42419df854936a2d21d08e738e4c595733f1a4149fdb0f0ac5dc3fb4f47238f324d9a70ffadbcf90bb66ff8a13ce11a7d21ff610c75b118886dcabb5e663a1e9746810eeb210ce58cab18501d66084fc9677356824890a6c2c4fb3c2a95e0946d74db1fef59a26a0df2af9990c336771c7460cad2c95b8f588c26e69dc2dee45ae824419661916b1096b2871eb56962223e64c2b27968fee9411eda8268dfa3dd8a0028956c6a8087e8264977cb49959fde0567eea793e247ecdb2fad78e92f5095e64f88e4183cad21f6602ca1535c6790621e55f9936f933179e3afbe946e1ead87f10de822d2d6029845dcb317c007bc7d03f77bd19ccfe7246fc8b00685c2eb7ed492ad6d969165d7888f543d7ded2f5e13eb9ebe14886bca375c4f11b39d506e89c7f2532556a2b2a02a6253b2532a401f6878bd1d7eaa12e52e1ce6649c594d5a7b4681074955d2b4d434d085a64ef2642004d9278817e24fac31e9eb086df036ba79058ec122dc2c7e964ef0a4ac73f937a53e45b21197f5bff61759be84a46f24f98ffdcce77627c36a68f0f03990c091847154af1c59f2087115c8dae9959b0e4450704d2f46f074efd6b47dabcd0a07db2e3144b679c14f2ca3d6e4cf46a7f08ea81ab500b3a4d337c1574255907042b20a4615b1bf5e291afcf9c2944ca24a42fa974161b5d0a317ad630891836a21e407799ae86525419e5501529100a0347e3db5d4c6e671c2ce344aa756ca4851cbfc08517f327bd3812c5b4ba0fe1ba14f7e8cfd000b5340d5175e96e750145b6ab0795056f3a231cec3c75c7930c1ad8377b43a72397fbef46f24bec49a6ee823c6e9fcb6d720d4728269518cbd516b8ceb05d038f32bf6d4bfe99366717f6e9875d15e2827b273774173731832b5569acfa70348df8adcb28829ce67e298f5d29b465c6545d40964802246b6808e5ddf4cd4fb897edb531e5f0093c99fbd77f794feb53df57203dbf3a718ac60755bb01cd205e28def674e5711380f49c3e1c1db8b67efdec1505dcbb9e3a958e5bf24e3d580a03da4d1b4dd26a3cd9e8d85549f5226c38a6b2186972edaff0254195d068991f69f35ad952ab1f6de1344d07fd8fcc386b72845d61cfca0bb63584923d40bf1f613e3a4b8a86023058d4910a892262a98c345871083f413c5f7f4b1001d78fe41c71005c52e21b789e2731627bc93a4ae49e24be6a943523cc9645047d0ef53f483d7a64d841b315f7b8e103988cccf0eb4768ad98cd10554c06e405cce4c359f10e2d4ec487bfa4ac7ee121f07b39f4dbaa6b3854cbe539b49bc7cc6401ab796bb7606c5b0f135ef2ed84d8c00155663b7d20104df9c57c504caccc78ffb17431ded63ed803f7624f62a97df0f4e7a796b7dfc8591128517389ac5d454863c620a5bc166dc655848aeb4d015b712efcc19948bf8323139e5bce6a0c6e592f93a5cbe87fcbee130bb2dedde1b00aab2ad90b38c941efc04dbae0024dc2d5756223b554106c7504406e8af6729171c948def878ce3d22bbbf72a435d3b8a59382663981e1799191e77f08fec84fc465f612296cce565902bcc6f084728dc172631c0073329814ac60665a39e8d56ab65d7a0dd8fac0ebf6d7219f7152ef50cf199d87b21bc4acb1fdcf08ac7d136000b6c930b7592db9a0d6f01867e7f52d38e977cb68c0d5918781763b23ade9abf44909a83a23321003584678ea880b859157be5488fd71604dec58a050d6e1637241aee55f955b3260a2cd5e7441e9444a8e89470ff26638c3e19396eaf9e9e31161f4e34400c8c81b033b430eaf72ffa8903330cef49b931abcea4a3b7c5d84b11caa220108ce5a8b9f57920c7583742dc6b42cd256a572f04fdb06af21622b9f618492294b850103a08350dfb19aa545d77d0a8fba08e373da1d2f0791274967c25b3cd0092ba9a26a3e3f54151b4e930d41caf83e319928af5146dd56689e8d613e1d78aa5067bbdffea71b69e3f7b5b92f81f015ee02f8eee09be966e72ad6a304e51276c05f283739b2785d429538aea85e49c1bb8c8d12846cdcc26eda9c119cf41e658600c06401bdc63a18b21e14ecc8a4fbdaaa2a786ffd8bd4d6554c187a596d612fc325b02ffeeb946d3b95e1cb5c795509e17da6368263e803eede17804c415ff01dec9ca4d3e52077ed0bddd5cb93ca618f5ee8841fcdbdd5f4e81dd7043e29328b5cad28f538d93fdb2b63051d58471a5187bf494de4e7a22df08423cff4c43e3aea9da65f68b9e81d4fdac0f534caee6a5cceefab4534a35529b9bb3f059a70b2d681405f56f8ae152bcb45dbb1e66500c0832273cdf2ebe0a596db7ab9225d665e4860eb69a1f385ae00248658a497dcf54f995ff66666c5a2ab22a23a06e3b831cf6c4c13266194c7df38f85f14fd4eb82740f6ec43033d96eaa1b97b710b1c10a5397aeba35d2ad0bd8933c3557aaa41a8db15bd761ec853a952e48c57e980d641b5bebe46ba2d67e3bfb3a35de829e287fffa01896e2a5edfaeb6223c541d033e1a0ede25ec8d2761c9a2c62b5451f0e3ec5994154140ab9f252d088c29ba4e75c72def7e805c79f2c2f98351380bc6ec5021894ebeea4434863bd6d18d0fcb6690e2d99f85e02eb0c988aedc647bd97d9e9f2803306a6236969aef71bab1a6368ddc3b117da544a908afb613790ad6cad928f8b5afbedcaebd4780b7aa2fcfd8362588a97b6ebaf8b8d140741cf8483b68b7b214bdb7168b2887557dc30c156e54797165c10aa9862aade19557ef1df8c194b830a566509e8dbce80c39e7170c66c05536efecf30fe88f7ba00dda31b71cc0cd54d8dedf21622365831546caa9b239d2b484fd2d25caf92d0e858f2d194bd97064a0ac819f89808e439b40e1ef8b3c13467204bf8dd03b2b5280045efb74631443ba9071bc097318120eec1c7328af6cc17490463fde54cac9e4f0fe04a146c093f0bf46db85451be3799147d7215917f9cf33a3d41a0edaaf105323bbdbd230366ec1b60c2cd1f1b260c1ab45fe94ec60d0f260f90ec950ef288ccba36f747fce4968147f09704c19258428fa089d7f0ef3fdd7ac4cf7ee45991880f582080983cf6f65275c17cef6a359dfe4c1f80a415280c22ab8a328922fad6fd10bd63a43ef3846ff6afddc3268d9d7966eb0844110f864a12d159b0dcbe741ccee90d0505aeca1c37e68e12a6610e040f1d43f0b48f91ecc08ba4e86abd95bfbac33456039597e9faf2684e42f2c1a7f45c117e1c4ff127cf6c401774912bee4376d580d8c8b16b8065efb033ca47606f2f1798734efb9cd390f5cfdb914136d268840321268bc739ea22fd66c8c776dc4ba20a21d88b7a2ab40b47ba910a50215b3e91f3eaa3444244268a9bc99c4c1e830c34f8d51c3c1e1942032ccae5071f4a177fce20f85ee6066b7ddfbab0f2e070be17c7f441bd195e5f80474926df4bc2344d11c8311e038dad7adfb597e9def7fa27245b5287469b6f385d9bf469b41813341cd5d81d44a8d7a3ad0206a05071788496276d68822c0d4035228698046f5f5573e7aa24405b68c32cd67799068ea6e63ba1d3fb2140cf20201a88340c53ef5e3d9bb8d28dcbb72a4554c75668667229285ea9dcf41196be8c8ebf5862abc14b75190116c8502b0e66f0f8cd0d9650e1774224d5192057ade788d4f986851819f4f1b1c6139226be2e4d208aeae61c4bcc66ccef608c90ca48718aceb3b564599228d6159d6971442f87b6fc166b6ab65bee228bd53c475a85c662fbc8c58d36bc3a0cb041e0a2e9417430f36f6a603d5b0d633b68a2b3a4ab4fcbb2ac2eb825ed543ffb880d5908098de9c95c3dd00723bd133a4f672e57a46e5936e44894cd6618f8406805a4fe97ffebbf9a0d883328085c0043e8d0f4f2ead7c88d3920fa92fa8a86b01c12976c5f81473cc89fb078c9c86662dcbb92e1b4102462ae6bfff007b8dcaeba7c913b12ccb87ef4ce1b1b319634aa07d684c197afdfb0d74f4f7014c932bcf37ed2b2759c8e64f30fac917999cd9115028ccb554ab42597ed623912989835737af39c822a502911610b5845e41667e2c0bcdbde99b28a5f35080d3776169111396d0e5d04db79db46a361bf6a63e494dc16cdf4f09658d0302abf8e3a4f4c0ae41126b4cee7aa5e69fbada491935c93299bac9d16e6394ed64b5b8b5da6f124d75d2805e06a16b210b433a671928961feee99de92392d39c11d528068af5d4f61127e6691c989f42548135fb4183d4081d4e4396d344e5d7a34f883078ce2acb4d1fedad8fb5ea3e214334411b7d21e73788f0e6a34cdaf726a746c933cee0bcf62fa834805a6ea05584189a2afabe5571ed84ff0a358143028fa60fe3e0dae46046ec819360729d605f0dae42a6ae0aa4c12c73f6bf46c3ddd80cd2d8bf3abab0f819c3e2948f96c1b36a2d27a67e8aa7d95cf1b592a96f3843bd25a9d1e9367959e0b8a5baa64a0e72931b32c01c0c1ee7c5a1e414b0d5b39448268a332fc7d39cb0500b4b83a993efa34fabbb7f721bef588cbd1ba5dc17825bcf1f9088a955f40c6f1a2329996caf2b59754524574394ba273377b6148a42afca2da633b65bebed91b1a9e7302849c13f1a8dd4c684353ec9d19011b368956ef222e15985add2bd4f7bb97d6f6cf083791966896a379b36a0057c50055667a28b6f77d4ca9180f53ac917df68bdf3b613b9c7b2ef258c0993714dcbf615e241bdf8f37dc736173e84d9914851afec12ca75f910cf89e76c0b26d2f2f57acd8586f6f2a1543f6ce609195967920067286587c52201fe1bb706503b0b127eefd005e8dd23de7678cfd47e86d3cc0f4b6a9a8ff4b9f3d673b415b174b6fe8511eb320e42daa857435d66e37c91e0b5ff3a978a7f84ce892cf22f38c1c630d953bf5bcb617bf0c252ce920a177b2cf6a97162208b12474b40098b4498cf5434d3f5cb3e8b9be7b219e3a5b58c95aed44dd95eea6a2c51cae84de318746724bf45bc1b4200fac756b91ff578d07232f36febaa9f5003196b029040606cc36dcc277c3f4c38677c917d03815aee04a07981546b53dffc91652cd2ce6e20987fe6c6c07540bfd71c83d9501cf157720dc7305b398bfba24a3e928b8d50fb4075a5bf7e6e30bf666b1135cfbc610c80d769e33017dc6e72b44a221583dd370d0d6ae50f61189e1f61fbf7e708387a8e7dbd1d1b053f9dbfa98c6a9990f312f67a74583b2345e37c9db8188130d9f95a92f865ba4ec0372e2c17e0f6818bc7202b6a31fcdea54338be6e967003b481eb7e3f49013304d491df560e50446b6aaff952e489e0fc8385f1c9036d08318110a95de813b244aec1c2612bb4e92a159251671a2ca734077ba932dc4a93cf78df3b85e05258860d11bafb88697c2c1252d9d1f3500697ca8bf43da93e4ab3d93d4c28a8e485b79756869c486248aaefc30777a61b200a971d3c0d7549fa5f1bce15188dbcbd432b7ed9a04776f35ecdff6aaf6a8f6be654d6a25a11544dd8f17015267d011e5a2fd0ac2a8499b08d7af623ee486b208413acdb7ee0795780914a14940592198161b0f9d9e69c6604a404f80adad0c302af205944b4b0b266b7ad41d2d251a3663c3c3daeef6f2fb5b4ddd898f9c27cf90a673a55080f28bfe3947e3b3793de241b99ba679a082a381e6b207f8adb4441512246509d1f63184e74753d39369943ec7482cc78cd56c12fbfd94fcd0920182a9b0a180f0529e9299f4c42fe34db3560673566db6c5a1beff3f4c58edabfa34696f68258ee9eeba59b6ec371259d53f505c82497d7093e018132fc328d897b6d0b059863008a1a86e27b4e7b205074678e3c743c95d335caaa68bb88bb5c5eff454d1075c4d9cf61c08d3df13761a8658f625adf878d4d74911e9595db73f4c5dcea775434b1cc34eae7cdbca3c1133c385819985c67b360437718c0f1bbf060fa00b4babd2919353623e9205cd6c8081b70e6744e96327dc05aecd620f65f450ab64212765f0327fef13563e5dde02884efb1ea33d7b3af3f5a9cdfa67b17fa0d9d9392421d867d9775aa304a19b098ea7359ba081b4aca239415eec9c776210579c392d212f7ba970f412273307a628440f217c7654ce65bac904fc7615b184b0551eb7f94a7d9c5d101d365c7f9d2611523fb19bc1aaf413bbd10034d10f10c26da295a2795216ac34864faeb7aeac6d4eea89bf6b7160ec3c97418eb474f542fb67d05dfee5747dad27b6229a3da4b7511649778c56975f960c343d616dc43a471d41b477a360563a2813a06956900e256df6457da73d406bc0a490e4c1ab7f0c662d2d483e9bc459126ab42975c7c275c6aca3b209bb81501035d2dcd23434aa1471529d24e516f3d84d83ef3f9555fe342594fc2d552a4676713fbb026b4c7c1bdd0c512c4c95156f926c943093e77f1eb15f1b14c63c804e9589c148ec5adf64bcb6c896c68853494bbac2f0690cc8d58ac8490f63f330c49c3133f9650b2ac3f57e9521323fb8c4330bb370426ca57e4cc8ae3e73ae56d3116c40ed958e82ee86a48bac6c6db1d4846f42e949dddd4d2d249c9af2f62b13973723e0fc05aad211fb3918fa62a1920c2ecd217e7ac2e83d9158766d71203b533911839dca9f4c1fbd267e6232264a9a76fb5cea90c64d1877c5bc122d93ba24febb558ae53e4c8042d313a09c407124e7710222dbc8de464269d1ddc8590cefaa536e17a2cc89ba46fc4547154c5cdc5adb2a8fa909e4d21b6179f731bd996ed2355aa215731237031f89d5fde9fdb75107671c4e2bebdb697a2b5fc5b4e8eb7766ea931b3bb1b9534e2f4a3441eeb810fd4ad0e8713416824002a721e0e91870c3f66a0f609a88cddd5eca36eb6e0f49c9e782299b2ff105a792457d825e756a567572d95bee120df01bf3998fa4732565474497d37da7ff20faba0414c71c68619d2b55a267ac1c31ac3332c7c9543fac332e03c56f6056e6340967eccd2710cd5d8a2df718fa5cae6f22b31a3b28bbf95081773c6760eacaeda7819071144e6d144350437dd2fb8ccdaf7e87ac52a0928dd12ec1f4f9a6d31ce860e2bb40cd4367316131a89cd3066558de38a9767b2d5de26a3b00e5995fa477029d2ece03555afa310f155ecd96d37297ec45c0a04924329d899da0ef77b9a8bcd4f6279e2c8b8fc2fe0edf6b8984417d68c63753c9eb2cc688c53b5e31669be9b59800a5a85e10ceba371c32eb60148b365a2d0bf0457d9b3dbd48104e0d7b4e16aa184014a72089d0e97fd52373b113419cddd9550fe79f201ccf694887e421e01308c2194312af00057a2fa97104e10c70aa3a6971f9c64858409fc384eae67786827024b294350bc6fcfc7d01b947efe67c90fb027490933d2348a2f43753d087360da11c60113d5e8c1d022a5a9a97e205d0fc01b3297a4db099f0e2fd9bff3441d513ae09d5969c6b95155afc66cb29888c791abd61d619129e0b310b98e426fc03f620a01f23d12a1794ef971cdf3b846fd7cf331603e3c63d8bce70168150beb050f8d3be787dbb4d199f8678e5955fcdf3601eadf3a665ac8d0c074b44789ba6594814152224a40e61273a6b11ff637530d1eeac14cf0e7433c5e498c3c3d3303982a1904629295fc1507ecd98588ffe3906f70f91b7a5cad82d626c25bb5b1dd19abebd233054d60c61b7fc06b68e0f557a400a0b527825a6810730d1826803cf0db60f8a9aa6da81650ad450f81756cdf5d91a72b516581bfbbc405e560aba234042940086dad86ae4eb761eec92648160507483670fe4c2e0d83c19e808278a256c40ff36b213873ad624b90ea50cdbbd0e685d45f73b46bc5e0fea09460cd968fa9af54fb8a50d7485d997f066d0ca9b2cc279ae82ea43fdbfb663d87e2ef9c1558cc7f4cb2381a12daed2188f7420bda999189ff8152a35d2f3510f8d1014c4545b580f3b9cae1c972887924bc4422b52e6c51aeb07b7418ab0b661e283a06f2ff5b8a4b2b940de1923da828ecc208dd11c19852e891192190c450b11f6d91b26f04bb17d790c21450dd897422f023499557afda39405efc105872ebd4165603501feef9566974ede2745955f26c521260275d3c1f422391a920ba8da4130ed7da28299ca7ebade7276580f823bf22340888a6bfc04d8979af14a0c51f3dd96f4f8fc1cd23708ecbf71daade172bcd9daec2b0aa31aa68ca2e0d7a917785eafd8001d29b2986263d6d516a53cd8aee0ae66ae9085791ce5ecfb1980dbacd39f3779c0640c1d145d4034cbcf254a21ed0748fc6b6d8695edc133a896284b012cce322893824e7e1a2010c5a4af07520705b815e960051fca47e826a8914763203e742e955ac61ed5137b6095879ae70286a13296131ff1c81fbee8edb00b087ad8a743252bf68f89fe8bd5c870967910ce156e234360340ab154bff3ad7cdb6f080963376dce23ce15586e697adc05958b9ad30b1cc5cf99505a413b5455425946aeb008093d6984ff84561fa9d2d63291116f56f8bb83e22d8caee12b7251d0c52eb2196f8e91c57824d26c89a9e3ae21d9b9b4f1919432d7d4ba0be5cf462540951be0a1bc2af3a8b972ed248a9085b080011c414c119133a0a3b5a86c09a95d24be7c71cfc886b2b63400eb31377c09b050212885fa87af77d022546dca82682b0d5ec2d96182e0e4e2c9bf36a03f412d2fb1e5a4d68f6097239b259c603b51e58b4daaddf28684878b9fbaa5002d4eeb1e1a9fb1c9b4078abc6534481d96fef615c1a0329aeb2c303ffc7b45fbf445e9fff84b709ee2febdd2571965f81003d581332f9c6042a87b08d8bb31b597ddc05fa5eac591e468635af5c4ff372114dc015facce69a82f650b8a8efcd7c70520637f36b933245cf67e5c334ce6a95a3980ece9ea50431e59c360baf9a8ff72f7350cdea03f65b4b70cc0bd011908953c2dce753f2de99a0f898ee0327f4e653c89a0223c635093cb55131af5bc74bc6c8cbf59670b8eefa1d5751ab886d4133aa2e26b361a81eb1e4480b3048ec23c3206c38aa63d8f65eec65736ba67aa1d8919be7ec96784aee324efdc77ef02df180263000432873aaf4975a0f7dd6e40008f4da0e9625f51ac7d2d5892b99540b3113b0d4bddd2a8090c705acdd71db45e813525018b5cb1ba4ea084ea1c4ae9c2a6e6c5c6255ce73a45804f48ce0080597c6bf8eeb22ee8fd3dc5c91353067bcc208f9bc65d6de1229370cb4fa4017fdd3e55973190965d376ec76074774f9fc74833d63ecd299b582018279e6d8f7861248d21fd5ff80f1ca09b710926dc6099cfbfa5de48acacddee32cb7812a024d40e76415f139ac6aab9257974a0f2e2e6860ee2742f3535440768e448efc4f30a98e5c45c453b47b3c46b5629bfc8873e75f17536601394b26f50004d052bb5423719fa77a230c02c21208f5a9a0540160f7f4da3816b3762d6925ddb086eaafd92b6cba96630674854eed50ce16d860d8a64ce7c121b721ba05e2ba4a7e71fc54cfb4b690aa61502499b3262a817ffb4ad3390d7dfa21d09c86eb7192a2a8e8f0022b4aeb478b3a70140746439b2b0c88b26d83894e636d095b52a8d8339f1728c24dad8e09330472f58b3f7f24216edafe175a49ef1f06dd6025adc2e5abc51f5d1f3208172aa59d4fb19204e73ec1f0f8497967bbaaee5aef40179899ef9e975fb7d9458fa9e99eba4cb15e4b4f242af42d269e5ea45efbed8980396b3266724f5f4c0cb94aec739c3c712fdfc1967352713fdf521e1437f3b917e5451f0da9e151015a70b7b6b761c35d06aac28d082786f7887027141466da70dd0c752c68f9f4b0a774f53964001e9fc6600cf94aa27aca3c4a6be3899005154b1a58488d63ce4221ce0f2eb09446e62a6ff3413c0d527922cc6044d81f1dc9b3b81e9fbba3931f743cd7f21f75a63b8bea660a200041e664268848feb77251b1f207fd5051a59c29fc2efbf920d1a01658b9c3c760a2d6e7f21a3efb6be6661b859e40bc5a403facf803c15a764a510dc541af442fdd9a0fb6497ba6b4212f3df53e12e45397ed9c2c153c52c26819b329d3c056b916857100a5cf2fdb20be32e7d802fc128a7c32db6a78cf176ad7713c9cb94fa845ebd834b5ac9849e309a0dc33df6b9f67849d230c2db4e8566c39285350a93aeeb4367159c93fe0c17edca16de4d821e2444207f0b920e1ba2a20d91cae143cfada7dca85384acc9a9dab797a31947aed023af8f286f8a5cf791259b52bd6d428203eb77083d417f2449c546c84017128a56da0b7a98997df61a65d0b75f5af3f3169cf602108b80af9c9e647acde14e5155cce83df13b7ab7b3653920de060f47414afcf91d5e7522f9fc7d7e59e3e821f8d0978c88281503c3c974ab9d812b7b328d1469c86a5631a6ead6fd5ec0dc10df366ad8206cd2eec5f615f345e1c17a82dcf3c047d06ed4449e5f9f5bead32ca621050954b5560acca63a5226663191a228d3d2806e11dc37d86aaac713ea3fd3caee64b8530b0df94babcd8171a3ad4f3c4acb8773782bb691734ce3fec0d029d46d1993e3f6b27d3e66820741126201ef9e1a07f1972b56b7566a8d9080a747e9d676d21a3174cf6790575c571a0f939a0891be41c6a213d18df1756c4abcad20ad936ece13ba798a1a08c581156fa2624249d81c99ad438739797c951a62211e7ecd16e28dbe7ab87de6deaafe91bb821b11b0224b436ba09011623a7e6f8b5e027b5f0506d5a4d98512cb3189ad2432082beec90eddf2a56df3025edce48ebed20fa5d701977a30d84e1eeb1e594306179f505428ba7f7d07a3cdd9bef5b617941026c6f5091ca93852bfafbc1049b9dcd1335cf1d4770b5e28ade83a43206322659fd1c4594a5bc3d29e9e1efcca0c5b2551edabe85601df012568b1d77b27393b20320b60e556ab8e1b3a97621a6e0b96950ccbb40f45c9a1ea1e12e727980dad9c49eb7fd8ced16789ba208519afe94d5d1b4d9f7405a648af9bbdd1d2c2e786508d2332d63779abe74375a9371be917fb436074bad94143441fb6ca5b21480d71dae9b67bdbb44f0be28c433f445f526be184e340fc05b5a805542db307cdec112a04f889a468780509426da97bc233526c782f08eade28b6e5f236bd663f9298e03b7de2c1502a238f0dcdc8f449c4ce8f90b495a72942d5be3789b44e47f8374639793f173e64a5146c30a65a3d7a26d5994b03fd41d93cd6ef28a28acdc8230063d73d402531a00c8e79fe29ac829697a88c7899d8b28b8f06fa48e7c1b704496c989b80909d50016b26337f5221e6689caf57c71758e8a686173f76210bd2c3ad4801547ccb55069a5a79c0a47de11579cefceafd4b21f6e206689f1f66228fb4765cdf982e6123d5e7fceac74d61d7b718b9c7877cc63af6987850ce2ace74cfc4d294380b29f62f6a12481a67e375f8e6662066fc3f9640f43287eec5f048edc2f5f76f3e8f30cb324bd37d8899dc17d9a904658e569caafb93e9b10d7bca942412198f3d49631ddcaf6a0809c0e764e76749173c09729449958b141205eb7879cdcf21f6994777276b655f3939eb2aeb88586192dda8908e4ce85239c0612b036b111fc80cf041a781a60f288ee852758fff417813098afd5c30534f4be78f798ea3064c00082b6e9482bb81a139fa5998f0a56aa8d143fe8658c8fa048065f55f32866585407450c953c8a17d8dc904a81b3a04cc59e1bda0ad545d0de57238c42da360a88388d58f2a5b918cad77627d2759215d867f34db132234785154a78f598f276c48e847ad495cc3dd119bb288179beb4978a504c21f7d473f22bafc9c74d14d3f2df4144742cfea3292159e243be89f4657f1599cbe5c5acb0cb3a47dbce7b6bd727f564d4b1bfd0001c21f67b0986d9b1db97bf986ce5a9eaa4796998edf01da05d97acab5f8abd3a43bbb6d3719800972ec0e33d8140bbc506678de3ce9b7e635f361a8475a6cd6ffe485687433120ea303132ff1eca3df1b0717b11c1ec25db257a257e3292854b05995056806542e0b4204c770f16d2427748b1c09a10d6ba50d1db940d7db2ed74df782277993a65c5e5b3b25586592350f4d88303e5b5c031620b1cc4bf68c3376f60cd77c2c1c8242191fd009aacc886b5b46ecb66913f048ca52c24f9fbbce02509e0a7fb56f694d9f9e3edda31fede9136dbffe8e7afc52152906d480b88d2936775539eb7c10b9ee5ee6423b6e5de8d10d26fbe823dc3e43127b3248aa5331fd96404e5b95bc407147e1babd7e816c98a6a12abfd617d4b10b650897295d22d227839d574e3cc226c74263943e88e054c12c9b4eeb58ebfddf42c2b689df3c39902963b49d3983c6fa0325455714b09713a6bd6a54dd7f8804f3c95b45e297ae393ab9788209b73375fbbd25b8e680f240f628d75ceff0673c243d35f01360129c429a0215897699f41e6634247ec55a4a34df0e55627af157b46a7dfc8ff268e8a80940397b6cb4ded7a2399071d4391171df30d73cd4fbac7b4a697217c5ad8b5ed469b10083afdefc6e165ba18b4228502c94f42ddd0ce14354ef73ed51ab4a05059c1a887f69e4b93740574cd496be0c84b56d7c98df86010a02d1a9efcd5f6eb24393ee44398f872d39457c23c45719d80d9e57884eac358895e87cc13ab5ceb43aaec5a95291630cf7708bc24e911d35f38728e8ea9ed744cf22a891afb17bb4f9312fefabebe157cc4003017a0203930e3742dc8bf741a19849ab32ca568c995ca9b5d7234e4cf41c9db59d059c8d04196d261854d597547a7d9614259f3bc03a5eb837f4ad73bbddd76f07232a0d2a3c41f720af5e92ba739f134a1c473b2dc1f99bcb46eb6515247fdf88085c01a902329830968c5c0f74e46ba8968fb00c17430f4f2ed25dde5283c8934c77037451874e97b7870800c1a748ce7e0f5eb04c24df3466ed9f57013476480abf44ec2014efc92c044a28aa03e85cd246e36a9cc013710835c64803cf4a3859056b31856865b453a4805a2c5ce0441d151e72c71b6458be5918fcfee47219f6305e401f6ea4ab5ad0b7465d7a6a5c1c12190428cddf8313d5926f35e670250a31c31b8f552ec2167d0366912bff6ba2b3d990ecbba633b1b94b37bbd90b68eb942a606ceefd55a851dfb7bb9712a87d4d9490895a03efc9f44e6a60f51bab9968723e3889cc84a21cef4fe991eafd6507674ffb7d0693b91589b2f4317ccd7149b6f3ffa2f125d97c901fca44f9d292106811f7a5d7041294facacd4aa27ac69052d12a5fcbc63d87f4f136e931217ba95d6b1f4fe24d5545b4bd73d40bdb0494758453a636e72b5bfaab277356445e0e76d344a2e2ebd2362602ea2f4f9c05a761bdb8f5eef7681bb3962550df57154158fde5e3431aa684d90b84681f05e9a5f14e04dfe251d4669f0fcc7ecda48d6402d2210413a3439d8c50b021bd8750011b4704ad2779f52813ace7db244854d5277bb973391f9df0b3804dfb3555834b88adff4120d603e321a084a22b20d114b4330e0f78c488f1113e34c11a26bfcf6e672a27a4f1d6eae6c1b44fef4f911a1c3088787fc30ceffe2cd3a858325777e6a865e73bb04872463fd4acfa7d32138567a599e82fcf2236d0f347a71e1fd38fa0e63213fcb8057d60626fe53ea5560ce8bcd536755a85929f74c62908493f9083f73c6cddc0544f88338bf905268004f49598fd7c93448d7815e6c6317e84932179ca2f9d670502de1962182716584166f201610c3dad3022bd5e0fcd01652ce417f2282180e3b911514046ed88ff14a8ed9828eb2e44e74813200942b5021c32884558018a5093cf0e619d331497e99ceb8879193848c237efb476f17399770b29ea0a1feea277d24731565fe577847f2ee17d3d90a85cfb0aea08f891387d7fcbb7b87439d883fe6d5f1f8008c0331754920fed2f20162adfb62b5685441188d9fae3ee4bbd311db79e877ffdcb1f930bb2a83b52312526494600293d0ce5e9c5b0969be054ea26bde2bfc6a5e67cdec8692ebb1ac3c31571b2caa43a2820c9eae23686c67b967d55f217210e4157d7528823ecb844c2bd7948b542e26fc9d18d1264fa84560df94422222e73f90955129858fb7cb0e9becb532485f10c3704c8ee8e6ea70dad64a16a1e26daadce2b650cacc1354783be6c0d8c4026b7ff599827dda156fc598df285eff04541ffc8f8bef8992346473f51843162e3256c544fe1f4d090a5cc59ac8e97c9bbff557fd982a6c065356f2c47b59441b6cb614fcce48531be107f71b3caa1b8509efa954e7ee01572c968ab05fccd854d08e697713665277e3a8d9e19b7c78398692730059ca166d730432bdf0d4494896c2974756ee8c5d11071a28ccf0ee8cb56553e02359f9f54aa5d9cb8bf2989bc41753a4ab64856bbfd4b3ef4c5f4818a416fe718da6ef9f865fbcd1299fe51f60121d8947d4bac8f1bfe466d98751166a2fe83c82583ba6d34aa40a20a2a60bd85768d0a77216a70fdfb15b843ade9d08bb9a7a3ad7585191199a87e01e47683d2b40bad0d783d6448818dee07471f9396458291d419c95a674bedc78ca2e3e90bbb517ded6e12f97d8db424fb186771254f2e0fa4c2df31811741268422562e4890ae743d92c18add60d12790a54dd5abeb33f15e99a0fe400d14ca666a209f4e03437e4ae18d9c5933e1e13c169ed29be5efbf3f36f09021b37fc49c899f65069f9330db010e0c52b5073d553bb729b43e5b90b5b1a31b833a2f6cb266a0bcd8d580bcc7b7e21ef3c5d3d2894832b1a72f133478cf14373c4fd920b052f679056ac8006216f1ecde0d5965442c0a388d03a5a9c03ab8e3591456e209bba899bd76209b78619ab568d384e8c158b6ebb1d759111353aad86873529de484d54b491d4c3642bede4a08c35d25be1eff1bc66a9c045c6bed5ba3beeae753618f8d06ce16a4f1fdf3e7cf33c9bb255bb433ee2b87eb95788ad8ef0297cfc2f058825a2f9b6e559469d891d21d2834bf49e1de9950b04b5f681c40c619097a62ffb39077c42a71159072bfb282a106401dc78f5d74133922d832218b3b8f6458017fa0806037d524837ea402f25e8edccf7b86d89bbd4a4c320f6158b0bb62aa5956895116546dcf147f65d399cd6d6bc4d77f672329de42dc78934a10ad46b2963620a863fa07c689d9aa6ed3ef51da6f12ed9c9e5aee732b7b2910b30972bb99e89be4debfbdbdee0dd5dc86636758a7967c3eb469aaebd0dc27efdd1f7b092b6f319d48f50a823c47113b54f6af7ae583e34b71116174d094ff4765e3530c76806edd01d51afb194f9c87a76fdbc953f00b260f8a7270bacc4f839df29fe40621a77bcb66a2c2a862e70ecf81716f5b445f16c8f1b491b9c5f39b2430bb79145353abab882aedc44db4a407a76e847272c5f2b5c59bb8c3f321f037fb8f37cb948c66a0b3648fbf419b68393c5de9047308fe3b247101d0a1b24e4573f68ae0b8245a8eb7a039fab2d0b5aaa7d837a817a5dd5fdc52c2aa7e8f80adece182a91c6dcf39ff961e8208c1b4f8e3ace387bb5cd1c951f8c0c502f16f59c3305afe616b3f8eeb6d2f98b1ba793e6682213bec5362b743e9d5ee3ccedc94b29f808345a3c289098fae14b1d96de5c63c53c7fe89b9de6b4a644ce47c46acccf528569bcb6152cb7714113c4fc75c54b1e69a166fa6977d17f8a52ea2493c6ebfcec227badfd18539baaa08428ac8c325fca44ec1438cf21d5818b08645677c23f4c0464de953579e3e3d8ea33f6f81608c3c254568d16d00c7d8d011438d998b8985c80dc620aad292db831481c785dd4b7d848f87e300d7ddfa7fb48da53ab8d58e6ba963af21ae234fada3aaa0d8a5a38a4aa248675ec7ff2a8b7a34d04f1fa0e5d8ca0c98d21ba181770946e0cfd2362a01d54c86383cc1b8ebd859e5a98cf5246758a506ab0d3015d8126c214f11b1518318b012ec8bbb612f294febc9608ce3142e8effd1bd0c56701bab8e645e8a9c25493880c0c58ca446363793d22da6f182921f30b5e36a3afce46d993588888bfbc2dfad02e35569b8ef9bde5512aa56be4c675453eb7d7fcdd48296a644f3f61924a6a57d3f244ecbc897cfb69990d789ef33b5fd2bc37c3e845e4ab71cac50cc31fe4b3220b3839a97224229f32b895debf8960f9fc477a7c950efb3b1437749aaa97164298aaa799af122c6b752f28ec9b3a0ba6906004964440e1c0b0cfb7d66c14fb89f31efa6c7f55104258c350e9629b8482ae1deb504954981b40eb9eab434b0e0ae5a1a44f01156416dd4beb1a389698d71d0a731f300ec3082dccc54f0f8791883c6e04d8e9a477ebc0b8d1c51f53a4ad3ec938e5fae63e6c0584607230595558a33570136ef90adc34f228c496881606707277f12db311c91b92a1720b36245d1460409b2df05db1b4602a093c6ba053c2ea9ccb5a33845a401aba992f80c393ff32e2270883a0d2dd64cba1ee8d286c9cec5aa05682c442458b06fb913995e890db29b62a9d7f0b170b7acdda45e3faa230dd7e4fd24c4c479a17e485727b2ffff229a3357abcdea6afa7ccd5e5d66f5d53677614deebbee916a7e38516af2b159bd835aaeeb5c08992fbf7abafc880731483d990d943e170e07fbff961534f7745c16bd6b0f08d65d65740b161418a4dd3c79cc0606fd262fd3f4dcc33de0d3953654a122a0bee905f6cc4e23b1558feb9c99acfeda70f946b246d373f5e1d08bdf2dbad6c353512517d10c10dbb5d410282a1e928e6e822dd56a5d2e9e7f02cd43d278b70f3e675dff410127cb32be9017f7ffb7c6e21430c6426566cb199622a487f2e24c394e7fa58d0b0c7ef5f73a7ece2dd491fb854d2f1351a9f6f4677c85b2903dd4dc8993b271f15e1ca982e20b38d551009138908be8fa00522ee6e9202e9d3a7601cd4961267fea6f749f62787e34307cde1ee744fac2b890aaffcdac0953e80880d13be1279ca6e1d0c28793408963ac963545bed33f84f727b8bd4829d2ecbaeeb970fd7970068d4269e5291d94687ab83812ec41f760d4c4c19d9c81dfc812f41aa682d129cb040e18e8a8cda79efb88c0901b59149068a16e77eb01bcf2c069c7196be1fa515648518b01e3c4490b8b45363dd240a404beb8508dcc73c0c4838925029eaa89cba9b258a49ff5418f7bab02c0089ebf358f7f6abad7ec46ddd2269a4ef6b6247a99ce315032a7114801ba4cb8b3d6bf0487592d11e3892bedbf5942e9c24af945cf72a5483f64eeabe7b0c26ec105e8dd2aea8af0b641da21453382b259d6ac62650d8359b2040df593a603e20e149c1941f0214710e42a49ea81e1664f035444b7a735e8a30de7221bda473c369cfc96ef04542317d86e59ddb24563200e6d44e9f0d13e82a22b4d664c499304c4ffebb37b5eb0069f26f57fa21acb11302d22cd8d1da43d95415f3653e394f4eb0f0e1df7194b9a06aa358c6f50f1f6c50867d80d2db9f59f36249981eb9db2d0b0ec02947eb29132b2def698e04db60c6c925e4c29d25068d304a549cb799026a1c29a18aec4f6e5a0ad1463df28998e21e1073f157c7485577b3fdfb38687fe5dfb04d0487021787682fca00c9ff8a83096595fa0f52b589f3947b0655ba1c3eed3e09bca93a5cd64f9f0da9ce675469c315208e99136e711b41c13a8a27482da02e31a7695f3f823ed37dac0ac2ceff782ab0fdd4174482b1c28ee05049340eb57815176a7bad3a31d1e86d7ea6b541cbec904dfaac9aa5aea667681969a5b6aaecffaeeaa9cb77e5eb750fd9ea00ea84057dd6202ea739c70f443f1848f49d24fa2fa94ca2a491e2de924af0c5f2adf191b453a44be72a7c78f7039f9e92b569512d8a573ae2adea3d74bd118c890a2b5c8bb9b8868eb66e7abeb10ff105adfb95e35ddffbdab2d0c88b99fe4152602ad4259ed66debea818a0e3e3188c9554a067832144384ece17a0a14e038650f0a7885e319ab0e060d41ccee0e62f4223b2a2ff54455b29485a8dd9482213673be998e2ee82c58881033e861b9a9500e9441f175570bfb85d9d07ee866f9c450dd9ec46cf8668affa71e1f8e19e96d9131576549e38b44c1fd7b10ae0d04f0fd0bf5588839e4c34329ec7cbcc7ca07ccd8d894c072309028f664d0dfb68d150d21bfdfacbb8205a5abb541f1d3da3fb7f7d5e7fe9220ea62bbcd9b0a28b5fa09298c409607a8fc1081f850e0d174ddb0bd87340f5ebd3efc6202141b7c5809ae608eab76b5703b4739c7593d0a69f4134f261c9cce90c2e3232c30a28c785098544ddb28b0a8228f2afa51ceb345081300c78f17ccdbeb6980656502dac60c3630ab992438b7f17a33a93fa542e3e4570f1350ccc4e811ba5351e2264452010a08730095d65cc1be5017f8b4b93ca69fcb39394e538cb53eb522169aa9f6399365725c17085139d838e42dca564a9fd062991c870be1f11526d70d022c42aef12703844663025237d8ad777a7fdb7d00bd732e57bbf24bcbe9eb2694d76b9ec0a3f7d8215709bffad4f740b392049e9ffe8e7ea06f9be8ae2d4927c97013d326f18751520b9fee91366c4f3890f072c3e58834cec1936a9f2b3745d0ccfb9f28380ff3ebb84611c31ea389d69241c4302d985a93cd57f74bd8d668d39661f49cbb04377a6d4a464ecfb0450a4815c04e460905fdecdaf09aa9d1f5b0c56ec4f2f850d9735e4387bc8666665c89ee3fec5795cd549ca97abb7efd1f0a7fb9b490907fe23de8dc0b7764625bd552251c684a6572101abb1f6d29b1a986e148e12ef4b2f0931a7080b75280dbc5ad25809aa40a022d0e4c869cbeee819b05043c197caaa798d88db0b8f72469ac1c112807976ec4f20aaceaf496d34ced01ec0594bae1680c0f252855ee863e472331f43a9eb8d3b9a35ac66c105ebb638f73bcc54a5968aaa54d3c45b06eaa8bd9193bc09d544364cf1dc5e9c21a845f0dd51cd12bb7ac04f435a42e1426846178f7c9922c4b59014c9caea3f771f11bc60742f6741610e0ee5693ea598a31a2a5ade05e5ed871f21783f8c4968030df392a71c79376891bdd838e22894fb5ff27f166aafb160095570fc908354f6542c7e1ee19b7ce98c55290123ed37376bdcd71d1424c0df99f8486e39688a366a2dc668ea92deb2b51596cc8a4916dbf533e4baf9accdc5e246dfbbac71eab539dcad1f26ab4f813053163657ab30430deeae9c4708f274bd3495496c23f1be994a72f7a9ed2d1b53c067c4b56c83d660a14e000926a7484d374610717b90c4ae4ea9c89e831a60934fae78825b04b4e914942a65fdc9eea2b684675a381d17ad4e048be6c403cfc4faa89bc370e7aa2f8e502e4ae8b9d242463804f8285f2d4ab91f7d2986f6f1e2e9195c6e411541aca0d465d9c13b41d9333ffed3d0b7a777cd95472f2b485f302594fc652b3bee1d2919e60b73f0f5d72f3071686dd7be83e32a6c4b9644599becf849cb66af39380aad2051c241e1502a0ef6c0ffb5b6a9ce9f9fd17642e10020a09ac2b98b43ec1484a57af9382b17e6f79542c0de50f1098b7bde9b22787c9f2d2d50718ac2243c2288941339177943b7390b0b55ad4ed1ecdd2a3a08eede1ebcdf067eaf087df875c26f4998e4f31d074de23fea333b9335e4a3d85960060235136a9a0dbf4974e5dc3d38861268b681ac24240d26678bc6165218953de8959e01c81b2977e006a1adaffa48c30e5b18daf7b4dcafbd5251e0cd97074c8a0f5f48fbf52d87bd2462ecbcc8e40904369f390cdf9e974c3e8f5fe1b2dfab79e0564fde624e1fd4a63d2a08b644e34b430d02d42c236445f8de5b03fad21202b6f16c2ae173b992a62d5e0677d796ef47f0143cbe4607d58392d14bd626be016d2f3dd4c4448ff195666592e50e0b58e5a0cab4dee136c4bceb762d115fe49bdb2b64993f68c88b6178e981aee33c772a02e2bd3ac95504f5c5f271aad1dfe92db29347d1dbdae6e47a101e13603b5f1133c5f3037863f0220abce9d622eb3b08fc4c28865183525244e1e9a18dfa9bd383a31555b1b63cb7f46539e69318f80cfb1ea06355c168302a909d57d46c17574c139a6af6200ee417674454140209136c485309e3d934c03d364ff6428c03ac85371438c70a680fa36c2d5559204600f56623e5a81e30a4fcd3b942608d500b280e752fea8892914ef8005ce0fa0b21381430b4983e0fff51f75b0c652cd7b0131264aef24c6ce4851ced9cf3e0e965be4d20709d38805aa4ef030a4f2c0b8c96d19c21c89c103b0d147c0f94166fe76dfb1e4631fd89e724e774f8810c128caff43ed25e8c424d441544f293f084ae169531010a6fc1568485017538a5038ad12d5c3b4754cec5a23bbf4979b345dcd8362d2fdaa635dadf29b8d2b96e74413d12fc512402b2c1be40542932a31d4588e15e41249dd208613bc53228adff37874b38034f75dab2e0d6b5020d93ae81c21fea460712cb2c105318818790998a18ec6cc493b58d7ec0a7748eedda8d3a1520912cadd265debcca808062c08ecfaa83025e03ca45f55e05318bdcdb0cbd9f1eb706eb908429458b52613af64d04e2a5f1188e0995fffb429b852fb13510927de586159112b8292aab0ea90526561a6e6609a983b1f7c50b39edba2303173e47c81eea3da9465b44cef7b9bacd802ce0830e48713b446091d1464d39c903fb6dbe11d3fae878f4fe663188b1573af76924deb1f73e719778965c2edd2647e644996a1d022045fe9c50d2f3ead3a765abe33bda171e2cf3c1d35056e7cc80d9e55fad7ef06042dbefefbd884c9cff71f97676e84394b258bf69da3c5ceddb8949c2bbff6b7e86c45eefd08d032165ad99ac4a25e915dd5aa39b207504af486dffd4b48150f22e54b5c186d5514b961d3accbfc61e086debb86772debc9688950501cb23f2112e0e03381cf135ee0446ec8891d19783be859134945e68adf2cd5207b3997f3df84c9c9d4f8a8ef51da5cd38e824292e038249668fb29189e7808689de3945e42bd5c7c5dca22cb07ae809e252561805027717a3ac9123b317b4ba45ac26a94fd596827ebf75f4ce6258fbdee31821b6d25e26af0faa519acc3beb2a5edecda0a681b0b02a8766158e5068a01bd5faeba7f072dde092fce4e81601ee9308037c156bf277ac321be4e73be94e4fc4c74238080c9c42d3aeefae1f86ae54fe67149b22036f99055af3dae8859768d2dcde877649a2c047adbbb61c58bfb7b2f87431731761238bd4ead436eac5610e2c8324ff8965273a9f802216750b2306832e2960f61952a6b849f1e06dc2c3a658f3a7dcb95ab53de091edfc1e6feb4243e316ff155367814e1424faf98cd98be3761b0e021de9ce1f2f8251fc51f2b40072e99c62040ff676497d033eb1c7d71267ccec06b25726cb6e92c03d11323047fda607c026bd96f9adf63a1479c733387c2c22c1fbb8f88b3e426c40172f59a885410215df81a4b5b68075cd8b017b47eb13ec48df6c1cdbdd824f902bce2b3914dec510ec330dcc2c0bc0089ed38b4eb3c11c8a9eae48b4f8f52702445846316811f0b562f4c11e73b6996aeb15a8247b57a1b864a68657208a899a91ae032731d49090b51c0efb0cb3f99b55d29324f5ae8bbb5d84c1f498b0288e193dc6f668667d2cbf920ab3f95e20a238a5a842291254d2622d212be727e918e803c4f5f4a6cc49254bbf1553e62f92af3e60efdbc493dff3d0cda6caba02d240c8a89536981a0e989bdc9265d193d570d8bfbc87bb5b401c884de74c31f5b2a4b266cdae870ed594b53ca0dc0106e826cb6469d5e5ac0fe933384b5b595d676dd6eb54cb1f38f4662c0d33c50478d005e3d91f4f0131a412678549e380c68bf6a9592949b1562495f0223671e18193ec6cbff5a8979adc4262be7720cfe475febf126825f39367cbee7f65974728bae62e2f9acbae77afcb86b2c875e6b21f094bc0f2da7e47992298bf144273b56108e02d8f28977019863096c80882c7a980c8b076544dd09fd4043b62884eb11b0e19efcaa7c7483668b22d02b6a8b182506b291b1c2aafed15c3940e853e5b909b108917d6b8475d28fecbd151464bcbe785ecfec77d9e12ae1890e872f8491bf51932d72c5be17f982d9a2a8cbaa2c3c8841d9b4b41215566b600ac990508214552e36becc4a6895bb6c4421cbd302e111b90caed1c92297d91f2d095daa58ade43ca2a66fd3d52547db04ddc803d0e40d559f5d015194013195c77e92f66f22f85486880c6e4585c91e9cc91544ac13affc98818d6d20ca028f9bc4d5adcdb32f3381538a1af761f9bd63c2fbba2356463d94fa8f5f1ccc9d869171730e1687b73de431a7505d6322e2fed8ae0ef85784bcbea758af4fbe03cef7f1a8b5ea533621769c1a9212b26ca98d9aeb03d53ec2dd0c441f520c970a82aacaf9831e5e574dc69306a4e4d648d901431ee10094559e78532b525b2daa933bca722c3137a72253ee65fd6fd6319f496ebb9bcf5dc28b20dac0541499b6a696843774c97ad645b70cb9c8d79fc48b307037ee1a7a828abdc015866fcbf9a15085604274d19c37ef520e71690f37216a43938e5627ba411f045dd03fcb84acf32ca13da7d9b2193d97a708a740cbbb1bc4de057b9692e12ba1d15d8d0be939886c1ccf883438bace25405016c110e0623928c3c5b3dcaf5a26285ae4002c46f3690623beb907bd141628c727de0d5ad41fa4fe8aee14f6d8b5cd853fcef70c56aa63082b203c7e9fa9080f9f3edcd93f20b8c07a187e309c92c9c37c36312d2349d9a583e0eeaf5e0ed9874f0ccccd28358679864eb3678d8a4d61b5048a8acadcc2d35d93035811c65d5fdea074880b0488c0080a086c01100c8da5fcb4adbd95dcb418586b65200c05e961482e8c4c0f93f9f391961b5461d1b8ea01686703ce7416a2bf69bf02c23930fb2019de6230961990d0841605f407f26942d162f97121a50fccf011ce6fb93efafa36621194c2403d2352145e4216eb7cf5f3f98c89886eebafdcf8602618dca449de0a8c5ad497b9674bcd4c4e34f3462e6fe9f5247c6d44324cf017be0a8ea92be5552a7a2b01c344ee7776c499f0caa51f68e7221d17a9908bd97f3e4a2bb4d850ee9150c62aae16cf4707241a3aec68adb22a8d832214f97224f9ceca049c205563580a365a37091c2be1cb4fa4768092c93d0287ba3c90e5baf9720d9401090f8c2c1443020004e458d1791afaec7af363f95404eb6ae0010d05db9df1f9271003fe8445fa24bba620d1b1f4c3422543c11caf3cb10af0f1f023d5b34dc72683ad071082531cc9231679d02707f95cd774da93b7545c2c1ee87ed305566de83b68d385a03adceee9541e5281f7bf6b4f5d3fd50226d84fcc0f056aa4a1a2878d70b0dfa2a16c5347fd189c1001ffe6410b8e826399aad4e9bd25fbcf9c9d7d1e9b38f012b2a1190dd4509ad6db31b99ea331931a783a1ee197ad49bbc012433d345e60e0ecc76f4b443911a4e799e2cd0e2bd89a987e50f00592dff16c46502971a468182f1631e54807c276ec16ab5d58d22fc82d79be4826ff6a2ace4603155dcb8077a7110d43002942a119f0ff8d08f8a078a213c1f2701600c05fb801d29184ca1f23deb384e41008b80668c52922a589fc7c262326d7142917e9db3b09c6dcb0d029a50829c0a45bf804c06a96a618273105108bb9170b55250c1ce48274f45cd0628d4032198313053386349f944b694350a08cc432288e3760334923e2ceffb0369d669d192be72f12d102039a1f97dd3f686f9db47f91d966e271ea2ab7e2ba8586770c33c42df01d14d4eb54ba8d235b24f5b6fa90c475bb9e57a3562c7dd5f0efbb81db9d1089ffb371f20264148ee9a65a01b0891646f5148eed7b9f7decf3c681832f73fa97553b4f305bd8d61586117c81e419ffd6db948d54186de94da5841553d22c95af4edfe331ae74c17620c8cb4a5cc4a2103b37eeb59891e450b3ea7347bdfb9fb40b5f204a21bdc9ea05f14f07a4f92f075829c21ec358e9e0259014411ff1da174d08fe71d6c2a0c80b69380c1c609130cbb80dee7b006a272da8eb32be9283baf2c7f872e16ad6d4a6e13ad9f7028840036ef73f88c7b0e744f1d517b389327e8142a1a94049272ea9d4393a258cb1a80c81a9ca53b092f01ecf2abb76874e740be10e53b51a99467b8853d338281f2d84001e42b525891d6bc9e1576084a8625dec1427c5a03a39f5fe9979f8d2b848b3afc10512d6180ee3021f621a2c02d1d21fa97206b0f822f6b154b4f5870074f337b26d2018475c97b48ee3ff03bd74b55df842597ca46659cd30b66a28bdd97ea85f429f1208e11264bc042de943ae942e7d5d679d96cf820e18bc07f46b98f196ce95d47d4c3eaf95597e03977832bcf40496f91d6ca9380418c481b38446619317d2dea33cd5cc619d1d618d609b4af1d327b71f5700b39a56aca30289132926c9aa75d577643a328de00f4048e99b12baa105388c7f5314396739de4262d0caf83cba539ce478bae3aaa9031eda0253a45530be833c9a831e81769a525e6d8c1c4c9c5f0500b34beba06a3e9ead827a1b43a6ac4a191890be10939db9805323176999c718f981f483a99b0589e0c68ecfa47bd4b1c4286a97750d3499057c6ae12a178ecc3f210e3159879560f406c8b446071aaefa8a335f38a6566422641d1d517f9f447c0d9153b989955ad637c04f278d7df021517ba8ecb4f319091f8c071b6e008776cf7eb3a24153582aa87f9327fb5b732f94f703d038173489e63ecd58a6100eb38267d04e956e07eb0b442265c9c4bd06da1a921fb3bd965608a3bc8afad7cc4669c35ccd58088ba4cbbd67fdf42a0146a87cf33163e9f7a4face319c8f4419e00ce32217d6f48cf70241c1cd6f29b4a00adfc6fbfcc4c2ed397c069c7e672dce4b16af3d0eec5d568b40bce580798d3e42468d609fabbbca8e49206c767414a769b6ca4e9abc1691226657bb16e61ed459692690be33604d9c056bf719160de987516ea2f59918f9f7123612fa5553c142ebd8cd1e70d4a611f1c5d0b8733b48964dd7c165f0e5d0e53bdc923f0bffc2cd504c82944462b3cc773c538e15442224323f85867079f06a189d3384a95b8aab40a282e836ab9ab45f49836b5202c206b827df84bc693cc4361a595ff1aa915750c0803e2a194de95a05b49b07764d0100dde2a18de4984984a43adcb8008c125a938f0ff023288ad4ce78cb6959d30803440c3c4dee0b366c07d8c5c3934593619183432004e13c5356523a023dc435948fc7be01abbf8e7ee22ddbe93c98193a3328f0b5e3c64e098538eb7c4d5144ec6dc80e30209889be22d9c9f4b1c051a369031e9ec4e94ff15871e98a939d022685a5e845a82b3aa7d5f40584f2dadc3cd3a0a0bef5a6050523b4c9b3e3fccdce7f621b706395758d9b8c36e2e45b262d8be6019d926f468b31b69a7e49c1bd163c3c300430c700389451506d928e7a487c2e2e344490edace265732cc588040258eb6203ce8730af62ed4b62e59aba3db90b9e806dec039a9a0ddb01bf0a7c64eaad3c56e887b31b0ee251f65c65fd549f8134c926f473c88d6e2c6b6c7d5d7659f61d620b622792fb654bbeb2148a323cab841f83bfa5f9e09ace3f963e25dd8c41712f2af8bbe0051c5b99ef3538da4a8795dd986484cf9baecc6f24a32f323cd52b8ffb619232d54eab57381a64e70430fa3c75e591c03927e3cc90bc8b0bc85a868103542524d21f22956811f3648abc90ef0df8cca200b61b63bc992a3982c3eb311935f894ac44445839c61381abb330e716aa16bd1ef04503bbf4d811c7c10d48d6310c5d3c0be0013045ecf1eed2a8de4b87bcb8232964b2088e9eb66abc0e56534b56699ab3119b7a26693cbd665da51f347e15224e24e95fce2a8d7d5fe05489d80ba391ead7ccb2719f02e75c7656674ecd415175809d5a10f5005734185d4792bc94bd4036fb52d110e891852210e27c8f01f4e06f7e76361c69a3f319563a73fc61f4290c357265be61bdbd98b3906f34251cbf2e05a952c51e3ccfdd7cb8850b1de4db8e53abb064e26a7d797c31a584cc9537d74c6bc49e25e49a458cb2996b655eb3fa0bef3608f87033911e22ce42bfca943c4267d3480589a8ad0217e62de8b5b1bf64b19a33402ae2d12aa468c794ccc52d4194d8626f7047ce570b005c61c5c1f2c4e37680c42f333a54cb19d0b3481cd0163a9bfa4c430700f4b3058e84863ff9c8b75957aa5a1606bd5b1cadbe0f2f0c3668de29ef6f2aa70cc92b76e866e194ae406da39429cbac3ab40db0c4963928224a4cb8c6c9fcc93b9cb3ee0e59084bb584b7bc308465067004d1dd8149dfe014b2693a150818f6981773965f892077b0e0e7c58f503988f61cb6121937bad281bf66f8f58550540e859018cbab618fea582296c95804e16ad50f74bfaae1e4ad8fca8938c8d5859d27ca91f822cd53503b016cb90b02ce1fd70072581e962df1f1bad4f80cfa764474a9c5748605d31e86f202993b6746ea65104a5007f67c7e372da5855444d294e9601c4c517f42ea4cb291e8a61747d6e4a9e2aa967e2367e028a5e65577da16a1f02f3906d83dbfd54d5ea671ef533ef4a8cb41edc23b9bcf1655b9a41478676963d57d00a67611d1ac0ac5529182472cdf05a7b5ad4112c4b6119eb460706518bd435749de548d102a1fb8741fb53fb24502a89e3da68c59ddc500f713c096469fbae8f6b3ec6c788f4f739d91b650551b97d0bf54284c239f1005c47ec1e4ae4fe05e789cf2bddd19d14e0209246e511e7f6f014c2046510a24463111fe5573d43ac442e6d8ed982a64374b0b3b1e80aa30dc490a2dd1ba92ba060c3c53a2dfbf7c51d5ce703708ba5d123802efdc0ce23e6ebe8b19c64d3ce1c803ace6b0e2cb64a0fefdbe1340e17544be5722037b8b2ae5fc1014d936c503da9bbc09849b37c8c5e37eb78842fcd501c5288d2013fd0e8bf01e83702cf17e4262c1c17777b43db652a65690bc2a985f852fdc158d36223cfe9f794b6cceb0642e01c029e023ef5e8ebc6c5ba1ae151c16e1d0a04dd2bb6690ddde98bb01ad63019fba98e9a82f913d0c97187e3752fed03bf520c35ef446fd9f76cc7111385d0710997ab51c252e151251c67581abe90644a27d2a9384b2f417bc38a42d793803896b01044055cfecf1328863cb4fcae8dc7eb3e1126de147eebb88922b4d87797332c91c1772f801b8900e849c4c35a8bed174723b771e0529d346aabe4224233e15cff5389ef36e5232025e0405be73e416342e1df0c07552c39a460bf0da8c3c655f4b6bd0cdef091059b3b12cd4534d9e7c6bdc2b153eec49473126d50377f3c159e5e57a048b59fa8a16a53fa19100f600ae451e2542ef830500628d20abba5d04ad0a8ed54028c8c0954daf76a4eb5cf877991caf0267459ff1dae6f4487ec670a9e2f06fa740820b223dc30c4249a32e5d7258ab26f5b64dcaed8112476b6672c71b2e526e05cfb93acc445120d8ffdf82f673dd182549f323f55383d2b34ef22eabad1e5e44450ebb4b79ca7345656b2c638e66171eb6035e529370ca8331138a7df21c40e17451d2638914d31af87a33c3d173bbb319eb589ca5a161833d51b61501d28eabc7508ec1180389180ae70d0cc471d21a3e3003b765428676a9428181d602187cc45d06aa58134bcd1e6674bd216c178246217849d0b5b1c1fcb881f7caf656481c9c60769d1833d8807ebc00efe779f0ede98e0c7e22022dc60586e83122c9bd8e266f0449f85162b2bda5de322061723e3da857966a5025a7a2c17dc707dc5862a8f6b1d1f99e22e484c993b288c9c38552e3c740aa502677115fb4c59c1af56b4d531bd33687f88192f5610626b23342a285cc868e77a4e09497a741ff060c88b0332446cc81d0547fd682cec464144b732f4d173b3a0203b5402e7d850d00e15ded989de9b389fdc2868d796d80d9f186e88a922a6b56830112086c3027b4b8215f72101ea1a7b8b169a3382b882d5d0343f58908c10ce3ecb1c5925895ff04cfe2a68f2ebc9e3887c6e7ff918092ee7f882a63599bab73e8dff3b309f40c64f2f2ed5ce4e9cba9f9e06a6ebdc0d7acdc214b708d1b6e64b60da4c619735cc0b052e6604e50d521078669c0e2858b89a86fed4d868e3d4d63ee9f98dd1cb506651360adcfa836bd8703996cf1ce22688d7c3de341ee9e867f317ea846760b00287b6b1320f98d80af7569c52e07f0b697befbda59452ca2465ba0dab0e990d5acc0ae82292023aec9eecfa45e8d0ebd9f52720014d1dc40fd045a80374881b509f081d6206b476fd21748817a0c339d3d12156800eb3103a2c01edfa41e8d093edfa4174580adaf513a0c34984005d04880ea313b2d8f50fa0c30e68d70742870690f1d9f5737411fa832ef24317913e7411c7d1618a0bbb7e0174f89b003aa42c1da6acb0eb6f1dfe8d0ea314a15d7f003acc3d6ec4767d01e8b0c58795cfaedf830e6b78767d1b1dd200e8b0e3a1431d41bbfe4a17a12a1d4629b15d9f071dce5061d7dfa18bd01de270edfa3a7438673be890eaa08bd01a1de29dd261b701a0c34944d303b6ebe79889edfa333a8c5914edfa38743867281de20dea10e7a08bc87d43879a8c0ea315367418d780830e65159f0ee517b40ebd06af43e7a2860ee7143474a8c5e8305a01a3c3b8862abee03530e9d0b990a1c339450c1d62175d84b6a464bb3e8b0e3ba25d7f4587dd6cd7fc85780f75b3b98a49dceb992bccaadfc53ad75c4516153ea42fec645dd06b87b5756123ed05956a0c2ce88b224df785d7daf53d1d59f2754514443d60ad94ec8ad8153caf9c2a3d1f2f9b088d2dbf1c97834142400a238c30de80753885b6fc463065044e5ef66d51c6a158d89f4dc85256e93e2232b7e4008dcd048d2d5f6e2edef86675ed41be366ece8631b05ddf139aa82ab7f582d490f144017939584ff6e356821aa84427bc94a08627405e392e39137395cf8d238d7c4e469f33311224e9f922ce95f480a0d65acebaa7433f4f882f74e207cbbe446aec0b82a1d009d81e7263db0eed4b04b75a23d84cc8973b7a4098b6fc62a4b936c7e560fd35f8ecbac3daf284bc9827f382bc28114a11d1ae5f796acbcba265875e9047655720247df9d11ba27bfa1da1df7d71be8c1d5d663156d099155fb43c8f35e95a567c0185cec4a21497cbec095a50299aa8fab48341e185bdb4a8c7c7f5d2e2478b2da2a08489957a26e632b33ac71503eb017be1c458ad946c0c39422962b2e78e50d4e0c48b85de948bb3846ae17deedebfad7d5f7a3fe4beeefd90dba79cb11b8520d831d2dc2f949ba62951a4a96f751c42fe1471b2a31b11143d557a40e6e6a6a67fb5cef49956f64c54fd29856cabf5eae36a63600ed6a7308f0a276360d53f06e605b9aaeefa5e145745285fb8767d8fc803c3575a7d2f0b57c52b9e10da2d2f68d71d7a42b35dbf28c20ebda15d83be58c20ebd2f76fdd08bedfad7cada7af9fcfcb82a94aeca53bff654296a925d6176585bbbceaf2f5d7345a3147c90d09d0c20f19d5b1d0a4b98c28d39e0befd8ce489e5d59155756449d055f41d48acb2e977c4acb2e989d2bafd7324d9fe4408f11585ed70e7dc613d34d8618ccda090b2c34885ca19c2ec27008171957ca2698349690fae40597e88afa6784bcf7e8cfed4c7a77cc2c59adcc2451b218c8beb7a40bf7ef7de1ee490ba5c55d232647ce9c1b9a21e475f73d5f29a28c72d41a621386f21d70fb153cd5234512d2d9fb9e5b59df4b59cea9f7e8735439fead3df2191f42988194f5f67c6d3cf4893fa46e8cff8fae9bcfce93372fa976f694d94b3b84fa9a54bb22a2cc76e920ceb96174d9aa1e96bae3c9bf0b7f090c06891e2cb3c1e4e109e28a268e99928947b3f5a9e8820683d215a486b8828cfb5c3b646e993da514beb2322c3d04b5e7e7a9d122abc1f998912079d5414697a9063fcfce8917e64d2d7794248d6c90b72fae815cdd5e9fd7ed5dd93882ca968ae5ede575abeb9827f6a7d13aef5f1f7539f847f8242da73fae2ac5fe95974d8d2437b5a5adb7f763ff91592d6d0f24438897c7cc8f8a812d0bef7593755fab3fd5f66967e53f6ae0a69cfb6a6d2e7fcdccb0debafe0d47a44e975be5f6bfdee179674b833e466661df7dc9949c8f2bb24e4b02568fb3551e175cfe9ee39acab900888767d96d9ae3f5a597919f547f559b00744eefa58cbeda3af5ffac2187fdf7a4058be964ceff2a52f6cf9fb997e3e93cb412ffdfdd273ded7fcb5f44386b1f3e74386b157be527d2e1fc0f45ea90281ff7e27efebaf3cf7579fbccf7f9f74f23e1f2b4ffa7c7fe56692b415d3fdfb25c0f42bdf11a6f7be2364fc4a4bd010da734d1f95f1f6a907c4cc91f1c518dffd952f74f968cbc7c4dca3bfef1e90d1b37ca1dca3910e91ecbab252aa9b074498bfc4d5fc2b5f1a7de111aeeb705d297de6bef03e13b314eedcb8cb55f5f35abf90896972997ef087261315dd7cee39e97dd5dd93484f5fb8925ef1517f4597fe45ae442f67ae68d2cb8f952f1c427b4a1f90eeb94a8ade77f5b9af2bddcaaf7838c46a9f3def3ba23ef7ee01319fe37c944aa5d2d75a6bd5a32f7121f71e1757bed65fd11d1172fd507a3e4a9f4b3aee8ef4db671d22d95c189b0839ec00d10eed93be21b467733ffa7067739dd6f36fb881a1100445dbbee9679a5c2d41515a84bc7e4dc8edb2e7db4a6bad1fe98471b5d4c801176d841bd1a6df6cca2a2ccfa70e4ed95c7985651945f69ff3f2e4f0baec5f170e4263d5efba268ade10647ffa1b91742bb80880ecb1189ba822ff299b923587badfbcf79f559c34b7106d9ac83b0bb18791471b6dc6f09c79ba7b4ddb6dbbb74f2255521dda1776813c3dbd98bb1bda4490b436e99b557c93f4ac1269e48f6616624a7adce3adfb9670f6b5fde66c68ce266acab09ef3dad99cbda28d0f66b1786dbd5c745de68442ce8aedcf11613b57c5760ef6dafec23fd8b53dc9f68f219e62e315b07c8853205482ed18053db47c8847e0f22126418845b0fd6388a1187d78df2063c3f6bf43d1e60bd186beff05835c91deef107ee2c3ab86f0ae61fb4d83196e2bd2788c77195bc6f6185f8af1f9a3f1e14f2e228d7f8b9e5488297f163dbb88297fc5c0bcbbc068df941269fcaf9e58c494bfd5538b48e35ff584424cf993f42c8244f9533d891069bc85a5c6cf18cb8fbe1adf7daa19c11e396148d8fee1cc8e8f8a3ddc2732e51fc31b3bfe275557e845aa6e2ca4b1e3e790aab9e3e7106de8cf1a3ada8c3e8631760c4752009115da1d5f46b4c11f7f46b489f1f157a4eaca48d166fbf8a54daaee2cbe943d222b3ed7e9d875ddfd71504fa048331a7d9c50a78bf8b85ecc279dae3df07e44076750d7dd2f7cdde80e451affd10b711cd775dd90ec216e7f4e684ea068337aff498468f373a97015f70e743f9c52acbb4f2e66f89cbdfc6d29717056614f2ce40f27155abe7046614e61fb8482932f9c4c984fd83ee584b2fd2712a4ff2c82ec417abf3edb6fcfeb0bef13db791041fff0f2dca198abc45557c841bf3107dd7f0b2e4a5a98c81e6e1499f287f9c29985edcf9d643c29c68398c57cb99429ebd92f39b6fc19396cf926f95f1305b579cc6c79a36c7f193a4a1e728d2be437b6d4725f21575d2531575d260efa75729f38e8ef22d422e3baaeebbac70e761fbdfc37de7df7527ba491efc5903f7ad9f2af92131357c9f7272edf45490b131627db9face8920cf9a428758476cb77c983fc1b7b91adec59b86df934623164db475bbe37fabc399b55b44813f32a8c0e24e7fe310e8aac75c3b85714a2d8524a29ef1d420e39d95c71429cd016be0c5fba63d2bdee11fe75b0af631272b297953d84525b6ffb8e8ad1d728727ef9b55b820e94ec1d765cc28b68735b47b3856dff1ab402ebc9ffc2d277ddd7c1bad748774c4a4ffab07bdd0ee6aafcb3f4db87a42ffd11a41f71f90b495ffab820d2efb849de12ef3b26bef27e7ef772957c2a8e9a51e4b8e5d69efbeed5c138edeb5c0e869c1072b8b3e5e30fbb9f3d1f7b40a84cf9cbcfca94e7c45ce5df74fcfe0de9b6f637e69c10ad226b1f72425984dbdfb87d61c7fdcde48486745bfbb81827b469921c764194d6a7d4c3a95d50f7a4d65a6b17c547400e724f1c9c40bae7821c9cb1d3bfcdadbd7b38da4b3defbd5f3d1ff839fcdcbdbf5df781abe2c5e688bed841e080b8ebc27a527170723fd13b20e761be089ed505390f53caaff390936d99aba8b8aa3efd298b3433e6e074f799c24564ee0df89691663e373ba9eb4ee2af3d9f93525e26fb2a719093d37d745d5e8c34f3ab923cbf705d92755daef29fd7b5a7cf7d9de4f9e18ccd9ff3fe449a39631365a90b16e69c13fbd39f37e69a89796357408172a104054181c1a0b85c502e94a1a1a2a20b452e818b00c873c617eeec197f85e60a00ae1d69cf8e4f5bf3638e8f341f6f7cfc393457397cfc493457331f7f16cd158e178f30c7cc064f93138d8f5f335736eae3f0321f5fdebe8c36e05bfb85f7459f3627bb17fd52f58c69daf805e3178c5fb48ccdd5ee45c7b0dd8b7681f9362a8ebadd8b6ed91cee5e340b0c2848a889109175a3547addd0d467a2e4d368a017bdb24d1cb7c9b6d936b4e50c00e9793807399cb3175dda3e3d2fd8088888f493a4694f1c351f464f20078b82729037d791f60dbd056d425b6ca2645c9f89b2459e572a95700e7298f78b1e01406f401315e327007a5aaed7083602ca44b3ae9b41317a0265da12328dba17edb9b6cbcfa7d1f72787be3e23d88cb638b49dafd16b038a3676126d2b1fe780d4bde8ee869eb38992311a4fd48be67e764b8c0dcdb566441cb795ba17adad742f1a6f1896ee45df7dd2305d8bdd55f334417d4490b436eaebc9e4e1c0ccf07e881b071acea5ee1b7af4a3472e9e102c81c3df60199239b86d37b42d721ee6576d8980904d9668ff107ec12f2f2f2f5c8c8e863ebdf6ca7c1b5a466f430ecec7416f55dbd9fcf92357b4b15aa4918ff1d3a081699cf0e954f17ed17473323a19fdfd8b9efba497c4bc0d1a7a49d53cf51f07cdd344d7783b9b2b4b64ed6cb25e3b4beb25f56be8259668ae36d944cd8992bfc9ec4f986d3fdc66fb657fdf6b5de3ab96acd3a9c69ff43f57e3f4a7d3b7a4d61a5f234e3aca0e4a560c67721dae3a6d1f77125f1fe78b221c305cc5e32ad9e3430a1f495c75d2763e2492d0433404bea5bd284a684f280b072b102007eb2be03989659c2320b03b333303a507a603d2091ee4b8c378450f98177707793efd7b83acf3614a36b5902fdcd942ae0e5e0750128fc4ced7d7e1c4554afc91afaf03166d646bc8873a80b0ebeba822f630e4e76a06003b3a89972d6df79124debe124a7c3227f136092592f85abafe105d8489bcb9df8826ca7e0d67649b56424707a96e69baa79e435107fb3bdc9c3968bfb993d07316698e28f145078fe8b891d071cb96f6ad0495cdfd102b6c8e8bcdb5b4dc4774dc3b13094d04496b27f12da116893fa291f8a62cd2702f5bdc7d659de7be90090dc70ef91be7386e880e91c8e8711c677f7ba9ed6f3a078f4cc9ebe1d82f47cb412b7fd39a08644abef6713bb1b9973a47cf96a387e3368d13f2793c0e5e1d2141f4449a7a97d0d0a464f24b51c94196df81e1a0d772b0f2cc4cf15564551c64f91d9183d4c3915f9183d5f70fed0b3df01c1007be89a7dffd104d70e09bb389d2bed39ea698a460a957a4a933b18963666666a6b5c399588e9e6de3b8af7595ccc4b61c229029232f441ff9e8e11cf91b4fc1769e09bc9128f1f5534c5c55a4f54ce02d9ff8faa957b441e2c3140f76fd940e620f48c41c29a05d77b4125d1ab2122f5fb694782e7b38b2f5c9acc45bef87b8956829a16935c6228d6e25f4f4228248741378ef7c732882da4fcd3389a20eda8700498b35f78e9e43f209dd04deb2f5cd2a11d4b46fd9d21e094d7bb977f412fa48f4921ecca2af849e4313a5fdd4da9c459a7d6f90b51f22e4877c1249fcf47092784ec8d484fccd1c2264c890bf9949e80ffc100d82770f0704da1fd19e11dd81e1607d10e8ee8b0fe8ce0340983861f138cbc709edd233510be880f68426ca0639acadd1ac888fb308297a7c7a66a552a9444490188ad4754373351bf0d1570d782efe682f89478597c4c12e46bb15fb2b1e8efc150fc77ed6e6bc645a7335838563441129599c713656d9f63b4272dc07e4e5a0e4e2131cf09cce5d175472d9d6a545cada62e964261659a6e5aabb2716357891aefcca714d9fab6fb55a2160c508e29e4ccd52321a482f36512e9dcc55db7352fe35810e180e1c38b60ff1c6f1717b1c614ab66ddb364345fbed794c79e34cf9c1053c3832fb29b9041338b2fa7706b2999829461507abb5560f99457b2845450c1947e62038c130877ac0a20d8ecca3bbbc0ecfc90ec86bae666272e6ca20e7bc64741fe5b80e301469800871e22aedeb6f2fb5f69c16f29c0c0f4788906e7e373f24b487d592da6e2154d895cfea355727fbf4774e3a4670b8bece752376b2df2988eee7eb743fdffefc8c34b19fceec8cccefbe1d96fdc20e261f098d33e5c2c087df18f074df44c7813f32bf6be23b429f03cfb5ec1b0c48c9927824bec6f8e831fec220dbcc6a6abc5310f3bb77c074007d0e7c71a23821385a427e880e77f690770f67c8cb70d3f70561dedc6b425ea2de2053429ed32108b485fccd1ca293f87062483c27bb2490f870a638f8d2019babc8a23a826eee4f9e385c1325392b394e721a76851880382b71b8b4e8623e0786f8e8abee87780e68199fb9eabee8a8003c0b8e6543ded971a8164107fd2db467cb64c870829302929192e10549cd4c999111f1d19b899562135527157288c3d582bcb2eb7333bacb821ccaf8ecd310f3bbefbe232720b0070234512cfa75311c2e1cae9cd573328b12f8ecaaa3b3c56c66364547a7fecc94992a57c866260f47fe984956d003d603a6029b598c0f6d6601901fcefc10f68005e0c31e59ec9c0f6762ac968355b68b1152d1db385b44b07e38b78f8f7185f331aa747cbc6cda661680afafb3c58fafaf13fb6133e3be00bcfd02f0f20bbd2d7d7218af8032a54c2cac7dab7f4ae15ebaa27cf39c749feee170cf7994d25527eb333147d517f221ce0130a9c29958003efa4ac6e6a3dbbcd53c7c70b0f2d8756e2257715fb84ae36962bf7e4d6bc88778f7d0c30379cd15fd666213e5aa215f7450c8a7e955126e097daba95ea5640210c0cb6fe572b05ab9bf0265fbdb735a7bee5b2571b0be0cef87b8656c8f57543858b94f72f676138bac6a4256ddebfdf09ca02925afa893166fdb9f913f13933328366ee06033d431a1e56f40dbe75e45e4ebcbf4b8aac8d79791c2559189b77a03cf69bc392b5cd0ca71612166050b9ed4225a3e116d735647a11180b1a596b139d9ad604b5d637353469f7494e242a8e7075bea199bbb8123437553ca4d018ecc77c5a1c26ae5d0dd14e4b0078cc3d14d2979a6bb29c8407880f40069459a1c25392fd4472fc7b583ed01e42abbc30ecf3914acd65c4d89824c7b3ce9e1c4559e9785cd8ca3e9e6147218e3c1e6eaa4339fcecfdb61d58fdea41286242d560cd044558ed30e6839015be2442c8a71e2206b033b5b7e314f1cf418a5152201d18e58b4a147c78e4224d8c18ef156ebfc449a25f4bc76dd5b70f193f2c255ae75578a9c92c91efc89b992ac964ffde0e04e6a21425e7e26c8550b39ee3025a39fc2998223c389711fcb67a22a941f562bd294205bab573e3260323e2b1f199f950f37f5944d94fd58aded3ff5c5b68d662e10da389c188ecc553854b81edc018ae2fcad43878e8f7305e4d5cd0fc8ab7e8e2f33311b2f5c25e40be5cca68acd90abe48d2937641ec77d11cdc413d11b28a2e326a2e396db8e5e02ecfe15e4df3e28472b64a06407e199edfa3a248934394a1cac39af7a85bc0da5887609b2fd30259b0228c66c8a27f84ce1858b4fbc711df553b2e87573e6a4a5bef87cf8d652b2149524ae7229aa69cd15cf8ce960d7afe9a991c2573c5e8b054bd8f56b92f8aa73a5aab82a2e81053cdb59f5b52de795a3248789ab2216e8dede6af9405e9bece1386bed77437623e6e08dd48e4fe12875534a5e7dc9fb21778e6b033168ae3416b67624c3d81c4b37a5641f9ec5fb21f7ca47935868a5b352728f77f17ec87d6346855c89e68a16cd55d7723917baeba7b2106db4901a9aabf9367407394cc9666211ca1d410e53b2942c0851b4e1b82c7218a1b4ae08720f580f18f7a5645494e41eb09929ae9a6fc803c0f66bb491292abeda58f575d8f6bcc145b4b10318c0003e0ee0593c1c227273cf390fbc6dd549cecf8785220d90971272a0449a95cf5c619c330fecd51ee4b0b654aa0f53b29c1c253956441aea24eb00a2c2bef129596a166d7cf340c487dcf6cbf131f7129a232365fe7e191ff98519870b025f71366d08fc6cb141d9a0dee639979a6e4a49c96662abe884d76a3513cb71a56443680f8eec013166e8ae311db818a34b943ebf99dc39ae78452c0f61f5b82adc9e7bfb439e7b560fab1584bcbd7348dcd8b6429ed572168f77b16b4a166f2cda6c91f531b23ef5d2c9b408f035c4310810e309f0dca9dbb6e7382134568e8b278729598c4fc5b83704d3c341e267627346364325f5136de24c42be50e4702636bf3a13fb5c9ef6a4644f3cf7f5806ddf10dab39178f77090f87a003938447b316f8a83f585684fe660017ac01ef0b587a9ab1e1074fff0a3f3136d248e1dcf1980bb51da15678a83d6e5571f3d1fa46d3f20af1b410e56d50dd2b63eae22c9dc88dd90bd040de0391ddc0e9d4c6b4f2c728c4fd197cdc500e488851798ec88851698e0d8118b2e28d9292e62b459e263183d45354f10ad61a80cb32fec1aaf90edfada128f139bab207c26aa3ec6399b4c3e9e124108c9902143860c19321efb449b24be9a5aa696c9643299fecaa20d125fffbaa2cd90af6f87a28d90af4033806600cd009a01340368861040335e5e5e5e5e5e3ec69510441355ffe52d2cda685fbf16459bedebebf43abd4eafd3ebf43a29e075828181818181f918570a80f91a146db89f989f989f989f989f989f989f89aa1f9302c17f9329d3a0f131ae7468d496b6cfe90bfca631f09acec00bd146fc10ad814742879f843ee2a7a64a68b983109a2b1cae88aa8f71ce26d3ff0465645a322d99964c4ba6b5f20102020202ba618371ce26d37f0f560a04ff4da69c31ced964fad789cd154e6ca2eaa740f0df64ca19e39c4da67f299fbb80b6505acebae28a2baeb8e28a25b47d2574dc41f8e490834f0e3e39f8e4e093834f0e3ebb7e10423570363d58430ba15d3f09bdc350ebbff5ad6f7deb5bdfdaf591d03bc080b406d2401a480369200db4eb0f118208e39c4da6ff0982310a44bbbe106d53c04b01331b29f04d19872d5e29f04dd9c616b35d9f933a3f3a537ea64c993265ca143f02870bb364fe655ee6655ee665fec3d40ef50eb048537f863297b5f2d17ae5a3573e7ae5a3573e7ae5a33f4c6d0d681d8a224d7daa016d573e967523f63dc6399b4cff1304bf0f5346681d82aa1119d03af4dc885596cd0c87af8f83cd0c079b190e36331c6c6638d8cc70b099ed0c68fb18d035311ddacc28ab07cc462a0582ff363e34d9e801b3f121de1b08fe9b4c39631c53a90982ff2653ce18a76691a63e06b47da92fa06b7e224d7daa278bd592b9f129f04d59e6a1b4622a0582ff2653ce373ec41c1e71df92f9f18a9864811fa3b6a6aead89aab06c3f20af4813460ea31497135e1078d4e7b8e68ae21d2e99bf847ef38bc087333b76ecf070ec8e192cb7fc0e4fbe4ccb5524999637daf565787c95a232e3ac23f95452b2eac2c51883e880c9b410f021de0c40c03340c71307750439587500459afad20ba2033651a9998335c6479c98836fc8e14c8ce36126b6ad1b3290cfc2c1dac52153b653b31b4f51012387d1092f20af0314b5214f202f575926aee260ae9240aeb24f8004011172d5497e049285ab84c4a6b88a8aab84cc805401e285ab4ef64b79b153440ed6d4506a96aa92a2e2a5646cc8f2e50ea31457989245e0c328c595800f6762517674322d57bdfca85b7e299910723813c389e14cc1304e08da75d7ccd55c0179f90e10f8033c107f800ff106e2a31fe0c3bc8178aa3da1928b87aeb6e64a63d59769a9569d4c8b0b4027d39a2bcbaa2fd3833d213456cb539d92e9d46ca2eaeb70451b9b9261a148533fb626aa42e043191fcf8a4853bfd39ed00d1b39e000a270cc7c3974ece04155e99d2e65a2b671dd4a096614db2fdbabc0c7c0a2cd85c20e5d663e60b6fde2042ca0c309bce772d5cb56b29c47c5725c1a887637f386be90119486d8aeefc526776d0ccc554e5c15af00e4aa952741ae227dfd982831423159b82a065d749cde9ac0bb7e9ced269d22aee41a22eafed58a484c1cbc3f7afcbaf75d68aeb6bfb2c8816e4bd6b3ef57bd6dae76d4f3e13ebe7da2cd56cd90e3de1cd07d91e5809a89baef7da7cafd10dd733f04f7dd779f034dd4fdc8da6ed1fd7b6592c8c1fbf893430ede7b9fab9f2c8a34f76b1745fbced58975eb770a62fbee87e0defb8ecce7bee3be23f4b72fb2eebdb7de7aebc559449a7befcffbf44e91edc77da7464477e6e4a470d146a811ed68a36dd6a9936c45b4ef40aeea4c5cb816765b93dde14f441afba6b9722824cabe75156cbbedd05bf6b9303c116d4a6fdfa1903dacbc7de7f155cb8ae54397427a3f7ccf2f228df596f3687a6e1f2dfa445cf90bb4d6c6980a9783f6f1e73f0eda3a861cfa8febfd67db7fe32e3457dedbf7a0b9e2debe6721aa1ce6a07db7160811b4cf75fa8439cdf21999dfbd7c4f53568b8e13c5a2e34495f48a6e226ffc69fa9d9e5e168a6d20eb93bb92f68d714e41d0f77e08fade37c4fc2226ca0a4159dee70e3451f6b3f61b3a90076dfb246ddf815065dbb79e850876218f3eef71d07ead5cc8fed2fa4f1779deccd509bff73b2c8bbf5310dc77aff3dd67a409fe74baf7be9b89b26f843ef7edb0b0b5ef40f60b25900483478d83d6e20e6f4eeb3697716e7594824cdf37d67757fb1da11179b55d0eb8489271474a290325408182a11428d961e493567bb1b6719d371a916e30cb51ce290e4a998c85218732b6e5cb9732192485ae90a3fc662ac8b112ec884519d8e002d28854317e2d0abe31c6dc799cb779f7b5e7347c31ceb163cffaae7df8a35670c9888080ec914984cc39270f1f62949c354d23edf06cf80a868818e5663e1151769e9046179b4cb24d6fb66fc6282e3c86d80b78ae6b97662ae5d31dfef1f876cc2e7258b3fd79b84a7e8d8377878337aab4e7a4d63574cbedafc99473fcc2fbda57e3e0056fcdbecfc35579ab20dedfe1ab17d61d020c22ea659fe2aefa44a1dcbf7f9f42c14ff3bc34d3fb1d11832a12b69f8fe34afb99b91b827bde38bbc8f1278ca925c7586bac92457dee00042d0f6bfd79f86004130500e394a0288bb3e8857555887380391c8c3466fc5cad1e10a46dc3c1e92d4102e6e8eddf92d197036bd08683b366cac41e7888a9f91266cbfcbe2a712fbf94759ca8ad7b0fac71d005d97e08e67070be8ea07c1e5366cb9f0fd8fed3e331f1aed503c26eeefb4823f59613c0d9fe5df50ece6dfa053d470d06b104b77f36e63f952dce710d7e663106a50a2843509282994f0b47e4487316dddddd954c7ff9f425de717ea1fce66c4a8905e5245e82046435c1ef1e0e7e1b3bc696ab65624abefb047d6c5d1beedfb809e39cdd747795da5b3d04f4718b5050bb1d8c690a3963530c0283933773d5b9fc02384824ff2517833c3f1e5f8d83f22d0c72fcb046b6ae98ed494468a9b5f1fd5fea87f183384844fcf8337e18c7a883e838e8f375de9f881b8310f1f1f89a3c6b7e080a12636c8b1cc4553a44c4e2dfc41863f489c10fae28029536cc1c33ee989f5b4c30bef2b898b1c5f83231f1b57342c051f3f15c193151f32726e295c3183302f3d8f47fd8f271fc708c3a46607aef173a81378d3aaeb25f6864cbf77282e8605d00faddf0f0c155e00bb23402e7a14b6f0c463e5bf370aeff887bf45c9c1d4b932d73ef1e0e776ffceec7b93222a33842184337a888d564db80dc31de3d27958220efa425cede207f2865f3bb1f8e6b9cac4ec8bea517e37d06551dd42aea6b42616b31ee8ffaa24444f40bd2cf59fae8adfc8d73b78bb9f4d7c3e16650d9739571d6271d1c272aacadad3dce8f442bc3ed3a0e7f968b2cb8cfd686dc055ba342f6bc25584a5cd5d7e9c3abc57ef9f0cab6a6dd285bbb42249f370a8f160dd1cae6e9e50b499bbbd5a74e515d5ed8f5055b7bfc3708259a286ddb58d3a289d2ac4c7b6b831c52224a146de4d69e9661e5a36bd8da135bfb18579504338806654dab5a645b831c5a996ccecfad6c7a43e0b7b289d26650d6d17908abe783b4bdc795c338c45929b7eddfa863c12c8fc49a6188859b6c4f9d5c19c48b83addd265bbb41d8dadb2b44eb86b802274a73d5b6b5b754a24ddc9a45c3d6ac18b666b9606241d66e145b7b4b831c5a9925b24373d5f21a7e2dbf367368bfd8da5f5d8d907fb7683c51da5b309c7ea1294996626b537b3b831ce2adbdf7ccd50f9f1057ea24aeafb9c29f93608a9e3a84adf9e73d9146fb1bb7320867909095cda019c555a5d77e562b8b34da5327e4fcf8e57b2b469ae8e4c79f1153d119aaf861e52f4f94f65a35014f102bb24230c30883d584f6b88a948030c64724c73f22338c30de41ede9bf681b0e6a6fa9c8f2e937dbdacff8a4cc41edc3b73fe5477d197390166d4df37150fb25f92b14722c5a626573657a2dc6934a3fc457f9b537c255dc6b9fd55cbebc4bdc8a8e9b6359d95cc988baafcd4a43578b51e5752a2e87ac545a99a45ced40d0ed6c6bf4f34f762c1a0929c6ea7956fe15fd23974aa552e9f3ccd3e4e6ef92b48c34f7a937fa62a4e1defb10dcda4fcf7b1cd4ded32e85831ae749b6f6b509597b8b71ce715ad9d6bebeb4fadadafb16b5ef8891cfbc17cce20a23c07c5c3e3294e793567bb1b6719de78d6e08a88d346feadba9fffd6c78fd6c38482b359972beef207d6ac341faa08314744adf06e8aabcef8d4562f8d76c81a321edc1b926a53ce286f6273f7df9dcbd3b7a1a02e4d63ebba377809dbd3526eaa6392fa98efa6a28a5411432fc487ff92da6f8d914850caf6da3f64073f0624ace48e34f3de574d329a97449a59c1f962fa7115cdb7fc6e769a23d963ddc0f3dc6e80121f7f685f2d33fe28eaca9a5bd6f71de72497dac676cae62a6dab7dcb73e9691465f57a529c863e0e2fb749af7fce274026956c9ef2ff7c3d73bced90cbae987a31deb8776c7951d4b9b7eb8ed8877d4545182f543b7217dcc79341a8de41c8d46a3d1472fcb39f34aa619af3ddcf6ca0e495a303829a57477ef72ee2a2c09b5d69aadb578165d987f534bc618e38eb66c80e0c35418a5159665b7e50acb94d62b32fd7ed45558ee92d07549c825da2541beff8c716b45222e602730cdffd9843ca524f1907ab6937ca837da241e47f94717a975e35f29321676c8b9482dd983e472b05d935a9ad4c3f9703eaea2efcfd1c77365dfc3a1a129683b671f3ffe8c4896fd4edb0eeb2fce13e5a4968f7f3c3288e70bfb7e21e987d472fbd52fc49b92781c74520fa9a52487736868925a2b426e6a9956667e5750e3a0df14c0410feb8752caa70e46fa31a49452d7b40f67ed0be96bcf510d6b549338deef071e35fa46675684ab5cb68ce896a0411cf48f0807fdbbed4bb8ca095731e1aa592c22c6dcdfe0de591770d146b8436bbbbc314ecf3e27259e82ddb453eb0579628c37a73ad13db76d7193773573655f8e74b4a3d7d451730accae3c4da86519c28a0516fbaa6c16236cf9dc95924f3e5b7e8c95e6597f727fe373db7eea90c220cfbf995bd76ddf119c96b2e330fe6d633cd330e7fc9bf9b7ab8f751d52bdb698eccb68135465a4c1d76ef1e99d9a5abc61aca99e5df7427afb79ae466f7f239d36372a3969a5c37ac9e8b7d1f7557194fc66160d99b6585cf489b8c2016351b225932d710c61cbc701041c46d8f2b7193d4657adc831c401c3b48503465b91e68b1c7e33e97fea39f9781fa3cd6d9d216f1f9e5a279ebff1efc4a235fee9fdc03fbff0c676ccb6dd87df6c4b1cd60cf9692bda581f787638605b96743db54e3c9205b6e56b5a6eacc3fa9946d06681b10c21aea61aa61a46b0e54bda8a28b9a28e922135414bb5974467f446f38b9146eed06a5112638cf16f3cc6215cb4114629f848e9118bcc6157cdd8d155a61de9081602d94bb5510a3d3d3f2e2df86c11052d28a5d6caa65099e260cd62bb08c576751172d00bf282a0c8459b6e29ae1820a22c442868a812c3982731b09992b514c5972f7469edc8e22e14b0295eecfa315cc4d54c2c1221ce74311493855d63b4d835468a053e8cb142c8cf6c11e34caccaaeff45d186c3b248e3522506c67d0ccc55a7b843b92985922bf0b90cb9ccee0c52320b7c42be106b5f98b369c7c0629cc4003908cea11cc6c04a3e2db218a05b84c6c05c8a935d7fc9fc1bcf7161890625bbee3006e652c565c85561c967d79ebd9aac1ac5c50b9cfb1589b2ab0bd0ae2e43cca7df11179fdb834cdf93df7d143bac269eea28765834ff769939e132d481d7a1df8197df8126de89cf48f74d38f14638f0b403bfc3aa414d3c1703b3d409dd011d272a0938a809ee0b6384626095de1898e400acfb5edb06d9b5833e4f4002efcfd1af8bedb022ab9b75b3899ac2f57cbaa109684f02dafb71b0be478547858312d0f627a0afe773b5d72385833e0e564981087c8837053efaca7b80d41e90831e6c7a2e49e54566d815216072adf45cb30948e0a3872381bf71eedefb37534a246ecc02cf5d6d010bdcc73af4601e90abf0d7f75c7325d3f25c32ad29e4d00b8a323e3237821cbc1185087704a230361312081391906d13f2178a9c1c568b524a69b5b7b25a42b64d13a2695a0f98cfc4aee02c67bf25dd123a841bc22d991f374e151c2a5d104259c4827073969ad55a6bb5175b9c98b66d56c86b1c67df85d8c9f22eda666731c658b390c39998cd6c4646238564f1b07a582d07edd7a347500fa11e307923166346ec466ce5732366a5ec019bf1a2ce10cd14e568e5e0c92185af4a3e33548676fd99d95cb9cdac87c592c255110b3d601863ac6d9c8673c58c6c29f1d1c351e26f5cc8732f5b1fe2c8706242deb7b671dfac96bd3cc871c896c423a1fdced7bf4c86ccaab86ac8d7c719c2210ad2fb21fe8d83a74d77f47264abb5f17bce8dc7eccfc307cbc364caf98789b23f7f7a73ce399d90473bfe24c2fe604dd1461b35fd7e8834f6a91332fd8c34d1d17e7b234d74e86b6f44fb8ce0974d9aa83bac7183fc0083ec1f46a1a969817bea01a1b9b83d64a2ee26e4a622c030610b8f1de2afb1d6628bf3be0f5384097fa63b9bf0218f9afd71855bad562b88154da69c670cda314b39a5cc338a1d9ae25c01bdd76a9a86a78635a9e1ebb6cef94390493f166412117637140bd37dcee9eeeef4b4e57702827e8e7cfa855262318390e5939c4e3ae7a4cfd5493d1f933ef570e847ebac3fba3dbf39bf29651bb818638c7106217b446418bbfadca1915ddf07fdfae948433f22328c49917c271fdd9e2f7f7471ee50e9602882b3a75310dbcfd7e15efbcb3ad5b72cc98ade10ddcf4e7a31d2d8975d909cfe89b2f70891c656d664691afe23f4b56f08fc47e663f924d2d86b838264ccfd0deeeede848b36426f6dea2a4961ae69fbe6bca335dad86ecedf3e23a39f6f647baaf144dddb4596f276b2c3b6ceeb126b78b4244ed4953ada15e4faf43be1df9efec43f04fded8798cf3df7de09bf0efded75a63d79af7df75807417f0b62d3be537ded4ff84b1f59a4277dfe21b42f7d47b8d73e73af7d35da93be918e2cce2322778c349b170465dd4cd4ed824754335197479c28ce93628834f7b1aedb8b48731fdf22a21a6fed8803dd715a8140e9fd9a1d3b68921fecf3b8ce59f529a7be7cf9ed5060ca29a79c71cf39e7d470ed226b9b8848c3a2b1fc24d2f8cb1ebc67db4d49c0c5afcfe1a8e9961e4e7ce9d92fc8fcaa65a44f3c7b0a625ef79f9f9126d2a5a63b4f14fd1bef02176490a6ff14c47ded75ee6bf3efa773df88fffdaafde49348e3540a511b544e3a9f70a41a4dd332a2a8bb835fda34544287b88aa41ae93ea24f3d1c7b298d56ec24417a39bfedbfde13d8f36b117bbe9c1fa53de01240028209b9e503381c148b6072c88583f451e801195be91c851fb8c16d1aa6a3100439943269e4d551680434c988e1d2c26247e111d4d7a01103737ab9a310090e1498c30d191b387c78c4cdc8df91929680070f1ed1667e941d608eb76182c92d8eaaab1f72d88069d961cbc62dbbfe0f73e584d0ae55ec8a733615091581f50310575207f393453982d288d7f94ebc9cf01869fd30e949b2ebd359bf7315fdfaf6c75575c748e7ce944534bf57d334986dfbbb69dbf6699ff3000deed2b383d994a38ef80d39be4b0f985c3533bdd7521ba40d032406edfb51a7140a9fe19cf1e5c7c9516ed2fa1c9d94ab92d334cfd334cdc3de63ec7d0f63f23c2ffcfa187bf83dcfc31c7e6e72989b35ac6f9fab36da58df5a6a79d41fe6d4b27d93abeacb87f9aad1b076aef254d3d3dc7b1ef5a4b49cbed974017e905813a1531f3ffe88f862ac7e2c5b026b3bfaa0143ae91dc11503178c4fea2377d982a148e41324d10ba690d25f4a29a594d10757bd0c322ba5945219140333ecc06165f0e2e3346507f39e1804520691069bbe59a5fbfc5c66a722e28740942ca6f80043e7dd418d98141d624db4a10fbe6c49d813290528a9903dd2f572b227be565611513356438ac98a3d251130ced964fa07e9276116053994322aae2262c241eadf12460c71957f45ac21fbcf8ec0596b2dbe9406f131c6f8d65afb494a2dad8934d17e747a8d0f95fae0c30c6b2a1968adb53ec62ea7cbea55ced9d1aeeb362ab76da335019ab669bf6d9b369fce3a25d619a457bf8334ee98b5d62df24d017e0852fdf3fd982dccedb2b491caaf5efdda5a69aeb1ce3a264441c16b86022974489fb4da8bb58db337e8baae33c22345122a64106d38fc8517dd87b1ca942ca2c49c2342a0f301c6a50c228d942f88200ba29c42065e0803197cdec6f79c760a39bc20822204182c21dfe7a2865111853faa215b70e3227483aef236c6351fd8cabec13888f16f9fc941d3c6184f9d95b8e4f115fd649468631fbfbc22dac40f25930fa5930fe593ee93526cfcc588d2f017238a13e23c6e1e7fcd5cd5e7bed00446fe62fb42ec85890afee8db07461afcd409b93eb8e5d86ac037647c67d545e97d4b7dd0afd5877c2203c0828b4f9faba9895aeece41fa947efc24503619e12a4bad88abf812888b4db5d8544ad994e3348edba298a10088dbb4e836fec9da4b291d0111a594524ae9db1b5dfae8524af5935cbfb9c355e1ce9edf0e19851c7f09267a438cd97a88836a7880356fc2f5ffc663b5c664c29548113f6a369125a6048ae2ab4c94444a217d767dc927f2472a913226fdaac069953ee787e516610dccfc9f3353771370d1465863b56632c5e7a1e9c97216377f9bdad4dcbf1c69e64f3b4f73621e05f055266a89c98298c876cd20076312861dfa609ad43d1cca8a1e10a46a77a4d328b89977b491c6f8d5e218e58c8f371869e2cfc78fe3caff7eb65a4ba7ef5424eef4c5450064210e7afc293f23be221c7423a4fc22a4366266c4bf114568210ebafd22841841652dc288aeebb6adebba4d7b6dfb9ed3300e6a9f69db364ddbb4dfb64d8b44b536a95f76704a6bade651b3c3ee5279e3a0cfe83b952264960f63adb513e37b27b5d6461965a49b9ab8b0c3df7872728485d0446489ec9d0fb8f85a1e21d2f0f8e8d349299d5f8d83723e89340f664a73a5d7be7f61ad7252253b32c9928a2979a414328991af82bdd8f18b1d1f025f0d9f5170165376f421a2e2d76f4a8ac477a863216e7e31ba6b5468358e178c34fed83efe10fff645ec187fd88606833fbc1f2f0ff37e784e8bf5dfc771453fece0d431d7a9857dfaf787b03fff7e479ae8d89f7fe43e91b310e91a762dc3ae5fd0b487fad4fc7fd0b73de8f571f810e7107e581364ae64cfaca999f9c21a10c717828ffac237e51cbe30e3f0e9efabd9ff85798735359bbb6f9288c94785ebfbe68f7efcc3e2402da5159813a945df67d1daafe8ed4bddc368ee497af4567bdf89e4401ee4401ea4bf099b2f9a811cc88362f044e5ff1b2f8201bd60aed78fcb67d7f771dce4bffbdbf3689f1f7fa7ef0b12436387157ecc77c29fceb5dad3f88ce4d7dec8f6f7775821a87dc532c8f485b854eb87510883354e04f45ab22650b556c409e42aafb50ebd9e4ca6fee6cbc1fa38fc7f6de5705699af53a8c6dfd0302fa34f6f43c77c0dbdf231f4cbbbe819dfa24d6f6ffc868e2c19fbd3335791555d387cd3e7bfd9d3e34f1cacb57ecd41bebb08ad1bfded3b727fdeefc49a7fe424bf201bfdc88a3281fe4996413f7fe6eae4afbdfded87b8af7d4768fcfdedbbdfc98fb0bcb51f59ae4d57bf354da03a81be977a3e019a44984091a66a1af81fffe34f88c8aaf1c17cccf39c7ee5ff3be92f08cb77c26f69c0bc7d1d98b79f9126f88dc47c317fa4f4341ee6f1a77332b2f21d217d8cf7d8df5ec7fe1b297d27fc349ebefdff74b6cf9f11d2479fc60f313fe6637efea6573e46971e46e73f69d2bfe896182f43bb7cf482d4f87878623c4fcbf3ac7c7e1e97e761799ed293fec6615e74644d2a48b9b4c2d2e21223868e2c973c5df3477e387fbc203ca3f7bae72ccf25e9c88aa26790d0aebfe938eb5ba22db2b4f924e32ab7b94391c890b7461354b4f1ed6e9bef4dbb77aeea5f6d7b1b60b4197de75ee79f8c34a43791908c748c3424136934613aafe376d8dbb7a4e759f8976053b8c4f69fee2ae91f45451ba71789ac5bbc388ebbdc9d94c5c90edcf1f564396bd32bda4bde61129b6ac9e2aacb48e9a81469e4fb286dfadcbd5fa6797aa5319833a43452e91e67b494be66a9db49b5faf1006f0dfd99dd9db6e8cb48238d94ca2d72f8aa59530057d9af7e41660caa7195fc4c23b539c839e74adf86a4224a2661944e767cf9441e81c78e1a57756f4a92a508258fe98bec45ac12a391180481f8c5f721ae6224913e79844823891065102228bfd3b28a08ca2360d18410091436ad9f746d2f1ffc2365cf96b04d5dbbfaecfac9d626b2c46cfb88415fc43f89362e2b12bb33e71d4290ab648dab68733ffe1273453fd9832351fd39fbb169b267ae7644e1c7527c368eb9406fbb955ff3a296ab8ab69d5ffb1845c2b896966ff6b0fc9d53b2e8d97210dfef26d2608e002d8f7fc71e5a1eff4db4b98fbf00be8ae162759c52f8cc1e077fa2f0bb7b38a720b627bdcef6e127bd8e8c4d14fed2cdd6c130ed2a30eea44c2b261136c6184fd978ce36ee22d38b7fb87110ffcadb18f483abe2c67f3357927557defe8dcf9fb9ea1efff499abedf1cf2aa2cab9c7231b963f4374325f1b3fd772ba1fe377589b3eddef14c4f6dceb6ccffd7dee33d2e47e3adcc7f88cd4a75da7292b864b8b6e02effb4dce3bfa2c23ede197b0ee9b3f1385ffc67b260aff484fd744e167c1bff9199c3891ab661511c48fbf7621af7cb3653f2f9a3dddc62ff1e7b92a7da78b4f9752fc47ea6f5fbc9fd5be6fa2cdb6318d4c36fed9834dee45a4c1f9932f07f16b9f7439881f3fe9b1f7611e7d68fa3d5752087245fa6e260aff8700d8a1847d7863871236323dc1cb4be8b04402f737a25c6d00705511cdb636a75121282bc84461291cc45dc8d2c741fcf7933d0e62fc560539c41bbfc42fb7f74caa31de577b6b73b4bb1ab73657a78cb4d60f3ffdf6d5b4b5a3377b1cc41f3711b9ef3fa6ef8fb7a0e996250cd7e7bdf7de7be7bdb70813dbfdcda788a9fb58fb0a22cd7dae56098683b7258b1cbcb2a8258b38d9c5beb7dacbbdf4628a17ec7b5d01ab6da8948c9496559032a566460200003314003030140e89c4c2c1684c2429bada0314800b95a25678581d8851cc29648c31841011181000000160200904cbd408f066225093c1ec21fa58b91a4364328247c4c666c66e5623ef696ed03eb88bd3d64b6a5fb6c620e2d6b2d46b2b8d18295d33dd637509cdf887260406f73e238943e1294c718bfa7c93b0a4e0033edfa9823899898514a2a58c5c1d3e7ae40e1906abe2848369e87146bd0bd519cc4c0d73a1ca291be582cdec5e30129a286feed394924ee6ac32eb351dbfd1ca2bc46194a9fee16e8fbfde3a8fc5fdf088e84dcaa3327e629f84fe6da5dbde299c1de0a210ab242d9d936792d362f22f4f382347aa6c030c5dbf74ccc1a6018b74da41786293eef2c5c5d3999fd119c1052e81810cc96f870409b428aa7d4ace1bd0492937aed69ae2885c7a8401a9a142ff58dd265ab291a85c53174643562768c189a0da4a55d10cca270d26a4e0a1f9e2bdf97d071438512bad4f2ca1b0b41e03846f1facaef8eb574575595b2d265851d286e68ea6dcb5680bce046efa400b0907de7d3a482c399e1003a3faac2de017905bc4fe3531d5d237410a18b445f5ba1391e1ff9506bb0e78942eafb15be78ff29f29860851d474b844f2e978bff601c936e294b84dc70529c8a520397b3f8453ab5842712947baa49a7273dcd8faeb440079fe8d745e3f0dcfe12711e36c9da101ba03e8b95036af57ef62c5891c0e5b25768314c793cce04421f2f94253639b56e5cb5d16269c8640f74e0d87d2db8d36c5910c555f5ca5c2799150ff902c44920922d709030d337bbfd0531cd77b85a4f4f68f2e69a5ee174aa84b5da2201a723951a250f95f2845de6fe4dfa154da063f7091baf41ef051cd8c2837463b2c0d92431b5a517e57565531ea26d394484ee52ef1327a37ce9ee47980d36d00db64f4c55e67b5b30bd3cedb4728088197f5161ae59cd0b39b6eb3b09f8233998bdedfcad05f4dca0b2d5f2c25068cb47976869eea54b3c9fa05a4ec1ec87c388676d8890b6fabacdb6212abb28e38f7a641825341caafcdc51faa008c7ece08a157b61641fdfef0d68c219ff54fd546298d039b70c41d936693b72459789b9b7390bd13f077c9d4936ce25a3923a764669a25cb2bdedf297294923962d3250faec740578c1ce91402946070711e8904dbd0e6cee1ab79a09248422a1b1d79e222211bf23cd1e1d1f2291cbc59b4b67da8af5b8d2441c9514967e678bbcd577b3a575235a05079c8301162a3e4b47acaef9fdcecc0792d600d038c9338502f80e33d43eb899bcc955f2ae8d5fb66ee35f6f2a508172261b910f6783f7d26b38ffb7ea181e1f83ddb532a966c4f68d2ebb4c288dd7e8ffe863ac740094c915a8f74689660ca4bf18745b6926d0e0f41c717706b4dcb13e5786a87884e3644df49b0c779b7df81a24d33ba7d5897d72a5c9e40b47ac386d3708a9afc177e3b492cd148b54c383e7222531110c5ff4fa31a45f1ceeb5011f54a5be44e8dec3dee5c018f44716356b3c11bf5ce4c81f087dcce612ceea7804088781bcf96e4a63371861b8a1baf00147299c95022baa8fa4b51ee87bf854d29291194f594d0668eef79c43b0da631c811975cbb73873ae2452ce93be87e2c05ec33858a126e715e352d36bc9ac9d4be592167d27010f9d5b4ae835b78b6a983fa499f781aa6a684c442407a91ee78f921b19048741f80fa7a1ab85b9a617f85ce5b59d840541a1199f690aaf3578813578942533d5b3a05a900402c0405647d08b99d115250ee75c351dfd87119f87cea52c16e0a2205106144ff557500ddfee3d0e474f33882461510fa795cd3e1904978a2b66d84203fa8d7efebe7a09bf5d2bac9123ee27afccada5e01d56373e3e51e0f69c91602a8807452bc50e0448fab5edde7d256edc36256ad63dbbbd1f5475df96069e1147536752d090c8b18050d9d78ec9131e25361ed3f3eabd8900e60f97acd297ba41d3204afda225b80b50593348c2f4940e89b1f40d50c41d5d1df618116b44c50a1a090ae10791b21bb914858f4bac3c0c49d2ed1ec4b5e85616862d66fdf22f4bcddf60845305a93b1cd295d2edd2e1fb842c93cc547f9ac46b4f4b06638672788f17bad33de7a682d44f146b505b8a7b849600abaa07c48d937b02aa2518d6004e6e5d53bf532ae8b04be8c8dc67ad9e79903e0b64a024bdddd0290bd4cd30c44c459491a88644e53ef98f5358f7d108222a3e0fa7d5544c14bd92ddd652e10a7a7a4103b83164181469556547ad976a974ccbb3f4c93cdcfaf89496e7ee4f382b33a4407b196645521c9b0363b4caf73a3f053f4992c4b85a4e6de5db41ab531e20215f8732eca7bd691f68318ae54c5587b477f62a734ecf8addd6ac455da31a4eb536deb806b9914615ab84b1a3846e1c192a72bb6cf10d98a22f62977958ad3bd8657c108263406c1bd20a0b698d8137db5b73c612558240d57affbccf81915084007732ac8ac37d0aa00f6fb2d0b00883a081961968915c5676942fdf4a103b1673e9abe02731a94500dabdd6ed3a96641e185fdc4ca4af0ca3302b566fabac6a89ca1dca01e58c8fc6ec85230ce798308b5cfd5b678120bc24888a605dde4e0220ad63e37b7e16c8e35b840e6368bf644ea98f5837a748a0baecb05d651d2b1d5b1e0869c9070ae8c802fa5ca66cdf2036a9818f556e0072f296d83ccaf12e502160c2113447d8cbbc28d2e5a468fa66fd1ac2a303abca44c164dc60c9348527153eda2678d7554fa74561d8f4af6dcc3d4ba64d8372a3df6991a640382c95e9043bf77f3053cb55083900f54356b7cec264a64f107c820f024a08abafc1362c4c0e2112b28b6f93c45cd540dc14436f4bced1eda03a03d28c7ba5dfc64ee16b8d64c30f228f0f1ec9db0e9cdee857ef66ca2a693103c2ef7c308d3979a90346f3919bd9e669e8c2822fe580a00e1216a3b142798a919e0b1b94cf0ff632450f09e6503bac1c42352878e26ecb1b268b2d9bf819b35a75b0ec01e2a3a81c006564d274e3c577f9393d7b2ab097bb14f09b9b95a68fdfa268818de07a044bd4d6d9c53ca23b65b03ee0213254bbd81528869ebf03f970f7d7c7b3d572995261a4e3c851b39362be2d3b39d4ace91a548e76ca6e59064d5071fc653b54f1dccbd0389a1c9fdc58850c3694b784936c205a964dd3ded5c521e518ac648ab182616af6c9f43826508346e08f4c896dd082f7ec1a9d2a230deda2254f2b428865d27dbe52cfa8eb49d90a720e174f09f64218f8062e90bbc67e513235f6104ac6d16a2d42dce0001a82b2f0c4478291c6e3f0e2104ca3389242fcee606fdb5c325143113e8d9df69635c064b6822167445cdf9ac9451800e9a159aed4cc886f4738747a8bf0004ce4b2f919566b283a082093ef21966a1f6becd8d210272044cd5261ef3651fe04e6524b8d530c085067a1f024295e14095a839c27cc17c8647a32f311f7aeb5b368234e4b857d66341008c989e0a2c79c1e25e5a2cfb4cb2cac1ab8244969287e2957c159035fe55d659af2c88d98aef4bab91294bcb2a1be304003f90d630938f540f4130d68a0ec74ff244f0fcf51268c53894eccfe28a22c700f9e8b915850a9b06a69867b6ddb8566c914597244896e06de28e0e558b871327ab21b62206c2c91056e2dab1da47072b9b63f548a816bc137259254ec7c20c22aa21f7d8b955d9ad419be5dfa5622a159d7922d7a13930b7adecd4e8e1d71f14151d91f17ebd13b41528c445a9510f30ce99fd0d06b087dea466b46826f784c68cae03efd24f45ecb0804aa22b348ae879a76813ab82e87fe7d8d625e61c3e14b970c4c6c9a00b4968ba6a1a14c7426c4ea46ec0d98d030d590e249671fc06ff07d657d738b77f6c85ac5576b38a15f2d322243d1325eb4375860a7da6d38bba316bbaaba8507da44db7e5e1a291bf25e623e750b9843b722d0f1b7a64e8b6065f74da830ffd5de47e6f03be0b65c6d9d0a9357670e9e54d2e609c5389d690003dc5aac99ff4c70bd4b2054fc61de8c648f5c3b82bd322843bb03f23bd2a5af93261226829b4636caa802ffce30ae6b471ac5088ac25666429fee055f48c9a3832729adebfc1f78eb485f85a12f40e07f12773568aba6c8e82cd5e1385a16b7e4a4fb6443dcf89afdd8cacc5d80e1bed7def52f3c26ce5af00f0e13ad710f7a9d5b632f87cd48490c1de96df578797bca25982a8a5f2bfc4753fe43cb6a634774a3995a7087eef61f8f80ea7fbaf250a5da39226322f3719215ff41a30c414e35ee60ed290197bb16c1875f89fe18a1d895573003a86e0f365a87a452e62585b500b981fe8e90f83f78e48f80fdda982ea44382969d4fea6324ed901af7c29819006cd277c27be463f4cc0291dcc714c810586ba84313b0672d519d0715b2c33aa4f62431ac7a9dc2a9c84a1b47d64d709960742e26c27d826b3940f9578678e041040ba290da5d11b7e1a7fc2fc8eb6a7809dd43bf21da2dcec14f2d1ce9555909d10e03ac4c028aeb8f7bb6b0f435a4599d7086c2cd4ff417f3fd19f8477a83d2ab0a57eab6dc474e769dd1120a4166debb66ccb1ef4133351d9dda7faf353aecca320c61ae529f7cd3bd8ceb77ace7bf39f89e09d189945e912c9587757ddb5d0667aca818b62a2bde89d4a1f78069bb798908600eaea2821bb4eb6e0bff2d10f9ca86ddaa7cf2b9ce6abbe1b13e99be5669fcb07f99f8f77684bf3f9783c7e342eb3e98c77b98c402a348003ccc4f97a6dde85232300fd4e7ee4934a0bf46ae2a38b8607c9ff2895b57365147e8bb9d26c5cb115e8ef6f0d88ba4620a7331ddd023dc5c318cb79c25fa268c2d99a4aa05ffaa1e2fb2f4759abd5448b271e3ed58cace006f577565fd8fc27c96bd0fc7e6c7820a19eb86d277a3cd9846c72688aa254fe70886898afc2dc263289d3c77c16187d5a3f54e9530443924f8be8b5d62760dc067ac709c0b5dbe2100ec6bc329df651b81dfbe866020c52054dcaf451badbdc978e5a53db68df176901ceba27cd3c513814759cc8fa99b7641551c2ca811b9479cc0d060aae34bfff112bb112a3d88abd58c4548c8aa582d3075c0677537c08077b44de2a7f65c1eada6e647a8549fec64d9476992cf29530e2cc17694f3be609da77368c433074e9db4b68baa539f3229dfa98aa3548b0a97fba5b718f0b1e3e8aabf9005047c5385f78b5d9ec4b4cd058f28a8812a2e655d6efc685f4bd417d7db1d47be32379d5b50f6f3812f816512198a598618372b65967ad7c8536b4b2b5ee78426a16a716f6a9d83017725cf47e63c2916719121cd75e9657f1e80380fb9859f014bd4df57ffca49e1cc380400a15a9649e3eae4872a8217b743012aa4eb23aa26ada7b351d783f0ccc8b55e56171a1281ae16bd72f195b7cf524e0cef2810d6cf3b022e6b966ad09f7404dbce9e4593b2fb09bae2cb3e05ff5107e3c5f6ec12b73da7857c61bdc45bc7aa2ba80b2be7ce4e6925d53bb96e452777a30a98909c943a47a20d1948e3b8eff755097b5339106706ed4dc6c1282fb7277c6dc056352211a03e02592deffcdfe99a1300faa78df810ab293cff30202c2de48e63d9fba327e6ce27b4f5f0179cd48266c742928763da2ca384e89fe5a5042bae0bce41f4ce85d3269d374b4b2aee2bb5d3c88f63af4df043061b21ea01edc680693f7c5de1cadf38c2b63edbbaa98629dc4751ac4c057341bea2cb3976977f0e96cd43e0e03e3d251709f416221197985acbfd9a38b476e266ce9ef032e6df55fb909138176213f0903f5f5ac89d51afd4724a888137b038530e640039df34abdf0926429f6157bed671558fa9f8cfcd2701361842e5f138a2cd710f65b548431e627856772022f24b0b568221f165cc26b752dee1d1d6cef9588f660b5c940419f571c658f2fd45209e1071e1e8c528bb04518beecfbbe3dbc5903eb8103aef61f3a26b5c23b6703aa4afb15a5b3dd262dc097f21f1deb21646461fe604559d9cb95c3ca0ac17290eb17efe3f0d0abeb68341ed419f8762de63de003eff89d20aaaa00d9038c1baf7cf589fdf274d730059bdc0c573622156647fff85a8d02298c1d9e70c3286ce7de24ce0e537fed3f73e41dd977966d3ea61010a7662f2013300b30641fe0e777f7dad69d2c71dc55a32f74d3e83dddcb71248c75cac3b08637d3f88afecf189e8b2be4d1225be59092eb89879f4c69d6d9e3d822bebaec332ac6efeb7392d00aef43ec1cd0deb0ea759fcb0d3ec9b585c81a4f53f359ab72f1aa4dc20774d18e335edb988c6d90869f60de6f583cf675a4ccc9c38a4f14646e7811f97e9d238925b212eb8818c2d0d93dbd259220849a908a388e5c4dfe38857435cd51624159cb6d9d8edc99e8a50df78a021dd1e044b9ee935fd1ebc36e864592be9f83980ec30c9c9d7467655896160ea3b4c88dcb48c3ed5ed324af3729c5c98c6c3ab927d4c335cf5d8f9381bceb14f27332e4b4e8893c793f847d98099d148bda39dfddb7066e9506ed913c9942d1c6c8b038c3d9e01ffad1f8de074959b5f7a938963a8927afbb3e3308a8ee126b5da5bb7f3158e021f66fa2405033baf69088645a337ee5070de8502ea6266b9aa10e3cc8b42b717365d4f5b69cbf3cb1375016cec387e3f43ffa0ea0f0dcdf9bbb37a4ef34e41d102ba4e37098ce035275a545f890de2aa835387065b0037bddd354935ede92349372c430a53fc747e9d746a0742cb807a21dd642010676c6d90e4a91f96155b86b67200507aee19cfbd163f31d26984b916f5ca12fa3348a5e9c202248e54e7b098cbe4cd8b3f498acd5650494216c37a227b980966f848622a4cc6dac2ff09c6766a83c6b01bbee0f5adde471bd01f321d6354fe02b3bfcddf51ee48368f22121db51e15d4c6439550c7d1f0741dc8206898d845040dd26a3acac0ca25344fc5d7b88926ea0720262140704428433d50f41f4e78bacfdf623d92a8a297aa8b930a7cc5921091b953b761b29ea240e37e12aac3c7f37ae4b4a7b1676ee292a3de30d23723e029b7010456a2cb362ebb28c08518eed46ba6ed6884e18804a68f038327dc80473ea775a1402e99d786846f30f6faad1487f3ae03e354ec84ef3c9017834b7d4e87be2e80530dc25089b7843a941022ad83f35f98b0a60b90a284df89851af4a32d396f6219ebfcfa2d263f8fc3f9fc73f789c733154d73bf36180c98baaf7121f9cceb98299d9f5e460c90bdd8a6a43b7b21f81eafcd0b5c485ca1f6f24e445c2bd730154df98be9db0cd992aea5d1109ad5120c205dbc2025081c1af394306b327e0a1f0b10d67ad059bb423b40d2f386202cea6f8714f1e08cdd293f67e3604bc043f424341443333ad0e33a75cb4bbf4121069860fd80ec510630f873c0677920702cb721eba12a78530921e4ad9488c1ca8bd433b84bb6263ce2fdb28806d1402b510f1a007068880f2b4d2a81d4b582218070dc9f82cfabb469b809c099722880cf450e7f1a125ef8c6013ba1a8362155dd52c3dbbcb50b53ff7b48aa9684c9d3298d476cfc9bc5758ef70cde3c7c779f442126301c0a99bf7b2aea0f0bef00ac2c572ccd28b28774753b0afa5b923030ac88fde7d24dc912922f7415873bb13ca59965adf73970145a15fcbe7b3499aa3191377e5c031c2acff09f1dd1b20e35580c87764d73c600c7785438445eb666cf48058a663b24b20f32ad9039b70bf1d899777bd699240754beb185302902176c46c316573b4e58ca85e2dae7d541f448d69df207e31e9ebf6565120187b7e874a1424c52b2bcde7cd54ea3a91b2a4fab1fa602fc646c51b6aa7d70427f8adf652eb7aad51bb235903b10d3d69903613d077acb4efe6ab444a27adceeade4b219da2aacd45bff87a33a335eb1683c03a6a8a9ed874631f98b56405bcec3872d8bdfc7eeffb0808100d92a0408e19c971d0d23b80d2ead241e51a5e0c7f12e21d94411f00eb9edcb081b6abb889481166d91b00e1932258b84aa9d0b3116d29cf146c241708873894ec94612531a8d72244f5882f1720311e803dff6b52b51fd10e408201c285baa3c3fa9fc590764cf31126227f20f77e1fa7c7f593a57cc768900b760473b4dbaa9304bb7c1aa70122008187e54dfde5eb4a6dc3d2bc3e360f26bf127d3749e0aa917495d0d6d6654bd1144624f0d14f78e91c90ccfe3e105647be93c25ae7854009f57b8f500f51e558715f0837ab5590de6230de99552bf82c2053c62acce2ca4a254b56dd42d2401031602049532b9200f5201061c240c7af98d968113f47cbe838b33c135bf36106f916723881c83e6392df746ea6e4b86fe67ea3f9af60a11e211140304a0bb0410dbd9650cc3e9c81aa7f3c8c1fefe147a69fa7537a93cb8a8a26e649b8b4e576d54bb6dc01da0e25aac3fa0c1046e400cd03dfb90a42d4f58eb2ff9be972004adcc57b5d6220285e04bd9d71545a82edf5fb1b051ef3565d4bc42802ad4a1356d4c6705b0728903b715b602613c3095f299e564dd3c954cef3d5f069e49faf82e298d874a9b2a321502638902c1b553267e1a2900d0789d850eb6fbd685a2220997890d6b9084c9311359855f648138b8de0a34896c8d9a8d1e3b80b4f4bbab46ebecf1cb1ce9b1beecdedb831bb356aad4baf292f46e7fb6b333f842539f6329612b6308a5bb520bbe334e502213fcaf791388cff9521187b9c77bb8ef476a1e6dea0273d96192ebd511c13f139a0164c086421a29391b7a11d597ca125bc7a192c9c8b5ae4839236a72a781c86f04b2284b27b03328d5dbab8e59c643a0509f633a25e41878dd7665bc1a2a3febff3a53064faf09628d907e29202f2d3620d921f3f447ac3748c8737368e73349c1a576329028c9fac8a093b80b9af530941d5908760cd6597984656b3d9b94e05f2d0d0d6d012bafe8e666042bd4b6cc9f6a115c3af947ee7b4256ad015e6a20fb01573762901b9f489c0c411e2a3f5fadfb88ef59693febb9373e35a5a3c84e326e495c07422d810f25e4aa8cafa33dc1471bc5b6bdce6ada938108b2a2e4e5b506f964d5905aaecb3b82a91f81d9836e93207862f3eba354dcb5e3052e20c04d62a64b169592aff9d63137e5a49782effaca066f5176e24d55dcfa93b6a091a1139fd453b22d11450c91c242831af05107859f35602bcf56c61d41f229043472e2569a0c3001021c2daca5f7adacf07875daf1dd2c81718dcfb5e0436de7f7c216017a4dceaf1acbb45193851d13d4b23fdc183573c3f2e5856e2253ec381107793bb7f9277af3393f68ee846a3416e284b505cbfa43dda176b64fe8ae1cfe4d36131eab7a67c31b6c6b2e627b349a67b55654942d3612bb51519f685f23de2e69d9e0ad59c744b6e87aa431a4818d059713a39624a6b0c599806a9ec9c532111c1597b14acf60247cc5f0d886f724ba11a2d577199304f81c4b81c4816d6e6871286cc3300d285f422650bdc82f7885cb528282c538f520690caaf1307744f751a7e549419fc0d39c171491fc7502a4eab56b5f8570c9cdb96d0d9040901d8fa143cc142e5fe52d4523177e94742c626476b943f91d1add2304fcd25b9a831aa6d185d0d12e9622fef77792361607f7c2b8eb95b1ae07f7a61f6ec779b8300777779879120851d66a8ef7f0502d5f915d5827379abf58683780253f0919e215b773254a4f3fff767d0c24f9e2b18f1eb8acf35edbf63948f73a9a6495cf62aef346535ce66e94c1a5114bf426a416f74fc1fabea9291f19c40efc3f1a84f8634929683fe5124ddc6bc0a9b665bcbe0a3f55aabe06cc5ed641ab0bb9e2352939a4044efae45d9abf3a6047c08e57ab51022d665b5eb68867ee11eb1999bf417054d80ef28f43d8db11b3b49b8715c3c79a6a1644c913902f688dce6bb2c917c66510e5e276f086a8da01af4037b6df8f859b0a4bf62dbe20b011859c142dd22ea39ba5d2188a3c4802cc79ae172a5e05e1aa2db5dc7311f8257492792233e90aeb21e6d638dd51b95e7281a8a7d0dc67c2072c1a845570a50f83b698e194b1307d0b3388005a8eabf581c3b15e93fa5929be0447cb8fa486e2d3c4c806106e3682249696caa9a2d6c6be373f1376b8785851b4fd784498000281bf2b8063c9af348e379d8c8c00933d078b2d5ea526f03790c6571b199b067b3aa8cd04d76c6006dfc6ca7890793c90a4641c28f6f3d3a12b2b1586a90f4e44eb5881f6071cea505e6bff100237466f290dd299ddad1e93d745fe7b4cc94ddfef2eed90a45842a18b7bc31dbc69b89e3ac7a24f7f9a47d8cbe89be443585f05991163c13196b082af120cbb871c581af652e5359c93dfaa2c89b664194098ba557a2175d69557e33c91a0667d959f670bdd42deefa09bd4ac685490f93744ac9944e7da2bc085d9483250810960c6ae8891a7004dac4186950bb6424ec01174de1319ba579e65163febe4bd69c2ad6187e965ef6e454e025c02e5a81f2625c91930071a36d1483ab288c49d5714381ec6fe5d89329547fe63720a5a92d25ad2021191332c1784a9f3ed3b25691a9f8f2f01d512baedb6e6849d27908ce60725d0fc16dca9b7907ed483f1c1aa3784d29b54d79a7e82685626d20ac876355ea9c930f07de8e87c682545120a7830d7e3b8e6665b38e6535e8fc3bd8b83ca221680efe27e191e793dd7b405770c791eeea43b2528e2d01166e2618c05d78aa33a5472029eb440ec2941eb855507c3b66f1c6bc61768c9df7a9c009995c27375cf805cbd5769f42bef7ca02b52d3ad9f91c1d620a3593c2b7a7a59e410fe4cd2fa07b6282bdf33bf8e4b0dd5bdffe186f9c6c88ed058bf8ba39f4744ee1dc199cb392061850e5fe3436b08315267cd16a48f96b9308ccaa5672e217c7ae99c77ac586d125769b338c53fb6fbdff92bb3712bef97e78beb4189bf8fd9ee6e180aaf613b8cb2039719394886cae3416f355275a2fd46dfd390a04dd4d955fa908b764b08d5ec0a0e4c61fb52792de0f39839af716978ccd35655c3661e4ec9990267f69f43f9066a469b4345fd4a7f4d1b53b064d1023a6067eaaf4ba58c27f3ac139be5e4c66d57869c8073c2c61e6af24832e653aadccb386ec69f76fad4d12f03fe096c7ae903ed7ca982a6e2e58eb1d435efb694121813aecdc1936c3b0c235a518fdad72e743b0694a2f91a6bfe21d5fa9b12b7057e2c4122995ff61f7d238d09b070617519a6b029e719c8e3c09d81c4a271f7dd849f355177720bfeb5f7f360bcee9226cae2ac9939033013e5c25c9fa6be45a64fa0d8084932fdfd4166f03e4a7c58dcd4212db5e544265b77332c04a9cb35aa7e15c1f8223b6ada0e6747d58254d8d8441473f5726c24bdaad67867e664877a863e88c9f818a103aada8c9cca265b96ace1f770342fab87a65f3efc16b223240133a7531e743ee983bd0ce1defbe1b02ac66e3d7d70e3e77331aaaa143451d428d426bf97a9a87655300d63c1baf565dd0308791591e8297a1918b700e6336cec91492f21aa53e1dfeed7b98156e00e9dd25a824e884d2764bbe6e7a5c5a81c5dc50279e09823def443112469cacc5e262ce2a493b79e9d25da873b746125cd2728d45455d303f6b242cd079875e2819df5fab40114c786ab8657688e48574bb9ebf2c72ede30a3f3ea799bfad169dc0e521fb08bcdc35368d98e51d4ed62058c602c9bf5feaef7c258ad4c29439e2f91f50be07bfad603a7d647cefddbc2933548a9e0eca17f65dc9b000b583646d3c06ab8568264a45805aceffa7df0bfe3fed69a60289a35ddd0c0e3fafcb49b820fa19dab59a0c7776d97bb0f8a1794a2049e688d96d8f7e4a14a39e62a720efac2ae7b57b12e753ca1a7adbe6f78002cc6acd061a276642a8140892df3b476436a41a346309d06212ae1abd134bc09483b6d056c69539a92b0b85d0bab083f65d503252c56a6d0e4a6ae2d86f677e581b17db17a9bb055b72022c64259d66a671e1ab438447a38db3cb373142074ad922dcf406bc51d110740f5d23638a54a2265635bbc3b35b57ea375ea6d4c79ebf2702afa6acfee6183b23c1037d399853439014d1d0f9cebb505e130bf79893c78ea90e29a6ce0604ec63b33bfc684a2a6c13813794707918a10c6b75232bc8f7a9c381d117828c175173dcd8b4cf8e4088c9ffeb9267a1d98c9736d2bdeb80250094524415912ad262abb9b205d9a585c0f06213a462f393b68a5826a6cd3aa0dfb99744da8f90b0a13756227e3556347e74bbdf8f53c453f21711f7e601c750f6808962f64c2df901df5f7e61255341b68f47b244a31c10e987342d1f7376349b98ce3dee9238205151f1d4ba1834a4b50df0f41d25b77aca10da9038403c2c1981bb3eaf77562663cffb9e482f1fdfec68d1ce2b41a2df646ee113f4b1d621f1eb962c56eb48d30ba0a83464b8be4200b3d395e8a4fba7f1ad9039de30c1e603ef72ab7f13ab988b418c622426b1154bb18b891822d670cf0f2c847b55d8c0dd89b195f6b916307fe7226c994cd354db40dcd4cf1a12919b4de6af2c3e1f751e2988f3e9614352c7dc755d2e32bbe08b12b27aa0a2b9d5a479615a2cfce4dc8a9222010957be8b64e5048a45e283a3f73926803546cf38b049c91d30f0cfadbd4b7c32dd3e743202547e706bc563c593c6a422a1f79ae3d50bafe5d955dcceb591b13812b7f51a0642ba5b1a565943d4c99f5c10430d5ed8fa7718db4b313bb152fa52d666e99224f65299819d2b674fb09879f1d8fb2cb5fd06f45dcd30d08b8efa010e55f0e74235f0f73815a715c99a901a6081eea864892971718efc187d7b8811bfa66cd2fb31e1c7c78f2e12b98ac1f7f12d5dcb0a4558f78943dce6f8df7c1d2970b45a49ce95025a128cc992675f98970fc55dc53e3bd195c7154777d7772c0cb08c4773adb5019f798ba83a7ea51bd525bed76d1c56a957aa5dfa8fb2086d3594d2b5e233d973dde1f91e6c3178902b54e44d593b7f27018230d713a48b165647b9c9b9bf82b84575ddca86d4a58848503de36afeb86664dfb3d4b51e72fd7afe80886ca728770ef03e76d5d41cf956dcf09964a9378862804fbd64893bd93a8b8f52f4b59b87ed3d718f6e1508db2f0ca3074c94f36903110a69346c499935d7bcd90f4f0667ef232fc0fa63780934238c78d47712e6d7c36036fe6eb5b5cfafc96d4d6fba6b45bc54cc1061aac8b09adf61829706fb840afd1f3f0eee96d2fcb7d2eccbd775b660b76c86c53d87e58e3896b51ebb5f80ecd2b7ac5e6fe3b9c560745d6e19fcbb74f6fad156a919d38f3a1db4387ecdb57d3bea18e60315ab53afd2ccbbef52a55b8fb558b383816662adb019f76ac4ad203d202f647821d5e87fcc380d0b5e47409c668429efad14e52a1041cefcc3138cfb2683eaa3a3e4029a02882201b185cbb41ac6ac3e77dc6cb711fa9cbb456d4e632e847431db4f3378b0836caba0d6212a0e5d5556adc75d77f21b90d12252dae2c7281ba3061243218f50ce9b00dbe11d0735462c4c3dab7acddba2a6afd9f5d3f9c9bc842199ca688074dc8c23d731b6a1e85ecdd3d5ca1cdbcdb16a7cc7f502ac321a51cd39541788e21c3710aa66e847f674a85102bf0f9abce4428085b001033b72f907dc4d7b68cb4e5b3ee13bdacfc4a3e26ee061068373c5390fa2f8b99dc02410ce13de7133cd5524ac1d4a6b9e8e8b6714514af275b0568839e420a850bdabd1770701123e5b35067e855f74d58c0b25ae3461fc0f1f33648f5a6c338254539a56f221cb5f039fa718c74a895915960a52489f9e4b768b60827a2653ed69d353055030b9eba31295f383b27b5fd999a43344fdef28717f7fbfeaed70e70ea0451fd63ce180805a751832fdfa4b3413a6a5dabcc36c19ff3c41b4edd0d108a50f8e00d9508185ee66516f4969efdc72fbef1313040cfaf10d4e7b222298bf39621a102884a1d42adbc1049d3156068364fa692783a2f7cde7b847154498e1898aca50283187cee21edd30c7c21313a3b4d00f2ccf76deecc9050a7f3cea7553a919346499f943f49cd38a6e73ba8a784c15a2cfe3a0b8990f4091c2cd40449370b6327f609eb36688b8fbb697a45a50fa0e42451f6a88136a4842ade99b9630f45ac7d09eead2ecb6b1100046986c643552c679b647dc1ea6ba385b8a2478a7f502aea49f771a7350c15ca9ea3c5e76cbdd7bf4ef0f9418225bb39ca016218a35a78ef4a55ed862637e4d58bf99cd134ecc1fbc3cf432ff2a1af769e589cabaa415347058f365c7366779d4e942c98a4078f4c7a6de9762d6621bcbffc1303cfa2fe2d15c1278a9ee6bc6c5ee9c3a79f4501dfe92e85768ff8aa1f6230690b0d67b557705ae35def556b23b82bb39f5f3a6efb56548039d510d7ba64f7b410d183e18c7d0d7c77acecc9ad41620aab7c9a7b67717b0375489590708190d9ede304bb475c0598f5880d1de5b6bc59d4893130aebfa59982d130ca675c4a0cca30893253d15ba2d7153447d87d2baa29b61e5abb677656e641402755ee64ba6af864bcd6e88b0cc42c7a7cb0b747aa4462240cab66c470b23a243347ab8a04f96ad98f56a047bfd52af46226c3af2de1958c9c160376f0f816b7f83a6ef08e2025d4aa6bd5751acf19378a1c19a092c366ad0eb72043a3d20b4a301f240221dc43093a9d2e5dce8089bda2f3adda733916528bc177e7d617807af048b2315e23496b0aac087da0af6e8a929482fff68fdf660300e6ea8207be51771cab007794ddf3a86d32ba9cf40c782a1f31c665c7c02fb5dbbbfd108b5793728955b1d1904f014b534208fdcaee17b9a2dec2c357c24b647ecc7d85fc2ee20926bbd8c4bb1d4c0e45a640bee0ca37b8d4731b61aa6996fc26333318380561d7193c30b25401e19a4d511d7050a08c1f4ceb2ac57143f2142166c4b4270c826a004db2621009fcc4d935005ccb62ce825ae943f32a7b10b62a110fdaf30f244f1d2e345a4e7ceb235000b09aabba60df2d694abed5b0c0445a8cd52af36c8ce9f3244d3c518e87b90201796de0e494572fba43dcdac6ede88c0ed9cd640cba123211f3407eb356f3d983e53eaf7f12198aee5e55c348780a6385203a17254249c7ba8906f40232ec61f7bc57e14ca9b28a34069b178f0e69862416abbd6c3a380425b8cdde9f1256b573f19dd4cdb1cbee8ef0d29653f2229a4f3615c80bb18b743b1670521ce8570145cae8e57929f928944b8b201b1ad6677996bf2b8f36324857c75abcf2df2c6cca041ec1a080a3515b70d835cdd42f97e52dfb8585566031eb48e781f06d18b264289f7e4449c91a648d80a89fe185fbaf3439a7abba315d7064bf54c90c09d35a77c4892baf67479d90211d6218c0f438647bde6bd76d9830d744924b819aacc4d90b5f6cb7a41750426d7496507b0de36604686ea9c0a1e3706b5977abde6b3e2cb3fb2adb17faec1b891bf99b9009a6d92adef8d1dff65917514bfefd4481c61836c0d2ac2403ab7fc816e3916413aa9ba6533cd923513c5ec438f29f609c737d274b148bd43405feafa9d28b44d3e30b185bc7a040623c2b51928a454df56b87994600292fadc72855c66a8079abaaad1bd5c6e282e1f687cff070413038da1e106901793dd950f0c3686ea8599db07f5ddda720bf9a0e61183e5f874947260bc51f7859c0502ca653bdd94b94bd5e94678f6da1006e614849b7910e11147d7750e290d051592467eac8606840e282482f59280c151a4c7bcab751119b087b899095c755b3b720740207b632f2de6068238082b5cd1a465e248177e7cba67dcd059acb6f2e88ca139d19105fefea323e211410af8b6d5a1a013148309e8cb8f900f1baab629ca62c984f8931b863ae71f0e695c43c3bbe8a0b515b4b346be04c317c3df52d86d48b61ed14211c6de9fc41be3e30557d066e378c2dac01065f60855de0841d49e0eb16a4c8a009c20d9f6a725782e7ae17de05130d7586e082d1baefad69032952c11bf78bceb0de9edb05b68a887f176e8f4999164716ddecc4252f9c2d449a60d132d0fe1fdd688a8954e461d14af4da27421bdfce2bda699ae9ffc1bba91e15f1b7f876dd0adabae9fda2d761b04c4627a5d1f446b0aab34c5984d4ebecae99a7d0ff3a89206b747d5d516c1de7a3f47a1e001c65e1eb85d2886441ff84a2e9ca390885e5f3d0e53d1df75ca4ddc46f5c762f466c45bac7cc68924ad2b0e9aa9e32c205640aa9ef3cbab065501b272087a32d06677155eb63d0cee546ba77a56318fda409b2ca9d18480db3dc110e65b2f6cffd272f2ff46ca7773ec45c3a5e187f91c0afb3102698a6382eaa598a59250f05d411c694f1536a2595967e1e0efef1ac2b924ec898eebc7541098710fb4ff1964c1399e25f40862c722857682a4c077e9e624cdf1a51c26029a5f51ce7da25760ba2e3d0295b7f5d591964462b5a5027a70f982ccb45725e50d7335fd644048a6dff6ab15c63722c584c5d007df1f85aac37ca5be1a9a30f4913b0d01180a51fd8a6e0e4ffc029e3d3cf37afe82338c0d89f46edc1c85f29473b02c85933b0f82557bd4d23f81fb0072a4a9ecc6abdb7867178da03801077e1ddf7cb64fe68a61521fbcc456f4338d0d40de81c6e46343ebd959482ab02c3a2c7bdb75ccc43efd232f6a92ee456e68bd0a3da3cba0da69a71361fa3daa4d8b4ec9f04307952e0aea2a04c28758a4303c87f67e9203139e431b42cc2336213e768766b486b5b23ed4a51fdce70d127abe4b8db9d53fc4562cc52e2662284631160331c56ab1e869ec4f384f639f7d5fc1af951e3116023973cdc671d2ff2e89c4e51839e4199a95f29f90e83153b09fb5531d6899585ed35f8461097dab37169e89767cfbc01d5c67ee899bf12faa9f43dc374450c4e1cb599882fee0e68c18e39ba83743302393a046f0d6996319aafa364c71969b4353789717d5d06cc32632f18bf0d96d1dd2156784a5250d90d703722e47f184015f069c1070f980b1c1eb325a9d7619c7fbfa3bd5a194e0474888210a58184dfcdb115df651d6a478838025f0ae9de57f599a09f07ec49e6dc7bbf7aa5f953a77e0aeba8c83761fe9d3308eb95a7d4879c575db646ed4b4adf65f0b171a0937d36aa53435d26d54c309dc187bc3996c3399e4c9c3c274f2bd3b95920a4d20605bd313de1fbb1b4c7469c0553a9e2fba27b293f15aa6a2fd1f05201a19ef18b1c8f5d8a0d4cad590f0df9b560b1dd5003bf1ffe04cd5a3c40b47815ddfc1fe822829a1197b1a16a620c1b2b047ae7da19e32090bcd9c8e2025c11d6fa577d3cc72ec3eb55e00faae8eadf586827997378a5ea0c5502872a89e374049eaba717809a6cb093007d8586efe2eb91b00db4e9c2dae8f9c6499da63f41935dea3f01d1b5692e9a1a033aeec7f73cb4c4c8b06867f4d7722b0c6d693ef140d907ec460c8b57d93b4b4d140e46b449017d6ffb8a3329d42818d01312d0598981fb8a67fa24fbbe9d8924bbcc4cff94de64983ed99c07c25b72f71c062714481e598db80a78cb7f89d6a2605b8055b042dfb9e4361b2f63192347f5ecc2cde30c3c130acb61b97da330ff27e766f54ac2b8c8a825f63b1b70082f4941a51846e6cdf2098535a06fd2c3d19b10ddf0e9c17239badf3a3151ae2130087d8cf9652024a00129786c3bcf905269240be6f789a848d944b0f090e3293dd0b065d6b6ba51669636f8bd14e2019d210b66b0d05b502fd59562ad36093a44c813939708a018207592e8fc35412b735f7ca0739be379e68caaefecdc474ee42f1152ffe33f22bd740595d9edd6d99744dbdfb592ece7301b1b31bc0a28b5b4347a0132ca72f1dbeb90b7ea7f482fa0a0c9bec57060ebd1a9209d8ff2fe13b0bf9a413f3f24e613e197b7e27636bf251c24dfb985e3cdfef70da70dbe0aca60baba18d2c6881b9acb9e9ab60beeb4e12da35134eabcb21e8f523b60b2a58d9b8e9b2ce857c8565cb2a47cc84ec148d1ce055b09055b696334c46590e2624dc2a8cf82a0893f987ad5400396923fcde655ec175d5ab81fa5b47414598734eadd811747454b49d9c4ab981f9728e9aa21427425ad134a27c0023440605c4ee1f08f2041bc6628ef2e96a97867a56c9bc9419195bc36f802eac5a6da5408d0d6fa248cb655ff80d7a5f3792b46df573f01bfcfb3c8f82a7e284973af2f445a8d11437ada8d60bd953ab24bf60cd4b540de00f298a2f5518f267f2d34a0a0a51ccbc165c3d8eb5b04538da0dea99acdc3ae943c5b59aea2a0b2c38d413ce7595efa6147615fd63e66e5fcb1f60d54d5852ab82830d3b051c450507e5b0bd4d9fe0a07c00553be74dbfb5778e001b311b59328443e9e4b303e538d0ec13710dc281d687fe7081e8f9786de24697264bf9ae951012c6c3db285efd9c3bb83eccf3af377c9e5113e67d6933887ba2f25139dd5852c51a11903ea4e5bd09462029c7c9954bc37aed7bb74d1f032fecdd1a9ea26ea4ee17469b66a3f39d6f0b5faaa5ef037aeacf70c44eedcf80b0bf5dacfdc55cfc07bb12e353f728f17e06f2074528602ce38bb05cbff42af4276297e50632330c95f7c4ac2be24e762a85cad25c21c43f62fb878005a3c84a5202adf020e74c391d295f9c85b56c43e36d2a710cc7afdc6ef15ac6b1d1f06a84987b17312dc7c3df95c503d74ff9328242b8ffdaf0f1bcc7ed6d8536eea9bd6f79cd9a747d0674d8dae8a46632d6bee30822beae5679fe16d84bd576965f04404aae3ce81989075069397e17735af3f3d4857614ad6c43fabfe452305c69cc0a2accea28abd53138e584285900657457dac55d128a1d3999cb84874fcd0818e5e29a4e473d1809a1882e91d81579d9082e400d55e820bee615961f2b27be3c63b3fa4e0d47d0b07f2a2ee79702acac58bc5072dbced429600256a0d72394806fc2e3763356b07d84d55ca7c130540ded74c9210f2c7bb1620c21fc06c8097715a057b84c3d11c8a3f3ecadf8e021d3b5a1d10ae4517ff18bed3d94a960b6bb466ff750d523c4bebbaecab6219fd4037af24869d785eb1d6106b34ddb26c26de55a226f868a7f157db0ea5db33ec4b45ed2786ec9c39d2fa3d4b1776d11c5649ed1286bd1add5c087a26e439bd6032cd16cba7684b0974156155d8eac23246184305c65462f1300532210a568eca1b8a692ba7c3cbea0a8950d5518e4b9b623f2ee2308dff8f8faef257ff87c131c99f2ae3e3fbbc31ad243470a8355b9699aab44aed3b910f42b1c0082d72b2ed82b3639e470b5b9e6319b5f9f49945dabf7fdf3311a5bdafffe8ea9b069485f8a6fa201263125b487086a296170a6c6b2845939e4937e44398319a9785e54922ec40ab33a1ba7eb8bee9a1cfce9e2b691211a39e7dd0ac4699f9ac91358da2bf810d932b1b99c509bf346687bd6073091b20a28f6e0d1f17b0ee2a84921388a5f871e1418d6ae984284f8fd98ab220ffd24b8dc522e9c882b6e1e204d876a34407a537e93e467b9f2eaf77a9f34a672810722ab4248ac4021f66c5509000504447da116e83553de6bae361b126b46687506967ff0be66c88bd8d9adb840770efbce9cece49495ec7f2a47dec3e9789f30284fb35bb4dfa1b66b7f6d1ed1bdde1df39136c6a0ac9864d92c153a4d47027597eea0e6836ebaf10ee380f00d15037b44820a152393928c5cc659c79a81cdf07468672b5bbeec0435001748523bee6bf4267c7f128eac152f089724929e4df8b7d48f999802482b25ad3c844abd7b8054a9e8183106ad752fedd5ca464aa32115ac9afb1657f37f58ce9fea7686e6de8499a49cd6d6c1f1835da0b216782e11621df9a05701d12bb51a2e233d30e8c18df7793977bf7d03738f06f333703994f650acd3ed0eea465b3e1824c3d4beccdfee2df532283ce14642cee36171bbfd9b1fe98a39a58ed145d096334a549ab2d4aa767136ea797adb7c1abfeccd86c3c602b0a80b1982cccea04a418f6541cfd90e4df1dce2e2004c28c7f5b3191d001a99757b8c48aa26e837672e11074b60661fdbc80b139c0b5957e71a3d564f8574afe9d6c36154edf722e6c524fc758965245a8a43d8d9b7085c7cc8de83ad05dd60f192f5499eb53b36133874baf7be63869633be421b21a7a581511fa0783d478ff451c7a54625058203ba3f348971de14b07b9cd63f019fa28f4e27c87d5ce3f9c958d753b00ef8b06177cad0701caffc8ed50f083850e6d147797593f2c89fa50db4558363b577c5b50e914379df114c65ebe50f105bffc6d3c925e7af388c3d48472d00214d1d3d8a49a3e63ededdb1d8943f34823f49f0618fcfd9be2e6d797f3397623bbbf2da371d2e84ba65baf2accc7367ca66d513b394d0ead70a03949df645c1c7bbbc48508f11b34392fc055b9d9d882ab5d61aef86d7a51a058ad45409a0d1e6efc1b427860367c3635550ef81c2f3782ae3733612d9f075764866488e707c1a633f03b52c8c9338359840470bd340359184b3871a46e71e9857a9031dc6f3daeaeb5417b60e8e7463b8abb4b1fc8ac6bc063a83fce47469755d8e11b9a99c21b26307e53b63e8d3715d6b29049204237e4cf708e82525a7539d3723bdb01422522646ef9e4c4519c29978f6c4a694926688f83dc598692e82ee7f75b9c3df431da055d5b131b4456aa73ae1b11c42af92230482e7d76811ccdb25a217062c4d039017b52c5516623b0b56f0a0f81643590c8f5df57184b99661a7fa7208588b8655465249287df1b38b2c070c961b1b7f0f0c32dbdc32088df88391191af5a034a882485c1ae6acc1137d09db3dc0f1032151da53997d0e487a681ab7c52db5741b32c41d13ec35987d2bd07dbf2b250c4513a68da8e44c0456c8e7e7c5a0b6c84d53f84cb81373e499fe271a2696c8c5a74d745c9806b4bce326a731547ecde01d61c38723cae7c57de5faf8605ab63caf3e733cc99e28b77be96d4072f80b7f0e42139b991bfbc6581e32ffa1c788ebbdb63addb62fe674a3da30fbeee4b006685b7275b3550536cf613500ce75f852721df9d7c01a9ce48bb09038418d482b81ff2f6ee1c853d91c894381006cff461da1c73992e3c14e17142c0c9f197cc5f6db0cf50ed9ac10ecff33df667228b58c13574f4a37612f38cd002dd3d64247a14dded909a66b33904d7645e9ab2d8abb444e8b5489d88652f57cb702ca62676016a40fb766953c34a16e70291a42d14523c94a109a203b078dc4ca5a172a96351898cc67d9ca85a10e31c7b78409511ec64920da738137838d7d8f522e03f20ea3356f6aae0935d3e18cfeeae72a0129cb5b7e2eb0153090bcc0219f63d164f14e9a4b48248e125e78170869f1ce162cec0fddd2871e714c66c5878cfe3d88d7fae518aff98796b609a5e89219b2e151bb50f3a024daea572294102307dc97c9e4c60debaed2c7d748f7f07ce2b8e01eda0c4578631ec3552c3107606bfe5a8980aca44b5b5a23a2a57d7206fc36bbe47f28a9eb662fa7538956eac37a299638e3c56b0ec71eaaa17119e5a02fdff1ccf849bd4db976213d9bc4a77fda0d175443ee61d48a56a2cc2e1c202eb22070092cac9746e01d4e05fc5a9c7354c53722e0d3cf55a68273d67bd0baae7a2854c9e0c6661bf7be340b12fa00d00b8d1b753adb8bd2083ce3d59d24a585fe72799e80d2ed18d27444cf538cd441d3cb979295e6d083c08226bdd2048aa3a7e34d51362af7242fe32b2bbe04a8182877902d0d26febd863c061a9e2eb1e4f4db06c5a8f3e252c548e8cb65cbc93506e19a8a1194770469e9c04eeb02064d19de96879884542e74c73c4191e996696d72aec4b25c54dbac486bd45e2f5c6abdafc83c4edaeb2b6ee436ed7702268134ed34da1fbff749814506d96bc01ae5b0e161c49e1837dc6b1dddb377670d0cc517f6e928c5c3d7eab12511047b5e91a53838d4202239b120cfd748c67a9671b247d4dc7334b14054bf5d520653275e64a05f0d6388ac5b88a33337952d8f1c8e517b8f807a45a375db2efb3a3ee76a84106dc7df30e17342c37360a09ab6d10f4a5f47805a683cae46a890121415d13cda5d286a38528e6926ea81eb4927a6c71f8c5fb398f974dc6f5d09b1e425ad13f85a7089e7adc4a9a85d0b9d73b67d8939419d48fc5d734caa5ab3e507f1c49af4a40eaee7f24e0efa1ce96f68ddc9ce51db4e49e832ae5eaaa909930e321981f510a8c003c85a6ef02f8a070ef83ba0f1458a3ca4679c8983f321f31683cbe77ff08e407be344466a5adcff82566500597fd93ff679df54892d519260f2ba046ae78f6b7a57d2530b1cef9e4a45e664cb324e5528832b50a13a0fc8a8b47fd5a9764c71fa2a3823dbd89251bb5aa594e213a94fe5f9428503c7267e3c7af3865846cf8517222927f0566afaceaa5b518bc69639442744c14adaed3bdcf4a18a4a518a2361c7e4bb3d73a7fbc794288d19e1c27ca227f70b5739d6d74adc7d55d5cd165ddec435572704cfa2e739a69bcd95a366cb24f022f288f05df439624a9bbecca25c739d94c29fc739574f59739d34692f76bad76bd2447ea8d775d2aeaac7efeacf0f4042e2421a61bff0bceef99641c15b4b165dd117b2d0aba17bf8fcb4798c5f8b0403269e5b6b2b11c2a91c08238adfd4bc6e59df66b6e531c095eb25a51b54e83e7143009827693a079ccecff637f2b408a52f4575af7b30d66d1c432efa79a0078e44eb449b787d5dc0393d9ffe5c1bb570e018ae67b2349ce659b5ebe6fe2ad5881b1e401f400fa07deb32b3147a74bcba93fc8b40840ee9785da69e1ca85a30729b9b27b2417d2bf097cd16c7c650f3cc3a459cb17deafd58ac34058e6616384e7e590420ed5ea363d690c7d1106676f8899ccf0cc9ada24320cd5f0e57573fd2120bbd7aa1e1e21fe174605a71f52963243ca8318045a27b38294710ad328791dd6a99c4a1f1e8ba621d81441996deb6b881751525a8cea3cedfb157eece85ce0b7a7036ed4687d43dd292c4e639a8d4d815c419da6e58b2a6d23216e692495d28f73475b25b5e0b77c730703eaf92823271bc96bb7155a0e522b074c8778bbc16eb5905e633283556695ca1846e9a9acf332c0aca89d2ba9e841d2870a8d61019e60f1fc0281a40e905acc0b10430ead7774645309dc375bd91ec87af4069b987b9599318127f27f28657f898e639241e9d6c0089d66d5c448a4ac81a0d3b7487d2bd66dfcd5c8b3dfec5be7b02bb32b022c8e12f50c0b7dc27b974003c60133bfdd2b414a9b65df10453bface8e2024db4f4d4e35d63beb437e80bb89519af508ad24e49f26e022fd76f1b41864a4ee01c0ad085dbbfacd1d57541c79bc839ee986afd2286ec7bc658cd506e1f8e51ea500e01e8f9fc657f73402143f27899407a66799a5d8f29da5d68bc781f853346a7a68320dbafdec48023ab9c51a38c88b22f224cb111ed8cddcbf02b937194fec4b1a02162fac125ee2b6dfe995efde2877e5b3e8a3d25a0072411ba15820800de1b39e3ee0131c3a5047bfbe9bf8323a49548bdb3c660cc65c1aa7b2e2a21f0a804638241599b0b842901beaf6e91e7800563997abe68f7a89d626540e917a0f1bef103c86b10e552b525a60b07e9aacdb4ada7dbddd66c473fb6368d5cd95d9cb8e9744ee2b995deba890d3e6271766622a5a53bf1973c97f14a0394d7b29f342ebe397ae1bcce36222c8be4968981bd7b87b64ba3bdcda39aed67ad2435e10f4ce15897be6af0b4406dfde2bdb06c3be0b6b9f2e6826b5aa4f8cc5e3fe0709531582d6c67f8f8961a265434cab5b5b28614cbdc2ebdae3b182df5d579f1540da79d884d14e654d8c91d3dec7a9a8aadc15d1d986f0ef61c9e7cd2954c2639aa8387fea1442b74ae2cacdbbcaba347eb5a7f12d5513b893f63cc8258bc2adc8a331b251a08ab15745684f52cc9f510c340a07d98d1caa792573a4a4352a744d7653376311e9a3484360cb6245f67e16ee98e0917ff1788935b9bf1003ce137e38bced6fb2bba609a20207a200d498310b3991a1871320012bdc014566e8154755fe82c80fb02f6b15a129440f5eacacfdab9c99cb789a4f620db2e837705536d855ac748426fe942c629aaa659eb3e28d080afe923d326817aee912df35168b439897c4657337f1eaf4c19b0414f0110ad672409c2dc4e550b4aa1fd87ece807ed0fc3f50114f6d5f8398b05e1e3ac066dd25ef2476b20f4795173b7416de8641c63ff3eb25adfdf5866ffeeb7b5c0f621e00d3859a4eb9096c52e28b58f11d4aa077defe01ab2fafea913f23f66c00da8a0d5b5eed27b80459b2070e14916a49da841c65009379c886d44bb66607b4ab058c099e407d79f8ef504420697dac553bc465b5f3a3533c61f0d5fa366560472ebbbcb250c7a7c444d1e34cdba6b941678c8f2f78213178101efb12ef951d0bc3bd93706b92bf963133376c64c32ff29652bc05e9399d4074704e84e63bac30329b038020de14c874d69d1b488890101582a2c7b51384e84b4cb0f8d62f6782e4273c9c29afe80ee2e99beb76ae614a57d5e9251688d44e6a6c1fc14757660c2f7b66659dd86a6fe1d945d40629ca48b7119af9200d61b4f5f3d59256956b9f7807c1ce3599f476da9be3733296d92b55e0c4c8a9efa7cd15d8b4b6ccf22d9e2a070252162e918263729b27e208dafbb64aedd5a38ead1fccb4cef19479d7fee24d8e5f58ed098cda88b283e2e579ebb2c8ca41732c510e1a85f6e6832beca86786206795f61d6e9e94119e51b4bf5ce4a3d835526b5c51340fd1fc26f3a0db8f56332208debf28241c004c17aec6964a0ce26b237c190f941c8007a0257686483c69f7532a04e611eff34fdfbc27ec8852287d58991e4d19904dfe12261498ae300a72ce3dabce2dc649c1c9f099da67b6b09221b555b450d043a2d08e25f8ad4c44c25bc3c5544438107cd4dde27452300c9aae26a27beb941545ea4365dd267545e5067839499aa8091754b12d7fd09cb5803d238ef710e847177aa7cb3c11b8d952fd1a174021c6be1025b30f7e38c00b9a4109f6a8bf9d35d7879fe6516e9f55cab66091941c42954f361c559be59e96ecc656f565a2982fa03bc3556e05795e05780cc82df73d3f1bbc29c1af1890efb24568265bab42348de3ba37bdb60cf8e3cb72b4b526a3f8be4061eab7989be68e262f6510c65b03bce510466178aefd197f07b9ef9407f71e8ea05233308a7259e302ffe4a004d1c6d30eb9dd8e8cc37d015e4569723f6b6fac487edc10db150aa67487b0350a1a1c8eac7178c1393d1b4e19d12c1396d54d8bda62f05c13cb9b0f2bcb1cbf3b6b327ea390d76f76eaaa310170cb61aa9095f782b373a6c532e7f5ba658ce111be9d11d2ef7e816253ebe2e2daba92fd9fd119712070917e6746c845e2808951ed983380e1380eb8b52b7c0a4f80c6075c7fa7af03ec279fb6cc5dfc0823d1fca8205be71f2d8e3c8c864e5613948561962fa7cabb77f3de69780baa9e34c4021e1b2ea1ac00318f6dd0b6cfcb21233603a6cad162d6a350e5ed5688ae9126952b04a2418b5353a402f1f531966b2f2cf2c43c6225ea75e1b02fb73530ee29cbc01d33b2da2197c7ed6883c00c371cab43e404abcba12efee3274f1b890515bb8cb183bcd08308449a7195430a9c0dc7f9c9ae39415f64f5f9384a984a2469ce9f7548ac4cfb64b1df398cfe01afc8621880a7c486265f2f5c633669a194c91dcd5b767659cbfecbbb1be00236267842f589e3e37fee07abf43d3cda46acca40213a7958e51873b12406aec037ba22bc165c54da1fc3846aa643a90ffeb770a07b8cb53f96def443253c971879a49f1eb1232a1d57891ddacd1b30b1676c0f06818940c8a29621d51b3a386eb10d3f38c03bb0f0196f0203e20216897afa4e44d2f4aa030226c558d8e5c664013b4a076e5256f74e48c7626d140751007b6cc0cf8a0238a931696e5723ba7c3188e50edaf2f60049aca18a21b197bd58e71556eb763fac7a3772ae2549e205b5028f8fe0c13e9b26fc5e11f710a0bfc13b31a5a0da6ce2ed88c5f58d155b5ec0a55124211a63dd005a93cf2784549b64619a901358566141060ef5f2fb884c13e66604ec8af20b0a96d9b6b5994bd5e4e4b9ed357ee7b6d8386b47145828486f1f70f632a22b875c0bb7f00dae49fd65e3e9428007d61b6421c117d98c6fb4bd67953bf50ce4dc425ef7cdd59fa3dbc250b8b359092686d9963c967cfd4064dbee25461ad9c26a3becaa95365859692db7f939c2f5501997a7f7f775d51b79fe889ad80025dc50a6a7284278ea852a4c6ae8d5c5d5d6c48811b6e029b23b015036fb7d134166610a6ea63622b1c288cf27364ab036c1566454484c19d72462adcc37e024c20c3a0f2d0653707f4817cc4f2bfe5c77eb3d2329d0997e731c31238277fc769e796fd253847c8022fd0e96fb196178c91b7bd9169210a0639a598917b11d1c5d5f4da766d1941f8444bc2eff6832eb484b1c757489feb0c8650bbc260099e2edb1c49305079391f76381f9a432397e370c72031a9a27feff6552f96ccd717a4b69cdab7d4ee66cf99303cbb8e9073d9f5ee250b36066f140a9fd8c90be2e4e66b06d628f68cf91a27032797ad61adb3264f8d187768035c12fc2534e2ceef8fc10f29c8aa37dc3d5265c7b1fe0bd6b59b050ed3badd1bed3a0f7e865f16c000fc3361c6e35d2ffb5cc1579d9bec1bdc266b2c2c6479b06f9e0c7b8323fed7bb7138bc2db8f568d313f79c35583df7ea39bb4adfcc5285107c43bd9a22aa8d6c51fce4b344e33f27f2af1832def045ba3f6034292df442e4ae138a89feef3baea356372425c7c7aceab101f0011e8b99d3cb80e729ad4acf7b4e959a1b161a481549b48a142eac39da428de12d61fc45e950dc0b2d3952ed119044507e8c517429ecc0477487300527b5e4942d6cf17cce0d9ea40c53b3f236534ebc0777bfc086724168ed2cc36c30d8c5a2116664187274ec1c7804618050ac748add82ac282e9a4e189b35777dac509385e03f999da36af4fc51baa7ecd0bf09bed36036ef9262277405e18a155ac875098978535ec58919d84c897575a650b632aed3cedb16121f996fb6cb4619d21d9ae2710a654ea47ccdcee9265d0c7adea701e6911c3b3621c413d3ba5e871d136029d87d59a6e76098ff26d661913145710d149c670c46e008a54ec5e8ae95c056885ad5ffef161f2a4bd08d46f0ca5b9313d2d1c4b5a5d5e86ed61955e6e96aa26f7895ddd58552a64f519ecc18e8ed89a2c39362808daddd45498b9ff0007fb700c3e849f50fd76030cf667c9f83dd82ad05564881cc991f0739578ab382bdaeb6b7a911cf7730808146ea6fbc0508fe30a54ef5edf1fba645955e370fb1dd2b6d15a0183167caecce36cc2649147ab4dd1ac424eb2999ebc8b4802233db4e43afa703c34fa7f9451f32fe1175263c56502920f9f1160a49c194ad6e93ea30181cca0e3b3d088fb5ecacb006a34db15b8a4b59557df0bae14a15670055463319405d4c4df8f059fca49a5970158cda3284c77f677a9059b332686775ee58cdb2f2e556fa446fff3f0124aea959ed705dae9de936bf60e03ab6326e64cb4009972cafd6a4cbe9c64db97d8b0e500800f5b9ed49025cff219cf237a59cd6601ab5028fa1bde98954e063215ee15285352097961a0d126777f6bcde421edad8364598d509c2fe2ab6cd38f718af3a69ae52e168b210d4455605ca4c3e6b68ef496cb8ed6482a5db62eb7cf489d70ec5ac73f298412c3882a5c921a615975738d0f5520805c11b07b18f40e4aa021def82109413920c16a2d121f49c64168db13bea7d856a39d52ed172820804e956786c0c7d712903d3abd41f97ddea003509c4cf4197d21ad9f2709d8077883a521402c39d6e454133cf1063ab3aee97cb7c7ef6630e719ae7de0c664e6719564da06ca49f3e9a9b850128531835ab9c0c55aaf570fa72fb429734a0fcccbda68060e164cdde2bf4f62c28bc19e81fb8422f4e3aeabc1a9d0afaf9693d47d5648729460ea6ed4b5e189a6adf65222535993bf2a110eba00d34150b90a1b7da463c50542da5b5dc88152692ce5a81525c6b99b956735e6952d54607e2b99d31c912041176b417d37558bf62c49e4a9c37e44fc263822a1a3ddaa24bfd48095839140d607c12533183e46ca0702e377df5268aeca66a6dff035988ac01f7c5b5002137964f5b9ed409712a62b522a78acdc80d7fe47262ef0084df6d76eecbf78a3ce3b9d22a4af76dc3cd9b2fbf2989b0e42d581523a734ea783532008d0370cd3d39c00efce9e9db1dac9a4e41443da89bfd5b74158eb5b836d9a813df89426917ea8541dce1665b4ca06f4a0923d46279f28f984ba833dc075e7e4f2d5f9f64ab7a1919a998b995a048bc3cb9b22e1fbb5340c3079f699f005e1b8506fe7910630f658dc827d80ce0cef2f441c5896c1104a51d57345168c23c267bd7599fe14a9f10301ba2006738ea7fc207a4d89f32d0471af91a61cdf6e7c88651526c16d41071c12ac0c77066e22b72057468ac1a6ab96037aa5faec6d4bd3a90396b042a7fa640307cda7990b29e65b39905db066c1461502f839319507e8a40021f60cd458386f5db3a838378066b8e61cdac1a2b94eb25f6dbc8d9850a66cb8676b375457eb0391482e161339ceb8845bc74db5e9219ad8e4e4e942fcd2828b96a7d94d4555d94e84a541186d9e51f492a33369bb9b45da05d3106b5cabacaa196f33d57ce8d8598f19d400a9505edd7f602f1b36f447a9f25835357cc5e68983c6e2afd202324977922dcae2cd1f6ad07db674b6410c90131bdfc3db7eadde9af81a4a25a0ac6be59cf2134fdb871c555d151aaef252d4f45f76a40c97599ed3ca133a9a3e4bbd20254e9b214154f5b453ef89d47a6604a395081a9ca3200076469f7db022b26c0be41859a6a7432525d91a7f5ee596a896fbbf3266b54103b02db964c86598ccdc93259b4c23e9ad446e4df58cf362acab49be78c852117a7aea8127b85bcf5adeea61ec00d7f909c8d658577d6a69bec9dc0621ad77bd1234e9a353f71b5f6dec2a554a453657373f8ff4433873c3a6e6fe515a0629aaa3baf62acd28e167537809d9e383caa118b2a9f39b6c2876f0dd720203a9df1d300a8b5cecb0a035aaeeaed0d45e361d0cfe223073ac0833d30cffa8890983f8c3e150f4ff2f2454b08c2c81b97e928b9baf1fba1a4e40a910212f9e46e53288933e172d796946830c3e335f30921a110cb47759f90d5d4c94279a4da301289fe2fd6e1588c62391ef05f1b943bcd1fbd2104253be546ba547cbb54e98c3292c53af544a62e689a62b1162998b7fcaed414ac14a944a3f2eab3b3332618a33558a478b51ed815204e9f58897d20077ad0833efa0949bca9d7a133ce1296a6d6e3cef7459b2a14315d348f27154fc3293e7bcb064381f72db458319c640ad3ad5e9a5089a53cd09b2685d4e293b00b818e3915ad4fd4e5877fa7e451bd51394eeaf880b126d67a29851b73782a01fcd251ad659781f85f824b35fc9182381c43af11fcf6e85a4b447365ab7cc82e6ca20f111de18e388d6aed44dc69c498ad53919399a67cb70139cfc52057d5389703773a8c46b11c8d652ca6c324aebd8a586b1dda39ad300e633010e36832f250710174a0b7c0a8d99a972a4101df03ca4816eb569318bac03f3ec49401a954b574f42a0f35c23e82790cb3910fc8705bb09563dce7ee686cb1ea4d50768bbbafd075d69d84ef210035bd3f9646105651245de336f9c7a048a3c470dc4bd894273f1a2aef146976e9da94153745a366e241651a0615a8b41fdebfb5d33f54fa2052edf3ea8a32cf5ce30a435fb691bbe30087324dd778502071076954a49f4922a6bac2db55faca7b0a82792d948fda28760dce91b2134c94b78dea48cffa464904dbeb8cd39e45db899691c25b7b9514883d8b26284e4e4d0ce58b6e8ce999e4d32b75df8f9842bfcb52fd1157c631e4c93baef04b976061e32121b7b29e3a30b56d8c2e74f31fe532b2d604f5f4c5aa3ab54e03d942b68719767125539f6aad4ec69c7f0c9967c018b9b29469018c673385101b6817483f4a00f14e8cbc51e01855595a789c6cdcb2e495172957da96c13de4b189c67f0112d848eb8bab18f1d169d2700a18cf85010ec76d84e26f04a916ada8b82f502921da3638b925854c3cebe6e3a088edba6509512432c1104da7f2391772c8e03158bcab2c0a7b5edf1dda88f73fb686afd40f12de983a58e40f7c4615fbd3c0391f43d4a751cb90001920933971eefde8a6b0161f10909f3994eeb253d7d1c8da12b452c32f99e0b6b2c8bd1c5cc0d11b7a11f2513bd5a5c4fecb95984751066b8dfaf9f4eb33d2d79af7df8b5b3c28561753b900c3606b93227819737dba1325b5fc6964b323664d85e38071be72cabb85252e0b59062d5a0bcba3939a8a2aeadb13c666aaba30c2c727bae2483bfae49d22cb3c939f953ec610136dde613869115d1237152f5b4b910548be3d20a264c64e36c9fd5d4367e5522fc00f1250d04aff85bc70fc3fb9d48dc904b5e75b812227e358e83f1801bed0ab14212a2721935869848f75afea86fa5b38f1b271c2a8a9f73886f0aae985edc737ecb0d2b77d5dacd88943cff688232a09041f75b9b63eb7baac0840a486ecec65226a16a243ffe7c87553c703c050bfb03c3e3a7574dc87bb6a4638ce3df50d7313d800b50d2ab31efc12b9f9d0b94103cfd2ba2f641e9bb9e83a3604723291a86bf77d4741322bf5754e9965b7ffb819828f9b5447af31ac0c965fe6a139c0aa38cee5b2b615d281bbbdd8fbb0d009de4ae5189645732d446864db1ca62c42a9a87ff1cfb084449a537346ad691be56b189ce7dd43658d9326a8ab7c5f5bb273b894fa8b0fbdf1c2854e510fc05ca156612b3f3a08e28a6261fa5d91cdbce4555b98999cf152bbac97ece818ce4bf25c48594bfa93cb6800c2b643ba87845ceb44f6ebf61572e68f6fa2f4f66508b1015c315a174fa870ff2c93ba3640ec9b402bdb72809bbe22792842cd706ea5baeacd8fc2780a2bba82f267272f503e5842a72f8eb84b91331a46a2ab5fe3f6ccdaaf810070b829a8d00582620f75b9df028607c89176ad31128bf94969a2497bd458322691edef8f2fb6ce8c99e99f26bc2ccd0d4da7ece46bad224efa631d2ab7474fade530510c5523a57e4c8571b45bd9ae921a7ffe488d8e120c9a6d2c9439a54dbc13c0f1ace8046822b6ff9e4a8e6cfd11b8a28917a8eb4888697ca799e31992cf330b8ddc12b08e0f6e6f4b5048098314fb8be94b460ce3f03585bbd65b1bff179f9526f1b45dafea141d8ddc433e1edc1df93693cc034642666598cc79b2a9c53ea8d7fb09c91961df8ab83ea25343f2735cb239f332f6b6fe8fe7ccb41a1a34b8e63a8d0815eb90fb214735279da745443590ac137b7556fa28978b62a0eecfef4f8395567a241ed3427edeb29c46786859857f8bc28dbe2ee74361ee11242ab3804e3d059c339a8e86fafe1a61c35a80d3090c856821da8561c3402ce98ef5d267d071b6ee8f8c07cd688763406c68f17850b7a90057cbd64c246cc3ad0adf8b00d42eb9a606170ce83058aa23e6bda88a5cd2cf7c73ce927033dd4beccea2c9b0393a6346b7f548d8b0b47e0d9fc54f6eb9241082230f05318cf57ae29f152e71139bdc4f7dde74407ca7980c33c5fdfd8bd3a7afcfb6b6a701773881a73828d93c80bc0ff99632f7e533efdaff26de34b5399412a2227f2d242b76fcb92fb29106cd2dcf5fb1981c14603e502226b09fdb9ef87db808c4e3f187a615315ff1b1801d74f4510fc41b7001f5111bce97d9552797892e7d882fafdcede8e086625d2304ad1a3c86a55030d0f0c54fccc6d2b02de1a9e20f0fe68d4bed1599f939026e126e193a96d7424bda1110e8ad10dd62f8e7a1b716d860d5b135c9c3c110f61131baf41dc9d97ab58a45cb8cd22ff87459a3482701ddb72fd8a8421de2cf1186324c452ee4c3627a0c86363974af59698f9644396d5574ec4f2cb18140011cd35775c054ad59e945601589ec02b8d6a9c3d02d259dc546bf5ba4a495d7572140d82c6259a3f2e0640a2dd6d54230980665c7ce83271140293bdf7191c7cb82b598d4253a22d6703d694d79e4f66be575e62c613ac838b5f1141af291b44b09d714d5e96a06bb46117f31c041d2af6ed3a3f22fe070ee843340bc950b807782b471d97e996da0102e62afacb821a409f33191d616568f90c900d1af5562ec938ea4de013a841e7a0080b26b9fb1f42b2e5d789db3b333713cdff882d02998766c514d9191b056b716f59a1b314b17ddcf6f5bf064bee70bc0224d51d19c7f553d100b3f6c165396e31de28ad691d402290f0b023457d3f8b9afa294ff291839dbf083086513d7e7cf9691857d4574462e0e290736151c4515c105c1ccbe928178366eddaa7d99ec0c290e6a87d41a8e8fdf8b4f64cb10c38fb6e06cc8683b657ed7270232920f44d5a83fc1ab95c27899717479b62440d136c015ef9f0644a8af2f75663040c56b2a3757c5783d612f02335ddd16e62ea40658971e538dc0019d3edc39dbc8fc045606ab63dbd2265340644471ee8b6befaa66015c1f1104d53026110ea85ca51eae11f717b2bb229301a362ebc2f92dc2ba0b38fcf07e86269e6bc5f45277b34f44f255cc954be8a8fad3ceb9dbbc8a106366d52fdeec43140b177c82106e1be52a886184a734baa3538dbd607bc73ad98c87bd1366839f3a6b10002278b0a7c772c17fee8a66d58281ffe03d660677ac0a720630a554bf9309540bfd6c6e8db7750b68a2d6dda5473c94f50d4d5105b51507166c03544ff92986f2b9c4eb3ad89dd4efd0034d6ef5bbe761f536097f7d6f6207a90c1b62efee155e30ec05ed17df60b7f874031e2b5d316058ff8bf464d731d3e6e6f72e8d147bebe5f1729f54a5c55968c85f7e65748162f634228e05bb4a178fc6d0e293bd1759e06e02b3dabdbb832f319e66b8db123efb7189198dc3ddaefd58002d54e29ae67638cc14953927a8026cb82823db32a2d08e2d7cb803561bb8f03e58eabcd68423f68be6d976b67cba79ef0897291e3ab693a82a5418d10a29b830186076ac2f9cd7610a8551fcb40ff315c19463cebffdcb0b03c10cf26881d9c1304873365d4922f2d4d4cd88c4c81be33831d7a553e258125d4669fec27c4863de0e1280246f405db8ccb56201ec3b6afcadc1470da7f0423c0ad747b9368688f921e543c8b06f75e36ba49e88165c28696f00fb6621fdbd51a168d36ee42d13b44840e8eb6805c7a6e7138cc317ddfd82184860be3d384a18f5d0b00abf339c00e5b1822c240410c6c7a6592e06f41d40472d09fa7f63f5294683697a50cb35d8466ce9c6ae556b2dcb2f931bb8593469c3f76bc62a56779073d23e516369e161de8827eb40c3a61cf442e85ee4a19ff145cd35f0734cb6d1d64554ec98863fddd456b11d8c20aba2ed5dad62c75ab1801882ecc80c289a3adeb920851168d944b92cda85a7633dd3b218aeede517fc25c94c2c5ebfe389d71b7895d17c10ac87d65746196dec8de8e739409321110e365a22795c367d891b68b2599c9622a05c53a4e537ba7967fcf3af2b488b74f0185e886015c4847f88a0c85e89b93bcb62092ff8e0203ab8b9c89e1b4ef11e045bbe00d175e8b18886ba03cddc0f75f57781483e42921275ed82c9914f9912d8d3bde6e857178caea2308b29dbf293928d893e9837516d1d83939ec9a8ddf243737a752a647fe43d2bbc61fb7ebbfc796a925f1e703515903c3c6e165d5b08ec78b111f2f458b8664026215d0e0ae47fc0cde95d5341d7ba8be1dc5d227d29e19b05bc9cd6a3a3aff8b72c8814cad2d01d3a18010eabb5fe7e9d5235663de1f04780e230c1a88fdd7ab554514314f0821758079c27fc10080e635dd498066c2a0a4507afebbfb4c1a5918c09aa5eaf31a8badaa813a79d2e6f63c553c99810d922ff4fe05278697266359cba14b787011625d4e3942854f728fa56e76625df64277dbfd641cad9884eecf8a28058d7b25a354eb64e7b6f2d365b85d2890610139d825e332a255584ab0ea80868dbdaef2f6a8bd2943299b2044a00667c5675001dc447f9db9474919564701a16302c64e15dec065919ac9d637831d401206fc5eb46254970e5f473f7400484c92f384d722316df9712f8b580467f150e1742d6eaceffb204f00631e917791b6257f21db6e23abe2f80b2e03d6f0ee34f87836f12a879f31749169a9d262fcaf5e15cc049ef48675526a2f236ec50350cdc416b5c73412c6f5b7207d425b019fc1304df8bc05757a0253793cc4e6eb2fe175824c92f1e30f2a24354761b8ea068dd848c2d17390f169fb75b4a5fb102b22043c251c98e8414aab7cbcfe5b087f47627d21c02d050ecfd5e53b3d679837ce5633c631001182a6f6f5ff911ee7932c68bb94a9ad92aa7ee275651aa0127154fb1d82f4263a32eac06e7ed5b0517f489e24cf31dd9def73dba1edacb01fe5c08de68854a32b66a00fa5210753fb9a68450a9202c2b84d427f76756bdf73e47d4a5b96a7e67d09988f0997c9a8ff834860b4f000f148346735b659c157fc99709d19a4a5f5e914b5b2b31f35ced5149fa94def53a1bf46bf4e5f58f04a7eea5f5442f039c9a6ea24aa6f5d236abe99d24c846cc8d1ca1309e924ba79e44897302dbab73d3562067fd7f8bef1a074e63fdb93a468882a2030f9c6405aa542ee3912960c92bcb28b8e6a4d10604e0b0f830150a49dfcbd968bcb689b33c8762f810ed1751e4b4cea353be9bac2ad81b29ecd47fe3837b6b755010aa525acd8c9a84f3eadfefe6d9cc609ca241cf718fd9353a66347811cdf7478616b5c10fd39d0696b11967ef9befd961f7fadde33ea1749599d4d558b65cd25411cac0e0109ace330afd31dad1d0a141ccfbc41fd28ef663158625c7f7933a2666b64104bbd8ec14c9ca06207d43b804591dd12dcde306a701fb3cfe1ef7a22a6f8fcd18076fa483250e40911a21d61e19bd86c5700082f6fd60991f5b3ea05d894385e7ccfa44155a3551346447d812c06d37be646475d5c012c0428931848dfaaf49840db943cd835fd9d831f44485acbc4d9de6dc1afa71b49d6767a5d411f16cd12452fc3037ef0031b76fb3dd52572991e3f3530a579f96252f6df173cbce7f3b4c135b99fc561b0d9db1fd082706746795b4d1424473699cd1b55570eec176300f456f2f837ddff9e2f8db2fd7c993ca08d77db3ce054c356260d68666e0ea7be21bd211f5318bf55477d4c2127b6d3b25c4d0fa4efc4410f5198b4daa9e4a0b723e0304703089af25186911d8e9399e5d65d27c1d310f485296bf2e743ec2332f3699dc277ebbaf54f88014a3cc883bc5cefeb7b0c01eecd723aafe8801f02770f26c74556ee6fc6ee923cd8f447e79e70abbac8e15531f109cb2fcb558280edae0f80b621b8540be43a6331523b9b47baaeaaf8d1648a69e74c2b90bf08ae583314d385bd6af51c97c339c6da8d01fdf6b24d2d7483581635f116b7b10228584273edc0aec027ac54f99adc39e7c2d2e348503aa7bf4927da1029fa229009dfab300df7c411010c49fcc959ae8c1f84aa81a889537717ea9ca7eeb337c95389a999bad10cfc79c4738a7057dbc088488b0c3b7b8b36661664a1cbb084fc28b05630b8e55f5da4734a5b84772a7654349adb34088711a92c59a32cc3a057ab56368ca96b230a1e431ddbfadf356f61a18f9147c00a84d64947a5d2494a79f4ab3aba07330031afce86559c26381063ac975aa030c4f0f4402c147a21204ea349f5c0f295782cd000466d3e010ac55771a46afe8d371d1cee482831b05b7a2f82df15e2a13c9bdcab68a25dc4ef91a219f86e29a7bfa36ca768fd1939fb549259c3732730684e8bf93c4bc3a7490c5446caddd91f8fed1fc655565a9513b4e2f066631c2720e003a5415005785805a9b1baf281dbe3e57786f3103327c0a97f10128eabd40b554efec3d91251258f4f19e0fdc6cc9962ad40717fe6d4a095728f81f88936fbc441706745eb52d31a93c9ccad0e227b7e7c3ba2e8fb6e75c309c24ec5554c3e79588dc211a98f9f7552367160d375534b3c0314911eb50bf1df368339b01777b7325a1d2d9530e4484dd06e3620c02cd970af8cf80b558a558ef1bee92c5d4261b61bb8f64cb90bbbb20047f720f8f80f841a590c36611228d7d5960b648e706db191c45db733e11b6861050d2549e596132d91850c793d444d816208c6cb2cdf6896ddcb1c1ecdc8816ae19366000df101067330969fe57a4a6f7a8cf94ecd3c4366cefbb6da30f62a32dde81c8e57dffebd1167d83065bccbfa8bb9b7b88b1820e78522af922c1f007b734990f696e5cfe059687bd10d31b64009497b01ebdd11e179c6091db71eee8e6123d1059e5c3c14f516d19d049eaf4ad4ec39c5db8757d250033df5591f84ac6759425b86c8cce666eb6c6fdf2f18773e843e97ca2852aa0d88a0721a52708bdf6432004052362ad147d49ef634ce9309b3669d05631967e5e4824c6f70b340e0d92f47e73ac6a002079775edb6099f84b36703c44828cb3508918f3b66c378e3d9720c92c2d3f2ec15d59aac2308aac49fd0a96e46613d244d6d40bafe0a7ca42c950024be3bb91a0fb2fe1a8213be765cab2fdb2ff993636826c116915ebc93ad753a1fe1229167275a65a0c090111ae41d0e9833b89295eb18674fb352155dc18d6345c21b68a04c1d3d5fce9e5c1eecde7dbad9ac6f27f70c1e520c9a34e7ce6f0b25573ceb5a6a2bb262bd3ded9a67c680127221b2ea39121792043b0c916b851f7000f00657753a6be9086e2778ba3b805e512e623d3b8d29915ceca90e0150cb858d243a7ca6c6999f8e7ba6ef8c6eba37bcc73fe41b2162fd97e59cead84f68e0b4bf09c511ba10332f26646226b6adfd68cb4da507cb2c3e86fda8cb44e910d5d2e72edcbc8e7fbf83ddaf408f4608191175c15e7507bffeb5be4ab02f629daf4ad2c1fb7cb26451a086074d769c4b9ba1cde8c5cf45117a4d92145fbb1e78b56fb46abf24e87cc79de7c22915c9123fb0e4fba3ffad788e598fb3b4e18c856be5c8e80541a72ad333360e8361481d295363b33c1f78e61ff9bd1b209ee3716b88dcc94da21c043d86aa446929453b2b3a9a4b1c286cb4d5bd49502380ae465f5f30c3eb36eba552e4b541f3e8898c9c178be5bf394aa6d345891822fb4294ebfa8c8e44249eec7106ba78796ae6381d44d82233a4fa880cc95a4ad84088f5717e7b261cf8341f2b1a98c58f33a2bc74b8f3b2e2620ed9957a5287ada7015ba8dd535797b62061b4c10d1112f40ae4bc0a22bb52b611a63d4be5080873a4637c4c52b4af699b7a9574b9c1d05113642bdf90c8a02712a851eb549d0e90749833e90cfc3b7df7f61991740e470949c993ed9834b6414eaa565c89406f1a787954f414f1e2134a95cd2e0bb0ea2a553ed0eb8731d63bd6c90b84daec37a79b3bbfb25d81cd63234efbd6761ef22ec8cd838dc775ed65c90e3d16214021de74172490a12b1eea9db4491c458bfe27e0a87bae67a09d38522d03c37411df2e515b9533f92fb6d84204c24a0f9b43c361b3dc44e3b2aaf4c336a3fab57ceba615a46d7e13e148c7ca4cb6fa6b7e095fecb894ee160fa1258b3c23d493e67f38850e4a96ddd5ff44344f27d3038355864581b9f07d9e475d0e9c4dc86211ac810a14f97f85a0a4c532cf10747355a3c5656e650781a0b77b3eee9b975bb1334c93b8b2fc0b06a051f6cc65616eef6128808164da3c09b490fb65bf1223940ae326e9472aebfb218e0e4ef2344bc270031e554f201fa348f0f907e12479ef477f89034e8bd1f8b4a8bd18ab9e8f0af2a5f831510726f4861a05b079db4ade20e02610820be0cf29905d92739f1dc9bdd6fd379c6d90deefd88b953df2acb4b7377da88568706c4ea4eb981e3ba43b33dcc49337982c57071f12e79accd9760745c9407d5fa05e4a2456608ab38d1cbb5381c127ca355491063b85a0285ab01730e1a02ac54680845b047e9810c944b3341835c850b59c643da9e9f00c32e5ac43f88c0b0640184f803ea2cf39f573060d1a803499cce46085d1c8f5465d0f19e584a4864390e07fe3c51c5c76369934d3983ecf78cc178fa5ede4fc7f7f29cd1f1e6f5f52286acfd9267f0d131de3a8d3fa4641a4f44cd08b791bdf7de7bef2da594324919ee09f009f309638e6ed7c71f7ae9566bb5c8084d816e57799dba00040abdf0006d66acb5345fcee79dd3353939f7a494977a2cf4b95a6b9522518b2ccbb20f9d739274d24d97e5a427585014d180bc22460803423fca2dec1617881419e4fb5ebebdb2c67c2576649b850591cc28e2e3f5c39bd8f244497e92b931a17b1a09c17df9833540bd4fd20e74992743dbb1d4bb51bfcc01c1b0f358288b7542186e76dd344534b19866b3f158ea07bb54d48d853661c8104ca89bfba2a62dd69a27feaffb6a1509adaecb3c49b5f8efb9cdc663117fb3e974bce76408fa91e728481412bd7fa805d2845a23213d6622ad3d31b7c54d892287c3f93a9d4ec76311bfd3d16c643c31f364e49eec572414e389de6f31cefb7b62c670448fded11e4ff7e3f311bb2f7320cec8170a819d48a4b1241ecb1248ae3784d5010b16f6b25ab40075df07fb86b8d4ed434240156c166cff310486dde2e2bae8d82243de7ef658e8672ed4dd13356d31a9f1bac5347d75b6f91b9269659197c8f63dfd3861fde27e65d1a29b299f2e2f3a206ddc20f3c43fff28ebb0a52c2261fb7f9431ef7764fbf3a38ce9bc403f4a2b4e94c4e247e9e2643f9ab6fc20a48d1b334f3c745d80d8de167240245f3d31d4844f41a68dfb426b9d7590edf674a2a69b8a99366e11176aba2b179a853e91e8989076f9f2c8de8836d7992a6305688b5e7dbd42cd731e8be639edb3bf4eabb22aabb23adcc711c2f16a8c87f43b1ecbfd8e677bdfdf554a2ca2495d3a6c7ff9554d678a8e5761bc3384dd52d495d3ff782cf73f1e11de555475a92ee307e3ec8f06c5c7ab2ad5767187fe7b7c12326d8484cc137f2142b6bf3d5d562826d4a2247f562866fb87c593cc508c85de0b8551d83744e41f12e2232464fb6b465890743c22d04666e35d5628e6b2c65017b6bf18fa42ad506bfb83b8fa03e4d596da8267367bc4a332329eeecb9a3d3d212b421e7dbd3421e116793426a61bf136706b3d444dcb6fc807d33489c7c20521f1a8cb25128944df1ef9ef3f79896c7b1d0fc80bc116ab034f34f2b100c2c2a3add697bd1654f8c8bf8547592c6f8a6ebbf0284ca652646ebf4757abb0fbf23684dd505055d636b79deeea09edd154aa93a1e6b5c7c2792d769efc12be975fba07e54f7ee9709df7fea66e9169e3b2e6c98a9a3632b1d4f6223bdb5da621a524f139bfc5341f1bc01fdb3dbae371b4466f645e70d489171e459594949470ba2f6399d7eb5552a4c4f3580c060c18303add976f8bc562c11002c3f39898183162c4f0745fb6aa542a15c3a788e1398cc3c890214346d578e67e92e14ef8c85f86e71f8e7e45945064e4cd584c935fbae764cd7c65312f336607a18b1a8e3484e44d184c865c4893a51c699e93ab1c69489ae7b2129af89cbfab9546f3d3dfc7fed8f0b9419ab8e61bb2c51c74d9fedc0e9afe6033c80ede74f100baefa18bb70288b7fdd560c81a9ae7fc18432c7d2cb246e74b9ecd1b0290c271ec425262c2279ab7bd91f1cc8e27c65306ac6da7d97e4dd6d2c43e27bf9027f6c50c438eec7f992447d6449e6a6cfbe3e60d416cfb1a9b844dff002ef6c5bade49054bcc13c86cb59cc789c576535be509fdebddf07da976efe6658a31c69d971d246643e02470a7ccbbf15e9e1b9fb28c82348f45d4bc21b2ad4142387fe3329527f6b56ce5c86a9264dfbad5bc1b9bf65dc6fdb881c41f4ba60d6f8719289a1f538460b5ece5382f9fe370381c0e87c3e17092d054eed38d1cf1db7eb0294020babf0680f925e97b0e97a73cf9de662a47dfdf8ce5e8fb2d7372f4bd964139fabecba2247d2f66911c7def6517d2e47b8f77e34b62777e7ef578377e773c1a8a473455a365f8940b792c2f3e42cf08ccb9470867985bc2954cb388fa837523d708212ee4dd107532b42f62d1f485093791c76249a627d71384d3c6fdf1da49a70dfcf58379a908e1fc6a3d16ab2f4c382b1327f6ed37c4475f6c3b11f0d55ed2b6ec2426e96a8b3d6917675d29db1b8c8b5fad38ad85b6bbccbd0da9a780991a42385fd330fece63c1f2fee6a2e3b2fd19dea12e57ab814da91cd9d7de8dba35cfbd90d6efdd1acd6919dee76e656254694bd6c07f599fc7725d2c4d08fea29a201cef0be797cc3ebd916dab5ff7418fe55a1852d81841b032803072da012f7941c317210c185d6d09477c2241387e302dfbb6d46ae9f483e9fb83707a09638c61749a185ac5bfa131df1ecb075b0d81c186f0e8cc1019cf1b82db9e981e7c98bebc745df73731990cfdc1a218dd5771921218b772dccddace7696e1bd59ef46b6efddd7568c3b9737eaa69bcbbabcddcdbbc149edc318468c9b65a0f037ecc34994e4ff3f3fd807a37a0c3fd8f6dd8f21c3e26c37ddddb6ed86029bfee6bbae64f91be2247febb15cfdc154e1fcf18351eb534a2f6d55462acb1e214ef2cf9ed7884f58c2b6cd9e9727060a4f8c4788162b29f1585e7848d84a14f34b3c96a93d424610daa77a2be2231e78697b7f8f10cf6bf3246cbb12b6f574227b1395bdfb79d449999166234349aec48e6c6f1af7a310a650be420e6883f352da8d0c35796258d30647dfd73cf10f453d863426636d7f0141df5d56c9323cfa238fe5fec823c2bf7cf796abcc642747f53d2ca7b68d461e7d12c9d657f16d7ec5a41d3a92477f078fe5fe0e1e11fee53a5b4ef3344f3b903a196e4ff258b4277944f897e9d6913dcd5709c86c576c7290275b112e73a8eddfc55cb63f096fba6afb81edcf030f1efd19335e5228c93fa50194e40f662466cce84c3c16fa261ecb7d138f08dff639dc7d2fdde3fc923d975fbcec374fcc7d4d1bf6344ffc378f2766bcdd53d20ec2f9346f45381ff6346d6c729027fe4d6cff4d8f21f763fb15d2c41febd3f637f186b0dbea2d264dfcaf0e7ab80f83b44307f25e424af2bfaa70eec043874fbb4ebab718081486fa01de8df7bdd541c6613b357d30f9b9419a3c319ed777c5f6a7d20b9bcf0ddbdf13f312cebf5f79e85cdc8425cdda0c13138fa58e342df556c447fe26b8879b039aef66c649fe27376f6436b0d2c8d99e184ada9ed20d6c238383d0feb891d93ee389a1a62de6cff9e083c7b2bdf4b618f681513c96aaf109d38dcc666603eb782cd79303544546e0b76f3505405beaeec4b328d507ba2db1a94b927d1ade8d6ce3ecdbe697ec71d65b1127f9ffe0b15cbdc57c10ce1fb7d8f63c3710de1154881a9af0c0bee306367d79a36efc5c10f79dc79426f67798d181e1077a1d076ea09681f85ab08214f409c4777bdc1cd2f0983de6d566154ae0a400422aa5947adc61f7448573cfe904478f10ca39fddd7dfe981e6e0f3d44992d74b5e9b4df6533f3fb639d5689baa56b08705bed27d92ac2005eaa7a82ae33ea2df46f0cc2f974f5c2c912edd2c7cffd96c448adb52a73be103ea2dacf1d76db14cf3a606699cc293ea233934284fe53d39c92b2a91025d752aba4ec1494149a12fa08e42349bdc449406ca7f63aa1d6ccdf9d0917df90a4fbf267e86d212831c804f25c04121912d9001a0903f8e8ca997d3f8797b2bf5f84019098019a35669f95a82e589cd8f667c1fab4c29028b23e2aa055703eadd66cedf1d302b9b67fc86a81b0cf0b14137960fb6f9fd676d61e3f2d91e5a23c680f945b230c61103dce3c3914ee5280010c60d8b40108307bcc60342bdcb5992f7ce10b5470f25f4a6aa23388ff572194ffd59772a2442be963ce56585f85d67cbdc54f5eb2eea3c54bce023cc5ae8f8b204bee8259d4e4c3d71fbe3e8691354c1c95aa2dbb7e3d49935d35810ad9f5291764c9b24ebea27cdde12b0f5f7bf85af295f475f4d5b6f28f23185fffa5297b5192ebaf3f658d192f9ec6cbf8185fb5b70809af0f6fa1916f067316c852e60639f2ef5c28c94b5dca474d90a5ee0672f476b5c74ed5dafed98b9a40162579f6e2389d4332f27cc5c44cd8e6bd4c19ff91e9e2bc97d96a8929d047d3648c3c968f4a67cf0bbdd2b9f37d7cb07c5a3e27243c314a722d3ee12317553e729dc592fc7169a1247711862e369b15943c59decb84d159ae6879f2020882a126cc3a9d379f9327160a89c418d125c2882b5125a644174aeab468d1210161600c0b1633454928107489a8ee3d1f8e68e4b90abd97a99a1a8d66236e74d668369b8dc8114398ccc848d6625192c7602f9920356f4451e474385da733d843fe9c621e98e7e591f97c1ec4922287c3b2ea882b4fe7db35bfd0f81f7208e6430ec998d0f8cc0d194c64c19c28c9bf87ece1217b6032312f170ea70393f23cd005c67810a0cb03ba40976ec285a3b3e7c3f3903f274fcc23e381f910861a1f6064b1b512559b4d16dbfe2827259d4be7e2f18850b0882b1f39144053d24f54711fae07931779fea8f3a3ea82e7a3ea48e00e2a19234f49f678bc970cc474e63e17fdac6038ee53a2b3b62fa8822290c44be76cbf1869e98cf70d855e843c9daf0c192ff2585ee8ea831822efe5df08ba67e419794a93fc2212d06579c8a11d624639f49226dd0dba9497b81f3b3088936028c9ff45065d3e720fc21f64b1c4948f56e17c153595bc7f08266b68efbb97255a4c89297d2be8faa85c3ad7179994433294e4e2134ef2ef549fd6674549ae692332f447754777c463a92c2d3a5a45a84425626e31e5239da98c2cc6c8a28a92fc4116c8ca2425a9c414357db24c4cd5cd85920c6ae1bd84a1ceee42e7f9faa5e46f89fe40f1427f541f95e8e3e98838a2487feeb1ffa74966791779fca0465ac5189280ae517c8d1e398c7409203125a6409798a24bd8a3981a7f8f1f154823a6460f1b465ac5f71153d9f8518d21316c7feda31aedf1a3dafea398dafe272ff9f0163bbd222476ed5a648a56ce83ea0b8413eeb4da8b336df3b8aefb3a0950521219a0241d2a9817ca1b134e2f01da8a01aae78006c468bc0d0154589b19a31110282842845e4a8ae871e6699ee607a6a9c662f3148b7d9e27d6d83cbdb8e05f85485395a1592b6b6da1c6284bd6b04f75d6ca5a55a663eb10bbc282603b689ee63ccd93879a700a428dd6582ce6232d84ef792f20d007e49c30048dccaee585e608e60904d294b55a26d835968550b6a8a9c628c93fd6620912f2be8ef35cc410a4b63f77ad108e32e6b4da8b336d9335b69a2f16c2b1ba94985b89b9a7ce60a4490f3015c2ceebb40520e17240036222b07949bc3eb09345d48a8140411122857a9ecabca60c6692a4fc991961ced2e6aa4b90ea739b6704dd76f358ae1442099b809c2d536cff1cd29401afaeea9a576855171532404dd52563d55505d7762b8462b785eac28234cd96b17a613b4c08335ba82983d93c1691ce6c0a274d6f8e28c99fc3e1749c0404ea743a9ec909438fc7bec763b1f2d359184a7285dd143e7216d519ccad420623b92eb5e50bcd16385932d2151b865867754a932a2f15c2f94ea77ff65616eaf215c060d3ab972448267cbd5ca09649e5c3a94f3e9a421258be547665b1681276524a29a5d3a50b9c2c89027fd745217d765ad354c06ad6d29f5d962b58b396feaca20478df7d033cdd00d9c5420bc858f65266f758e9b1e2db5b60563d4e1fda873ebab739b6e58a943e8c3db61da2c7a672258fa0b9af8f3cae67c40f9b9e58ba6f67bdfa58cb512ce197524b29adde975d2c6da514575b450747e5ec6a9dd2da4d497269af26d3648680acafe2f656ead37e529ad85a43c0496a8ae2fe026a10b52e20d35392340c502ecb51545bebb4d57f36a0250a0ba46c1c3be8c63fda3d56b2e72c30eb40f5e8237b1144618194bd83fa50bd7a44f4d89e65b962471f795423c46d8fa09b46b184634a69663fac97f06de9b697d694d4ae766990d003fe9842f2a364c9d6689cb175e8ae450b1d1b5f49f238efa89bc50ac251c22a204dfcb92b8570879be48a3f27bba9daf06b40c222a8699ef07779248f3af6c8c77bee661cdafbe6383984a6b7ef383d2631f23ef21ebf8b57f1eb79dec7fb2ecf3d927f47dd2e5cb890c20eba6d1f7e3ef4f92bfe27cf1dfacfeb51c697743ec65f3dc2f8121cda6faf3dbe3152a777c4f6da11dd73af89a6bed1694e4b15aa8dddff17a0f3deab3802b4e7740787507bfc59cb2323bfbd96471d475c2df2fe6e59e47da7893c7d43878e7d5feb5e739ddf7e4477700837bda3e6e7348ece7b1a47f8db8eaae91d7577741dffab67848bdfb40cbd83eefba2dff41843571f613dc2d03be80ebde8dd3b40e83f2fbd0384b810be9fedaff609e9b1035af7c9be3f07c0ba6a7a14fd0eba3fa21e7bec8f165ff42a5ec2f94f16bf248b5e84f192a8c729bf7e5ef4dc274f98b9fafc3857a25c22c5ab38c705e76a7f3367ebd8dd57d18f5d1137f423cf8532eecc8d4319dfdc3deefcfb682494e72e829a363e3232f2223d66de11239c7fad691c1cce9671dce79ed338f76e19e75107e8a7f61ea4e5264b276d388ff3f5779aa6715c17f75eae765ae67ee4fe023d70d67ecb5dbea17943dc2d8ff35fbc97471e1bebf17ffa68fc9f9bf32a94935d7c49aefb451e91d8ff3a8f3af6ffccffc119ebea1171df02b20e7a8979a3b35d7c9e271fb948a54e331585f03e71c33d57d4345db427b4d962802ac271baece9849746b986ed2eb3092fa12a206bc85d3dc9420a27f9638f85e43912fc5893c0e4b9ba37f358348dd33025296127d951371619b1fdfdab97a8bbea8e24d77dbd2cab2af0fcbcad107ccf7332145f72b01ebb8defddb6c7ddbe1a07fece8f736b824c26ee5fad42b7e8559cdb2c4037d78139f417fcabbda669bf817a7ba9e5ab69990ad5f27d306f39f45cf6e8716ecf833f5b42a19f3fbc047ee8f19c029cde0d6e6fdba66709e6c9f6386bcf7df2c579ec76f79788ee37d646f2cbe6bbcdabd0cf739b0cfa4bfa741b13d1011f67d12337f8b304d386dce07730a867387fec0b85104f297cc47dc83dce776f3f6198d818eb717bf13931cfd51342fc52dc22543cdcdceceae67eeeb9f292f8fe530a37852e7e75d3e6c5a71e8ba86788b237d9004ee2c2ab8be080a18ffc57236a028db6e32f9748e99e11746b5f04f5add363a84b1cb0ef4f5999c8f0d52f551bc0495e04c863f6b03c660f8fc7ece158c60cc8bfba297bacc71c1d576ffd4158bfd66e575a031d0f2ab312c50c7ff888d64e266cf1d1ee74e7224d7a70b3dc2d5e024317ce6301372a93898ca85466d74ea79343691266de01f0eeb24e8f1910eb8d6d6f886ecb74196a5f2af696a17c04eace25eb3a170dfd8e52caa1debd1dbd1f08829b266f728772f1511540b0a35208c770f332942bac282f498a426dfaa097006d25cb509913592acc509c4613bec663096b05bf7e53ececc70ac5a6bfd1e8ce859268d7848f501e0b48bb4df67dffd96eec36dae1acc4a42a8e02440aad28afa85d39a7cf8a2fa0313430d1426351a031abab4c6da1311a23428408112244881021428408112244881021428408112244886c33dbcc36b3cd6c33dbcc36b3cd10d966b6996d669bd966b6996d86c836b3cd6c33dbcc36b3cd10d966b6996d669bd966886c33dbcc36b3cd10d966b6996d86c836b3cd6c332892726aad3907675beadcecb13310dd9b8dfb1d67f2beea3107675bec6208ad2dc93e461e847b6f3d96ee5ec798765b892bb10468dfcf3c168ed2fada735ad57c4a4dd3a856770f9ae14a01ceae9a733b072e4f0ba4b62815beb9b939ad3feec7ef396d3bbba347cefc90d31dcef598b239518f99e8f950d4638eae633b0fe60e0e21e7c71c1dcad6de8e9f8ef67e7a44e0e87cdda0c6c1111fecbc7dab47943d417a87ef8edee19bf39e1eabdd53d438380f1a016a1ecdd1383a1d2e7b2ed3b71daec36ddc732adec9d5479b9e8f637212634e7a1d3d32b13bbfe5f91366089f396186d0e9cc0eedcc9f524c1bf4c70df41c08a437ca715c9e2fb939b99f4f593e7aecb13bafe273725bf67c2767f4a7141e0f7dcf538fc523e3c9b4d31942b7a16c6e046273299b9b43989da9e710e6c9f696935fc20fa969f31ebe779cf69accc9f0e3b84e87cb3baaf71d27bf6c5ecc2f9af7b2cc9ad6fecbe06f7208e6efb53c5b7e25d4eeb17ccf7ddd98d92f83df65ef67f6c7e38ebae710a60db9270c0fdae3a36015957b6b7dce5a6966e7e4822721d3b14326e8c5260e7e0ef7d8d98336ad6e4a29f73e784db336c374ea1dd9d5b93b42f3fae29d4d552728ca9bd8f567cbb431f7387fd09ff7a7ceb697ee5addb87be925ed99ced1ed8cfb4e6f4febce340e2edbaadd35fb8c6abb8fb0dbeaca05ce7379dcb1b90ef8fde6394e7aa11ebb1d7a449de73bcf7fef095fe48499f380b9fa68945df89d478f3bf6e67bf9e51cdde6bc0a1d73749c597b08c3f045da7fb4ff2ee779c9fbbc1602813ff2249e0f7fd3f9af3bc2f3e1122ef6057aeceedf4545c8dd6911e77168be7b8ee6bbd774dfe6556898c3efe4b17bf905005f136604847af37693bf0f33c7bd67c7119f1671fef36411e7bbf77ca7a3451c2d3e8ece735eec3ce73b1c2d7d247d147ef83bb6e7c33ceed0e4b1fb1b821e8f7e0b7ea87180afd138441fe6e8468fced16d50571f857e237af92479ac1bf4d733627ef8d6bb21d23b6808fa115d7d04d263f6d53bc0e735edb98fb6c9d3bb413f8ff67df4d881ad7de6b16caf699bef438f1e33edf334ed7d26bdcfbce4e9717e5fbdd4fda7c71d94d372a669bfcdcdd3bd276fffc9e38efdf9baf9ea25d06f36cf6df2c7d19efff246fc8ee63b9a0f5fc3d9df83ddfebacf73b2f7d24d9a171f94ab8f34cf798ed674347aa33b8d63db34f72af4f3dc01b4dd6dd9f3d2f3783679ecf6e6bf3ceed85fe7ebe8cd86b4e9b6e7e57f79ec3a8dc3333ddd73bef3e4b1c7f6741ecfabb8277b9fb9df3c597a05e8b1459ee7bce735b9f35f0ebfdbbc277f1ffef71dcd73328e504b1f7d7bec5e7c15bac923f8dcfb96e1e3f87ef3a1eeae084537bedffca7a58f365afa4823813dca07758eee93dedcdb363a60c7962f335bb7acb25b896289d919e99a304f92d501f9dbbe505d9de494094e7ac97676cad1b49347284d3e341d05fd6c1e1187b0beb43fbfee7bc3ca2d5142f7ae9e61cd8cb0ba524a1d0a4e968c2853d33423bfc7ecb5a9b3c9f99477a3482124f111cd73d75548020e631bdcccb6d4757360b63939dd3f3933de3367bb479d18e0a494236b2b139bf6a8b3029c6888b9a5ef39e75715ceca5195d461e6733206c4fd566d50faa2dcddc0ce2e4755ba7fdeabf8b6bbecbb7ae9f3266ed979da0db7ecf9776b0921943f6e2dda819bfde229ddd6fc92fd966d2d4a9aadedf2a48692447f6b5113c8b5277d89bd1b3fa5d3af3e7d7b7d5e7bafcc5ffdcfa55e7b77c0c99725a3bfea5cedd09cf2c7b97a71c06159168e9c1c731566570c59877fe4d4ce47ce630bf6a9675d3857db5e3b57bb3a0e3859527f859b9dcd9948aef8ca5549f715771e5774608a84a93854e71312651ae7cd2b42ff1799c7f8cb6560317aa2289aa22ababa56a552a9542a554a4a4a4a4a4a8ac42cc090e301c9c062a7165be94c494949494949e984482e2c8642a15028144aa552a9542a950e57f9ca619ce52d7755140a8542a1502a954aa552e99030988449988485441d0b17a8974aa552a9542aea288a52a9542a954ad522cf130a8542a150a899852108f43f9a3093355bd33563e6cb5128140a8542cdd77ccdd77ccdd77ccd57d61d0a6c24f32f508cbb1c95726a7141a554b465ba5c2ed7a3680b0a65511545512fba794558d2b94b4a097397eb3103fd5bad47943dd296ecd5424d1a0c97300481fe4723149414da224d3c849169f6590968824b0b3096ca8a102850a042000300408d00fc9052fa6a8100f192e92b06d2c38f334a80f8fa2427367cd834bc14c48e5da19d505478a9534141963a1ea08cdd0ac8f66f8581b44c7ad063789243347e38a1418305fa6c9b6fad56a9c50a72923d52b44e72478ad613aad40745452b649d64f187fc59cdf078668c8cf8484b0079ae0ce04400272d56aa05c4156ab1582779b33fa90f2a460c19624c848931a24b6c892c7145492e78e0c1c5480305297401633eda61871d56401026c2c81a25f0f387add25669349a4d8bc56a9d64cdd66c361b97e8e2b44416abe697edd20203c66b322f4a72140fb44a877bc80f3f6c44209c168b7592c100a05c4e2d3f68fd8253a4e4d562618c81b45aac560b88cbd5dacf6a9dec5fc92217952c6a11627f7645162379c504207f5094e42e2d9ed8499af080858a450bce1017628cc8fa7f10464931182c8330d8890f2d56ab75923d95af913fa90fead3f27191262a1ecf7f3a3e402aa248238b2d4a1a1919d14edb7f00f9031340fec8fc903f2e94488402e20ab558ac00e84fab25840f2d56abd5ea3a9d0740c9c32afd7092b9cd0f9146feb8625a1ce7b47ed09f56ebc487939c6d1f4e7ca091c195937cdda47991c722b268d8e8c1460f28b6461601208b52722856caa2933401614ee201a7e23ad010efc76f055ae1a418f0e5a38fc56a51138df717b9c81a27e1832f4516ebe405beb63fc949ae3e64919592452d3f68910a3fadb6bf298ff8984d6cedc76ff591f9b87ce4dbe65b8b86feb45aa516abd562b14e7e781a590c228bad17b0153a102c6afab45aac16abc56afd7092fd24cfd6090d1afa03c407fd69b54e7a4031f9f9273d98ccc8e30766a4558c1d298fa311081b39a7f10383ed0fe3d31a47acdbbe8aabf8f6def776fb4f8f3bb4cd71334808656890ee4b504a22b7e3efdcf9686ed505c7201cb1cc0e42eebbe74018c8ca2d4e06cb8c9c4c8cccb620cc4bf6c393975cdb0f5dbc247230b6ad0d5be67bee0e507fa4da7375935cb1224cc3c37bdcaaab80c21328cd531c47ab70f758f511e842b3396d643ffa26dab6b92513e80043456dc27dcb7038c3bde7687763e1585b7cd7d33bfedf6a4bfde125fcf5899daa4e6c87a1a46ca7a809cf3809c67191ed9fc243b67f4a009ac32f0ebfb8cac178690a37cdaf27fc725437e68064416807dc39186ae28038c91f6bae95f9c51577d54796597bb11442ece2194177f71c5622fb1dd9c64f3bb0ad4b13eeed3bf75ea79d731f31fbd5b2cd2b045a5738177e4dcdb5fccbde79d4933d551f5ec2fad20df291ebcc5201621a0e4193286e4bd1c06e64b0991bd8ddbc36323f5e4d803f9ce45f57767555f46b716922f5c4bd38c3d4b31a6cc9b22cc4d242ac6d4afae1cdcbdb5b118ee3384e4a39b9bcfd4b9d7893eb7bdb4c2a954a8580d44a27c6f8822e608bc7b209430ac2914badbc346ec2b0fdfd091740ca4baa4d183caa2bba6cffcd6b13134f62cbe6f5f2f08f3815a6b8948f5a77f332f0e9639ccd6ce2d77c769f5e0fdf3521f834839f6150bfd4dfb8a8c97bff4d0b5cb5b4a4542da93b3fc3d6faedc47855509a802e172ebbfe5f8f853ed54268ab9526fe3483406c00b6dc10da1fc11611201017a00b978d5d1b66b7bc34670663b68a833508c198ed0fb2bc04ae36b863bc68103859327a52dbc72cc32368725e5b405dd973128551de8771965a966573bbaf792c57ca1c15b57d13e241bc3c887103b309c9b20a83fad9cb47ee9226592ac64b5946f506a6e557f06f60bc34859bf0944298eb17b3fd5d1e7529405bc134c806c65aed71c65bcc660a0f2208982d6603738210c8e7fa8278698ba126fad9d77265264d6f42b6181f512174d70e39a0d646a1107676db37bf682fc3bada38b3645bccd7dac050176a0383dab84813dfc07cbe81d1f4d7a22457e85f35af9b39dbd9975dcb851dcee0ca7ca16ff38a6e21fc5a316a024f1fdd2af5e9495dcf1bf4899a4229256acb9a2af26283c3813c99d3e9b7c3bc89a124ffba52a59a708253414169b538dcf3ad14db3998ed1c0ce656db35d3fbb1b68030195c5150f5c34d206afb832927b67fe8fb11ab38958fb6cc3da7f1381f6ea2324ef24709d15a34a1b5406d7fad850b122d5a282924858fa44784fca95d20f398e37679aecc2cee3134c50ead4230db5bacb687565ea2afc9db879b6d889b688c93fc83041122c40a2b6666ba215b03c2594aab577fd2ec5a7b31f6eae35b29d56a765fcb6ead3fe6b829160c54ad6068cc85fecce00673b542c5a93895ad9552ced39e4e8dc33ea6946a1c7366d987a7debce0108656d8fef75262ee31b4c2d9be967959fb1184d9fea00b35d118e7e0aa9e64640d920fff96554576a6bb6c69d627e7417b6415e482d7763a29865113d6190cc7613a1d3261300f0e349332188661d204bf015669a5d7d2d70bc09124db93ab36948ebf9b3b38585b27074e59a3d6984f351a10c997e0ac840404a2a4cd62359ab9959a911928af39ca9e738f74dd38c3bb479d58079cd7e0fc89a0bbce93f9446c7baa60db366d9330bcddcd6e5bddb68d6e9b6fdbec325963e3b4ec9b33a8a88a929189c5b8aea39573c5c4bc64b60bb7a81442bc8d40a08a7136a2a0a048133300413ba95150b40d6f5c771a51eaa945498e5b5c677d80928282e27d5d176a3a8fdbb4eeb33fb714501885e512695251994e4dd9c8be59ced884a98681ccded294235b31c65996499c5d8b5dd6eb0ca62dda9aeeb4250422bc9410cee7ec1461374548b3a7cf4dee71e8ee8a50d34d6cfaf8c7a63fc4acc3f65301beb2b92b80ae504a155057b65a6b55805dc1d95a6bad02eeca76efbdf7669e02f0ca86531425f3baab188c05635b5c2ddd19211cab02b297ad6ad10dedf113a1e918e9e123b42132fa588ff7ebd33b7220b673d496b959e82ba3db0b6a4b6db1d65620505252aabdb4e47fc66874319d242050f5d2a45698abb9923534fa4eb38c4a930e4ad231067b3737bbaca39cc57607d5f0570d6b320e3a24c9ff02d294c4eb8a245e1777d9defcb517140e7759a66d1444f2d9d4344e0e0e07b4d7669da64ddf1ced34faf236563ffb9405cfd245d1362e535d77f8886e4e53bdab75f840d6fa5dbf5ad6695be6a12008307041105ed0022068121fb9d398f977ea18dc9a2b3853186db9842dbc29cc0c197d9153fa37278551988fca10cec7afeaf4072ef31524087dbda80c95a12f6a2b862943c51ac360180cc3b95038545aab89934736687f3cbbb3410b6049aa7fbd1bd9ce385bdc1cee6ede6c2eeb6ed66c4eeb6e0e37b77537839bebbecd75ddcddee6bceee66e735f7733b739b0bb79db9ca6c3dae6349dc889ddcd77731caed3793e1da81385429f7d893570a549ad1bd8d4651035fbd0ce68ad53564b7dd64a6dbd33c093c236854d6fbba63069e2030ac359a88e5fead08384b30e9c2c195bac36b542f888d618582be5f49992129a9ba464841cd1227c4461c860f155ba54bb8ed585445f9444bffed7af296aca2d5c7ca545b62886d52f483e8523c92a4242921f5384d02a3ea28f638c9025bcc132921eb391a61ffac189b2cbc81e184a5aa940bfb9fc86d5fa6474f6c45ee4cf09e34ccb44b96a9ab6719b28db0d237b605621ca65d3aab586a87092c752f50608cbc6b56921b1615112fd667c443f51c6aecfe7e329e22491fe9c68885583e459e8310785edcf3d43582f85514f111f51265c6a1314b63d311f799b446f60d2c4072aee89798a7c4e5e921e8bdd284c04136920505062c48811eac8a24ca4bf26c0573c2d2f74325b94ef7e915f4a5eba29c4a224fa1f8cec7151127d16d9d3f282f8f4718cf89c954a6c6991c513fd108b9a3a1d4d173e196a2a79fa9b95ac217a5aa2f3a8a394928040d48a2cf5ac0eb138215688158622cd777f432c5b3f30d47cb04d3f51a6bb45deb42889fe27b319e224ba810501619e58163cb10d8c9a5cc81a242eb427e689918060c8719d48c8c6ff227f3a7f237e6dfa398ba9cf22ca45de6c30fa0df111fd629b7eb04fc647b485dec0845045559a5412d1cfb755a4ebe693d943f8dec0bab08189acc88646ba417af4e86053d81e3f1919d14584f1543152207be47eb04631e5f9c1a6ff6525eaf6c436e542ac518489aaf11bb2e9df0d2c4508156b5bac6c0f11762184d1a62c9915e1082271d30c941ae36ad51dec4506f7144db7142d73a93015663403a57a2cb6da5a5bb29a04ae83433865360bce69535b5140f8887240a6a2a4f4f73ec54b9da65f5ba849e47c7dc9fa3a5fbfce12f8f5b3590abf7e374b57f3b5a276f756a3705d4e5143d8fd880244f72aee3df765c718574dd3c018900a859651328d42989231f76385224351522acca1cb18d6c8013e7773e892c3963484f7c7b08588f007fea4d1a8444c1776592c15cd8800004010002315000018100c8805c3e1609666aa2a7b14800e7da84a74609a49932087410831838c21860000000019009091d10800883550d3cb0af54ad4c84c3f1e411bb68f625a62e43c9f4c932edadc20b65a4034281db47360d66fee60373f63e1f881488388d276ae6330b1c4051e6c03859031215aa461740f9ba2f5e4716169798db218a18f7fda6f4f3f2424188b30ed59649ed026d0b4d66ede1f925ae7790c5e50e29d717760a7dc3b6aadd027384fec2dc315789d4ba5bdb290fc5a4c633cfd041ce64f05c1405a91863560f765b8ec3cfa5ad0769bd444913c31418dfdc2320cd89878955004e972702d9915282b0edebdd5dd733ba319a123ab65fdc0d1a73703b639465aca880e7c1e4977aa55a08d4cf695231fd7fe51946088fb2029c474d6ca23ddb08704592acfa052cfbe9257c67f783bd3a17ab8b65586294064ec3f3ba851372f59e6044552572c551a8d1251f64e0bd2d020912e9672ff53aa972f5351e19e7e05e7b3062b57b077d5b0ef0a037a19ad6e0660f8e6821ede3efe6fee7f96f274324175429e17337cebca47566c96e44ad855bdb18c9506e6c86a65aadb2fb341797953959e7b6090fa8948fb4f4a63d7e34abd244d9475af2274c93d2a63888948110023865ead8e103d9743994a1a69869154c21df21e2caa1dc5d11e37cbe8ec8303b11d0d6747ce4eef1aac260f2a957f6b69593600962ba2ae4658d4f6833b410c38d3d089ee1212afa4318d1820fc87104c4113d934c55083bd2a47d6e0be27fed4f6a7c21327ccc53734276929360ec0ecf662ea74517d3458fd5e0c3d9692645e4fce4482c3097d35bdffdc212cbf5832596482477e3dce53ff06c3e08aec0bdcf4e47f13c583dabefea668b9e8d4e2945fc47b310b87e6f6c9af71c7d2d8e829874223fc918c2be894b6125abaec8850ccde261232c6aba3596cb9f5a5d76cdd07a1d6121aae0bb9e90f915ffd6f6bbe406e9705b4879f3b6d93b38b960fce4a22431bbd225b9504631692eb72e3df9a5c2ec9c7ddcdea0fb857a64540e100bbff4396cf50024b1d4e9bed014b21cc70e1e828ca231cf39c382a1f2e5f8fed4e2614e8a9b3f1734e189d3ef8d6a44c28d45e835f9ef6b173a3e00a82aecc8693ab4493ebbb59de6682fc5512b618ca01e4241b84ad56217c665cd1f27547e8e3a0a1a8176ad587c70df656cb9073bfac98904d4fe79f01b8d56bb73c85ecf711997e8df9199f8ddbbcf016df2d578c2e1a82dab0d2c9daff0f22429cb2f87b237c100712f26f39889819e121a6ad5ccc16a5cc64e19c48b64bc1dae8b8c1412bd420b7744be397142b6c8802eb25973d59c097017bcf4b1789eb16f8aa7195df8c52617b3cd3abb9a692987422f113b543d64918d3a2cb6ede3b285a4d2253a29423f490403d58449ad10d2fa30b8d66ffb68f1db9c2b90f75b506c36af0092ef1f264100f56d307ad2af20f9990537ca34b60849fbe5af1e443f52d983e8b50147fa0c2e889f3b3101bf73982275662c0788153a16aee592be71313b51afe0422d01a98149d041e50d0468ef3d9a8259a4c4427267adbdd603d4f876abf91d53e741613a9998eb6e121748937f00d922c381c6859441777d8c0125171bb86ffa99215ec16583b8971dc9d856765f78616c53858cb121df7a3b821970fe8bc249d66a3fc694346bb8dcf207f72abe6a28da2bfe680908a2216363131ca0129f2a58fa1eb9e314997687014ef01439f40eaa07b88a842cdb0675c8b8e8ee5be8ec67bc24f3d0473e50b508daca3a8737bc25632699c5e42e868e745191fef3b753455e23d8f6dedf8a1c9a3e525b43084a77f1d8edabca41feac262bc7088c19aa6086ba6222acdc790ee38f29c48885cce85669b87d221131a97be332b118aa022857b90930abdf0ad00f37449a88d97058fc103b510aa49b9618fa47f7719f81d1ac6216f4180af6934131d2dab0f196cc0eed354cd871bade5e7a28cce96ab05690a77857bd7de212456ae65fe7afed05b8968ee26022c61ab8e0e343c7f2652d9ade16e326f03d557d7b9584c6d210b5b5a2db9f370d6f1662b4640a5d639ec143bc66e6769bb78324fbc44fe7cb7b705aa070c0bffb273bca14862bda466abe248b7c2c67bc7a161b8fd232c0954d269ed0f8272631d8abd0f0e92bca16607def1bc471b3ba4506957d31c16f1b829f45265c42e6893c5e24ece6d9f2ee685cb4957dd8b97dc3b9c08c17052b795a0ed34b31d5b5de4f62fe49f21b24227f71583fc05bbe30238b18739715d611522b79672aa85b951f64ee6dabe8a4e25613e86306bd48923ec6303b004b04b1698ad64e4a295cff3a5a3bae478f823ae6da3415e3dd944b8b272357a2b5541f8515c49128f1d1a4a6b0b4317caef465cd2041c3fe4068f1324630ea6c4fa2f1a724ab1c0f07735d3f24022728967014be3fbd5a107421e190e0f203b3ced1b80596d127c3a38ca44509b7ebd88b149c664e9b318d1dec187ccb260b86eb208af5e7a8e15c55e0395144677dc385d55fddd1b54046fe0e87b20f08480736b241e75806451fe9990aa0c77ddacd2ceebfe207efa18ff62b3309d6972892eac9a42784ed123c59ce3a31f04ec9c2b376eafbd5783083724132a3e51c97dd88da73d31f66081cddbd462b7c4d3c4e44f7f0254e847232fc6c3a78d0c3c26c7412d11f5df3f0bd197c7834421e6f16ba906420a6a8a580e08133f4ba933acdb95a8a377e91e26efe095f6b24177e35768a0619054d975fd4656b00a4b2df5b5630e61186eeb1f065cd13018885779542e1765e0b40400bd2e217fe1613dd43e6bb1ea2d27b8680fdd961f34182e50fe4d13323f9ac1e8ffa1b21e1ad05a4a9133bb49bca3b637bb63fe23e039926af9304954622472a7c7532459a629d6392531908eb5033a95d77420eaee944662df785fc983a65a636df5600f45f13f9d495f78d5aa4d364878e2085f49e924b983797f11ec83c1568000a2e50e5f51efe3ab4b04aced858123d5276d8a6e26bd6d8527830549d7d81e2f4df8d50be45e6ecf05c227996491e59136a0ee28755a698207d548dea337f08d528b15af91171393f15a309874743a7c1e3dd93fea644b16a97015cc46acb2348ff34e1c31603eff24821e0808d563ce5fcd4c836e02263c50439f660fa74a1de7ca7ea0e3e54c6c0d8182f1cdb47392a190f7391db6ff9aa3237d92910405697df707fade640e0cbe5941207dac5ffb613846f142a682d9c232010c86a13b098bdc4a84b780640279c34835f2d40d3934058a59726fb0bc730d2a0c0b66d768daf2930f757699cebbe02daa1921959a3629ed4c91145cd78cfe0cc685660f50348dd679483f0c85f235afede521913c9ba965c32b42724faf126e9d90ede6b9dcd74bb7bb427703a094c141b3c8c816c66cbc66278daa5b64b5cb4e2f0e8987a401282f9b0453163ee1e25ecf49f60babab39867f7970539c18b539c98b81aeaf270d525293c6c85f27157591170a8e841965a840875fabbd813fc074905f9e4bbdd699a8ec8f39878b4aacd65f3787e2661b101ee34767b9fdca0dd86aa271adc28a8e92441738abd87895ad53aaf0353b25c891e0ae1bdc689fa60b216c539699faa1785e89990c32c63c1095841b1ed770f81634bc2d826e5de8e22ea4e556d71f71f4ab1444340ec0133b3847e0b6111b413754d45b21ae27319765519e1b11bd098d578993eadcc42c41b721cf34f0b7449ccb93885f6ee273bcbbd2f69077189a47903814e2e6c7d7e9f8a96993039321300ea9dd8766714caf36499d64fc1d0a643cdb69f394724fda59cb49a10b6d13d43811cdfc38c7c1456b246fa44260544b7381e715c63fc0b57602e96987ad2b85e80cfac5922ae691d09cb43dd10c527537598fa13e7839ce5fe9c0313ec70c5a3a9e04d2afa274e7b08ab910b13bae6000ec58286ccda32d17d284c94d995b23adeefc18988e9fed5302b545ddb34701903309c95061affea1353c5d2e181dd59cfc9b86031df88b6aec070409a2fb605115db0e120dc0f65292a5b61e3efe3276e05141b5ce8dcb5ca92779a99d99b1da0484aa5f0af3e6c58d54b3a2cc29273a641f2832e6252057456a09f51c117d03f804b48e7462fb6f0d212b14df64d6bc658617015252bf6f2e108c4150ceb318bcdc6660a153e6901142a30ea4d1020845897157b1f72e00b915d1e5560e4f4117a35e312225511c2697c71c154d760c1ee9205b55f8f7d6c1e7e56b5dac92c3c89fbb10f580282cbd7cd4b0b172c76f464ca64ad4f44f1fb1f64ddd1354511ab5f8ab2732b84667f8b48e25628fb73b0c97503ca94fe5912b6c7e6b59bdba81351e3a4f1c5bc1c7aac0a6754e3a0830ce72d3587e04dc77cd57bc09dea07ace083ae135ae87b1f8cd141cf12a6a795deb9a5f82b8699fdd3e9422042bb254fd175ef4d01abea1e98d2406004ae252ae9290def8e6de5d556153538603b6aa26fa579bf4609f8f1ad07058fe99af29ff85ebf6d3bac5d638f52eac16e5954e37a755d9cecd3e9884353202122c9e8a8e607a0f03937e7ef81009d53443d9fe967729bb1c6998cdec2faf00e8e32f8c8c1a8f1bed144b458dd9410063120158d567d560d6970bbb23c945150460da350a5076c800680c1a85026237441c868544f255e5ee2caaec95f486ce8569cf79a1a2f3aa6cca627f04ef3c76da0d5ea969ae52dd4495350ecb0d800ebc6a44ecac896e8380d691098377656b8fc06dcc7875e4f8478375ecc6e231d8a3a4e0e0998be528987425474620ee705aa4a81527808c630b43ec02f3366ab07e92df339562b7e4ac165547ad2a12a929cec65b2f21e19477021bd824dafc28ecaa491dcc92913ea42e4597a09aab1e61b1ee8f941f311c4081a42929fd594f5b40c7145654a88fc12e5dfb8293d0a7eff69c50c7523644d31e8cf702adc2716fa068326a6b8180e91987fdbfbb7126fefb3295e1266bf590f0aca96f39ca54756b6d0058911d1d0b11a2d27e2b144fc8c6e563ab59b90e340cfc683492ae96b295bcdd68a03886ec336ccc31b6318292f8f046e83bf5f7fe3058814b6e825a5a90907c60188351935c84f1b01e6f0b189f0c608d43cc755c18097f9fbdfbc175a2e44fa10c3025634d76d90d31a9e2421a5af0192b287338cb2f60981102b43c89c7f2857a616361923e4ff3eaef08c4e2a1ca88ab18599ea725908193106eca6f5bed818bcc2041a0df24ae0a1c0da0bf4df860f9e2385ffeea5a7330ae28c1c6a2cdb90e4a3e739561eee65bfe7a93b8d80caf8aacb6b6051075d7fc265cf412a891f4c9cf631384fdbea9957820ff8ee6de922c1571e7113deec0af25ca1605cdc50c442ee65c8f30be26bbfcf7528205c9d6386273c15dc1304bd1014a8f1e8dcdfebb59c59ce16f8b827ba5298dc22b7f4e997ad52d656fa2b73ac9f269a05e5c2fbdaf344c124ea92ec8942f83124e0ab48fadc8bc8e9401e9fed5584c4aecd580cb7a64c8ba623830c9c3df83dfaa0bf7bacb548fc9283e1c1f14fa9015aebc49a9156c2aa6fcc3c50c22f551d9ef8deae0761ee32a1ea95649086cc8fd1e09529cdc69edd3c96b98f2ad5f52c7340bae008d63fbc8e42ce59bac21ba19ee9a93efc8086399ca1725af18eabc1be44d6c835166ba8e8dbd822aeec029fc042b3ffdcc48380449145103021d26f602f8996fbac959299d7e09ffce16d77d26f02d05e321786e91af47811efb19422d5a1fd0d88ef49412ec78abf7d94ae869951fb41e1ab0b43d0dba2126aa64a0b33501f0effbc76d45c1b83166cc1c2879f41a05b64d94c4a59e06f4866016c4efb92ead824f4af19dcbde13e6fd520366fa89d4964c70bd5365b8b9b33226416f9d22999a6c886d90f37390acd86e94d458a4761df0745099068e1c91af894b295488289ccfc3907608e1008a497e1c5fd4cc2699058e579679d05fb4d8a3eeef6d2e4b35b2b8066af976aec81afbb8f12da2bc3403b2236834855bfba6af243a94eed7b358c00388634eadcf0718c4b3137a73c91a0d3a605801ae589e850aa900cc991c87519a50076aab866310e67f193044b45799dae7ce8827b6e7502de80edc1c912dd49d223c7f7020cb8492f2f85cf97c0f08f80f5a90888f3019ff884aa41812b882df6f3aa7a3c0d96c0e1dc9d813587fd46147c206fae0c1fbd15a09a802591a3148c363494c90ba85011e0f0ce56344708f712b0b14e6912cc0337c8dd6cee961442e41193c1d821e4c1f7ef808a9df10413abe113df648c1a3983df736d339421cf7ce703f809127020d82b2e8855fbe58114ab67f370dc09525d7b8cd3dd81ba9f5f77f32878986ffb2904dc9eabcee0dd8d1e90ce1200a9d732a72c8e372282e90c7165b6e56fa4650787e68172bddb1a4d88812ca171c33caa96cedb1c3a84c4c7bbcdd98813a9317495343eee90f26f9084a99667c920a21eccf82855f0c5e4bfb50939228c7601b4e5fc080814d2a78d6824da366cabfb9fb91205f77618e614a50f484057cd607d16cfe865b6f8c8ae52b62a345bf30b7c0a116e60b05e12fefe5809597982c137f267eece7da7910b9a5277d393ee1ee7e4e2bf181fc7c6a8c222cbaced25149d0771352e87764953964ac19e32c3823e349ea72b66a3daab49e44dc988e130323468d81d38442b378143ab7d8c012f9c45a63583f3b2476360cc80410e2c4901e519ae0eca389675774f3978c68530a6c623ce2c3074a7496e8bb3aa31ba9848d5dd11eba9e62b1c236f1d6b8cefb14362123130a6e49beb25593748a09a0d40716e6a1f36a6aa555b183ebdd02ec30b001660681cdbc0cae28ac8aad52a260f84299d087f0d225062c31641b0e3bc00d5851b816742991efa1fab3f7e1c5a6ff31ae44c02113a9a45b9367a4d571b4bbd75106e200974e032fad520d375be2f2d26d2afccae2a49240ea299c1e45057b3d36f010a9f05af8cc496ba7fecebe0a1c8f00ac92aaa56d887c52ec8bf15799c9ba7e136e4010362b6438518ce30a2dcd9a6ac18880c0f7a5927b4d809ef414684dc442036b39d11a7afa10d72310947f4b52f093c9cfaa665e8699405507839868e6d6c3bf89935397625873e9379d38b7b6f23ad79fb32e4b7c4dbca8bd577598ec3a05b7ecef599e3ace809bf67a97c7f354de7fa1e2ffb7fa5310dfe6ec19f069a6048cbb8b3667717cc1d2188e41c8076ccc596c075a5ab316b1127ede5568d31fc6dbceb2ad2c7dd678dc210745959e6063937cba7a8782878670a03d5df46c65baedb99ac03f74cdb9b168173d5a588c49807a544d4798e9aa631add12d2beb55eb5116b7ac1a998e94891c2246a3a8a49e9e7a21cc03dc746ada5af5c654aef3679854f2bd2cb3cc5a997fafb9cd8bf510d733780a37962353f81c65c6a2e542642de687d6c1f8dd26cc7b1e442b5f32ea69ca94c4710a0321c6fea48145610e4f62074109c9fe98b74f003c421e3b8d8dcec7ac55dd4cba2711a54e72b8d33b505b8eed6cd998ba8b1bd84f8ee664a44c4bbc38b81e12d09f34fd5823394b6b999d49e1c983f592d477821216e8a62cdbc2d7d5cb4c8dc8cc237814135876136424b5a52c38067278c6174adafd97127ea521c7ae84f44155552a147d0dde347370457f25970c93cd47387dc07f89e5cc8ee2c73dd90de3f0758c202b664d24711aa304bcc86320185593c7f1d7450be31e3b97d6e170ed9fd233bf06ff75f1fe1cd203128e4ccb38411f3e0475a8365d816d3d91a77970a3c7214f9fd15f6f52f1a6be25a84d909723d2ab4a83212939bd1fcf2370ac837914647f65647206f38d0cb0e5171b51033accb73b7d1311bbd99dd8ea2aa2b53b6c430b776465b42b0c64fb3669f2ce337e2c19c9857ad4fc5312dec4b7d80015947c97df85f6a9f7fa8439fe14b1b7f7e04f2c1ac554dd18ab6aad81dc32fe55cc6a5072b80488baf1f492f323572da12ad3f4a26eaed243f30242d05609eb980c6199040c6e011094a8b1f7c78a8680f1be36a16a1ca2680182cb0f40a308e559c7c13925a14e198793700299e2947edbb48a1acc2e3253fa9b3a35177600cd9004db0525addab398b4f132f6c3b9cb73bc9670eeea3cc78a8e126106c4edb243827b7023157e8201370a77886994969bc901242bbc1cb78e63501b56e6511cf688123b43b46178db92c3f299422b864ac9160d6d18ff5287f14eda5010d30bad2cce21ffb0bcb6ecdd2b35acd35afcb9a17860fce1837bcbe9e85d06ff305d9224890ee47766670f7243aefee843a946657549ebd728f0f9e3531195d477720528e15f324434eff590a16b1050e955849a9948f474dd9047e2483e3faecfd0517c00ceffb3d0a06870ed237977bdb78c13f656d67434ea761304f1a1f6c06c874617446750d3704bc3b61f02ec586776f6195f0a50d70a74ccb8a22ddc2bb755f17cd72948ca63a7049403271ca4f81f82056558ad356ce25cda5d02e11920bc9e867652903a83239e40042c9f0e325a3d46a4659e20ca0a24a7b6b2482b57d5655fd39836ac3d0e3818ef9f360c7c9270b5b9ee3b93d78033c6417ba834d51afcae6202b93e0d87715c513605100f9858a03253231fb93469070f1dea72706c95f23b954bbff0e76d2c5a4056845ed705fb96c111dcc02a01edf2673702be5fd273309502c254f2512deaaa78cdc12cb041e0da35bdb207b8c0be27a5e0b0618bd9ecb2b0c4edeb0512577724d955cb71e4cfc8b819183934012bbb6495c87699169822ab89908285fc008124a0cb679558a36d5eea39688b9d9a9dd4a9902d76cff939d019a88042df58a100c9cc281012fb863962c478726efb9ec359dee4c4450c82fe430bdaaf29067cb03bec7d56294cd8425bcd4ccce5e07464c79a1c91f84eb93116088234344add4b07c49885a88abd76a3b8972731aa83af8934f3c867a1f38e3a802f17c50f4b62a3e4abadae127609f8ebc72763f6a559d012caac6367faaa6687caf298231db0469b31252a15642e364f818027a76a5d4742a54c2471a266999ad08a1425534328c3a69e08f3f3b32ec6ace016ad2ba685b9fc6e65e1545f1022e566efe84bd981646771aabcb6c806d0e29281511052d0ab8a2794264137015d178145132317fa9532b97233d7f1cf710a54f352b8e555b8b54f7a4ac5b2a61d34d975521968721254c9b7e2e5cf523ee1252fea687ecf99a7e5665a0d7bc0ceaa1180b56a6e49c34d6fafa9be753f92725da01f5bff5b4a7e68d3c89f3deae0218bb2b25b04716b358b720a0507d49fee053fb8e5709c7e50935d443db302524bd2d60cbcb9e56d04912193382140b0ee8f22dfb2e9d49b8372a65913085138f278f41f88eef21f33c8b876811130cf10d93106d1d0e72407760e154454293c482bddfcac2753cc99da5cab65a584eb6308af33be38a5fc4f99661ec74e568d2a8c10065c1801c87497ad5ed2b6c70161113795c2c91cba0e1e893ed3bae30f47cd465d2f141f6fbf56110e9c88b0d89d2bc8353a3629811263f858836eadf4722f79d6610ffbecfc1738df029fb7de2a8ee8671497b48282d39ed676eadf9df1ac8262c06cd96c29092023c3191766867da05a2d23333863d5ac836a060fe54ea21531c293b11e3666d5b145d4c3b5575a2e3003c14e4d3838315ebdd7e3acc43aa87dd06a0d5927c1c9f944d4ee6faf48cbd97e5cf408e50791042722f17d887783dcc57a8dbb092fe92357b5411b628cb985d846dd012462f22157bf5185b04ee3bc1919a3b0e69ac67df8d8824f6d24747c794aa361a502f25d6f6e845dce22c63b608b6b13b84d14503ba5d9435372292d84b9f1d1d7eb1da6840099058dba317718b5d65cc1621d0bf4b6aeee8cac77af60da0aa55d9a38ad071756495f353179e6f7ca7844793c294b03fc79a9b6f75e4f2fc8ce9e928cfb551d6165c787bc2a74772fcc8b653e12dd32f6e507026a45cc605969cda4677371468311710a09000b1e61385a8c9d407331791444e69df587836972691444dbdde8efdceaaa9c3fa2c24488ea9e36eb8da37d2506b71629f6a5dd80d70b4db2491138daed7270c130c6c18ea48125040abe2e247070a11fecd4dd62b39977212e90ec3b291d735b86b772b80ff89ba502e069f42166cdeefe0ae0599eecc0c35cb1f202bc38aca5607ddd932ab901c7a0404a6255693ae5f8f473707c3460e3955fc53fdc1a3eb145a3b6ceee81dc1854527ec1911e65960f0e7614685e7c1bce330f5278f5782e0b491edc5a13f4b62f6df684846f1daa88147ace5c9697bc85c8bff90f47848776962966f4a20157baabd7dca558336edc42e1b9a7a0d8751726f6d7b72f965767381b8ad1a4232cde9157aece4743013863ba1eb3560879f70ef2ff265877691dd71b1fde06c5868b8f9512dd7a01d2d57cb6c218c5d96e1d9a4537b5babdfc2b14a2184ad1893a9821d058e656aa273b33c58ef6571154f9d0aa01ef67524b46a6d5ab1b06b8d3ef0f530a1898e1584ff1d9a8a25dfe9c62198ca8b5fc586b6ee7fc58f48e7f966331191672d0944c91c2559c37325f3fe2700003648f73fa06becead73facaa993a2ec74a095b81608d1db5cf7f34f279044ff9e4539766b68e24c1cebe4a68e005dc8253bc206d3be532f9dbc3e921317d03554ecc3465bc2311f15aab5bff9e33bf681be73f51932c1d64c1309b9bfd04279291b498b8f2ae7ffab9ff9eee37bf356ddaab6e0d7a1d9fb24f0ed5f7de88d6ddfceb2110cd13fe76cbd2d94b31bf46c9ecb296e703928beb9a82c779fdec8b94f93fc36227763adb15a5011ec0b1b540833c7661d344f6884d50a40aac199336af23a8788317f80c11e970b184958c54035104569dd40e28de772bc48f155d87e6a02cc4c981f13a7eae93015d63176d8971d8ba37818c2da43fb743ae160c4bb7eb5b806e7cb1c23036071a07ab9d5fdf7e37dc26f9d6f632cfbe7ed2f51822ec017ebb6d1675fd5920ecf442ff29043a457568038ddd78c608be1a9e001ea8dc8ca2ac568a41d6140b1e0988271e22f7d7cb3d49a528ec9a2a7436d028e58455df120c86defeaf62d9e29cdb61914537f4e72d66a4d6d5ff8b372610f7b2c3a8ebd7ae7ffefb53018f21b7e8a3633c010b67fb16012114642d717fbf62c8ed68fd84b140ef52c13c4494c9cdf73f6a2d325f5d10ae3a4104143dc53382c36f96c7bf26d244fe58b0aff1b6c4983040d1f1b0693ccdda85c37b043c683816ee64625390fec218800c2b7042a3626471de74448ac6f8bd406d58f56276a073d742fcf2492a880512bdc1e9e66533088c74ceab0de975f13db046ad92f2d3fe8a1a5d81d4e30de2cd8f0b5aff1e84b4e45e6f77472ed9646c5877a068a0aa3fb9a931fa5a707b62154e2f0502ce1b9907cb4ec776c99dfb4780259a85504521e6f3916fca3b222c71b9a4532b38f67e4d7ad5ba69133ac0bc2eb75d30633c4165b4bf858bcb539b39572e45075855074adf3d45c480ef37db97a223940cfa594233a4e6dbed0e5a85cc079b8fc90fa351b554ef2a99087c0c564ae355cb4dd11546d3e5507b68938d01eacb0556e5808776007cb8ae6a984845187b952f900a7e8060edf6b69846c711e7f25ae32a8557e2855080259dc31ac6963b5286b852656f99d8711f42104debd7df64708a51912fda6770182462861ffb9ed00f505145e3c998b0fdf1b0abd91f3f2b40701391e68138ca519d3ca92a8a4f13a74359914529e5fb90ea67ca8eef80519a88838067f5d9f4e6dbad3ea18cd7db0add1d8fc55801b4cf20ff19591d08dee8859b423ac33154d2b32b628f73cfc77bc42606bf23350f1c2bd305f41a448f147e7fee42483cc7d48d8206556011e4214f2db4a8645f5aa9fc6cfc29cebf9e32c1da4cb3f79f5033038985ee64e9d53c95d23d5599cd78c78bab0c83a4f10c5f99738631a1efbabffa40ab2895349eccc962359ff1589aeaa95c90ece9444c5cb4b8de56b697a7448df3b00ff1e8e44467bbd468c6a8dd71b49aff88f02d9fb23853bbd82b01dc6a48a87a251770cdd8e8416d898380d378320c61b16584aed94916f4aa1fe02a2dcb944794ceaf42184f8d596e7e16645b7501e4ba9324b4f4c351d34b94f8b21728dc2eceff0cc4ebd5816276a270d8e9b0a142e973479261c50c5d702c5dfe0e9e06de7ba0d191ccf7e0f13f3f43ada20c2763b3b785a631e6ae0c6c72a587ec9fb73d2bc5ab34678c05e1c868222a74a8ee3bf2890a942fc87e4a23a2fbca7cf211770bec621ab598ee22fbd13d788c92f7656c0b994d9e3554b51be3c50bf16aa3f86dbf59991140bef9df2d1c293a895eafd9536b8a0f7a0826aaaba90e3cbea161e7b54c541397276cd45704a5b7670a177b685957551e4f01f4800f116134a5ea86627653d4f87389615cd5e4b8ac5a6f96f608dab55b4094b4124194579e43697260a0ef002ca288cc76b21add364431bb63504582f802c9eefe17ac9b261c4accb590a2f2bab08c93007412c583fd162bc7d352bdfb1ba1d8055c943f5d28854f631cbc5029161a6cd39fe574b69d63bfe48b4d30b1cb0015f65aa9481225fc6259c9bcd4a8ef91120f085d2f834bee5b17f8c6c3c6c7ca84304965e79be631f35b03bb7c5f26fd2b83c8a1c48107016a88c20e1e09780726b011be96e27064017d647795c527b3330ea30a55f90d76e82bb69e785f55e03ac53b157700f4419baf43ef362f69814369fa399ac112c504e360740110302161e7cd105030ef0ed184105bec6644d327d2da2dd21ed06868e90ecac143d27d3511f0130fa33c57e4357845b80af717d5de35085907865438d02f2b883a0c1155250dc72df28df2eaee21817b5a6de78e210aa0dcf58732cbf3388d64108dea94e81f953817c2776d3d7bdd0da6bc2ed8006b112cb1829b834010c5a334153b7af4de341834b399bbdb95c1024bae97141d4a4967ba7388d3186a058457c2c5959117ae03c49fc62b64e0fe55ff5146038a2c0ccf9e73edc5e2d97bf8c902a1c8a0ae3a638d860766b058155ff9f7bd60fb5e09ffb3723116fdec1bd9a785c87192dc59447791935a2ee0ea633345db8581e29fc354c0bb05d25c18d6a5357f8246611e11be4d8dbc09cf498664b99bf72f9c1787fb902e827b83c0a1fedc6c00a48bdc9df60e1a77d37f0216e1363cb173febb622fd822775a09d781be6f8d770e14a058dc19096bfdb2d36c9eec68e0e35ea10d554b4fa0ba4cfa1385ed91034a5f639a850f894a338e3adaa489af391f6f316c09775e1a1531ec8ce51002b10545ceab692dff92a518111807f42e07336daea6a1e0dacdab2f237ad238a08bbe45bb626a2bdbcc16b1ae28c4dc68299ca6d26dcb3508eae30882cd2d2c8ba7cb71635538c02d4d523b0a077308c4f490dc0936a5ddc0270653850d8338e2e7fc15bd70eb15898033be5838c811230053144befc9fc754f694854be52ee49195a106f51b997961ccef1184a5073fa96763d41030544052c4197561b72437de34c4ff132a7ac5c88e0c2c573d8dcea940d1ee8b908b28d20492c5d9814518a09761da2451367f23b3ba4e3802db193a946004d3df9a6a137a0fb4fab20a5531dca3a4da210357e29ee56bb5e828c10f851315e57703f80e3034af2510b20f14dc140b764c1b3759967ef1e7829463824516e0e531924e723aadaa322176ff022cd232b2f466db74c99df2e56b37c8c85fb037a71c350c552c9ab2fd1be8ad97e75d556192c956f79225692c852dcc7a2f8053d578d14eb6b61903c548feece9e5025f050d796ac32482fdbde904252acf348b489e0b7c58216ffda4712648df9f5c3a26c2ee4191168741bb8138637f277d346fa036fd6bc7e255fffc0c272ff37d0c3fd4f26ffb4ddbfaaf90fdeff77d2ae137200d4f75fc450b063e546ff99cbf53a17c94440d75bc0ca1c161a8dc22c68dd2f0601f93800b3d09ad864ff39fd23054c9d9c39a2314b856916654a7a370b1d829d1b21654711f9e5654b7e4048af4e6e04145bffa52692553d8908c9cb6b4f2fd69c15d19819c49e3322f9cf710ba2af31965651474da08bd8416a7ce8e8682156fe4fd540448cc053ed81f1d5817155a0d148dca84da2741f95f5e3330483be7857ca6c7aa869882d219470a6501f84d26b15b2d5218dbda0ee792498fecd584ca5e90add2bed065de44b133fa47d8a7a59163fc3a452195950c63593a60ed0eefab143919e0d65c13e1b928b056da83218dad0348668437a41a30d85a48241ccb3609658d620fee45e7b1b530f571f88c11fde3378f82d87b1b642e68d8de10f97d9e205cd5f505707d982163d43c17c009143fc640f4cbb288940e60929aa03259057a5e3d54326bbb8325f3d2dffa8ec8321f39efbc67db5f88a36a8f70c7a45ac1054290567c5953ce2b5878ee264f48ccf1301828dc890c37a83b620df7e841afcee7b27505e4c19d46c238850f85a53f0e6f15c93418b29b63044b44a23e8440c488a432559860c6a8251a8810a51bed2062b3db68c4977f067fab3b0e9301a4ed504eab486ef99f1f4631038000707db9f0376a003f5036d7880f45aaf21764b2c3bb3309fab72952ab3bae56aa1cb0e7a70a74ca85fe8514d4a86c32555e6bae17089eed71bbbaa60a0bb02351ed3147c4f0e6f525e0045f51615ba013afb1eb28c00369b19e844231a7dbc8980552cd275fe8d5c37e8ab3269e662b4d84738907bf1fb2b9733c34fc9af2193fc66e0063e812bf002e9cac91c5d3ded7893f2f02138d4bfc01092385d4628e17c53251e5900b7b63f58ea9ecfff2612f5811afdc4d86ff4a31de0e82732b6a39fd50adacaaa48c332512b53f3d2ea0eda6396855b3bb68a71d1c4a2c486f8387f8dc19411cadeacba51432ad7903ac297a783003a06953644cb7e6a80658bc8752c5a1df81ad697a75935562e77447368f86adc0a4e58d7793ce2bd85d4fbd682c0746f589718b09aaac28a0c9b7f43e56c3ee300e5dd57d8527459e6bf9d4b293752c1314f0a989da7a768aca85926c00527ca4ad1142142ac9346526b49ba90e2ac2595ace6526dd2f0cd26cff4aae8a865b9046ca29a666fb7e09653d180616704aa4cb6250b66ea167e0ee305d6fbd246ef5c1848209f7ba0378edfc4b3da27c2c7b780cb8f71728aab0838899e2c741afb6322e5a6db75ef3ba28edf7ba8212b13bd1158b35345662e9c668800a5f1e569c32e76426df7adcf85e415374d804f7b2c65d99772b5cdeac93fed780b8eca1b26d421b8d0b8984d168d0f146d06db29267742334268be8a548d8269c553321d9d649db813dadc2a0d49db192a6a90354581181236436360b661a4c815ba0f02442f2b85226c8d412025b08ac78c5de8e9e78bc518ec2121d5ec1f0df697b5ce40fdbd842724d225d0c7b33ebaa6fe8703c31a2aa07a8502a13347ccc0810925abe6906c0a906a8ac958841943af4771a06dbca7cc83ce6cd6443a2f943a02b43607dae15eb7bf5d6c4fe7e8679b045d3e01a960d486f8a051f3d502bc4f7cfbcc6a8029cf8e0e1dc7e5bef7987530f01874f04c6606412371b763c35e6528608fa8a050c2a4c8b1a9f8c3dfa52c582809ece36690ff855474cd9ef84bd5a36272108d4637b69489c64ce2fd34780f33d44fe26631e1c6526915d58cf07abe4b0370841053923bc6d263929b52346784dbda735541dfeceb249b2095b2363a5acaf7c47c2b52535b454d7f691c32ac4b3517854df8266fedd5a76e1405d7ba6e9682278edff803a0da057c6c9a74dcb51f023ee2b26cd9e1ea26c67ab48dd9e4ab75eaa39cdb6c7ccb856b6843da339c8bdff3f061a2b259f59292f3580690d79689bdcd225d66bd60195a9f8d5d7a740e573a1bc48d38443441203805c9eb78a67c79e05b4f9bf53902bb2444ab068141eec8c00c284e4844d671c3c6534763b397199707e0db6b63af52dce4dade4b250838e23697c7d3788a8bcf64ab8a80772db852c2b74c5a7e51bf715587b958eb5c620f8d79aad913fbb288e768970e1d592d88498a3bf3b2df042e723ff03aa135c1719df284246b8c3b36d4adfc3fc4bd7649862e414e672fb01d213676fbf793cf45103780397e4c151843d59b562f4c638138c2ec043cb1ea070be8830e2c36daea12f499313f5b4be03b1b2bc3666c8a174a443b4d51d3ca0a10d7cb97a3037cafe894dd6503146af61da6c9df6a7913366af6ba8b31fb2884ba8d71b85beeecb4a8b3b2f4b6d9deb4e1f2908f1e708fff8f39ee1db3f36903607c6a6dd6973a7df67c249d2b96a3f338c34b2ceb8cf7f3b888b9c12f4404870c38a9181a22313f298fbb4a4b02568c794d663c22adddf4acb2700a1efe9a890378db1d12c0d1ac1ae192324107f7a35e92156383d9685d13d475ca6d0ad3872af1a74b3c0c7747613442df181760f7b7508624c3eb6f8ebef4ceaa2502b0ee23176902c0759620e4fffed60be967b29b4da707aefdf3bd7aca51d79f5cc2230145c50da680732c4a4f5cbe1fcbdb9026a043c893b24b37edc60ebe3543e946e582dd6628d7c04994dc7176a40adcfc78e08cc5dba8cdce43cd6ce4576218ae81922fc2755a4d57696315e09a3ff42a398f6ccc6fcd3035c1ae11c6cc1e5c03c25c1b92ec5affc21b8ca94904b65ce0c3536f78e2015fa166abfa0cac9fa8aead83fc9d3ddd92275ce3669e07a04f2fb75b6ebd1ed79bee378c21365af56db7852bfbad5ddd50b3e3b5f65bc2491760b6983c37fae737cfb2b7d0cdd6fabd0e70055c511848e1c0b3e27351d12c8b392d92626edbe4d42ef16f7cdc5f9287fa290fd3447064c3b4109ca7e8da776495f5fbe69ec2fa34a3362b39d3af2861a4a11d173d43539185038cfac2c9309eede024078c277dcef720c9f184dc39ed3cbf6a56569b0c6a7d561bfe169b7f891af3fc5d7bb576514a8fb933a3077685afacb831ed892144b5a4760a6f731135e3b78af8f5e32e66c24a87585028747df9383c4249c31940e6bfa5fa47365a8e1f7237b0db1f0b7d0356e4e6bdcaff7433c125bc2404047958509293e5b5a9e70210c417b72c23bf7c9be241a47225b7f031cb1c19c4f237cdd017d69c3be07643724340fbb447666bb19aebf9cf144c949394bbc458d423690c4bcd2158c3c8c8caa1f0883fdfcee215a6f72004bd6998c7cfdf433f9253991705fd5f9d4e544b0d382c7f834b6acf5fcb3adee9cac786189a3dea32bfe9941d1a2ece8795cf2325b164dde233130242f983cb824ac8ddaf06d8072b294890aab01e132cf08342b4e3e59276379bfd2da256b8cad8ff5431873e63ef6bc14dca6e7fd2b3a427df328606f95cac75b5a15abed2046c5138af02961f62ada6a9a5eb04967026565c0d2afafa71eca054e1b6ca57a7760d514e677f49894af7ef3b4b0e1ff1477925c82c50564d0ecce13c09c59308829df227630f4dd4632b74f78bc34fef852ec9410ffb60d31f033693fdb01e192a0599c1d068dc3958c004db085bb330dd266e03784286a80195cdc9d9bea6e146c940b0852283925c7a6c56c8e20796fbeda72529ec258c64210b75c05a1de8208cd7a7271691106041dd27feb587929caf90dd476c6129aceb79b5685f9d2a18ce1c3dc86a9e91d4fbbc078c95e366cb50555c5659ab92f34351945655fe114a6eecfa8d0ecae5da44d1f121533ec5870e95a8da7069674917afb2acdd818947455566772d4db8b68b8dac56c846e0d1cae0812b9975b413411e315cef75ce9a0c58c8b0983c9a08952a5de36e933829dec403b8383162c0c5946c8cd47332ba43995cd965898f1a3ec65ceb9ef55fe22a52fc65bcaec119ebf98c9a1d27bb1cb46557eaf02907933ec9bc172ba53fc932a48c5ff45c978ef4b8fc6264d527faffc8ea411a0c51d704da39c966f493fe18b2fd9a686b69c4b9157fe4d776f523a40da8c87a41894693c9953cc4b58ddb118aa0bfa747cac83ffdb719fa1ca1f3481274531f4c6a1cf8b2568350ebbe6b3a474e101663671e0414c4611be1944285674a20dfa02be059183502ac758becddc005c4145e7bd3c1edd990a35da64415ce9db2422c9b3ccbe2a92cb89ba9c4a489d6b0b4d4012b53d8294ab20cd5c301dfecffe6fd5b0532200576e87f7f38b435eedf48933ce02c4e45c27f2a35bb47f0891f3ad3eb20fdc199f290e0d09241bd90d9e852b188b1716f08090400af5a2e8acacf61c5490222582c500b210544be240fc5812731a591f8feaef9b817f7778b617bf6f7e3f32fc321f82bf4aaf70537bcc20e94fb40d1cfcfbb8ff152da40cb65bcd815060f6bb72b0d04482a6afd87d5d660598b56e72ffb4b4be50938296d737aa5cdc7d3b89154cf061c3c0db6fd72e9a70af177c1b4d603be5594b8b362e2d31bbf55da1854e58002c01fc34a019ff5e6392e4cd6f589d78e860dbfec506c8624d19fb57467278b91fea6a1f7a47663125d5c035909ba7ad6ed96cd88917274d311720e07d3cc6c78ea8ff6455922b6105702f1d04ff2ec55fcc94c2191789c5b20a6af62ce9e33d918d9af5d5bec752a3fb85a5cb227610449cd487eb2b53f57ff9e5b84bc8441f5c121c1006bf98ab61219586a09f56da79db408c57a68e2c47e2dce1481a8f2f4b1dce4dbc401465c31dfbf96841d40c362ec25a1b930699270cf11b81e321955061fa753fdec9a7b02d9214b8812e710c6663c52187c0d94e42a8f272c9d50e9a43cff260689b92a42bb7f474eb67e24093ac28cefb88cf18d1ab65b0f5d75a6a53809614bafadc149c80dcfef1040c8f36c381547c1cfb05446be2401a1a9e021486dbc0843936a302d95be273726a5009a388d5951fea1100eb8b70076809e343b483f7a39a255335b3ce5c3b335b54aa73410fb420edb961b19b43569d43a8027d1a392e871cc4804aa744ac038f37914d25f85a2537c1ea01cc675c6aa37477e04fb617c098db79283784a6d46b2401b300c58e22d5420e183d65afba9379f22b6e7948e704a1d1ea0006bd2e50cbdc34c21db6cc021e3f3fab2b24fe598932167c8a88704ac2c8431ef8f3438e92c16245c1493be13a297f26304184b42b8ee9b33399ba3d1b5af583e5a5a9c7e4feba1671fdecb2aef762b7356111c8c7189129ee121af5f4d52f683e42d50d587b73de50d695e4f170dbe464f064e41542413583651c9898c1182a304813e32da2909dd097f51fbfc65deffa25d218a5422aaf67b8fc6f4193ab50982c17a4bd00bd23451bc28b9c043aa9eace2dab2826cd571775d0b172278484410741b19b30440f06435393e22d2180e618235967169787b52b41c20edf64bb038781017d90ca497a233372801f95f2123e8ed3cae844d9c7350f5a77c3d4745299397909e58bcaa761c90a532a14a33c053b4c19d9cbba7243b90d8fc9353148c315ee7acaadc97cdca4a607d2fc3a380fe5fc39acd5109103b48826cc1d51f5baa3118262d36a4adfb1722a066a79f690b9f7d95b7d8be74abd81979405c72afd6ed35134bf9811878e63c1e36583b91425e0fc130fde10d9779171607d55c4c0bc6f9b14d14ccb8f961f3c006411a1ab38593349ce4817881291e0c0ea33140365845fa428da5ad01fbc6b9db066a02d5d645106ff96cdcf5ce469e4640cb786fd65db83c5e19560a981149b96e35f7ad95c99fc80e4c8b8a913fd5cb8ac1fe0bcca2e1f7474704dc29e6e172e09876ba9fd0b3ee0f379fd8ef75f1d498a0d03cb80196430c64ae3cddfeb83377c8836f531387c2e8d12952cb9db4ed5476873cbca3d20a8f8185b345021cf86fba6cfbdf49e45d8b42730a85f8f2434d74c4e866003d44003b81995057e520c65df186b27c48c234b0c5b0aa21e35e1f0c0e0fa9a04730064737e2cdce89e8f97d3d65d763999239a548f7f5845dc5c2a6d40d1e9200e9485a9d43edef96af0ea8365bcf26b4b14614a99d1db07cdb4ae3664dbb06d428dba230338fdfe74d1c208e06afa015816f234603919183d12165762689a2eb125e5cbe0bbd020677e707faa852558a12171d7c9ffed94d307a3b3681a2ece3fb8583bbb81a85510a936b549b02db2fe1c418c414c95315214e45a7416de442d48784d1f1bec0034fe51804113de7942eae55239870fa8bc30ca2b18a4f66612a591f8ebe1654c16702c101efe90843ea05424d9aecac207fdde456e623b3da5ed6c26a52ab4f96d19163c81c58f1fd832124ebf9b47d42b14f6f9d740a5a8ab9d7ef69ca2930b5c0ba762e1af9480d88bae2246e0f57ce95a94fc85cf995eaa5955393c13c3afcf2cc9a288a7aee2aaabdf4e00a28c25bc4ecf7b7d3b15e6413e0ac24b67c598416e62b81046f4183f8293d11dcb6b603e60a5ad19b694ba24f8f5f2c01713a4846714bb68cc2779356bd563a28a063b3370aa157afb48c028c0059ee0817f0946c09246e46a432080d00664df7a89096e21aab7cd3810b741aa7f0c121fc1e41fcc0ed7439f66c7395a98af003fd239503cd8217721e8a26a0d508e932e19c29940567888653ccfa0409770d9b56e608a0d210faa10f9320fb9d787a9388312d9c034dc2bbc417c9cb057bddf7016a4fb9c3f2d1c89e55e25b82b82c48cd57ea8a9c954b227f11ed6523793098ba3129cd4abfd977f638e25d0663ff3763802a7db8cfcdd1f62c185b99cde30e5c5c4bedd827b341e34e734063ec1feeb539a0e99d0a37e39306a2d93e78b961e2fe11bd687e8a32c0d5a769bae690f4b19de83105fab57abf9efe2576ed39bdad9785868f60b430a0a15a856d6f22644b87b692459a69a8cced52fb9bde9d4d34a6cd7071b3a7fe15ea2fb3a8ee661c53bc71fe0a3a05b602290a369ce7f901acfed7c86951331f6648d8725cabdebb1404da54a979c509d2bb2e7212504361057835f509f5381aab6dcfada22cae3a4ec91b771f207a689e85737d2967e6cdd202f36082599d3bbf16ca02743a1d42aac5a13c0b54d432299009fcd5350781746f48f2c8444e5651ce249d6a3c32ab69dd028122b244712420dd75e4118b70e8ddcd4244b683329a7350c2f2238c3238c5a122b78fdef99e8b463ec70928d97092ab83b7c2a51325e6dc28f58f57649484db91968fd19f3cbbc0e0fb352825ad9ed59a6d31b92fd6832a359d913c2ced83ad2927abcac2b751c98b3bfe38119774114d9b67690ca82d7462a061be0871bb8bb0cef728235fb6f4a70e1f27c9c4cce2481527cb0343b16fb62cac60323223a2ec798c84d162dc152361cbe22eba61302f7428334626d9f1dd099cdb09eb1135aff1057e62938e11acdf92e304252548908d7922dcf97b13e32a007d833f4a46933adbcb9b1e9719098dc9e5f92b09981eeeaca88f2b09a6ca4203a0782d0215e259925aab3b88684b59428923902eff2bdadcc8182190b51538d775a85f61bce417a885d19836e11a4283380a5ca0998020fd03d89edb413dd2a14780101d5c4c28d4f145404eeff8c995ed421168fc8c948c7e535834220e471f1192bb92b6142baf02a4a46bc10f16d38d19a4c5747a1b58537720a93df6e6c4d43bfd7634313eb2e64ea0dc75725b5470ec74e8065a87ccc1ea557df989290545d8d3f251bb62eaa1edae472a25407c1ced986ca7ce4eb64eff447033cfdbe28ef4a4c437f4b872db234e690f0be2e633427631b1e039d2ce85a33fcc981464475f5fc5913e5ebe548f6447b31765ad30f3508ba09b1e20c8da6be6f274014a2cc3c06a220631062aa3d700aba0a6f92e08bf5934f52bb9cd5ec5447a12ca58a398c2ea717b3040228d27c33db2e4793a9cb7c14180a18782f48a7ba40481a55d8aa0211f6d75cdbefea54e157fb6e818e78d146838be7810be911a5bee245029b28e2cb6c610c7f4c8be0029e5ac0898343a5f7e5452189d4708ba7f45a7a09ab5f094ba9610083339f0f8e427e5352c6671986ef5b841f8b714897cee9beda306c273cfa83b4d38161c633b54175d22b404d387f5ac59320e9476eccbb6f8b9a78b248cfb7fa3b8718af88dbb24a61459efe1cde9f0f752aa6a8efa38aad011d573aea822155e32444006dd3e263c478c28634a0f60ca3c47345d95b2c822c97f259e730435d09fd0124d984e07d63bc96c4f42d53a87e5066cf686c949623942f0ebb4cb239923f4429b906b8a137eb5cdd43ed29771675d49484e37a8d6c1e65d38554b338f626312edfa8dd725109aaa844696aa4a987bcb746bad8abb06627da5af8581528cf89682075e0773ee61665705b8f734492905728ada2fbfbbe4120afdb26dbf5fed3393b1e5bdab6f263ad60a11cd48cb1658a4e4f1226b91d085da9cb30b8884e22f76dba5eaf7e60fd435772e5bac9af6d036f2a6d945f445630c23b7acd4c12e493d867865975737252cef609dca5d4ca1b9d79295cbfa22891cc6178d7e5859adbbf3dad90d46165feafc149feece02216b419f7562e262b41bafc7edb7baf4a7ddbb4f2843542e79797b1c1040458f0883bb103d90d5807f98a5bbc48a35d2807e12a8b9164b6c7e211d028885f4aeed11a24024d24e3276af0cccc840423bd8eba8ed5159ab57aba9587e83af3a0961552ff5df42247c93e6f00eebcc8b022b1183746a79f536820a87f1c4164e3ae1a4e15af7a7e271ad5d53040b406c4c127f7cd5f4a0fa06d6ac65116108eb2764e340828ad46a60d02e5d827878638b759bfb1ef2b9144a0d1472058948979fabd5d9fa9d0ba0fb8c80bc82591f4fbf53660ec36ae492a362368647cc1416c077fccc3a7fdc9f72fa422db0aaba967eaa1b18b2a8a71789a51d33b170aae313acc9ac7a3e0ceb302368dd19b4870294aaf632d704861eef4e9a1efc05a8db6ce6d4ce2619648d2a96c5e00103a06650cf701a1a842ef823e5b6a1b6cff873f20f81e385f257711345a5f4508bba1f8e623342c9ab457e077ce480b821cf4297d92d4cb4db76763d33ece98eb136a26b01d28398d8884add3a60fcd4621b23ef52bf16cfddd301503de8d79ec11171b42f6c8f7ebdf98d7e9dccbdcc1c5c47ecac6786a3899f71fe9a16e75f5dfd25f27755a132483153f75a90a488d01e7792169011b9c760f95460cc420e6d253da88258b4344c54da9644e55c5476f345e8c28a4fd4f26a07e37d4514f6499e9504b6c88e5760d64489b7f6aeb1ba3e53ebca16ef0f0029527434c42e413d09bbc8b6c794c9146d8098fd9379aeaaf55bf028a2f7724bfb00234a09f1281746b2a9c7d1f4128f7de815a4b1ed43dbbe80425fd47b91048790a298f857126b40451197f80269d524ce688e35f6567ec468e0032385af7326c6f4496c60b76bc24f6a1ca5a3eb4d0c287a4595cf1b324bb85047a23c9c1955801f09f43272a0581c0b1473238a59e4508df200e438b57e79f4a592d762220dc074430819f75c7f5d2f65d2df73df2be9e4e32a632bf0e55e579e4ac34b8291e753fca50bcf705b0cb429e72b92be3bfcf75d4ac647b711db11f832a1b03f3ab7f19c88a05c099dee35929083ed9661d5e096bb36500ba36fb0cdb6b5c78b5857447f27c29401120d7b2197965ad36941c6fa71f292685a908b38bbf80e4242915f8a6b3c83ed690d3fad8f4d1d2b40183ce593a0855eaf0383aa9a02b0a9a116d0fdde3a7c5ad148b4c236f071903a219edecd0cf24404d1b2299d00ce62f1d48da69c1937fcdf3df44974685536fae13df2b1bbc10138b24e50098467323930524f87993dedd667711db4562d3a9057ccce152333c5daa750027d0d0c9b584250aaa345c741e99a1a0aa3f684e8a422fe48b9b4a0b6ba6a79958cc08702a0c13820e0ce40c5dfa3133e19f3dd0dad7c7eabfe6ac59a570c790a150cf06b2d1487cc5b51f8d268ab9cc1c646061272280f4a10405618b582b34634a344c5c7add21bfd611f6a9e533bbd4178dd50d7361328ceaa4b18413a0d038e9bd511b48c55966dc5b39f6b4fb98588841034e19d44c78ee469999c066228f200be6df087a4c987edeae28eada24b21b62ec10147b266b614652919cc19e34e9c0da4540ab720b3a8245877d80c1508886a1041c45c7ec80ff3476d8e26db7fe04048dde85b67beac7c32cd3b87f36a7add75016b5a425daa0e7b2aaea10c800e833115f9b1abb57649531068fa25d9f6fac2607068c18bd1625c106afd0d5f71bf885e59b493138d9c456dd554c88cbcab439fe714d982c929130215c3e629c0426a8a206870068176c3eb663f50a680eb7bf21eaf8d23e9655c665c24fdaf4c5ced2c8497474bfb6651bc0d0b83c8594e8f6b2b7e9197012d00de23e74496838f75bf40b3ea50617a53dfcd38c531614a2bfc8c78f2d146d4d6cc40a00a7d697e14714cf0afc55c549cbed0a6b7cf574bb81ed2da9535f2e69d89274f4b4900cea40d52a0fc94d61adcbe664ae00c6f27c59adba4d9ed3593d2d0fc9f27374731914118ca191e6fdb5a3032f38e5d0078b397c106ac1409b1ff6a65ec71b94d0943930cb9190638d18dcd0d9b483e2027412fe1063c1e8f4bbba4bf816d5dffa4c0d7ae5de70762cb0e77c78cc4e3c3d02783228d83a4262aea0d5792a4ff16b1cf403f5ee142903aedb2327fdd3a2540fe99ab9fc112fdeaca00d74cb24cd6826d69a08ddc6fd5c98ba2929248ec2296f5b6b7cb696174f47a6aa1b68f77d7cb1b30cd7e73e2b47ad54e1aaadc96336294b2457dec76b8e9b227802ee333c6d1b7d591ff5dfe9eca62092b4f25abeb5df9e46299e2868e48b240581bf8cf923cec2f71397ac0f5da5769c27367fa6941278cae25a4a5e61016059d9b767c1ba693838b5448d925d3722a3ba9feb7652a00516f17f56d4cd53ca1cfc4ee43da6d6e080d7efe54ca44e69078776dd018dd7a335d0d48d806b858ccb8eb75604b703d9dc85aa5e5626085c3e09ae208d028266419bcdbcff13da7ef3d978e46a6f152f0c4240719e88a0639181557bb2af4f83aca16700dc1b50289c7e0a00c78d06d2b98947b64760cf70fcdc0c2060e9e1c6326acc247ad4cfba68cef85be09c7bfa4e436e3ea77cf69b764b5375c756a984519c9193d42df02014ff2ff6762832d58cfd8269114929a456230cb50e9ca331dee55a42bfe940a543be294cb3339aa53eb935376e3ec869cbb6f1aa14f34bbee386e8e7bda9951a290e1c84b7157e577e7107f8ae1e8e648dc8971c719f077766f80d5b971f073ca2082ce6633d85a0b3d52601673695b964cf0adbae8263564a2c1467adb335b96f3141aad6eaaa8b889d332b608f5aec00f06c1bc7db79d4c811c98a35725186027624a8a3ae4a6d39cc2566cd8e6371a0d9022c9abf336549e4aaba68e506db6f531e1ed38a7c830dda9efe9e1025855bc2411a0bd1fb454fcf4ecc8c8a41ca435daa1317dd4dae205dd52100fde6fd5c20f6847cb28e6a32dfc9463fd62b2930016b790c032b2e639fceccba149af2596ace1e928d38b9ecba2f78585d807bf74af04f075dd448192d363f5a983a828c4ca9dc2cf52a0932fddfc0eb0bd11546edb07711e1c7575b4449e4375b460aac02cd3ff0253b896d3ae2d6d57ffd7ed88652722d0159de38724679e4ad439b83c5ab83c924c7083f6a5d25296a2f97b58ed34d30d76444b8aa34a6f4ab77d1ba52da14238812b59cbf31acba37d648534d3581860111f31844175990a57c6443d84a085bd686517e47b0227b152badc6e5509844dbeca277870affb9b5ce5b97a19541ad57525a21c3916b20c9964e5de544258a32ea821ca285a16f6039bcb40e47a2731543390deb39d2d44f4e022a6e738badd80f6bdaa060709398b0d8bc02127e0f17edcc321dcc65ec1b7102b432d2f3c3028e9c6293e1a2bf60976977613c0918d215ebb76cceb8b5b9fa6359faf77ab2a5a7f56a42b30683263a13c36ceefeb9b7127cb7b5f521ea0548f1099847b6568352552ac42c569746f4de95fb15652b6a13c136662cf686c15da0ebc75a2cf6f1d0510fb9bf60cffaa846ad192a3d7ca57778f7d19bbcbffbf679efde8b0e99aac90f827262a226618a6c11c431b17d0413a6abe8cbd6a28c71ada06dad57be39434b1a8a5961010364ad329a71ea0b13015f8f3b41d09679ebfa1cdbc46ebbfaf2fd8688f707a2034263fcddbd34750630fc4423f170665e10e38f0fd2184f6a270d6b8a91048ed48ba272a1c7e095452bb1b5b553c0a781ba4bc1b9d459f1434fd7d07f1b6a95cc292564348b6b22a41987564b30f981df53fb9114c44f08ade05747fb10f11a82e7e3e89bda8b123152abb00579c41b1d868538c833874581f9a558a9970d0c41c3cbb47ef26ea1526aefa9ed34ab74283d205e6214b502c9b2788035369e63790447ffdeaceea30804867f592aeed947355717a952209b4d699d2651d4f848a6eecaf8a670cd1a6bd2b25773e36016db64f494229baa0f46fa49ea47d599285e9969193d20da3c7be2a45e7c510124c6689aca4ee10d3564c2a6813f57b015c8f9bdbf8441c983da827c774d85659c9f0a30667cb3af2f712b8232f07e9c4fd5e47e467ee85fd256d612546d40cb790fe51b191cfc12cea57507387a52e01b1380488929d19af7c0288d0d3739bc4e3c5692ed9a6a510ba365e859559d548a369d6f97fe2c150a142d56dd70c039923181f6c3220840e2c7b99d2a2d72ecba2aaa339d469dce7bc3f05604d7ff0abe34c0593039d39b6efb3ae5a6031a8138a1927d2e11d3d18ea4854913e11a2c95d12c2dc144770cba99a68c78e1aa3de407e9c6e1f9e135f2bee839694d2a7c7ed2095bea76fcefe59e67c15f3e51677e010ec5bc3e51b1211d40f73e0297b48a13297852d0a5d9dcee35cace037fd33105015d77860000070cc3416cce1d2f230cef236d176cb13a3cacd8e44e82b8264483fc0a7e0bfc3b4021e6f469ed38488421f1f009213299475e39bd99c1274d275e36f31d1eaa26533222a224cc44ea803418b538848f083b5a45a8d0afe26046237cbac18e349eaeb7dde58f999ea0d2dcc1df30285e8711a65cc58efabf1cbbf1e2b0bbd1f83224751eed500361d601cfce958f58089183831396f3363dfe95854bb9dd772fc443921fd09fed9dbabda910299281333a9f456856a78e67e4729b6181809fa1ce24928f4f42540944ddbb0b2621e12862dc36a0074ea5fcb5ccca165bad5673b9985c7efc1919a33c726f475a388248c4da673dc4ace01e7506a69f48bdb7c4dfa0a341ced101e6e44104aaa7eee135333702849e38e4c82ec650c07a21e4448fe612bab881f85582b5a9d7211c12ce4f56e8e57328dfd09e8e4359437b3a29da7c629eed3b110113161638b1fa4c2432515dfea3ab3dafeb641cb969357308b929dc4c205568349c4a55b78217d197a1b856f67ca680d3ec84cda9fa72c3cc4d61e12c839d58bfb3eb3846d1e8843b6407553ea288dc828e0587b90d93f5764519fa9160a12d971550f50e2fead99d6e4eec12060404208eea016d63b90e494b63e947aa32b2b1f8e737788ed7801aa01635076229d5911f40bdc3e54f15170969a891b52da9a797f8a5d36fc3f52d6ce26ff5f8fe4e1ff8f2ede4e6ac8038884ebc511e43e58e850383952313f0678e06540bdf09060bf94fd8817e6cd74343c751bb9132d8be155cf336ffce2892485d22880726aa652cc9980cc2d062a12b92e9b4b56d8a744d6115d7d4293d6eaf6a1709b57e1d22a19f57e1c4c909b41698efbbd117eed3b3ce7ffae9d49213ef20216cb2f58926994f18b40a8fbceac69962c4fb784f760d4ee6960f3335adab16886a8aba846956d8eb8a4c58ed71e810b261f31062c71c7cd50a71ce5f36591b25b4f8c33fff9cc05cca0f990de6f53eda96488e66fc1264702e77a4b33ba78353b83e006d347958291faa162bd74d6ad825f1414731795a678519b34cd6e3eb9037a4b6e32ff285688922e3a2f3ffb27f96140ddac0648acb28c8cd42234db01a417b40ba21ed4043948c4b207f1f8ca473955fe2882b05c334d26f4ce0b7f846fae237a8eec405db3c9b86e299300016a536a39f8041918ce4f79260251149a4585bf9b2dd165a5f7c80543ab0cea43ed187d9ca62906f7da06789b250c711b9f0aa9cba88c0609e446625af69c2a43918c791c9c7e2eb8a41b4a2ec66603c58474e5e7ce18d29f835abda22affce72e1bb06eb2af69368b491400c5b9e4a7420920556710bc7e00fd22a68821f75c4be6de0b4d600d41e8c1d7f8c5bcfcfd590954b6edf722dfca23ea6c4e2dc5287a7c610c12e1cb9e2c354bf1b0f46bffdfe79ea27c156aee6d7073189afd7f4d6a589d03b7b7a4346d69e1bb13c344f06787c8660f8618a7fc93226294183a91bda105464ab658ada7bf5dd2f3a670ac264532847d76213704989908484782e59ca01ee198808b35eae13c8fe5c702561ca1cf2a248c37c719cec5da2442d9b0407761660182801516561be3a148485349661f2037f164b0a2c6e572573cab358675ac467e2cf121f54b27144618791775d944d55e07da5f4982cc2ff377f753f757019dde72875a153a4c0fb321036d09ffb3982d20c8d7562a4355b6a414596b107bb9429c2e2565f5d563e8a476e0100e2c9cc35f3efd2ef85d608cb3c1dca0ab4c7f9beb3db63d35aac955be55137e17674e76e0410ce9a3e71f9df67f1d819c212be2e7c873e5dc86a5d4138643bca475890be4b007ae457dd8113ce2addcdca788acf0000dd25a09cb2bab0d3756fc3197343548d6be58c60138d78e0b93a26f8fa268fe0c306ffc31225cd93c01f42c0b2d15603836878818ed1a540103e851844481171a7bc8ad2c035d1e2b3d325506f3bb58af4970f1884322db70cdf63c222ff4087d8cac4916b4bc22e0cb3a006372232414abca57d9272c1826cd9561a49aaa3818c2be523c8a8e5338686bb510b429c125d227baef6085d38b01f398da682c481681e41ec1e1d40ecbe2b117db678f87aa0a8340a5de4896fd57d305bfbd9734d3c19857e508723f4c483179c51d01403addc6941c9a6ac634a94f1e1228f046d1fc1da240d7a65b4eebde77188271b51a12f615e1b45ccabf9d25ce3dbf22d8d330e0cee2e696b6c986f7f45f9d21c4cdada479af0c348a29d5a690ea430dcded3637a0d6fe605cf76720810c4c8d6e475e8db3cd504b0c4e3d71239d97b551232c80f00d7eb574b34b600316d866560a2d69ff62f3809c2ec81ee20ffb134d602c6c702644851b0ec3cc37e6096c9e4ac3975964d615222ad99977a9edefceabc3bfe96474a70228b90ab4bc37df72b3deaa4f0c8a3ef9fa30e623ae8eb8e08417ab99db5946246f514de8cc658449327a75f1b7f76fa4605a6b4828cdd15031a6ab339910da0cca28ed81654102a3a5f137af434232a1c3a93e0bf4812e9356092f42268b3de6fc9af8d90b279e57de416859cc1d710ef7dac38807aa66bcb3c3023d86c6059f0d538d8779b89d3d64614aa6c395d1254d4a3b03529550f123c3469eb071f9e066a962feb5d09b229efdadb741424b16fa6c3cebc2d0a584e45ca37b425c5d9a5ea18569ef1fff93c431ac39dff812c2d4d1652be4d2c3ed0c52ebb7bbe153c214e042bd2792fff039340f7c1df8f8146eb38142214f8b420128895ec4b9d4ceacfe3ac430414bc02fa36683589f78653b2e00a9c6b4721e516d60184c78ed16631849bfdc48d53e0190e917089e05250f0cdccb6670b861138ad84ad8b95a8d0c938e086aaad881e3f765e4454b78a2e907616192b20c29be31793fdf2011e0e6b3e80aa57dd42de4b193bbb5a5788b8673104ec201f308ea0cac37c451e88240dd58a36ef8be742200dc70223cf0b738931bdc069ce06dd0b5858ec661649c8ed147b386dcd171baafebf55481848936c3b8c0d1b3ce6b6696752c5fe5ad3ce876e98d6efaca4d529573f0fd671bcaf42f1d540ae4a1d6094e450ab38610a8b2ae502a4bc30ead9b5a6d02221754720ac7bdd7b2db4ddc01b2a6d1f33f469ffab25bd4e3e93396146e14b57e4f83c886060025a85f1fdc9be5ae78a5657d30fceda394edd09aeffffb82c36d77b78babef17a49350ed181c1e3c083170adc06130e1c12cf439c1d3d7fc11d56d5aec95b30175e3a28e21ef1209ab01b044b1b416c3b3ee4b659446bb899a4b8fb12bb3e2e4c460f1ab81f1c83c07beb5a618a054118264b29e911e639a91e8c5d6746d30505ae9a5293d0cd98d79ceb78ab4489f576768ef4d428b73f6cf788fd60460501d8102507a667a3064bc614d48c7ca1934b938239e11e247c336e89b4ecad909fed70490c78c5a9a22f60465777ee1a3d10da920174531747b3fa36dd1682ac7e5bd9943e539d8aa71b5704ef2d204d4030de4580f63e478dd70385a32170bfabd879d00691f434e24fff545c9ee12df2bd853dce8a991fccdd6b03fc83f79222922c5add572070c8901aea15e1add7db7b0c01344289737129e8ac5d13f8f1ef7d83c3be80cb148788fa27a1332d01388467a4cc5aad45f4332b554f07175783b2821323591cbf7f2266c60d4b13647d023b1cb361df3ca4688bc07dd589eb6d573a6d7e00703f014e10d50e45f419554c77bd06293222ffc0f2624c97809d1f3e11b49016b87789eb6b8f47b64f9103791c81b7abf1df38c56cafdd0d64dec3bef72caf526ea7c30986990578b13cc4a1b5486445b589c19bed573738618e883688e91b46220615ae1e1beef152ecad8801bf5abbd7a718d203660257ebdb94419810deb3bd36f396858a65afe8b2edd6190b663621ad28f454e6f1661b3820bfb63cffc4920e8c8cf712ac7439b9738ebc4fe03b7e9e3b73bf7f38dd8383b76e6fc2bc1ae6732b48ad90429ddd0477b4210e70078f3e8d90c39cf388d6ba32381fa19be5af97862d4b25ea9d630d8150d12dd7a297e0120b27b6b3e76829156336ec569f2a2b15056244d91290b3e85fa5402470b2d2eae0c7536443786be7d0506c5ee8b7e0c18b7da9292c7cf6b40e56ea3a4aa61c924383e1be884c0564c244f24d2157d710f03aad1ea9888a8827dded987161e159c970e5694b9df5b6545cc89051e8c38954fb1dcea58c53cb2d2b15a2da287dc4c6ef258bcfbaf4e2fabf033bcf11a00c3aa05ba40f636ea4ba18e242fa3fd3772626d854c1338cfeafa4a889c97ac55c561514de432c3c8bbba29ec02659ad5078ac46448b881056db1c8c41b65fc681de4c256cf632c3f2d0123c11048084da1a6c322feee6779014884768e28469376985e9139c9ad3db765c446ef14a506b44e5cb80fe35bffeb7e3b35f44c4ef199f78711d2d1c940279b8e599948d603ca7fd8f0b8139b1d8501e919da8fd9209004fc54dff06b6b96a0d46ebeda76b6dcecab3a99fb7360234bb04aa9737b15a409c113507afb424542424e307c49d5282f09da7c00061c132a23edcd2ca1c91e9466aa36062a14e24007d95be350e1295d80731dcb4c85cdb44af49f2e198aedda5f1091cd0909269601f379bb5dd5a5213111122a594494a19060b0c0bc40a765b5b37a51bbb58459dfe459d4e4aa54b1852ce794b7a463aad76e4caa91685a2d61ec93e04ec7f03051c2768ddebc66dfdbaf5f7fa6b7d8559b1ce0ff6325b4d873098d6e22e2db5f69d33b9a5bbfb046a39f500a69b7ead71db85cb2db7308c33cd7dd9ebcaae3455eacf9b05366572b750cee42b5dc909b5095d8933753134db098bed44e975a99683e5639f183fe2d4aa2eddba94df95b4d35afd5d5f2660e9d4a9a47609377ba53458d788d6598a7199f67a3f524a29a594d21fe36c575242addf88f47d2caff71ad1f217c1cf773946a4f1197d84e0a601dc9d08b5737ff287fb743607c99ede9b7158d6c54c92d6c510c17182d77b5859de6a4a02b6b48cae8479a5d7ba34ee83d9a0e606e7646f278c4672d65afbdbc957b0b8b1c0bebd575e69cd99b9532cd6907f658f378212bb35980db82dad7c2b2d95455229a9858e0ef6d6c2ec656badd7d6b83926b5d5bacdb0ecf7de9b61797a97cde122e1b4c95472d7d45cfa1ee1a270ace14fb347d06f24f9c798e94e7b6e7f4adfa23228ad94564a69d5346e34fa3e2424251ea595c648b69d3e93947011c303c1f8988cbed0cca6719847d674a2172ef24cfeda4e968b1875e63a61f1c53c285bd365922dc26405524da6186f675a2d694fb516ee6997bb3dfaeeed8d0e4dd154eaa3a34eeba13cf433daf7041fad7d68161f8de6d09c2e8f10a1546ba18fa90dadd14aa28dad2b280e4e9739fc9de8719db1a9cf844b784c36698946b2205446a68b2111994c9707da48745885443aec807c6ceaebc09e9fe1ae84078409a13414486887346a2a426e69696f7196667154a3255ab27af01669cec313d2e8df6d6b22ad8be94a9da9051bc285ef60ed455a0bf7a2cfc6b21198f7dd9be423aafd797be32b9ce9131ae11a4722af1b69e13a3a5dd6ba229aa7525a16d9f634cfc9c94e6482f3bb8c6d12cd51a82e5f39d47d050e4ed795642c6a0635e4d3fc46fb4f6bd1fefb7290ec3f39c8c887b23719f9d188bdb1298c86a6da23d969b29999198ed3521f67f112269814363698fe0bada5fe8b2e5f37955eb813274c1f86d6521f4697ad4e2a9582d1337962c4d05a68972bcecdcd4d8c2c626833476ba1ff547b29a68d4d977d635d76226bf374d2729091e746b417e522e4e6dea250b3c4c363042e031d1291869e5a9b3293be0cada5be0c4ed33e6f51bec299509af6f2ed5da2cb40878446eb694686c585dcd939f15aa594602a951285b8008d3e8f67c33d1ad791945097f672216f5c274a202e66666678e48dcf246b7c40361e1a8c06f7cc60343315033282f6b12ccaf9b1568eb02cbbb75acfaa5bad6ad755848fad9f7b6d4e6ca7d386b1d672658ebb2b75a50912a18bb157d42526381f5799215419fcc15f928b907bfb5b92374a78640d27b645c91ad357b69393809c4e24587bacb5708fadd1a813798f39168570e8e797f0fcf3ece985b4a85ba206b5e776b235db692b21b13720900d4228f40102c77159c4da735a0bf71c4653019137b693ace101e9626e0d90cf54ebcc67fa7ef45177a598cc997cfe769237b4ef90883426677548743aac72876bb416896e57da23d547b476ee794754d5762949ae2dd15aae104a72a840f8bece44cbc106c1c42477a52ee64aff0f489782bd823d3ffc3eb04f2f3e996ebfd5d61716484c57c28181ebc7d05aecc7d05c4a32925c84dc1d679a31e2056fedb98fda0a1c2758ea32106bccd7728784c9721da38b99d91d109923aaedba2b4db05b62774ebc9643dd5d09085dc9daac6151b3be667fd738bc04a6be6539c947cdf2efbfafffe9ebca7e5d2f81785a8b7f2d253a8419692d5e33c95b99e3484c1d20790984e43bad85440a12cb72baaf7dd5ebab55eb55a9285fa37c513af2babf7ed48d686ad1ed75a32c7a8cd35a445fe5918b747dd444d848467308731d083905e5eb69f6af39ccc2faf8310c044c6928b38de2b84117c6f8455a0bd612a7ec2a73402649dbe80643dbc11d05bc351aa8693b3867e24cf4ab7e2c48f679c3a0483fb6d2d75a2a00ba92572a69b6403023692d57d64c2347ba378a19f5d6d46b3355dc7d5699c366645173c9b60c87c8485a8bbfcdb76682ba86fab7e646716d6a89d66249329a896668185b8d05406bb1ee743bd1fb9452f78cd56034fe42b693af7026274dceb49d02c0996e14fad690b41daa09d24c155bf395d03a016fd309c62c005af583aaa2501aee54005e39209a330dc19133a5540cc8141b6ac040ea95da5b518b5e18cdb40fdd28a65316e093d95146e643c254653002164f428baa0af0210ebd017cf8367c08a65402f8107b28e0b661ca052ee9821700b7864bc33db935557e70c37811e26d85defe6d85e0b652b615bab84b748d5ca3abbb66523086b19c975f6bb057160679249f9db4a34f5155b8003ac41e0174e8fd0074f836e8946a85966ae8b02ad18837fa2600fa6686beb171d2fc8aa4c30affd3a043f0448729bbaa30f6b20e3d591343d6d09d141d5fa9344e9a8fb1f7e9d0fb07414f87297bcef84aad3a1d56187b233af4fe4130a4c3149b9202621d82ffde29e7347372f62ee3322ee3322ee3323ab4b6749a2f8be39caa194ce349c7b12cb4546ba9966aa9966aa9b2501b6a436da80db5a13699b2d09daac2d8f3fe41304c71964a5355187bde3f08569566cf9f2c35654fbe92920282ff9e87716a4b167bb2277bb2277bb2277bb23efe5a156948196f228fac99336e513bca80b1c18784992e001c4c39274571325490e026d31b2a44a0458a8a11c84c2a4194d75e7ef2e34d164e3bde60610a9be64fd2186c9af1c66ad6032ba3f54f11be3f375a2861d3ec29b1b3e9e76692e66c6355e6814d7368635626f3673fde6cc104db3ecd9f7dd1d6e24d912b36cdd7c6aeebfad4a72ec854c804fd25cddad66ab63f4669eeac2d698eb1b12b23bdf46343a4e14f33c92ed99ad2a4c41b620a35ede95fb99632e59cf4bb194d2a714c34d8f1ad5db229cdf6ff4d692c5ae32b9fd471bf7a4bf3a8b2b79ec7c5be7a181cd7d794fbf36586f95575e8a5f89ddabb35b021d2e0405c19802956c1841229d70798c64cd0bf4ad99ec2136f9091c529fd4c4bf4b376fb17c05742334018c1901dda40b9208c45b67f182ba5a692cc5409690cf58ff26989c68028f4c6c250c734129bf3f2408919255217743aa947d6986f238987d4c58cd28cd29e51b3714ccf249e19a519a5095349bb022c9e84b494e32b91a57aba2bffebf49d7e48e78a1399247ff79267e9d504e764992c51734d2f0ff0898cd8dd2b697b70b8e632b7d56e7b68c90a583c09b99d5d1fab58bcaeebbaaeeb2fcf12a0a63df58eeb458f5d5924faeb67c6e486e343ccb6b3f91003e31f86ee01858eec617c0f4c7ffed8c7f8183f758f4c7faebf1f623cf641c4d01f048ccf3e7b180f636213bb1ec021a6b3dd745ff7755ff775b70af8c657b2afdb47df302a13b5f3c8949494689aa67d3e9f098e749c6010183a94af8ee774368759f5a22038ac76d5b4df28355197eda78ed1879cdd049e8fc367ae3c85c938a9d608234b162a83daf553bbd69c5d6178caafcef7038ccf5e070ced7578ca49da47275d73ea6dc88663b71b4c4766d62853ad65f4d86796ee13d8ff637dacc7e1a30c7a2b877e6a2da1df704afea5da24ded7df8698d4df6ee20df3fb91dfa88837be1739a9be68dbf172c9cf6cf78b929f6ff2d8d55a4cb4c4252525da7b9109d64c7bec35cdb58820493ea2da25da7534ec312fc9ae63a2bd48043513ed3fed5d0ab186f6582dc941b227f132ed314d7bedc36d673472ada5fb4fce66625a9e47d6e8af11f7a38c7f6a2d58fbea4772b8f960d717613a211c0e5161efd9c459ce266992e44f2cc7d511e96c3a578bcb539974ae26f00b70f618a6d3036acfeb87f09c7de96da75299b93da7093ce7942ec0fe55a5433fc413ac6f32c1905e9dde043675883bbe4bdc517ff377c88f3f755606fce5901f5f6a8a6d40c809c47407c229a540d05a6b05a25a6bad05c2de7befbd405c16fad896e900877edaa9d4a4d9d9b1b191255992130351b1d0c7acf93e7510aa7d6a17dfbe1c1b66472d07d7d1878499b36a62de77afea6319f6d607717da67b647fbda57b40a1a3c7f541d8dfec5ff67b5c7f3fede64fcb78643cacc7ee63afe33ef69aa6b1b75113451a9407143aaec7340f28c220a5c7b40f1f2e9de2a44f7b18162b7f9a364287f55be55d0f4464c97ed33c78440cc3b27df85ba631a6f134000e3274014796ebad0f23cadb302c568661d11ecbd8d77c84dcc1772d597f691e3c84884e320288c86244114044162c9425eb23cbdc7546cacc9cb09950cab4bc96ab3e421631b7f65996379a113ab2c7340f1ed8633a26d3f2cab2d7728d2c56962c51ab7a24d2a0b7caf525919ced7ac69ded51e050a26ea68a5481145eb0e7cb22f2c6cc719a793355620db5d611309c0e94b66782a5ac3802c39c0938c65ff941b2d44a975c9b1d2f394b966559d6bc35be722d9f285f9173bed42eb3dd6a0a64ead0758254ed29cfc9c9c9c9c2b4c45ce95245782ecab9489580e85cd42572b3d8f1ab84bc112f4aa7086186adb5357bcf045d27de3043324028dd3031b794723aaa72d2c466be91863fd5a134fa80e7449f982b23333fd0c2e4393466b443dfa1a690cac8f8600c4276489da0727ace5409efcec2b1d837de50439580c59315ccf81176fcd089802905b08183631902ecb884ac213fb4217b1f8a4ea0154470668251ca483f9f0742b2f8fb0aa28ac320ce4c15a7d136b217c9b2df441a2997dbd810d9439690375c0ab1c669aaf81122e8544470be53c147b0f18a0d415ee335a06f3d9328bca65d33552e07bc0651e50289e0bca648635201876e93815875e841709b0f7fcbf92ad703119c77ca087a20aab84dbcc610553c081194f1862baa9e02a6da717449ca6bf160ee52ca2794b63f36e59c74664446464f2aff64a6844026043559067e3270aa488b4a2a3719e7463f740c918653f95281162226e85fa780e38e37442c284f35e59cf4056a5209ba8d0d529e1d1c28cf05acbfbac77deb2fdd038a8f7e64c9be87f595fe288bbf494a1eafaa8ca7f06aa294f2b8fcab2d1eb0a28f55bc65b765f5b6a43b9b665bd21cdaf29bf345db5e5b66fb588cd787f6441afed40c91863fcdda9633df2258eee943bc818ee187b842c920494a6c7f5407a450358005cf0278301e1d26e8d4694fa5a951cc15aec668b1fda37be9b4dd85d84a89c0b9c05409e3152fb1479e4c956995e81cb5402681c51339043c278fef4c9067aad03dbd8b997918a46751abf5e77c07c39c47c0f2bd67aa542d7fe66c82f5299d609d9186fc2a230dc9c385cee7c82be0fabe3341c933dfb998736ae799a07cdf097d47b26ce93aa9f95b0c5c80677867b049665b4a75741206c372ff36816deecc5489992a31bc7a3656daf3efcc7dc28960d5dfaa2febdf1c823657c8fc9bef7d82deec33d6c78491b402893720807e3e541fb70ebcab5c39693e66bf4eed5681efdbb7402c10ecf69d07ab83d0a8cd4ade884562f68c32de107d6681654790989cee94d25a6bb5d65a7befbdf7e6a468766c782aade5d2204e1027d27099a37bee9e49cd9eaf838e93a912ad18c3cc9e73876f634f3a23846dc518b4982e633555a668cf292b93ef00cb28ec504a292930e5101c1f47745211f20cb1dad6ae228d193fac2e0d64d41608de1184bef40f42a50c82c5931d1b76b4e20a526cca81b852c938c99fbe5753d8d8cca0c6053429983929a16f4ea4e15fc9d41a3540f0dff3a2ff10592a6b9a010eb11c1947390a7314e628cc5198a3b0944ac657aaf7ca51590d0e2b2cb6ff749c78c397439e61571d1621cfb01d67f6200487d4f4ed40a98e7b6a39589b9a228d59eb9f6187df0e7507c5317754ed3891868cdb7ac11f870a933dd0b799101c7238db7169fb35031c7e724a42b08c8c8c8c8c8ccc27c757b6aac2d8f3fe4130c53f4cd99bcc86136fb8db3fabc1fe285cf295fa1e594a21769c2260299a5505583cb166c0317a599c73ce3971d683ab6963aab8c9a3a4b89c359bd615ebc3cad2d14954536a69b5b129e7ac543061ea50549c760230ab3c0151ae06702872db05f692af542193445f24b3e947cff607a4cc05b036c66281c27e186fbe6af357b15a8b706f5710c86cfb150435db628f39462b566bfeaeeb6dfeae17edecb15bb1cae6ecb12cd36acd3136c6c93839faa9996463139bd7a70879865d31f984d622672648bf5201cb2d4f575eb7d2406b80ad3555ae341dc0f5691ca284cd9652626614e2b069bcd9347a008795da884336fd6a83572a1c36fdb09a3b54ce5039437580654966409664695e1f600708116fa82e8834e8d387405ca92f9024fa94648795c6b33aac3ad8f443d0ae3abcb65569ae0f70032648dfaaacc0d54ebc41521d13a45f69aa10fa35a716992b2335358aa9128140022736fd483fac4336ad35389b56d4a6358b6ab369cd3a8c60c80c119a9c9aa912c62c367dfa52c8a6328a4de5eb688003a68a4b94a9e26fd5786705164fc2cf52f7a905f191d9f728308909b9ea0ba5a81d76251b6fb4a21771e215d7d6a010e1e210936d51f246094fac31dff330f69345b37a496959524a10602076c8354d154b8fbaff6caafb921c12b14b70e8312beff87e6eefadece59843981c3e3d7a91a743214a7ed403c9ff04431fb51c278f635aa1500893e81756f72f4459ee921727df9d9c7496c6848c46fff841f8ad188fb3dc3fb1a5c3196ff26f3d25bda543f0fbd17fdfe528798be4ad4ff4de7fdfe510ef2ef491e81c22ed7d6f7de77d490e45ffe2435163c0f79ecec280bfef9e866cfd974b4a7ef45f0e89e8c1d25fe8adf7befb51fe42717e219d234ed07b91f67448c4b6fe7b1cfee550f4357825d6d3f09edeb17d48eff81fbdd03d7a2b879f7ea17bd3ddff8ba7da0e273fd233f48b6feb61fc4887244d41fde21bf4307e6a3c801eeb506e1006caa18f8dbbcec2a3b73e0cc20f03e34e8f3e1dc2c0560cac633c0c8c263fce31de24c388a143b9f1cfb7dec20fe3319cb11a8c06bf8990c731f3c97b8fc9efad9c7f9445a20c834ed0973c06caddf65d0ee5ee40b97b921c7ef7dab244dfe5b97f82394059565689f5255f95943c0c9dffc57f7a477e2f6bef71b86894e397b3f551b3bcb7729843227647d275d51e753f1a753924f91a5ef47d7a87f5de4f6d8793f7deb32ccb0bbdffbe1fe590883d7a51cef17df7560ee5873e8e7248f200f890d7bd7812fd42b7f7c2933be7b8bd9c1f87e77cf226996e00bcf81a5e3c4683d5d0f016a6414b4c436759d6c9c98b6c53276f53be724ff42d59ef722d5c6f69aa7c3fffc67cdf675356470a38ac3355c854093f20f589a9d2fdfc4a335564bc21ee50595d36f13c4cc86ca11d4643272865cd54b9aeeaebb02b633555097c5ddda8fbfadfc8eaaeaaa356a74339a965596fed4b7baa04d6de9f7b7f0e834094d64a29ad55efa01fdaeccd55862348ff934511a45e24d1709bb928e680849c4762c349a914125a4de67cdbddcb1ac9b40c8a7dbef28fbe58d317bb7210ade71ec9426439f46bb5fb661ac1fb57ae2278ef77f908f0de2badab5a5be55b79d96b6facd5a8cb1c652a694666e4ccbdd75bcd658eb2ef3893a58c8c0e932613e7817cb395a301428e86b3f66a15ecf955a5d1b7ac203917d03b44ec5897d6f2d7cd464146dee620d55bdd6f279737ea8cac31df8e641c1c9025b6bcc17120d698ff04a7390f441af3e24c588c5365b371876e009b74a5bc3921ef76baee35749bd94efee176da9cf09aede40407648251c0d5e6c4363355ac3544dcd994c61d2985b491f6331919c9ee56c58035d2c55c7faf68f2e2e24c5da976a5ca1fb0e9bb7559bababf8051ef88656d5aedbb6b0e207dab01c1b92092e87f398824fa165baab9d4ca099920fd4f8ae9c24531c12113a46f391afdd9441ad5eb3ee466b5e17dfb5d163d66339733b9cacbe6ae34973355accee16a2e8b9caab29e8bdb136523e8d66d2814919c4d3f8b4dad47f961692d96e7926feeee8f43d0e3f76d7bb136c987ace9699bf669a311ab2920afbe5358b3f459fa4e512abd58f3c57ab15eacedd346239af5d96aa9964c414bd614f8eaf0c5b2daf2bcedbd5abfda8bdfd6adc2ec5a6b685fecf6acec79564b690a5aba53e0f002a5176b7b1fbe589697b75269ce176bdb227cdb362ed503bc7d97e2b68f5a0e9ddca04c4bbb4bf9ca97ea525faa4b7da9d497e2525c115cdad65aabc317ebf20047d495027fa9afc8b76352328931319900d1d9f44b7d3c9bdaea895e763a5d910db5a5b61dcccb718fe4f0007be4a9cc541969eaeeae35229187dd1ec7fcaaaa3cefadf75eebc5f8be7bdad337db27f1907a66d89bed7b79dbacfd4c6bb155e6b4e750e8bd27f584423fa3a4692d214f3af6b64b5d2782653bc0e1869a2a5567aad86b896c594c9522dcdbec3da6b57045ccbda1220dcec672529c6e13d84ac075b6eb1ddc90e9d2fa63f9b3714c3681af0e70b8a1c22fb5a14ab21d7aa94de56c077b916dbffbccdd4c951cb8219abb9920ad6f79a2f0bbd9f48da07b434d15dff4399ba9829f869c149b8e1e7fc80dd9f43def2dadc5ab2af76cef8f1ec7f45c7dcd96bb6b7c7576f8e277f4f82dc98b72dc556bc1ef917c3fb59612ffbc953f8f89b2b5bfd917d5fa21fb22fba22c77a733554678d8de86be720ffaaa43ed5d77298d07d15bdde9eca895f7568743b88e749167d8f6abfaf815c031a0eaea3ffb3577ddfb7b9e55bde7cffafc593a87fbf5bdbffe35bc6f52b9f7eff47f5ff50eee2dbd23f4f587708d9f6a3b8c3ea4e3887ef1bd3d48534dbff816f120e26113e55b6df5d5567f5f8bacff8bd7b96da73355444fad157da7d3a54680451f76a9aec804e98b3e23ef6dfe7c97431ea7cf6325b7d225b2def855e6bec4e5eacfe3afdad33b3e6f7dba68adb7ae83ba390b03bef86b0ebb37f9caf3acd15b56adf543e7bee6b0d32fbe8738c0b6fe85972deb290073866dffeac8fab1ffe22beb02353bc46ff5103e84eb6cee7108e365b93f396e1c6ee5d17ba6fb450e5f70367e931cf2386dfc1dfd4e47d35a3e2d7149b52b1de4fa4a0b627a964b1f21738cec1149c6a61ce0d187d43473a0a3af20d16f95af5c5fdf065f8f71349c10ae868b62aa748f7f43fdb6e56096974398ed79f6de7b99c08eed578fc32bebabd759f8c36c43e58dc896633d8ed97d36f429b77d3ea20f4910b683f1c4484fa32c37956282f4b9219b7e2807b91ef4a5c22d8b4d7ffb788e93e85715c69ef727706b4f9f02d1b0d7348ab3b5bf5a8ba625de66f6c4b099d94f2581e7572fc0d7631f761ccd5409e969d3a79fed52fb078ba54b6da82eb5696943f94af6f45a2c99de5017093cdf894dbf14767dc85d364e506f7a233241ea39a84d8da0d597b23af6e967e9fc521893436935050eb3180e633d881b60f124bcf76db0ff9482521a7a11cf022be239f425bd3733584cc1d906d1c7b6696badf6d66aaf7ae9d7bfb0b5edf558f862d52cab9fbd4c13d5a1d476b836d59acba7fa28517e98e2f5973b0f0c0ff9f7863db6fc1ba22cb17760ef63cb1cfaa64f297d0b05c8b51eeb01a3fc9037eedbb977588fbd9453da97fa5ad65b6bf577a90ea5944f5f3e4a49bed5f5aaffb93417d04bbd433ef696d64316ca4deb5f5f3517fa3bac0ee5adf5025d9ad6926196655996855d5abe95516270de5ecbda7ff2bd6fff23354a6982779b917ea55facbdc33e66a3b603a6f587bdf6f7edc6c59efff7356bd30f5fac8c6aa14baa658f52fa682d1966ad7dbbb12c77cc6595507e7c45b7945fc97951d7b259565d843c43484bf7094c3f741e2bb36b32741e9f256e47a44496954a3636343418e39943bc28f0c00c576f6316a04aa93c30c326bfc58c0070b5eebdf4deebfebd7edbeeddee7531c8862e06dd7baf65f187f08370acc2eb432f73484b282510e8abf0c5daf841176b941fb2c67daab9e0b78fa194507e602ab34428d3537dfa76bb165305ef3817f8f1831ec3b4165005aa58d8f23f5dd8f2b5c766c45c0a5b7ee6dbb110b1808574d7a1326e99b3d0b1d8170a1014d346f9216bcc4791f2de47315dade5da1c690b308aa9a233585e53f0980d641141596a3d58a16bcbb182ac19ca2188e378aac8c77fe5d073b6264332f415e82b5ff93c0804fa1008a4495d80de3e262dad45ca0c947d67825c384ff5b43c3fcb98fe95c3193120ce8c12a98b2a9392ee19256a7395b100cf284d704a1a35f925cc6d0d74d4a7495c9d44a5527399d5d45c1cbbe642b1c0826a2e75fb635b8cf2abe662b73f66abfd788ee7441a97092c9fc2cce922f09b6aa5cc9ca2e68ca94a67c7c69740134d55836dbc9bc7015133a7c225cff432e069ce489b1b1c544e4aa7c2de0c48935293c2b3c1f7705579f83df053401b9ec900cbca4fa18d9b9a71c74e1af94e53776ca84c511b59aa2797a58863276ab2c89c79e8a66d5debf32943753d8043e7b941882a36c48b79a42cc015fb7e7873a48deae907513dd53da0e831bfd241d01efef4cef84a8fea69e524794fb8d25f10f4e3cb2a9fd2443157748ac6ec6c293fa44b6c19d2d2694b130a764a0341906fab7c1ce6cbbf39537f41cc1ef1a3d600d737475f54c96124ad4d603fc071ff9669744e2d3780452cda8ea30aad2fda3866103740e4cc09bc665e043a49720438c4b84a17028ef4e39cd23ffe22b5e7df2038cb3ece6c8f804c283f504a283128a65a2bca8f1e94124a8c7b7d1008a584f203b3d97b7ae9506eef7aee5162e48db83914d354e1fe7a47b14129a1fce871941f3d2825941ffef706efa04e35ca0f4a514ceeee54a3fca099bbfbf5abb1bb7b13d875f8625d1e60518f261132c1495233c149421369ccefe9e9e9e9e9e9e909512d263825ddd121f9d8f344f52a724c52714fcf0e4988d8cb032cf272dc5cbe7e2493e450ca4451654255268abac469e6099a1a1b2986e05c3155ae8f8f5242f911514cdbca598629a6334d92d2e4a4884d1e385c6a397c7b4fdf5ae916fd5a2b09890e87a096a615c69fc4537f460987d7ac431877cc5e2fcad747b9473e5e2f7a528fbc11b7684669aa88fefa5ab3318c465fe93e0471464fea42dea0750445313af2770778877fd5464e53e5d2334afbfa39f2237abe344d95919fa42e5c6b19018de48c8cf8fdee3681c311948350391809cdac96468484266b1f6aa8119aed43122271037d5e9aa44c1338a4a14698c023a809d65abde21114c8aafcab65b596533df42108b549424f693f829a2ab5823ed4687ce5fee4b607a1a64a4862bfb2f63d5b5acbd188cc6d7b30fe50436de99f203788c972a5c95726cb7c1c4ef33592e316e5eb39102aac4e50102a9423a8eac454a94f7b4ad43faca60a04fbb09e669ed8937e5885d49a3d6b147bd28f52ec999178485d4cade5d212cf286d2b479ab3cf2a8d65114cdf2fcd030aeb795c5de9b85f7da579441816fa6e5b322a787f42051c824210e1830e1fc25864dad06182536582f3456ac2683e264cad284fc0e289c43e92b28f7a466982d4b78834b08c836133be82ffbaaeeb31ed310cc38ab8dbca1e8bd921f6894eb27408a2b6351f6710676b8f5dda7a7febadac3d46e29920f69a26f5c81a8ed5646cc649fe1f7fcc5f873c76f658d6da63590eaba700ccceacc7485dc81ad8b63a38f42db6e3b87f8555bfc5b5ef179665d94fecaffb588efbba6fe590d4b3efe3f08a3e7683cdabe3a7d4a4d9b191251c347bfe090d9f4f4a0ddd86ca4bdc1a4f0201906b8040a11a2734d4c0719b0068c8b8ae0a2500da5269ba5fc800200363eb8486eb02533a358cb8992ce3666c43d9645927c3da36eb6880d637df6d73016ce89c80120dc7cdb6868c041135fc47c38c195f258100c832302c9371a26ba0e13a4146fef9794d86e666b8991754034086754283dfd4a03b9a9b6fbcd96ba04146559d5c2fc8b879de2caf0c195a7734375f1b3f068c17265f0989d78d46445c08843b9a14ef02a98c3e6cae06c82245847761013af89003d2428e034ce1911de0e1f9682d77c7dabb45aaf3a608638f4466d5e542bc5bd094e0eeae2b1bbf58f0a1013a6c3405071bb28a38c1ca6a2d47b56dbd5a5c2c5c2cdcbf29fc229168649a78dec8c8c8488ab0bbbb53d702767ab310aae2425539f20953665e131670fcf09a2ed4448257efae7df6ee2fa7bc711fd32ade1ec7cce2a653056f91e5a3d5ab59f70955bdb7de20d767d7ad8fd5bfea5bb5d6fa93feaca68f7aedcf39ab6a9120a594d6d6eaf2a6446f1cdb4a2bb5c2a411a4940758a505b0385526f55923e818d8d32b7d29e5102b9ad45aeb5e17bb2f755b8a45ef980e3d7de9d47eaf7deb3797a425ffbbfdef013677f7128eb304f2ab2d638d55f68876524aa9b52c4b0d40adad94b26894d25a29a5d6565b997087cc2d3570a5d6039dc105c296d208f707ee33d260a1233bb6bfb4753ab5f7de07fcb6d5d6a71c90a5fa3eafcf1cd466eaeed51e3137d578f04db7b4028b2918f32ab2d02cb7bffb5b7fab3331607fabb3ea07583ee1d6a4f0cafd584956aeb69655b5d4a1eb00992927cd1415486275a7805dc748a3092e537371918ef1a4d43dcf0588c8e212b7bc3a5232a12aed8b62aa282594988a62b2504c3a0b032ddddf79b1ae2b5afb5a283f507ed02db01ce419b222587ea495635a3dbbdff971fb943870afb665bdf8ce417e11ce8319f7bdd7aaaa9f4fccfa9e9d7ecd2831745a4a514c28a68d6283520ab20999e0acd96838d4a7aa300e3dece23e8f63665996653ca85ad3a1f6fc7c55615c1272a87c7992c017088b658bc121f7e186da134371a8fa21c6a190c01ceaf33826cef8b5bf3c53e5f313ebc8e5fcb67de41b4151a1e7589cf79c641eef50dbb438c0e68c92ac3ee610cfac923f493ca49e59cda94bb219a5184afd32c319a5a865d587d87bf59f0ca276953d28472755dbce109e83b1cec9d1f5676fe50bc77316068c69fb7ee96b7df8a2bfb21adb55fb9018b532d87c6c6697b86515b28a5b45a9646353050d4d15b70ab977766c6ca49432d0711d51fd58d85b334a1bdb2a336d876b5b8d692e551733a6d652b3f52213bcde3e96ab4f112772b30cfb2cbb119465f70514ca1ebbcf899e6a910e27c6611916520dc3c387b53380ece0dec7a679eeabfe6527f7f5a2f452fa180d29a677dce79efe45f5b5c37dee7a9b2bc53e211e385d69f6f62f1e72d4a73dd4a7187d8c86334a58731171bf693d64f2f3a17f85227bd9ff682ef577603a945ab59fd7f255e98bac5befbd7f33aefa2b57ed41f97a6c7b99f193783ed97eaefde81df5b3af1ad37a47cd24fdac047ba9f19061391ce27a1abed09dfde7d25918f0109eb3b10f87a0970e5ff4d55cb0df91e950daec35ccfe653d89a7ca9e33c168adb572d707717c45fe8c5f9fc443336ac2643efa81d139ab09b03ffd9998924481283670b8d7bae55635e7c42193807558808dac01bae29857519137e6bb0d1b3838c24c07f91ea53725d801fd02164faaf5d8b351bd04a5c949f2e583be720127c9c7accfb2a44902b1192297a89ed8524a292c5b338983d42e90855565c261dc3989e07c22fc23381d40c4fc7f11623b1153c5f34c44bc4c15d732021394afc3b46163a29e608518aef09d94d4366b4504585f83e100b34124c00ca2011cabd9c0e44adbdf1a79eead19d4868268833f9737134402f85b7963221a40db526fa71f78da4c15973908f75636552c9cc66a6880c3ed3467b627ead73abf4afbb5c68f139482891a2b5a10c50b6f3af5cf9763d7af343082d4253241e731636db56b1ec25358141374cc06ab99e096040e2f2adb4e3a88f5285fb1b4ef38c943dfc1245623b7212e4f1583e90e910a9b7e0ef5ba504ef22f87fcfa55c3e8486dba534a6badd55a6bedbdf7de4cfb30ee7c3eb4b1b7c71fea00fa104606fbd087d6522181431ffa98d9f2b1eae6681fa7797de8e3048464b1341facff20d607e17cc8b0d49bda8eb24cdb7f0b2f2ab478ae9ab03a5d1589d12baf58581493e4d5be3bbe52b1f83bcfd5588d0670b89d68e4445161875bcd76f2925328156fa8ef5f6580c96cb29d362770362273458a60677b62aa442a9ed8d98e6d516cdf66b66f36db9bb0c3ed66fb0c154968b1c3ed8aed5b952651b81313f4a755e06d66ab5560e932960f09632d490d164fc20ab57dfcf85806eedbbcacd3b53ce9106b79f2aac29805b39747c42220225d4b589e4a748448491a59236d6e3a89023df6e5fb25d93e49b6decbd57719fb91f61c8ec9e5c88209e19185459e9c44b196a590be400670f82dc0741b412513f21469d017e1975a11a137c286af403162fdfd18fd8934fdf71528f0d3077dc53e7d1f7ce5f3fa0b3d77a3bf90fe7eb8f7e78738cda37afb3cacbf0f9302fa2dfb7ff23c6dfa3205a7a93237cdc1a67206d2059bcad396288ed33ca0087d48ebb00fd23ce65b9c7dd81e93dae783cfd71157392369648db4b9c141e5c813f8f2f4a8e9434a1f17ccac3224307fccf34f104c493939913f785561ec32453b94d4c464ba780e32d2902f238df85473a13ec42491844b6dc9ca80a7cbd45cb60a05d8c444cbca80e76772c2ece952c5cafaccaf5a98b4da82892d4030e774df4208582677bc60adbd970b55f86c21647b78472bb6d0c167472b765410862642990c430b70b66ddb86714877186a463b5a0186223b31a35017ba2d90d8de68341a75dd165c6c910546c2859c1c7c99cc3b4c9894ec684518705e806a6090501163a7099fc9bca3155d48627b139439927c3418541dd04c1521532536e0754cc1072ab07f8efbf2cad2b52f9f102266823a7e8829b965e5838e0678feebae83549584d9f9cba1c305b8cb5fc0046735419409ce6c0ab5e4a44c0a38ac2a1de2b0e354a9169477ca29f5a5b5a68e018b27a1bc1f65fcab7b581f7b441b386cd8f8195ff958e64b1af9f175c88f4f3f6a1e5050ad23bed53cac8ffae3115f6a1816fb5706efbffd3e7f1d72e78f7e0f28aaef21df7e0f28aad6713f7e0ffb51fdb9fe41be7d1d4eaab48ef8f77b5cedc3df1a8431e5373894a558051be4c4e00725380214502cbf3ffad12913bf7ec4d5cb927c3ba79499519ef694a5295dc7c88f93563ec05ca2ccb418a564410e155c28426681cedc910a2e5cb1bd096a2e25bb08581400fe64d28b1861c57729c41bf78f702aecc8434bb1647377b93f9f1c37f5ca573ca5d95d6526ab5ad5fb75c7499447e7a2745bd975a20df4b59cf996d95345f8286539eeb9af1336fd186b848ec55b99d4412eedd8ad5fa3bbe64f3349afa5d9df521cee14c50a155c314f68ce2826b74e5112e03abb3e7abbd6a7d4a9dcd5ad57690a156958ee45dc7d431f774689d49367949e7eacb90e2a438cd4a65f75e0d95a93538161b6fd904be5a8a157bd7adf8b9920e58a5833e0d08bd9f4bd18777777f7ce7234969af697e2384e67aac86daa35c8f551bbb67dbaad86d998cd5f0efb264f98e4e0dbdfe48909d23789992035030e4d6236cd719bc454db5a6bf5c7d13889c6f0dbf9b8084d4aa66b7d68b2c4a6a1c9c9c4894dadd0e4894dadc0f4b3a9c2592f656ac78a2628b7229b5a6ce5b841cfe9d02f09418fa5677cefb52cafdcadb51687578c5242f971bbaeeb1ea5ebb2f4500e654f85f223432945af6e2c14d3bbf536622194431199a0add6eeb0da752545cb7733412ac324b81a27d1ff6e9c44df8573410403ac96a8440d1676450b199a1108000000e314000028140c888442a1583490346dd60114800f8fa24e6a509d875114a49442c82043888000000088008ca64900cace158f9140a4f6abd936dbb61ac399a6d3ddac34ea62cedd907a9e96648f15ee832be3af016957e7d273b5adfa71e8c8f48ba1a73ca5c290ba4d615486f2900b2a105fd07232b05e1b73383749620a5292d63ee59a54a87d86aa8373ec841f0e1052a721d2ebad0c688d1fb6503eecefa0bf61d9e4f96e903a08e4088254413f5f0bccc89fcba8dcb89d5c53d59d69406e9886ccb6eec987fa3ad58b85655f91fe479d402304a99ad7f9a36628c0e415976971b1e8cf9779eceb4dded96ab44c43346f8c462ea21563e85c8d72bfe55aa2ce0371f46c7bd48f39ff473dea1cf471454ea6d47f695712f455e0565a3e71a09cdb6daea7793b2ab0b3b02d156d238d4729ada3c69226d0c93ca18c0ccec1d19dee0395a3ee16000b6fa0878f3eda40826deed083e664a4843a9696b188a3a350cced94c351ff8eea4bde539c0786a32224faee18c33200b58dc05147f89d87c3233309f320b037aa65cfe398a0df0c017ba39a8eb443ab37ea9c43dfa1bebcb10b74dae8255bff1b95e2bd2d2a2d8954e78a046dfeae3b5950725e62eb46b57f2c2a83104947b3e6e8e66cac1b55a57d8d7adce929bd966a697052296cd408224e8284be41d09f511dc51955d89a51e57c67823d54bc8c9a1df1ce8ae4db37e93133aac291b48c7a42d5a2d4cab2d954f1c38d2c0bacf228b83d197582d137a03d3a905187e57e491aa37e60e038766c7160576b7d45da0a278305bf160ea32e326984514fadf60b07461d041afa67fda2a2cfa06d398b24d72cc26f8ec1723a4662aafd15fbdc47a8128b7a105da152a57bdc58656295aea8dbb2c4c2dc9aea5d495f2a16d9f43104b08715f57621dfe11355dd2edbe7d1bd41a02126e8def7d2edddbc81d11c8fde0bd89fa29e4f71da53cea1cf147518ab74532a9d6e4411fba4a80b51775c7c3b0d8e159ea85c7edca0e805060027d20075459f5c7a4a59ea63fe3712d5889501f1735ebf7f4147d4010e3a121a512fd8b9b3b0bb4f1c6d1244120bbe6593a93c216ce1e070844dd02a4c9c784922a2fead596415a643d434e6ed49fd8e88aa2d8ad4d1216ab67c45b535fbb681431711875e362127fb871aad90b3160ddc4897653c0992e12e5fda3bc5d6459d8f8bed651d4f2843f250f3212344382dba286ce8b042ff67298838d10ce22c74d08d0a7f8979dedd3077e77dcb12e0c8beaba1fcde5b2e0b1697f3a0fa5d0d18fc178fcfbad1ef23876abcfba3347fac91137c9c943484c1df33cbfe8349d870a89fa79ea95b3c7c727ff286da1132d2bd8d50563bb2393a67da69438f2a687accedd9a1c0f65640be68652a36a858bb53ad4955b68ad8ed3ac9dd1968373de605a553acd7a7244b841933c40a343cfb58d4b052b83268569f608e88870d4514565626a9fb03591d7e8731a8c636cbe21d76e39137acd12ba579fc0d8b458efa4f12657ae6a6aa8fcb928577d8e794aac24de04a7735aec19953d8510ab3aac6638d83c655d7fbfd0cf5e8b182104b9bffcf72e89db5f70bcaf283642c6a8933824de1775bf52d7a51a7a924bcc38eb3994703cd6eac0c1b93420f637987d927f6a991254246153d1e2c42750774b098679e76ce61f6c22046b6b5233b0f928d125b03f0187cc8699c27b1a1fc8177270986e0edf297f9d4775edc9a48bd6ce323833c8a42bb527c4b78f5a2c3ecf06a55b628688c7f585cc6c3516150cefd45497cf10ba36e4087224d71b8b9910e35d2ee8904ddc3ce86008bdac39a55cdb67fd5dbf530eeeee8a57b1148afb9a77027d75d416415d4828b74bc15d9aee8a5a36377c9b2c50492486210d10b48f56a06949712fcae5c29af803a152764bc53af394249082b51ea958337e5962e9bf9ba1377dd01e42fd6d9ad9e12af8e6aa91997d6c48dfaa227b55233476c0f01a929b919927ee0788b037ab7ea892491d11a41cd7aa687977d8ba055d72bc8594b93bf457064f5e529e344585fc909d774361b159c882ac3fdb95931178d17a81fb4090e979b42418598e76e2ab798b5d2814baab15cbb42624d8d4ec74a932c46a49c72d478426ae91046b0cda5049d138a454690f933d1f1a152e7b6d169a7112f1561c51144674e4aae439dbcc6e8a3c1438c2f631432eb441d7de7321fba481ae3ebe188414d3043ccb5e15c9e4de2651683e6c82c6b60cfb6f045b59e30d553c44523f5b7295d30c58c88880b7311977b845e8a6b0198c915212ea52d9b52579846f874ea60f93c8cd47d6e8e935741537addec94cc9b8923f28fb75d6b0ea9763553fa2803cce1728b4f94e13b1372c8cc71372999523b7c94fa5645449600d4e70188d9a4749adf811ea5adae47fcd2c86353ae2ac1943e964ec9c20e2c79f3dfc22edc6c29f966e8b7f0521a77c03710e0034b7a01f401f07af2609d40b2d0208f886f8a875c835e95f4c1228c8deba20e231d80131547408addaf89a183b59f082410bd871baecdcc9f583a1c6babcbce34f27c83b534069004aa0b43a41e7265dd84a15f7ef533d74cc28a62c27ae03e253a34736bb00e1e63119432166b99b184eb074deba236c66acc42dc43f898e34441e77926b6c7a253d40919389c31be76bd2318014649e183f50be32c93e68f45655886e56d21fe8808a3cb112848570ae1ec17525823ba836a491031b688311edab28753bd15b8aeabae8ba0a9cf3dd85a18adad817e9c7dc99c2be88db40fa5548b788fdd68b09783582e5609b87d28ffac89303789ba0530d85db2dda2077a1da3881067cbe81ed981a80429a034a235f1fa8f4e5f68f473afcbbad4e17ae6f60cf961611c4efc876999e34aaa34c95ab10960a9f2b67bd9fb1d55e92c7dd3fc0c084a7da32b2c51b30f65839e2afbe8cf02ecbef0a386d25a8b52e751b83a5f69fc72bd6e94d497da73274eb0c91bfc8e0a3dc4a5e51828c56ee01fa0901a0c95f68ffb11512bb06bc2f74ac71bda102104631559ffc05a66884839df1f6592e24778d9fe355d894b0674203ae483594b19d119075a4eb6faca561de003d9d51977c0816d720f43f3cd56ec7b1d9c64cc9b67e8af5f53a974f40fa9486308a02428aa072c7fa552401a2bff66add0565bbf2df2893f9e6f7e8d7af7cea05747b737433cbca1884a23dead30d0f8662fdf1961155d7981e9dce6a46f315a7ed2e7bba32a6fb235e50b8849e57777cfb58c697e05ed1b46c4abb87e0b3639a3175580252fc06e6350bf95f534bf2f1d755f1c2236b3317ba1abaea214bddaea9ff8cd81ec8e0f9acca2b0d2652d366e8eb8793699cccbc132c84ca8ea3ebfd0a61bc872d7a9f7e1e6fe9d160ae348165e83854d159bc465c95d3b60b458d7e03f18520501b2c28efc31a1f256ce4b2f3960037d1a17a96581ac391ab3ea82049abeb856d054e182d1f9481072782d834c12c00fc75c36635da645d7720fc4f1aeba0892335e675d1248f25297b5dbdab84be6e9b2de5b5b395572b9b1bb1cd2d613d03f2b885cc8fab27dc6677b3c1e57d70d300a867415c61f9785c6552c5489d6c845b68b0c6ae78137e8bf500d0bd7bc41187ae9577d6e472f58f28d202e08dfad678451e75b706280a1de8d3d5ec69675eaa37e15bc67465b1fb93d87c40d90a9573979164c57dcbabb5adb146c9efc49514f175ee48036411d883af5f2c13bd9917bd51edc55602482d74fb5499506d0b8812accd632b1402bc3f2f7561aab9d0ee8af4a1ef9e3e54d4ab184bb0acddf547b6424f0b9a9b4fd729843169017f406ddf5ae0c68f09e62b65feaa738da601a8bf2890a490b610b687ead94de8d2c4df620f7464b10b8fef9a38ebcab9efea3857863fb68c349b3c1344edecfed4342237289708b27da7d80db5e316137d19500b9287eed89cc033f3ed81b8030ca7faa8be49b94c0a8ba8d50893851b866d14a3a8474ed8c77203d3e4ace95d6b9153a2f7b29c31560ef8f4eb34f3817859fdd3e2bc3eaa4d13a1140436a1f3533227d8cf686eed95e090e6921ef6ca98fffad0638a3e44bb158c08234aa73d4140f074a24feb91bb628b690eee80e59bc1ffef4977c9fef3eb7772e5c5ac3feed190cd5ba9f14f5e086f9c7b2124f5b1cf43d228e748327009adefa156d3e63fd94ad5f2fed046dd93c01fea9bf4a666aca3fadc8756f1cb61940d89eae2457f0578bd275c0cafa951ecea7bf3afdf01e61e245d1001e11eb7d386e2eac33a2cab17520e2932d38ae653f66e1f3548e220fb49aaa6faf18d61e7753cffbfeb213884b61668ca87129abd5d89cea8d1d36bac030ee36eacb157ed1a85cb40df2aad72c1335f4c164aff56dbd5c8081c5da08d976ffcaf5bce07aae073b223129d9933f4c147b697f5dee5a1adc4ecf5372dd747a8269b6b1e7a7bfeddac18ea1bed4b3194db50c24ec5d7bad4c0f5d65f250894f8f1c8573610d6e89bb868d6841280d11fd17ccda3fc6d890ade6777c8fad7d08ae3dd87fdaaeb5b5379d72afe7fcd1ac3da05bfb2d053ca29b76aaf686abc2e6603edf74a77d8d887de85f7dd3b4dfd316a3bd727e5d5521ed9b22caf347c08e668fbbb1ede67f6f03cfbfd4049a57d0a84e37feb392f3f1eced80d77f5f6ff84729b5f686e90668a409e0dea57d0b0148822936100d511ed1d1140e3140f9a4afbb3a3480046136cf1444d72fcdb5eb7126074485a3ef3db3f9dc895c2c777e175605de917f1ebbab0bfd0e53c923cd7f68584dcc21f1732f0d4f2ec14e062cf33305636c7b8c6585419b89a6640491ce87e2621708e8e0aebf8fa50bf064cd8e02dbcd17222980dc5ffd167b19ece7379637067a1bc6a22a82498631b7db5484c16b3ae83217826154744eac29cebeadd6dfdb75dd5efcf1a2bbc14fa2a64e3649e0da6ff1976aeb8a32191cd514b3a6ca01cb684f57813ceeba9fa6959dc700c49ab54a3b973eb2726cfc0607f2f495b766d76c671bb74c5af925b6e79c60b1fa2a42f825a361de1020f9546ad18806bd95e6d6ce191d7331d7995adc1a66cf99af3a8605ac5f5e8a037dd5a83be4370a47b45bf78659ceadeb5c2bedc76a3f680385b24ce0fb0373e0c79a4b6c4f2c372764272ee642462282428f9da1d5aa84c629b78f2557a2b70b9fe10e7e6c7832d6e96adf9d93a7aabde2ff5289c832cd57f4bdbe3aa140db531d4a447b236604194c732f82190735e8bf29cc7309549b6c860e485aca3cf6a77bde7588e22aef95a4be28369de0c7b472a2829bb711b3edaad0384d4f66d3f62b3f487b779b0d88ab04f17c274d4d2430945ec9e6b7bd6e6302ff6f2dc22866f3fd89e9f2bf151baf21a7afe7b5acd9f325584d22040fbcfaf7769bd885ae5bf10f7c15ee7cf9639af66165ba0ce52e0438fbba889bc41dd2c85dd5b76809ce921fc63eb3a78d10426c0b8afe6e4d75e8655646f8428953b629efeb08e33460733ad2ac7bc561e22db0731d29f72f1a7a5fd99aec3a2441ff23d107cbc9c58aa0f1348607aa6a443463ca8ace7e799a8649e53ada016bcd4790c9f748a64bc9b29252d7c4cccd2e929755994c4723071a14c9ce35c0c464158dc4a1c58a74b62c545310ba1232376ecab345d0571644468e0777555da195f73ed644f0f9d377c790eeb0a2ee5cfe3fdaead58b391fde87dce2fef68e06b502f748de535776b6293f713dba79cf5d4e7cdeb17f15033766274198f50479291e73e7e7e115ed24476e2ab9e8c28f59e5787aaad8be119e5a2dee98d575fde4138e2941c9c2a8328172fb6b0173b7b0335129cba1552edb846f96694138261db1b3918e66b40581bc8fd6371e6fe2f9df8706be076468ad103b20f3195be7ce34e874d97fdb678bd68cbbc13b6d2e5089750388958298ce6d390bcf12526735f9b69414c09cf9643a930ae42834dc038bf4b2d67a7de5419ca0b14becb00e783f8c918b9e97d8c7cce22eb6337f1ce3b042aabf679d791739512a1fcab7be1ecfe37c23392221aef5775ca6111bea9449299a6b28dbac4355dab95b9490c8fabd1f5dd8ba48c40f001d26ac14bbc63af898cdec11c6fa97a27acb170ccac556fe7c986e005a878b0650be7e43ff0d40a8c2c91c8171e93174cc35e8f83a782e51690464b15b043aee8e251a9f5e9e174f2f4ba69be33ba174582504d8e94c46949333e40bd70456655954234978b45bbd33bb4ff790614ee88b0b96bf434f01ba89113ef82927d6c54efaa5ceddcafe6264d4b21df1c7d0234ea9b81ade9b8ac876294f7ec5b5ca2005ff4f7f9113ddb261b838729a16414823b85100be6cd4f4d47d55388747aa761b28f6fa7479322a910d9cb0d6d8bce72dc927928944162bb62ba3ed0713a72989933cafbdfc58f2b9d884f9f13085d08d88724c153770c2db82e6ac310c380bab001cf4f6b4c185aa702087f4596c554673a00eedba458b8000c1a94dc3e39d9fbd94b5826c80c013356fe5419c3417b2488a67b1fd63807311e395d8ba4a6457aec297593d0c46af5011c13a62b6f66e7067126a0009e846da027398e745e7f39431001aa70f14977d60f687fa4c1ecc465395c9209c6b1ed7a57c958a77223cf2436ca7dfdc69de59bdb7a8e886486675d357bd11e08169043e757109b52e71f5065bec368e9afc292ca3db1e727b5294a145448f5089f06a0ea6c8238bd717cb81f01024a7f5cd3a8a91e4feb36c8ef601f91e2eb456cfa016fb3d7ff96f0d6261bd488a9ab7741423725b23844418e6cc98e9ce9cbb18e255b831891af2775192e8847a55d26565e08002d562419c258f0427456bf7f63093315b505ef6a9e7463cb64d80679661e77d8b79004c346344f76bc574f68c3907d952d508b2c2d281a0c9412ab8d2fcff66e5904087ff1aa8c92bdce8647ecb88780805117b63b68a134b152d6ae5dd052b306c657bcfba1b42a94b46344cb9a465a5c722fe3d9d0aa78ef99dfc84c2d1c205e7a1b58d2f2407f51f0fcdaa9c12487e50fbc24491e709e1e3b3723a90ebbf328b25ae4164805126ec2012643590c6d441d8ce978f063981520cc78ae69823396ee065a89a64daa0e37019832ff384ef5e0ad05aacaf5d0fc9ab078efdb65a710588c35f38c8d62771d6452643e504691251a51df6145dd87bcf04a325c84c47958798ae5bdcc6624c719aaf109b826190b9068b9b5ee32e14b8cd2ed181a2ba2452c00682a026dcaa022715b825944110f630c67a36167fa087d36ff351924cec2b59106b321f48e602f9a556519b7a055cfaed23928f14e389be2c35947405cca4b78df8594189210e0ff60353254815392242188b73031cebfe4534b5fbabf5a69d1372e4fb66c5f749c286353520cba0251e3195e9f3ad88ef392928e2eecc441801d9b9a84c2ace60969958b1133685173107cfdcc9ea1fb1013abf128bea4b1fe0a37ff14f75e0b270b65cc19c2d71604dc08c675c336fff3bf4db70cde933a6fde791fa161e89c44015127e4c0a13b9cfdb1398948d1554fd4d4620d16947955a344d219dd14f57cfef12d927af64097826c032603d9d25e4758ff80bc6bfd7ba271d02587accd4644d85d1615b9557031d1345cc8db054a17e7341f4d8eea2e71acf93ceb3062289a100bde1dd90519273b5b39926f8c45d17848ae475bf9c371e391241a2250502a5bb98155b0fbe12f44cb62eb5240cfffd1d2bfab19888a931c9da223efc3601a461ff75e798494feb5c618880946034a766f73588a740e28773ec3ccf44581079e627e098fa006bc287d03d947118d0f56c885963e5910a0e7dc418885ece0aaac0efdcde820a70508265d40671fec15a74b374dfbe2f2ae2894e63e50eb3d7d4fd0143392a1cce41f34288bdf06ccf2bfe1dd616fff6668de31a8c28fa7e06c7ab6afc706c96b28162a0dca6ac089baa5ca9b966eb0ea168677f8a489c4ba0cf520474fca17d6c30b2e9b66486fb86bdb92ec9d456e6a5a1202bec09aab0bc41a4f528c551ca096db3153b6b194f1bff8c03b7d6e9bdffe213106a1803db948142349467e6cfd97919884588de61677e2a3a3ae7baaf2e25d86b40fdc7823c9d3cda4408ef5e8e491f4c84203e60ef46ebb569d3de91cb4797ba3a54b9e127cbd6f3e709c25717498f18fa9055cc3de500b1d4e59db77934375a2335b5d838760577ef2741e5a6276ae2352138c5bee0eeb677425cadc17e3115982e68eb345611525d63874c407dcfa92eca3dd7718685693da638b9273bd851a340a0aa381d288ab5b766071d4827b053e1bc61f3fc348564c179b0077f1f36da957d12a29767f74cab082929705dcac2167ad28ed4d8085ab6bb2288a9546809041db73cdf22dbbaaca86c43478490a117d51aa9c5a80254e4cfc2ab15dd0aa7fb287a7d5f85e0fdc67767ef4e2d903b9fef2c64f1b830a875f0fbeef6ed02f523578ea7ef43ac9ce882bd0e80bf59c6fa9482c5ee06cb5381366255effb1616f502bd57bf2c20b4c9500b84a2ae03a123fee7dd76073be43d87765b1c6dda2208150a1e8210b385ac857381485a9b2f8c6b02efdf6b6253e06bda913125836a474448ebd505b9a0d49d0ab4eb1e6cb072bf15e2638e6fd86b01fa7bb96f9268211718d46822aef3eb1cd415827fa7bff37464d7f7c39c3d484002d5ce53da9c37abee4ce89c82e7c4c43d05aecefd0ff891b50cec83af209cc5ea6b87461c36683fc68918004242becb8a2eb0195b3d4cbda79c79d54c8522897e2a1d4eb7f553ec40556e68c5dcf25fa93de54b0f19643d1bef7310d5bde5895f04498e35b83933edad3f6ab53ae6d8ac901809894bfadb46d2096ff5358cebdf50d7871a3bd470ca34dd28ccb40da26d5d2d6a0577df5d48571ebd6eafbda11445392c8a4861b71440afb4971aea1be1074eccbb99cd0fa38ce2ad4061564bc7d028efc23dc80e1628f4889f2e638feebd39cf2938bcb3463a638d218661b0ae97c6e84e642e4769016a4b08335cac2331f3c2728922c885ce7946f8b97e75bf2f52b81e4cfa3aff76d0c66ecae70b0f53a9063a11eab6b5888d1de08ed9a30283be6cafe652e1193ed40a513379f53d5f2928541c80ea7cb313d9efd46c7ce231bd6da3cd9b4a7c24f09c1cfbd7f7cc6e2abf8f0d3b36341eeabf4f435ea607c9fce5aad1113d3c542cddea8237610e74f2f83deadf17f96f202ebda237bcea2704a62a374bcf1d84d41a419ead04a42d0b022500e2ad63a8189b3bea28371946b7fe33671061ccc3c982b2c47dd12794499204ba26d07cbffbaecdcd8f0115942e21040da8407b02dd00d258b23870c727ca9794030c98d65f551d7a0108ee9f5075e8ffe6b8947550a1aec1768c90dd4e9b381625fa12b3b8f2e8ac4e18d8ae69d869904ec9ccde7895b9b171b4c4bb2c56abc00d52f9b725943e0ee0c788b2b265447485bbd94b4a934a2e3c3cdbf7d0484517081b009568a5ac2144597e140fa26972e680c2b6b9301b7177661de008a2f7f756f47441ad566bc33b6672208cda1add9fcf8f46a834fa964b67b9742fcbd965b5ddb02c1771673e0b7e1ba40aea2184a351b130759be1f57dd605e6bd53e1e95060743aaa3c11bba9ee5d05d12a7b7085497d008168ec4f835f825b03bc9e45aa7ca6885fa517b7efe3e26b2a644ffe2d72f7d283d1b4c524f8b0c4358f5e7a16a9f1fc2a8d22e5f334c6785a601e6b28b88f2750c104297a545b18ad0c1040fa5ce2d06d33e482583322fc37e4a81252d1ee45a474ae68492ac4e38ca0975b64e8215a9acb5d7a6ce45404bc781e3d9d4dc126c6eabca22fef4b6b710a271be84972efe1285d60e7ae5bcd734c41612665b87dd5958ff3a2a8fad78843ff3d0127bccfcba36c817b53e1a633cce3da6c2833a88353d921634908dbbf653ae2965c6da9bd76552e6a08cfa4a549f1ed4c44d5e5e8ff3cac436b11524e855973888f8958b0220b9bf6aca32ebf94590626e82725f952e29f6d32262cc998be88e65eb43076e2ce5ce2ae5c3bb7a5c348328896a111e43dc55ab837ef7a4b94d574aa70b56eb4e13b8bb0ae608dd9435b550f6f89e28fdec1a8e9f5825b0fc5be119ad69eb759976cebc6ea27387a45a044825b0879a54de729f7988c8bcc23a3f9767c06f7e5d76be852572b1cd79531071c55ea742ef21bbae3d4a9515172fb30758d090482d05b357aa90886f5fa85a92f65e375b38e0c202f415261ea68e85dd4e857a4929d1b3372c5dfc30a314cfd62c7f31ee0c8adeabbebff9e3373d2f02fb05cbb5d50e63413e05353931d1d258ada35e1cb32d3fbc48ee81dda714a5b48efa39924542f4f3380789159a61307d8c15c4de696f86517a7e2fbc2ea15cbde86ea6ca8bfab603b38d885306942f672bc57bf9a64fb7f460403a1911c3ed9f780a8168a80709b3c9644966f46979f579e3579835bbe955ac184119b1c171f1b402f75cfd518ad14e482641d00609fc975a8ae747cdcfff5c3195f3f1a2d80fcc6af66d41469228b84bbdb20211f3c8a47fd54a5bb31ea385d5d8f5f33f517628c9064ccc7247590e69720d6e10b00171779a91a6a7fe58717858445dedaba3a99da217b8383f381d447f9afc93367e75565c93a8232f8ec94598388e3f383467b5ed807cd91dde78c7f350e760d615600923a6ed72a5cb02720a341b0a55440a13712f3b408d7024de7cd8132ba9bf73eee95b4b017d9499c16680a865e8cc4b299500c20ba8d07c4a81918862b25e589fe74f27bfdb57505c7fe6d47c05a06924b80e979165c27ade4ba5e19186bf95bb63b741f466994bf64aba9c42b306ac2d02417a12e9d3969cd9170c9bdaef453d269df27bc3fe544b894e81cc1e27cdc596e7292d74da5ab32239ec1a64b0b112ee9c833ce5087d2ade635e0e236491f4c47885d23f5cb9e3dae114017c0e03fd2ca2b5d2261e114c89dec295558959d97bd9de8b5de08f5ee91fcc5fc7e185e4ceb99d872a0ad38d95903d49db23aa315455fb4ee4686211770e8161380c4ede979c2e9a24e4ab0fc8f5d4fa2d3d9fbd5439bc26287c1ba258bd7a11040e6e0f4dee03ef199daedcf0c96ab71330d2b6f28cca2507412927b44b93ed098416cbc585070a50c14c066a14ff768a2af0707b3be12a274ec1651c36a4ade863516c9c89c938898954eeed2570ee436748be2864834e069766b936066d4048801f96189831b85cdece6dea552cf5eec0373be15638c568add39876f5b1c77063bfb40a0bab66a076e2a7a898261124c82d7511717230736410fa450a1fc51a2749334c1b3e19f7cc8ea6654a09b1fec964f13f31db6016a2a16552ecfcea9e6393920c0c63c3d672438e23fdf4c73fb012a5881d97df5605c94ea3b713291076861d3730381efa6396cea7062a15941652010a62caf58cd78607f648da58e9d8780a7d8ae2bd9b830f274c8a7b225815f9f1f398ef8c4a05c3b815048a0177aacef12dc079935ea8517050ca25d2e7737bd14b0d3914905afaefdeb055a69902b9f897881cc80b1dc54ab72334058b1cf2040d0607da54169307a76c7b05d964ffb5683508a1e6da2450915415c084c35a8a11632e4229b1af0fa5cf034f83173682a173c4fc7d568c5c136240079e7c1aee4d0755ede1e7a40aa3d4a91e67b20db1a30f067d3bc9a2adf833061d2947aa3ffa87b202d8a20a4a9d11e10e2e6e869d83c0fdc1451dcb5df46dc889be6c3d8e1ce2489c3a34fc9749abf606a8bad47d994c01405e186d9d0762542bc51b8912a45c293a10f37253a5678fbe7934c02f333c7f320549c8c4e391282fe5f57afa5799aee68e43daa84b7dfa032eea2142b79eca1b4ec9c1d38dbb1266353ad2a9d63ed2c5f8d6952406d22118de395f7746457f8ec1709947a44935bfe4097585a90b833fe621600f37fcfc1aa8eca6546f9b0a57858d37b3a05d7f2c06c0ab46e56430577e5c402b4aa811978486ec2085a41f3a76477c5a5535d510a767b5ec8e28610974527b40f39ed56f641e43c59ea3ad074fd0eaec461d6f98810902a6490aa2f19f0c77acafd011fbb0138ed928228b4805b9fd99de53c2e184b5a157d9fba05c308d77b3bef41d216faff5fe264e24228f8b6d54811ed2897b10bec42bd19c283b0944511dd6592bac2fad1ffea30934f04b9d77ba48a00705308eafc7ee85f91f81edb508e721d073c21e67248ca13c36e2cb3d5eea9d17d977ae3dd06ebdba00518138ad7e23ba22de6965d7990dc810f7401bb102eb07278a2701352d92e1ca701dd76243b60a64c50e6901f49096de7dc3e36d9ea99986c20f415b43b9c02e5d3a1f115c486bdea09081e83637e8be22a6d74f9c4b5855ef872186bb4001a9a8bb7b3064781c51c174e05561bc5b8cddd4a7487e30abdf9996741faaecd877c75c759ddacb84bc80196d4830a10cee8023e4df5d9d3f82251656c16b31edf24563ee5972405a300247d718df3e5762e1b0525a1ea651661a160b84d620be7033e35cb7d3cf842998c9b37e4815192f9f657bd53dcee4a725a31c47b8bc13d06bdd2b227b641bdc989b4c9c2a6f99172d6620beffc086dc29f07c290921792449fdfbe02c3f05147f49682519077afab778b2b7bf43cd2609331c67d9ce92c2f6e076dd6a6ec9a2fee051dd6d82a449bbe68002879dd2eb6efc62fc91088871e6410e821e5011ef9a618da22281ac286242ba34ca8296e3f37799a240b209b56c957faead6d9fc4de8826929ad8bd42574b2982d9cacb88b2aa48f6b72f2802311d08f222394bfd968d478d733ccf86026de37343c6534a52c5a48d2f1d7feefc2a78ca0f2002be8844999634295a4db4deca8bf174e54c83098bc5e4d0645df11c2fbc2db767ee97b2ff5e35186de47232da250a1faec5480559fb126f7c04a5c614cfe13970394a72b00c586e0fcf8134fef411a2f43fd81e99b20eb2f9a1a42af9df35c3595979e7506ee69df01f981b77f78595504ca63cb13e2baf865c0a03e8e5855c817d60fdb3d856afb7f3f98dac2f1b7f0c99937610a0fb88fb4fadfb4d24f14cf481734182284bb30c7324248126b39f20f41b9d83ba71baacd4e46fac06825b6686b37981a9e191fe95ed62bbde4f432123f315f14c3683a91cc1c804ad44c4464029112e49d8ab02536da431323bd50044b75b3504041d48769a57156c4bd48e688a884407c8c4c45dc561400b8caaad613338ac9d091275044a2c6862aee8268740a646bfc46bb1ea88d0074e2c0c3e7105b2c38b7aee610ed07ca9c03c28a63d31c54201e53684294a149e090ae22e8e65036bac9a385ffa9622b4f450e630d2871eb2d0aadbbcf44bf770d69443b70c5d871664afabf018294cbdc99b5639aaabe1772f36d0a0969033b198d6bbb2bad9bf70a74d955840dc159bbd61c6a11c0b9ba0490c614ae875e08940ece8fdfce72f6e0a4db581220214f2bee8a796f204b3b331969a1a812e18dbd4296f53d32d22615d92c1c5b977838973c9f9c42efca5abf876342753112c517f1d6410ba622332454a0a12b9b7d77255f85f2d7d121c78447aa9095cb0c45d4033b886383044aba40a441a451d582a9370f84046710c2e006d1e30927da15ec715103921f46bb2783c05aa5876e5645bbcfeaba94e2e2b845637d107bf062e1821bbe95c686e39355788a12ac44d2e1e6688d9c78a61a439f992855900799b6b9214ba36409e9971da757de4b706f46ea15dfdd6df09588fd189ff2810d849915b10bb7ca6194eb9c052489e4e8aa8f03e6ed6758a2aba37319f4f7b8f181207a6d493776fb2b5ffc0c8fccaf77921af004e6812a422fecd38aaf16c29368b1fc6f8d3eadec5ebcf3187e6dca83870ecf9e964454273560e1f92980e117c40da002d738b6365cfca7e7442713a04cc46e4dc2bf485830601df7e673270032dd04154dbdf086d5339dbfe391ae498e19d2cc762d48fd18294f844a4665100f92b8771699190cdbfeea868cafe1b500f99ba2365885027f8bb4b321664d9598e0af9a269f4c026050867d7bc9dfc9c3f3ac53bbc8d40e00885c41502c5866587a765c3c205cb8da472aab632bbb2601b81415a265afe842398de64fd32d9e2c5f3a94b04122b460caf400bf124fedfd057d722766911a191a32a4149853d393accada3799313e2c46bee868a379317755c36a4ee049b7316819f6897b603b627a393fd78d5dfe738c8e00d0c40a179463d0008bc61f0788d3fead4b15d862ab531246e1e1f401afa989d8ab6d36e7df1befaf51e29296ede257c46706ae195f5dfe57fb6ee08119ffe82f7a711d783bde74d8cb35b81195566b1118cc85ed0eed3553962920f8d0f3cd03844d2bf593698dceb05db36970a0e6e78b5e2a71b91265f9152c695372ff993aac4e985002715033e636a5d6a51862e19efd338789ec780fef39330476d1b456a2cd91cd6b6f999bd159848ab7ce1ee85c489559bb121a9db998b260960edfa059fa403bb17695a03aff98f310df0c2c411260bb36a5571dd95de4ef392408e09bc9d1ad0cecc75bae7f2af016f05733d2b75496277db540ddcafca8516a3cacb44b4251a27365c7ad75ada53e053b94a8f6354d9b24c1a04d15f58cd02588005370f8b562e0d445174aa8307dd4444121af28bbe40de07cbdacb187434c81a4fc2edcf4d8d486efa175eef32359aad51b87dbc5acec27cdae13040de3895874eeef0e8e99af9352e0c4ca938c651df84267c052163ade7aba51628f5dd45d580768c55df24405ca9fcfba640d5d0d5fbb6c5c169a47b716d71e4730617ca2989aaf4c5f28f86fa27f08adb8548fa7a66e6fa82ebacf690d77b6b19d410b52f59e72d4e32ec2a8cd582a0134199d0b31709be4236669c40a44050c39b0e6f80bd74ce2a8e06089f19b71741a5715cb52d25fbc1c1410c88dbf8fda2ecc05e019d8e588e2ba690dfde56d2f9e17760d01e2d8d6203010daf734070398c2baa24537eda0868ab8adf298570ab9d0cd3ac7b973d3e81c81117a2d31b531039e329ac82a33271c098298ec6c1bb0997411709b09bd03a069eca640934c1ccd48bdb156c9bae202e211de85dbbfdb540822c7e76e270d12846eb1b005c8bece5fe1192f79eb6190f21c81c5ad13059ab28a5032638a233076990d94591f4a7066fbecaefac34c2a9fee0d03dc656465946ba8bf51359a740dd5170c1b1018a00d315b46f04701e301bbf6ab9b9fd1e20dcb7d90f2417014c2ff3435582aa03892d64f14fd3d23fae907396f0f53510c97baa0284de7ee542d57d06648cec94ab15d8918b1aba6b5f6c77fc06c6116d464d6cb57544ae694603a68f9439ce7c2baf89056ce595a45cc105ea7ce8b850f897d14b588be212aaeb140dd4d0331da04e33134e9437e3236be59175a7565459479025316e36e28bf28d1c3f1707542e2f29570cd4b0212343b717f5ed8f21c88489a897b411411fcfb6ba7b25cc121d6f27709adcbe364775bc45038d2598e14b8d49be92d21f376f4ca3c5d2cbfb99e87cc6978fb744c73465675b2349f1472791d843fc82dc64f98b9986cece4d5dcc628a4c4a087115d1ac3e0b4cf227aeb3da2363f8a2fd2aeeae19c8bbbc45581dbf982590ef29d0bac2994140e62e7ae49c1e4be990449531f1742f9fbfc43a21974adb984a9de46345b8a26b4bbbac3e3ae18d3afa3bbd0ceda474ef463ad1260c9d66b9d05fabcf8dd666286b6ece1e9184c31ebb689a8f28f6bcf2704df3894b776a0525c32d05f9ae71b7e004fae5b9dbfae7a3eecc3b885e73bb2c05ea2a9a0882d8535d534324d2dc5504e76ab402191ec719b52dea2dd4c5a63207f96b27e02ac4641c16cb815760326375f0d1380363419ade1aa3d34fd3547df10e8d5a51d9ef34192bc972a3654476c8e55fd93dd8c5af67ff3a0d8b9461a517a99f9208bd3f0c3878ed02e9cf4975d575554e91318c58bb9ba961151e8afb23493bfe695a89364f42d4c39bd87b0a46c25c4a5e33b1f78fbc4519eebabe730f8d493aaf976bcbff5a0ea9b35fa9b7e3d8a24295ccb79cd37bc479671e4a59bae144afd361cc431255f2403544af17db9d3a79cfbe212ca06a8bf1924511e6222e4e125c36c488414054966028c527b791da06413eaf59f25ac9a628708fa1d18f3ad164856631936b1e6241bbac2091b1603a13b48d13fc06a1c8c5aeefeea2fbacaef75c17702dfafe98ac9729a101f98b1bff5bbce772a6f6db336ff11b69b4cbd34142648fa26ff6665ac3ee1f58680d29451883260b4352e83646ea0e587d334ab601e5db37f694406d1ebbe72ad3769fd287dfa03ca14466d67b62df89a0ab393815700888a0b7c24cb6d328c296081aa675647123831601952d4e29ac9b03d9fdf8dc46fc332d35bdd253ad806087064111d6324755cc9bb7c947e3335110a911c3fa994e139286167d99f7bf96aaf0a3751086607b3ff45942182573ba518915ae2a0a610ab8d648ff9fb1e0be9d4824a6ea3da696feed4248eb333ce9984476597d385763b8a29edf005533204027d2b5aa786df65996c65720997e0cf57a1c2ff9e5048c17a530593312a5f0ef4e32d9a7e13867f386f7dfc61c7ca2827ce6844d63036683fa4c887c2bca915ebcb503b4f9a0a586fd3985cba4bae382418ae4d2fa5185ca70d104bed67d3f3847488e74ba3b11ed3a6de58ef31591b7d452c3d03fdee3e266c0c88bc1f53b5aad230f242c4fc7cc3fae6f02ca74cb011969d53e0ff215a350b70f3874a4b0eddd3509f0fb33a4c0d4ce344454cecf7fd3cf80b8c00d8187f89f9bbd54afcdfe3664126d23f142c2e9c40812a9e8ec4c648a05106759449fdcba547300e8015b82228642b99af58a6087e60df80ba6c298671202bc7f87a655e27b241c64406fb116272bfe16dee1cb93226ed236745832859af0896fa33f2884c5beae31e0ed736323f26a44372e92f316d6886c769a6602b7882871c362353975cedde39894f157c1b4db281b3701493127422e3809356af973085372218297863e7714f903b300a3ae97290bfa45a37440559d84c9901170983936bd38697598ee7fee56009319c14e5231219719adb298aa1d1c0ff58d22607cc5e82c37740ff18018765991202ef70b057b0c297692ac894550e0223a4bcbe6d39cd50da849d9890999b3834599e1388c3a2a50d5431885472ad583cc76ed1f56ea778b9d5e370e0e7431bb5be3548affffc387ae2418937664ce2dca5be99ad2d04ba7c38859de7be8018fbad7bc7700648b07f953288aec5936ab536224d6ba021bab06cd867df88d3f2f63fcd6fdcda7bea7cc10c16fd72d79b858f9caa05a13e710b379a4803ecf7af5eceb675fe204a55953e75175ca35b781a4aef646b7777f47c36103c9a927c20c1a302bf07100a3b00bac31e361c2c626f043258914d25b058aadf8589232ed79a148d209390779f5d2ff1e83b1c80935895a5d38c00d99c0220f10a7994b388a6b792164a97aeee047587db0c7680660d990a5d152c49e3ea1264a9fe3100b048a2da8fec5fcea5afe9b0a43e244c0f446a59a8cdfd06c2ad1be4bcab5d3ddbb1b61a280f916312f9bedb7f0bb840feac9c8bf9622eae894ac82757882382a63d4bd1ad8568de63ede863c886b5790954033a5488b2d029eaa9cf056d3f0978ca0863dd9d003816ecd6fe022ac2917c6c20bdd29632b87068cf0dec611182961ec3155538f464552ccb975c8d60eb59c3a32c8cafacb6d7fee4afd58cdeaaad0480c42b57d2da9c8e742b67c89e7a761ce120ea263f881d19d7e535eae118cd4993ddbadeaaf8f7c35c1f82c1487dd24211a68ff141cb676dc410d097e4706c0c8a4e46a74a29483a0a200a355e7010445cf6ab441b2b9834fe28ee81408ffc7620b3f845ea7ac330e73332b8aa1498d53d72f51eece6263e5bbfb796a12316a3eb472a39101c57e4ad8b5566b7502b6d846f4b276a4c826f12005bd167aa54424b1001a7eef6b77d5013d0fa1047e2539dd77738ab674eb47fea5073862aae2a40d67c09e0ce3ec62642cbc3d902a744353b7487475ba6e889e35a5cbd77fd1a569949ba449cce1de4e2d9dc8ce6b958c7d70c52ae17636d8594836b986fec1914a79e8addc432f429c53fe459a9c239347c64dd327dc17a01737aecf099bcac0be043efff02289e731e4065e3d9a848aa8409b6cd47fcffb77aae7ba0fc9c1f555078854592f9bf26befe1dd650e432bdaedb880d70d61869a53c97155dbe6321bd9f0b6619cd7f110588e0b2c7e79a925c82ce848dd0b49b4544a50773b18a1f070ae296271618a2ba828466a083905860c00582f5770bcb136d8a0647517d2e5a7dd286ef7f967ec281ea5695cb5d0f48412cf30a901d2729271632c7d7fa2ca2cc5606c538e5cb6c6cf006ec9c1f6e892f13d6fb98ae779c7e3411d96266e13cff369febaf587902c1fd5e1b671969d791bcae327fb3872d4738cfd51b4e5cf27f0cee58a030b56706ccb2d708ae153afee92d94362d7d53e459fccfc7d3c58a176c6ecdd3dae185f005c88a3aecde0e467237b79021fe141552dc4f4ee90ac493a644d6ca575c43961f5a6443bfa53d7d9c612725e8fbedc9fd27daf6edfd77f06413a59b59d8583afb3ab0c4919767e17e928c9692b6d1327df634b8c206bbeab4a4090fbb48d4d88ee7214e24edb688dde8b91be52d57de421909275ea40a7c859ac6eceb685582a7e23561c7457b4feb40be42dbf611fd38f5d0283f3e620d02a82d940e13d22e642139d90639b27d7fa3e5e8103d5c66f23377033c9f40bcd3e73e1fa526b7b69e5edb6a38f57aa1c1db02d968090ca094f247273e7d86b57b3087d42ab43a89e03638cb4e3dfc3a4a116294f2ef161602b70e8d88506b8c2f365393c5b5d2bc1f7fbe44ec930cb1c4cddfebb2c08ea17d1959394e16311f9353919daecf3fd2006af3514c50de7e201fa11f1bb65c962340649035a7536a422b9ae6a8942c7979552d62ef50d1736588bec497fa9750346831857151a47d4eef9c205e87909bfd50ae15a6b88188ecbdf64828a42c7ac96f10eaa12b90971df8d9d45147d88a5f5776412b7540e0646056611fc91c297169ec8d3b387460a3530d8ed475dd9559fe546d1622dfab535f5da5afce69f86ae19000a459370aa3983d2dd7b533018fa441b528ec638131c39997e263238a9b7c4860ea5cfe83a874b23ccf34a06ff8af4cf45724c2043559e83134b37e024f2fe87ad5268cca2703e9270f81cd6b8f7423f10c9a1ce367b803851ac46f3bf10e8904a47b3333fb8f6721737d7a3f644cdfbe4bd134800d6f4932227926b9497e92bd63ec0ecb0c2252b19fbc3feb2a07353220256d7aaf97d1a6701d7cf50faea1ae49ed5724ad7ff33031389ee046ccc106ce40e0a6b8a20f4b0544749c6d43f2f0b58322442d5508e0d2289e9fad5400ceac39d323fae5b9b4404b52fa43a3113633ea89d44db9443270f90a400a58077a1e6763393c87918f71748e1b1ad73f6a7c8ff4ca59b8f259d42c2b7bd228be3914423689127c9a3976505f1a5e25232edaa472835806a8ceb9eec1c3bc41b03ea1ffa0577c4b5d0aa451b80701f5a2e7c69bfdd08ae6a7c3adefa8b3cc24776d14d01d805dca0365d7011b4ebf531842b7261db0010e45a13d94fb1c4fe089a002dca1851158a78d4c7d982e1adce491ef31125b77926beac0652d4954c3fc04e852670397de8f8dfddec51f24c85084c84746fe6ffc8e180b8af3c36e12ee0294dc6e72e5dea4f98f566665208be79cc3b0a5edd72d14fce6b799b51d17a1c3f4a67e663e93d9a4ba882d5687832fd351cfef09103028aeb1b71c7a6a634ec26e9c0831584fd7228e4d2264cb61f409ce5d69dacc1ce444de71b48fae51e538fc674d0531e27409909414f8e13dd6dba86f80471beca5d95f18700c4f0aac5de5955a89a8b22ec487af00bda1d9146ea0b154b425521a568f7f9ed351520cf0f3f0415d1981d2d4b1e9e7154b5d3c3ccaa8f9c252878fb350692040d917c0b1ff24e9da4d4d60c2d647befee560124a04417e8cf7a2bf2e50b279f8420aeadc63bfca4480bbce41cf2949c00ff33d25d617d5451c76a7b1a7c9ed37ba500995982dce5c2c3fdc6d76a05ba7e244cf63703e90782a97c8af76dfac813d0431ca04118ed1ae99047e78e206ecaf868b473c83ebe1440dfce044ac03db8542d9d70cfb194841af361c57dfe7d7a6482382d4da67e77be970791b46c613ad117b42fdddf07b86537ef643a4a0d3a3a1b5b0a9a829ac1f811edd8e8c4fd9c1a10f800b675b4f63c981be4c424943c625797ac08bd215781a853940cb70275eb7c5efca929ac83d0ca7140684a9881f0bfa66f4c253289b1b6e5ae2fab87c3e6c582faad1c995e171ced570ce7ae1d6be4712a143c1482a7ad36348c10ec3b0f0480be9320943d93bee2feffd56d8d53c28124913b7c9ea9e265073ec02ec0e646d4faa6874e4784fd36775244d7a030804c678c2372814a4112a14be1a57ae05d020986f357d2377ee9294701bb2cc459ee7957a430be3d77c06836b1b169b4413515bd693d803c8f95e5cb9fe94a477e928a19ef7521dff867a81458d2c91001abf574752c1662272fe8463ff1861dd1500a49a2b158f9f3b5ea25387c5aeeee83151062423ddb300d463ed2569870a0dcb42afe7e21faf717ef02fa6cba4e2768b5dfd703f83e640aeff2b5e01ea3dea85fda5b7d8afe145ec5133610db71e7e69e6c8a211baac7f6a0f112372b43970469342b8a541749013c4c115739c93a103dc1a6d7dde65c0acc7b4e73a47eab8c109c68d1aba2d8500d5f91b45347a3c9840ef6d99f981a53fb6cef1ee52cab8554ab5fa8409c3abf56751ad49d26ca08b82e0d115ed38a656240f6da9711279af8bba132e9dcd28d03e5b3c0404bfc6db4db6d0eafc2ed4887b161d2098e6099389f77b94578102d3c2f1fe79dcace5566e559ba7ca84a6ecc3af8fff12d5c29fc8b46d8e3af98e653c781a091c32d4524a571984b1325619d70a84e720ee4b11eb1808667fdcd358f695834643a3f52c8869cefd5e9932f33ad56a5d71dfd4277f90de1a8a58279f6a7af3d74c7e1b06e06d53c30d5daa6b825c6b280d3bcf93ff4376353c40d3c55e300b4f59d4c85348767394f574a51bf5c9ddec1d49bb4ff08f3c30c1a6d28df01b7824921525cf56dcb0837647e224dcadf8881dab34c94bbfaf060952ad276d9fbb94809f4e77ef355b3cb86d78f9d4255d9badc7f29a4077f0b448b310cdbbb41d41f0656755119bd85d725a6bc6d5ce8193c44bd5043c6af11f34094e2da88a463c2e63a6e571b8a885d8fd1384019fdebdd81bc8ef09d95c0b9455963e5f7f7759b46946c1b479aeb89a66ab5ab760c6f3aeb080e20d7e82c3ff37165fd1606a469e690f1798173e896f2535126ba4c104f215b349adbd180c90eed24ef1a077a9361f46870a30ddd633bec0207a32d27e1d4c2494e8a59540f514ae695c1b8fe1c379b9c200cf90aa2f8d28a0ffb027b654bc9add6651b8ae3c15e64bf1297d10dfd1d5adad693919001607eafb8d5daabf6142f41c2bb0d869ced9daab6b47995ec40174da8772fbcff75ec90b3defd348809e6a9b1914ad11110810d96c331b34b36a29e9ec9d927140832e0b2cf66e826eafff582e690ee3092bc4e0d1472a9625e3d185e9da6032a21e72535d28b5d2f55885a345c72965ae73ab40c458d04585b1b5af686adbeb05146c3c223c14c9dcf1ec7077b289d7e90053d53a88a5d84519962ac5bf7655f767cd7eace3bf0353b14b0f068454661c006ec938289a769966221e2fd600a54003636c3fab8c05e68e828392240d70b17f5641def0d8b73f1214db603039a1750a188ccdc461981b55e6be98d372920607ebe438f64a19207f0286cfd9781c8a71e543e4a2d0166c8e42d543edb9dc83e9dba132237a8c7c6380925d64e4ffc874cd2851ea85794aa77d20007338b66b29a1d0d2633ac57fadd5974656f7fe55a462750594e2a4297fd8324887b214f9136f0be544f86cec272e3ceeb75d4a0a92e27b1a27aa72daff8b55e4692a1ce40db3976a46d07c918b809c53f16b060e7f44b969557c49ce2ca0bb5e1e5b9f91e96ac1fa1c97a32f33dfea3e6262ec2a1742d389a784945350317a74defb1b7826de84cc8e0597606f383c1201012c5f31e935898798ca7bd0ecfb0a49468daf1469d18724515ad3493a0c10884920a020719d15a94a26fbea9053f53261391e026c73b87eef015187b96c9b538e39f0368fd7de2c7e4bb63211493106c66d67c10962dc035cfb2c1d42cf3fd1aaf4414c2798d1d2e5038d9a2ab91a05f165e50b2c92cb435bc59e22bb972893219ceaa70ab1f522ab8a1162567e243c64cf79c33496daa7cf9d86790f23ceef16ee5b51d7ee39ee99a399e6ec2278652c411fc0df31f75c1ef0b866923a230c4ab2ea5751c3cd49e88e5098d8ad0c224a646458766ac8c754520888599d486395b9327c546420979ec91ddc5f358dc8c24973c30cf2ef57fb7755d00dbf2a8bf701be57323dd91738afdb20c020a7ca0d1594c10067be0ddb4fe01c806508dd4ebc13f5dc3b4fed45581bff67ce1ca40d8181a6db58b47b7fe19c0d0b0ad3165c080aa4e4fa8d8cc95151fc7b8ffa2284d5dbaef877e1042a05a7ef345c8a70d4316b202e2fffbba789801cfe9c3ef6abca7f154845d8af5a98c8d930be8d8da9907f0e7785c72f76b44efe035532d4401f6b6a4c81dc5823802a04162f39600e9982436a6daa2507ef5769e92a0c6ae2ab8c464f215b79ea609b1c72bd1325e8bbb4a33db88b091b3ac951b8d62290a48587b037fb83e1aabcfc4115b4117ad82a69366cfb834b4ab576f16acbb18fbb8e2a0bfb413fd07a5f0b474f3fc8bbfc603e2b2b683c20fb20bb2894c46be1f539c96a84133644a9b31427a9e60de65fef7605d477050676b53dee83b5e94af841649704b4bbca31d9d6836bf97af983cf20b35b7b4fc1a65893076a9a1c9b669553f1ac11a2c447051009d8c258e7a16974b95fb2f5cbafd42c7654b07f59ebd282d05c74ebe105e13c260bc98bda186c3e4af7eacd07f2a19683059fb90045ed079cc8d4cb9cb1bca193aa54588067a8d145f1a2c3cf93890b041897f414baade0898be2b121647dfdcfa10d3617e887c653be31328df6336a49d5fb4ed9a2d307df60d00114bb611b61711b352d5d4397166f71e0cb57cd44994eb225b4af64b80d4e44bbd7b9455825532f381b33f38848d44d5e99bf66bc560c1fd9fb235230f7fa1d1ece9928bf112c8b381e40fb1039c853f5ff3f43b8e8b4c3a8325263696fd529c2d70bd6491bc9632776e420e042412da03636224bf45b3cd6eb391ca2448f73b8aa8265aff09e7a8b5521875d850cc2cd16cde569c712ec0b2b73ff255421a7faff0c08af7413ed16de9aef9ba87cb83acac47fba163c0ce35eee6c38835d91773ec94d499056ab31a170e77bb15846742309b45203bbf6c71cfb25d73c22d3f89f15b4074b18c718be8a40f391d0f255b6584eaf0cb2d441b751f5816740232fa5aca0742dab364e49aee7e1127ef53ea88713d6ca607334a112a9ac08a1ae5e0a781720e5d702bdd3ea5309ef3f149e485b98f5eaee4117eb8f04215fbbc148b1794c79d3f53465e2d75e46087c2c8092ac48c8e21550ca90bfb1bc2d20a95a9906026da4069c7b4cf20350e1365d89e100dfc86e4e83fcaaf9b8da9339c140dc28cdf59f096dfabf26ffa46d29659cc09840c16521dbf4f97a124f48c8209be98a56171ae63bc9647087aa8a5863480b53e8e76d3b438d578eeccf604319de640f5474283d3602ed0aed5bb2224023bed13b0ae29d413f8e3732c09c3e5b56f621ea1fa95a758c93f7813356df7091420d8800326e9f2688775cb21b2c688c2a1f8164defa5c41066840ce64ac2cd80c532dfe1e5e3373d57cecfbbc6787d15cc8516b2d25c84f8928ba0b8badce08035ad87a2e1bd3b1655b22d482bc08c61b369ba618e984565a60cd56c3e83bf22e8161b19859b3a8a3c24840eb8206c64c358c3efaa8394ce8369682bbf99494e968855670d5518eac04a1a32262df3e6768827ae95630a7e0c457e1eaf350c29a0bb44d0b62ae081f3a20d45e5fafa6ac246f1921bf91e9496293261be16bf7a3b75a9caf4e2b391cf57d170fc241001bb8b00e48be0c95b2e71b3a8e48a48769db048da1f97ac09491f8da0826c6e0cde4b6cf6237d68a2ff15c9168ed5189ba14d0b9ef98b2e0a25359352f6b61a92c89af553b15d416251bc6e1148822a6bd78c1a6aac1816ea3377495bd260ea89295814ceace8515e601dc908e77c55041758a191826e4d76b583206df6416870d778c19c94eaa8a2812ab6799fa51f022469d0a87aee2166394ab6c95e32e46dcab4216c977ba9adde111b2a07c7d1bebdf3fcf2323592e02f5c9599d744e61418b803e75509b11abbab545109bc25e127105d78d722711c97f40cfd576a807af4aa27dc97aba35f83cf1d641ce0bdc95a061b2aac56682014461eeb2b3c421c173fef3f6b9fba191506a8f2487a1df4eef91749f50989f051e68a6dc41edf3f4d9dae25e89a5f6f091c9801d4e9a023f31c908248e190d984a9b56680927924d9c79bb7abfb9c89dcaff4f55ca603558b6e4f9870d7ac5b30fda425c89a06a23984688d8aa6c105feb2bdc9d67bc01a26f098b4bb124c1c116e8718020bcba906461f2b012718124a0fe506ac041c49a298b2042f68dfbb7d4b7a1d6254ff457aacd03785f287ecda6d5924a5621ffa3ccc5d52e57021d9703a52f0ff04a7ff8a6950364710e73c80186772f86e8ab35cb70f1fad0b83b903568555e5bf8f03a908c49960d85551753bb64d6e761e1d24677d196f1610a3d5990bea547a1bbd85afbc1a9df5522b71ed2ae51564aa5955c69962282f15daf60ed33d687261089ff7834dc73db8269d5d40c8faf4268e7e2eaa24d69d18d22e1fc8efa69cfa397bc56931d22b47d64f6ffd4518104f8b8aaf44c610e807dd2769c71cdcc21db5b259c5a46627b943adecfd2eb25190fc3c8a5186f22dfa9faf368a8e0fadd6f6960241e1c855d4ffc53f8d7bc4327a23971c00e29065d3d3a4b0fdd25885a29934e0f062997acdbe63c77d9fb1024a9f79537a9135bac680508366a749e9bba9eba4e1c710aba2818a420e013d479115ca42004bab18991efa8ee3e251f6d474a874fb1243645624926a3dca36427d63432829ad74d5bc245c8e17fa57865f9fd68923de50052a37d22c764ba4199ab5726e509c04c098352f52f2f71424c787c01178a04c39803ed11fe2b6dc6b160117c15a0bcbde85aed86df71895bd37e8b01af20f7cedc60235a0d411f028ce215fa21b1ff433fcabb35237abfee7ddc054ad7f3718cfb8c97cd7d047d6641b3b5e0ff28850ead62f819484e158456cf014808145264580cd3982bb52ca82537676f4cf5d04a9aa0223bde5cabe7d79f4bf58873c7109ceae182c638533dce50c000b468f5ecd9c6b849f55811fcb4838ef016da306207e01fe2c2f480645eb982924d11f864ae804854ee9bffdf8173f210ddf7fdb595518ba3f0e98214d4001164e4e679e7827782ee236615b6d206b3daf74caee16e4059176b0be2f37f410f9ad8d86192b6b9e19e5e3d1ad1ab55b3693bc208e7dd5550ece3c3744cce7e570c66a8db77703c26b281c55b2d1b5ddd6e7b7c84b944932c9539b61e2c075f3ebff253ceba55c26882fb6b2ee504b283347299d5789da4fed70916becebac006be0b4956feb459785c1c760629674f97f52ef7728694a188b5a7bf007582e7f032f2746254aafb8fa2dc9444f4694ff225439193e485cbe26de2f9980f6ee3e8b8d65054b7aa87551d57df3ba8d5ca63b41fafdac66f26de7c67255234de4a764a3f5de8e522ce23e879f1f383c18542def793c4871d4f014ec69227e8a2cc53d617f730c4727e699dd51d49ffc57ef2bcd1bded4bfb4ad781585c45e3a9530c1bc42dd7917f43c4bdfe7a5efba2a2561a7d2fbc29b902bbe998c8262a4a1b2d07d6a1a2e58714e83011d97fd036c8d8d5f1a770c112efe3ea086e72dc14dc219b1c74ea2ca447b4230bf7bcea40c5bc7b9780a8b39ee46e45437dfeda081ad7c8d35cf77a99b1bf63ee6bf8c2bc5f71f386180384a7ae200fe986d8963333b286e2c2bc73f099308ae7acb4dea5dc6243f18a0c9b6bb0933855deb4e847318867d06e377c6d01031851b2f780735a7c10fadf0c2f44baf6f1045c1e1b8743f438aea4f2b060e366e202b3f1f02a97192095b8747a1bdc560421f8a196cb8a09bc757683bf9a82f03b61198e56e63f427a5b51b15b4a3cc5fc4fbad75eab2f68944985008766990bce8782efc541c5589a266047de4b3951471b55bd1676846eddebcaecdce2b7fea7f20a69e1cf75b425f43d9abd780debc42e4c16943b5d019cd65947005adf02afd4e34e4c16952afcda6696729f90108fcff7dd804ef50ef1b8c9c9d4791649b8e53a188690471e4400d3b7d8dff40e5cb18a5a260057284bfce8572f712c3fc9d9a2df1700e0df0af98dc7a70cbae556fa446bb19a48e3be3cd2e3222a41ff3f55e8dd876d0969e7a0292d66f11287a2b742224613244559d3ec22836cc8114dad67090295799008e904857020565a48c9820087825a1f9b56ac7dc3b7628c752acb4e81b8d58a9fc778b3495c59b70e3b70c95c7c2b16ffa63e01096e10e468b1ce29b1f94181660d9e40fcb9fec04ef5f0273000c1b7427a6d387aae07045b3a167321c8b942651cd5dbb43b0b4ce44c429b86d97589a0fbe7944a384801be57ea2165134399e7b006974ec9a1fbf0c8f2521410a79a8e32901d5a62a734e840eff4c70ed041b7051d33e83a55353f982ed2fab5a82f76dc071941538e76ae6088a98bb4eb3fe487b190c991af7966a1c1b7628bca2e0719c609b44051dd311ee5f85690d2be51a71772848d25f5656096c892e4ba005587c190bebdc0540166d84fe6220461925a751bdfa180e26337b53d6d81f6dd8c3a0001df8a775265907ae2a4df3490e01081bbb7e2388af4daa000e5a103da0fbee6da5ae2bd1554cbdafcfe8e138a3ff73fb53168f97db8bb8d36c0e73361321ba07dfd3c017fc1b1835451d50595b709c502997c1df4328601eba667e1e0b795adc07dbf00d6c15a2d93f49ac81b7448333e4dadc06333525a1e010a2aaae78b992d37ab6f0572ee8310ab73bacc8797d05bf18c5c956d12539b85e9026b5c92a6a193870514456f5b8fe2d1485042cdc0edd4cccf462ebd1540e0be8b8a3e591eefd8841a06853167f4967341be1772ae9117bd159f4d0b032a44c2e122f37e23f45630d0689de229b2de640ba43d41437a2b3865ac11bc96d65e7279c0394e5dce848f8fabbef6ffc0f63f6ea77c9c4a8443886bc850bfb729b1c68fd12fd6006e6832bc154fb577df6625dfce7f4e1f31b66defe38ce3f382fbb2e48ba986ae15a62fb0a69fdff946c5c4d3c5d31d079da0a23d5a4e46438ba35595b306b2388a8dcfef1136071a21dfd32be60ccab4cc84ea388a8d1114c560ad32d54a3c27eb0d9a433a015b4d5a61e93458f386a6f62a94d3f84cdcde3729122bc6d6cd65881d8cc4a24b6f7cb59a9f3d985596fba7c1077c6121a91fe5377488f6921a0e037ec1c2f720be8ad9ed3ed90ab9edae6e3b24b357e812f58f436d8988be0c1da13a8deb751e21b112723311512ccb2065499dbb47414f1134b620e0b6267d0d3135e2baf69048d9594507a127eb4790b621eae7e1afcd4ce16c0dfec2528e81b1f93f2a2c8600cc2f581b2c660c2eef211767fc97ff54ba35c06115fb300b6e5dfe812c867852bfefbacc41a6e78eed9bcbb0d16925dd6f3436daf915c9e0cbd155204bdb4b3a6844299e15e8fd3d76976251d343b484e02438539ad6a8d5b865abb6aec07a583560bab50e28ca1bf725b995176d06c7176748ab8252585365c5d039b4297055ac7f204aeec9656a276ce2289191431a81125ad8960b2d505f7a67fd0ef74918f72de7b6b3d1fb2e7e50aad909bd008fba591e3189e803a26c10d0c2668160a9cd398d2d3f7e6e88cb248aa005937bcc2729ef1cef61734e5ae64632db3080a7f4e3da6d467080fa26818a513af8a5196f66bf741421b9201935680c72b8a8e7fd458b654a39dd6b728590972236c32e18c8eead20d906db4e2bd422f7d2940049d81284d8317de47effa096097cdd2194d160284f65c77933b297f5c3da3084b8b69a9efe15dc0e2e508a2d94f688b6a4cc88a98f13a029cfe0d6ffb7d4cff900626aab919c10552434de084f2c4c8a5a1759cfe412503895a98869fe3cef073d4c9813e864abc88b9e78ada742fe49502dec2daed8c4d5564060c2b2d5afb223965f31be783a7dd2ebb5f271604c6644219894462e76b2090e0df213bf90dcac2f48e46bbbefa48056dbe3b8a695268a7651b218887a5687ed353b3134205559f25e5f9760bad3b32def95c7f292f19d9eb35e79605a74e0aae5edf04e0ff458a5fec55a621ae4a1641682a31e3b194c79afb96ef503554d2ab3ff1dab7bab28a27cd72b9f472996a5c46c21890d7fc713678a25184eba64193352dd79aacace130d779f39ad8a5e4c9c19a2ac287030aa5d04e3d1d014cf2fea1d86ad04aab991c06d008e99cee0e5426d6591b40e953801f58e9e7dc8c8596b5ec64d7400ada3b429676f7af743ff6203f3a67b05822d4f6352943a6fc7ecd686f1ec8974913587cb36767fb93543a422aec1da4acac991b7f029a94384dde3ba5f443c4249bc063ed481ed0d3177b2c7830cce923a364b3460f00667557428524221d181deb0e38c57d9c9495961c58ed329ba1f0bea9bd3c54900f5a937fa73830a66257d7ad8710e8f9ecf2910b3cf9d8c9dc8821de72ae20545a608469eaa741bad49b808158cae77f69965b90b10202200769c56fae654ca066ed69bff57c92962ad5d177632a774fab5bafb8f21ebec033bd21b73162ad609ec03310b652ca7a1c25ee38e73a9ca7db7a9c2a602a5ec1328bbfa4e951d04bf30f9d881dfa33763cef97b2cca0b71ef84bb4bbf324b7d8aa1d54eae452831747b3af3c3b6fa0e0b6bbf54ca3b0bba3461c2d4244791ba12b4f2cda5e715afd29a01302fa24d052643584d5bc75c530dc910803298650f37f9876a617b4c31c68384666c9c800d034b5205b5c3e4beac49c899512d593d7504b8b345a47a884b088c90d267116004f08a107a8a690155635369b75a5529ae3e6624be6b9392b5a1052f4481c6366d7a301d44c0bfa340d35bb492a6237bf961f004de311e4da331da0ece036b2025d55e62836c5f5e791e5df50ba65cc9dc1ee5063fb8ec106e274f33d46519de7fe931044b08ffcc4621a3c6e7427ef8881950283d5dc5cc5b7053f5192a47deeb5218940f9ac1f0659c8d3e4881488ef04c801e95a01111567abe99516ab4601676f01ef9a0bab7f1b05deb1b3c0a22cc1797a0597f668f75c980bcb2abfe5b5baf93bcff9a17234ad01027bfdb1172bf30edb8e068edeac06e0ebba4c7f93bf33a3721c91f0482139519d1e98a7742635ef74f9b97ffad572b8383d1e5b7fbaea41c7dd56a67e30d0f37bf67affeaf48d923998a6d649b82d4f29b11e858872c3d6b7f1277469cc923ed3700b766cbb7d6618ec2ca0203219d1dd8eb4dd4e97a2c3103355b2464c95c241174cd96cc966e4e336058b308fffe11eb0fb9b57668769875c0ac90c113c3379df19c331e0326ccd1fbeeeea555bc4a609a7320283c3cd615946f70498cc96c7796e4b84aab900889554b98fb3cd470ba8c2a1020edac3256aef672b16f6ee3a6a6e8e10fc3df31abdcecc870b1408e106e07df806228f0196337f39df449717b59f12bae809c4f2631048cd6b3b9222b9b767428d3a8d117ffe3db5c7702abccd2c09d33b00a1c55a50d8d5d185b9657c5d1af98ee9bca838adc924377ffa075ddf1401f77385dcfb467930f90f1404fd1e715a26573551846dbf4ad090099aef2fd3f5f7573c2bacc7e65fd5c15a35076c6f5a7bd3e937dfaaf6abcb2c4030e99de518dca7c696589cbc86addc59a259b07987fb87d8dfdc7fb0c2e5d9f488b983ebd1d9791c58aaca9771f8ad36d8bd14b622a0556aaa0322f2743ebd4acb7fbe1036b9f83967224e9ca0cc6bfdba0774e24c429981f7e5449d7a4becbd4b79a495512c2499e28f054f057b76f5f4c52ef335fbef8ddc61fd216eccba7f17bec2aa327b778f8e1d64a5051dac91c9c90662d592744556bed884eabb1bc3980734c1620c0c425f6fd7d9f05cc2cd90ebb65e8213c5ed8d80bbe81fa9724cd022309e2882692026c0669a7006a502052309e76503dce1c2b4c26d03dfd030e28a484041e21c6b1f75941f3c9f5228371016708dd4c727d7c98a317294c58b5bb776b2a813f92bfe335a9e13d279128000e4c5b6b7c1193a2f267fa32c8da520f8adcf608faf39e9cd1fea326d7a8b7692e251e90054c8000b03929da501689438a893752c473578f997b5de956395651dd13bb2a94a9fddc30cf568e450660c114b47a36b002ca7b36b758a637cc57f690540ea51327e0599a91cf927943907dfa52f5fd475b365f1194564cd0afde5fa9a3587a9ea2ff9c93a36b8bee6a5afb8f670d8ec4b45513438de02febba6a978e8f6a0d273c02e816829b873bb8c8b3017bd07ba2eaf9cb5d849b82488f3cfcab8b375771e358220f1d052f30b4d289a03d4704af94a0c313c81a1fd84a09523dc1be52ba897e5cf32d0f650cffe497c1498c3e5e5a0c259763541d21842808d9437ca2c17df2e22671bec66bbe9c967b4a1e662e8257ab2a77967ec0ee6fc65de81e2dff4f38c80304159a4864ca1da948140d24711d82ccb2f12f28371e0aa03037f9cfaa9b304282e8150f1912ee0115ad67da2a8085a08d8398e2d70c0659b20bb1f83e88442fcd1bcd07dd030d94af88ca36a680e7de62ab4144fb3446ac0efff90674750149a7aaa4fba6ea069f2da7d725ad496f05327ee9a6f78b897c225f6ca0c4e478d81ef631d907505af1b0384b4613cd1d19b52f988aba6a7bf094bff1f458a702f0c58f9d222ccaf462680cc392b881fcc97a48bf35a2fb763eb9e2d7076f643b660a9cf2a467ef0f187e81610e0f06888831ea190f39e9d2e465f2e8b240cadfe9409084f0f28eac0d51fb6618845195ed1c9e82d1eb00685527267a7db6b454410489a7de4e65a1fd780cbb3a5122dee2093d03a2f93fa8a3b93196b2d02fa305aae16b0e1795ee3dc9273aed9ded7a0eb5eb8923018e5207e5f315c761b94ddeac57f40ed7547ee50bccdcc037500e7502fd80b34ab4facd7c57bd3646557a0b1ac6aae4394315efc00c98b123063cfe4ee06442f2abbc50c6dcb0636739d495b8633fb09532434d05e8f10be3f4cf1fc3153dd7892f7cb5298265cc03d40771562660c7bc48099a9e5dcf5b3f1f36e29f1efa141d13ba16622b70659e77e173f5810eeb91f08adeeaa08e0748a51c1b2108a0968bbb1736a2a4e97b1b278078ff1948d965b138f2d89800b83953ad6f3f2fd4f0ea990f5f68f55803059f6ec84c93dd507056d9400bcd5938d935241e305dd9cdc2563cf1b8cdc1ae1514820ca8236056770ed9d31766a53af320d5d8824a2197d5b6d9fce3da9de1f91fb34ba249e07e0346c0041391b60e8a8ecb9ddf921638f103627722c9e8d8abf60daf887fef82dad1c9b208b53275d1d09724439dda34f83e8b44d73c34cb0c5606494b281526eb1509bac1eaa51bdc89ce42847bb64b648ba691804845684481d38a9d549d25c3cbf054eb940c53266d8d52a01dc607cde99e82ff9c5b816b83cba852531c7522cd5cd26ffb0c80a0d7a0dbef1a1681162defd6dcdc5fb383c5b29fdc4056b8ac952f2c784375080e53ddb02152942ec0caab17f236a4f6d1a9d971f76e93b45f2117d1de710014999021dca489668ca44cfeeef0293d0c55a9e0d5d205734d948710f42870a8a3401690b1336906625d5090063a4a948a195bf89663079398d692e837dc3fb372118cbd44d3940a83c9d348199369a822d0b20ff755d8413436d6e8a845c2d98b32cd7358d9d1bc5371f842d62d219d1585af03741d310123bfc887e626c678f0e370214ba4848d86064e8d36f58ad2c71cc28101eaa0074b376b3f064de01287f3498ccfcd1a1207f3ff08493eaa5274ac64ae15b00c6b1bb280bbcd5ddb2ae23e0e4c3ef54776b64af34ea27128034b7275259afdec5e874543d6617e5d22eb08816a0ac5747e83f6c72fe0b2bc5e578747f38767beb910c3837f670b77ad2ac5a1e613acf8aa0342e4263fb19cf36a50d03a9d57b3adaa69cfa0c000e7a80e82db4bb89bfdc1d5aa44e0c21530511df646e5dc4bdd4fa27ab8ca467518fc0beea65fcb646b7ce81420220a1f65426df8f77adb5aa4b8295b1f7e689ca95790994fc3f463c8a8c3bbcf7b871fc947ab4adf194b88a355341d6ddd97e517366e779c9a7cd987720660218f82de8548e2cf1cc06183847df82ad8277c5db88d8dc38019c31af6321462144b4df57930dc3fcc3961dffd003e4eb89acbb19852c798ce62522c7ba6b89afeee093bcd110f39c1a8b33c50283c27ecc34485c62669c64fd8d1d364d2f8848e80e6a01e2fe9b0156609ecafaaeb102f7ec56b2013deb0b94f59281eb5af03f1a216e4ccdb6420ddf9fefbeab708807dd6e3895e4f74d013cd00d31d3fb3f2b8bf83e3f9aa1b4357fb5628155fbbfa158aba4eff450704373e6278d56d73554f3c99c2ebc9f5a97e91e2412cc9f6c85fe65aa72340865cc75d65792bf54835a3cc13f195450d97954321314c4a02e2aa40c861b14775548721cbd8a0ba51baf9a9e076512e91bb64bb97f6af72735a9c608fb8109a1fe96a71a5cb0f4ca6adad88bee5c8d109b1aad6a3ef2d20a9e7fbe9ec214b13cf5bcfbed06c5b8f95d2326149ad69ab1880e666fd496f3e79f49a6c5ff0006bcedc08b96006f39839b8be1179e7051c68540e2ed6dcc13a55b66da7f1d79983463a3e965127dceb21fcc3b5b36aa8b8e0b3f5af563172f2605c39e37f9cc5a9c98f0aea828608eb2db7321727d43811704d92158d8f77a9bd7e250ce1a0e6c982ce67d1c35c423025492fc94e7389f49a7f10dfdc1087ec6c0811fed701607400ef347776294a2d8a0aa5986acfde73e94b15036ca0e0d080f88cfac0667e0a9c4587f59aa527a1bb07bbc6e0c0a11ec61879916e7aa5c612600428742c204827cd9fbc00782ba0e408290e54e801930d09fa018e915e414fce70d76768623c6526219724091d5837bf0e6e17fb3e4685f89e5dc0aa7faea736601b32e5f62631c2fcc8746278cfc0cd7ddb1ec5df4bca714d1b8656c152dad14bfff5050076fb6ba3efe7c04fa5ef713b65f85a37172b2204cfcf8cbcfc039add332ff836a3cb0a873efd62f57f0e169d2d5e6508b3570fe2f5f239195b66e6017739b11a34c9d56113d7df5cabd5af55d9177ccafa216b66ac7e9557f5eda70f6d465d649757ed491997eebe909203a0629e7e25d6fcd52ae5574aadc2da44a3ac5117a9a25fcda7ae670d2bd03a9fbaec5277d020febdadb24d08d6d833408cc0c5d12032a37e675ce834d776d40d57cea308e7cd039350694721f50b6b79203ae0b467a72a23c3056303c78cf2a0e9f751a040391cd30a84a18bd2a6a97f4b7da8f75dd43241665f9cb7c8f61cd82d0f19ab2d75ea002f7dafbb0a95029e817bb00d22d67659e3c5069b017507f346229f4f2fa92b2e14a7195d99c03e734eb50f9d08f9e3451254f7c4a73f54a3e1ca7a7af89f9707cdcf07babbd2172b2e8aea11c1bbfa167fc51f82d0d8ee5dab03802b34718e757860b2df6100a187a4bdf2f8777ac4fff6d74dd4d9cc7c366351cc01ca416344934b10529e0e0a34485ee3f8bca7b8c15f404a7e2b9f11f88df0e010552fe76394da047dcdc504578f3e68475a494e7080b2e474a2512e374f32f1803346a5c2501f369e25c2773c7828a4aa2562a97d993806cd47356a0928774cf4f88532cc0497f131442e4372e659382ad5393c13509e870cdda9ceeccca25a1be7d0b34d7828bc2443e5657e2e4c0f39962660336ce737b7b860187bbe3b71129e91658802ca3bfdba06475bfb2f016552591f0c66172fe1bc70859fb6c9079e209e540730b8cfe22b7f7557eef53c9fd7d70b313c0cedf9dfa7c162d9cb20d7e4275608f01f3d0ae312706c65054b3d040cca6660f11d08942fc90e8ab67cdc18619060c57f2be085979804cad15133ba6533f93fdda4f982ad1ff0a9c7d0552142f8b16dd6207080fb8c82803f38ba5fecf13f39ac984a983176429b545f39f4452d980764b47004ffe470ce572432d1a094689883b384891a7e39bc18fe7aea439900a16b418fb23c7bd1d7480ddf3a1824a94ce12d062fc9b967868211fbc87ef5042888894ac6a9a3ceef1ac24270e7dab138906aebd0d38a3c47406ea690e99c778d48c0a890451e51d30218e2b1d804c15b62964d0ac9bfc28c0161ba3d491c00eec93c9921d675d7275845ac3bb058405c07ba2087f483a6d7bb30ea87021c89dd14f648f3c022735f178eb346ce8be9ce038bdabf1946ed97c03c1ffc1dbf1ff44a7579202333dc3ae044abecc518799da6d30ea3b6b2aa1e23ed4530a0ece81842cb3073a738f69e64674c571750309774244679e4415a8a5826bdd9858282abbda67976d6e4977c5f29b891d5d661ab4dd506298e1d4742a85e7eec10463d935f9f8d7298cb9615a3e78b031e1ef75db852f34d15a7b032aa38c931c17d3ad575ab9ec6e4c5dfcdbec2be71e54d15b46b3787fb0dc24190dc46fc2c4a5c2c483026755cae5aaaf5bfc3fa154b21384dda09a5b28383da1feffbd88429022c5c96388cb935149f8a437b71606e89392c353487ed9a7f73759a96616da95ca1a53aec5a25b9778d50af4f6f9a8a114ec547c6a2341415bc508c357841b00d0488e046e0dc1f963c2b87fcb6a93861ddd24935df8de5f1d25e2422c77f4f55438bc4c5d7dad6a603baedd3a7a2cc86ed55729a9a0adbc87d0ca5b03218f1a9f99a2476f90ae63a0a1d8b1ce58d8d583faf8f15b4f9b2c139e811ed5b4b31dbe08759e9e370e684dc02250218698e3ee340be73f13f3957ca9b4f5afcaaf0a4ab4a0170045735ce5ba5ad7b4cc49db4804c281bb2d263aecebac60bd090d94a6ea64f86c62c5d97c228ec653eb959d547f03beb97e587febae1b0a8c7b7e98839bcbed10488b8797643d6f714634fdf28379f2c4d6714ac413a01d4ad47e9479fec39d4edb827b2989acb1b530dfc01d1ee7fe3a0f813af3c146fe7f35c4c6b0c6743d2e2d9eea31cd72b0f00d397cf982e173ac03e8f113937be47b29965a174342a859aec5dff4e266a81ded0db4f6a8f6ecb65110a4e947dac08bad823551b77509407c402122c857b9e3e648ed651137753b7e6fe66ee07928218b9ea19333e1d5c370e44294834254d167bf617294132346dd160e55e05cfcee60425969d4df051b2970181d4e69aaba23211488c046daa5849ecd305539b377925f787c6b3a52fe6e6c539391b7e5bdb3abfe9c6132f7abbd1583e07d2b7a9c574f971e9d231b1136183d421a014d1a5426148377ce219741d546407a134df26860e216820a050e4188c239d7bcad6c2d947e7cdbbc5f9e054bc91d8b5ef983838ff4230a3b4e0ef7ed0046a4102f207eeb1f720c1cfe6803d2a7a017643136b46114c5426e7427d40ae11d5770063da43795c1b073df11e27d40d64d78370aed02f0380e3b66f22d92c09f4dfd88168dc77bc9b41321eb5b787f8a1876a0b6e05643af6256025b406141c9ed006ca2017a40d5a8ca5c39563200f020bc3b14359a78bcfd805c78230b1e5031428198b5eafd5e9a7ef6e8fe12504a97d931cc90ebf4bf6a0308e018971ba713a03fab50301eaa26c2b11c60303103560fc5cef841af57b49104379833868452f183672772de361fd7a9353b7715b6e7043a7411fd0003d880f28262bd3343fbaef4b77dcf707504468a2ef5b5067906714b721aaa6fafc22f118a23e04c995c13292ab8dffdca1e59ba604406e28bf91d74b7df0041076fafb611fb1b659c6da6d9267c3cd5adcf578dce213668c61d2032a331495c7e0523b4b27fb5dbd591557e7520fd87adc15a5eebd50c955b1eec8f768f1d5c15e9a4033e265ae6aee8a12e9962eb6f8078cb0282f992397f7d1735b576c1377f5c5375782ea032069f516a5535344814a4d25ee4e52b4ee76b87bc036891c7e86e0a37e815d00d6c9c44bc467933410de1a7a19cb595280fc4b1b2b48481d45849d690e998484bacc74f0466707112d2e63b690e9da0256547d111a2a895b3161ac0aed9dbd1aba110605f7774e869abc6019ea0708838aa36cdc3542b02f804705ede5ceaa725222a3cc24656c0230554596485b12d5661326f1a684b8c08202ca7d886fa6f4bc5b82e0f7e5cbf065457a862184a2d4571c726652a189e1e5801574f51f676686b450960be688ccb56ad1bce0e97d57b42a4df60b513968a066be55801605b1d9988d99bb2e4b1d49577634624a263fbf5698b26d416172d452c92f5afc61de2f4faaf10fcb9504054d728594aa0f12d3c02acf39e808bd667e82bf091864f71fdb317a9e731421c37a317d99411e8618e50a4ab794f73fddcf298c945916d28458ab6a98e565d524f99d5f20e74cfb1cf0d1aa9a2a8b413c76c00a0493c0d2fb3a8973d6c092ad1bb9e7b9839a9682a63a41cbc23eb3fd65aac2de640ee427cc291c000c36850b244e74f9747382516c95c8188b5bb6f712ab7674326467e2b0e92c19fb7fbac394ca7263fddebe8677b8fd902ba883920d589f238e92f9f01d67ce9b35049fcaccfe4aa8d6a0bf8fe6166acf39bb5ac9b6d2d60eb18f5ec7f0ff6736841bfae9a06ad50f5c39f40385eead17a30e533da6d26bd9c4b8be11a3e4013798cac1d6873384fada0711720a812caa1bde1b914a4fddd5258ada7d9f33a7899f7ffec64c6b0b742b1efe67d2bd7dfd41e7c2669861906172f1fe25feb8e857f0882dab7a282d7a6f55bdbabb103a36f9f3fb13300ddfccf15231a2f22227d5179ebf762ce3f71c1018e142b3d057b731320e54efa3eacad4a038a94e0b0c59e860736af3a14ff9e56451f3cbeff270111c819450062dc83f218c9962a437399059b143e67ec285b179830a1828b242b83311723757af77c4f4f1a37a6627d2bd560df8ac218315783632e6157f5b44365dde50dfed5d43b4dbe9fb3c1a233212116662b2b22fa812751dece78cf93373e3fd0b47e799e5d8b3e1dd0c1ae43be59771f19ee016f918afcf967be97bfb2e4af0985b5e4c59b3f40d3f6a3fc333175da7d889623fa707e19458f8701a7202a5d4231a7addeaf767cc219164279b34ec185b1d1c1376b0c228ca9eccfac4fa612764c462207d04f90aa08b89c2a66d6a4da4dd8501638ece99443dfb6a14d686aec3bcec7f2bd80763fd0d3c8f62220ff0387c70aae5fbd9d6da9d50e12a371b7c8bd47e2a8c484bb60772d9c62d2aa8be31bbce998be61f67bfa0bbed0253f212fc7050f16649269d9df1d00ca99d83e34b7652a5a401869f98207735da31eed48ad2acf04847e2a47fa000e5ac57e80c044d95daf93046bda49021b14472c51da853d9c9bd15c364cc0fb87defc871ed32bcb66fdb57b51089b5e092f5833c96014b2703a7408d61e21058e72ca728ae79e33c8e0515e1b6757f52c2c190a08b1b7b40d3828656a6ea14b4d1eb80e244c639d90f6fb9a0c331964689cfd882d328c1aa30bc1e5b566f365c0968e72f010a74614ac9fe89fc31f9ae7fd0c09e4da7e5480617213be774709fe9e43e448a0bc73acbd81fe382d82c07681156815544c247bae40c842a7fd73ab8e93c4f7570aa26089d8c672930485b9089eb7549106a87f6944a9141e822bb173df6d8bebbfdee8b9cd0222402ec21841ef22ded97a4e900bcefe90ccce72803c54f08fdb77f296296605482a40426842e820eae1eb34e5270e161cca9732d1d016f07f1eef3dafbde07d8a51e1d1d784c908bd2bd0b111081f47ae27ff87ae05ded4ca8b4074c087d6eb6bed3440b9382f51b9c34b6eb7afb806215a9195e5439431794470fcb74ae88bfcc1f8f71b54b518a8cd6c0a08ba87e58fdd77aca9f2b7116b24a652ec435cd3582b2afa4b601688476aca7bbf4ba8d6a93aa825bd88eb5480cf5317453fad2628d4632ad232b1cf14e9176d40c3c0d9453e5d27427a6ed31118b3f5aea57b4c08c9ddf8ce03a6918de8db862fc5fa4ebda0073932f9e255c4d98faf07486990c93f8a3c50ab80ff39f3ba432bb98d4ecb91652a8cb3a58988e667bdfbef7f6d65fbb79127d2fd4f7f34c0f5429497afabd60344fa410f65d232c3986bfbac1072d984b5dac82eb8661826ed1ab218a22128abf87d2679e60fcdf600ac9eefb8a9e66e3560084f80e8c684c4d91a99fcfb62f03548702faa5e5535e6098cd3807adc791e31577288e6763cbb98f521d34c6669d6d3175278d6632d5da3ed5883f23345502cc4acc055de922e8459d7cfc259a0782e5bf31cf28bc1a012e5043452b26e7bb813fb6245ebb318ffe771311111121524a29a5943239054805f7042b44fe2020151fcf478a8e0767a3c96042f0f33a6ed332121de3045044210a51b081135e5e5e5c906dbdf514c059475b53aaa5608bb8f75a4b2dd652c8196bbbb74d82cb65c17a638df5def4a79e409e233853d1624d2d80f5e79a4b60add54b68250880626df7b6b525c6ca1553bcb28516acbdf87a4472c8e3f92d8b7ca4d8342ecb326dd33e11100cbf6ddbb88efb32c75d0404c3afebbaaeeb743a5f7973be4bf8602df179fb1e2c37bb9f8fe82140cea28b5229140a659e71fedc6927bc1c92c1643e118d66c3e17030ba09219fb75e888889e5912559afc3f12f6b3f9d8eb51f087e30df7dfe60e54fc6601886980ce6cb5fe8692584bc90e761f2ce344dd36834733335d6f362db4603e1a3e2f3a1f1b919dd84fcc91fece1b37fa4e87870369a0c26043fafe3362ddb2dc448a998d7a05a6bad75ce39e7d1be66cd53091a0902c01607d65a2f86cffb78f5bcbb6dded7d1f979dcf7799ee729c1799c9779d306dc86d3703a705d14dce9ebbc0e47c792acfd5039731b0cc3d0fb8e107a1a099e6e02b351de6732dee7e92368bef73e4f6b9b353360a148d8b20927b89ec56b8a027c79797979797979797979797979797979797979797979d15eb417ed457bd15eb4cdf2a26d166db3e020037f7d1957c6a5d5cefbb1148095ebdf1e01fbb9d7bffdf6db1303ed9e1b7aedf3b3a71b03343cc97d8b001d202ea08ef06bc66a0d0195014b033310e7482d739f640fb14ec1fe227be001d983111db28755ef7013e4dfc03b431de507f97ce10b9ca88afea42b8d13a949dc5acca0296f2e2365e94fa935d451d664963acaaf1175a8a3fc9bbfd4444ff6e4e3f3cccff2f0fd1f3cfc143cf31d8e79d0fb8d7b34877bb407efb26d9b917f9cae19f664ba7ade88365cd101b08a3157b30f1f01d987a1cdf806b79f614f3cfab304d89330cc321d863f553a1bffb0434d1d9a290f732473f62340efeba7010ef73535657e7f0be6c3bf9ae8c944cf7d0df5213f35e59c81e879a700b47d8689723fff01e609e581fa00847c456a9a23f9b511c0fd2135759e19e0cb3055300f3e8dec3334c0c7fcecf026d2184223ce10bef63432a2478b3430a24787e057c07e267a3402c00fc50ad407458f1665982a5365cf404f96943f43f5fc5aaae7dff2735d7e2f9b2c292760461de5cfdc0ef5822ed866294c112a4d52c5e2a529d5d2c7220df4fb4845cfd37a7ba8fe1381871d34e1f6cb39da4b3b71b827f89594bfb345fb60b71b8b22f464aad8dbc7ef3098a88c24265994818422ccd1eca20c2434315bccbb92e964a534f6e6ab73ed72b6ed863336e2b54dcbc43bee00d6ef64797b08802570fbdeba24054c811716e37badb5d75aabd9d9adbd18df9c6dbd37c7e96636873aaa358c9a6effb600b438cf0c6cb55aae0e59da13fc931996544b2590e790ed3db50ed5e4defdd34e18fbad0e19b7e1e660bbc7694b0b35d517f577b7f26559d5340b72daf2edffad5bf144ca62b76e00dce52a9d1cc7d9ccdbdedadfb4fd36e4a04335999d76dcad645793dddbcd197bb7766bb7f0db52a974f553fb7782f4e4d56d0459679df50babdc4a3150ea5297baa4e224afb5d65e9d842380f3c7a79506b88534e96f51a2020b232423128b1522be424803402c89849458d89a7fbc08a72fd70abd6205c97592c0e97eb0f9819759c1823412f1161f868f69111209c96446385521e1237caaa8522cda09558ed556a5529a635428793c1f9291152c482311070484a3221402029588708f077989d3551886980c260c31184c46930163b08f8f8cbc9dcee5012693c968361acd3f16a49188afe87452844244f65e21ea24e8d297b450a1b46d1a9291152c482311df6c383f7201a8fa9df867e3ab81f518810e7a1d83cf345140310089738ee0b72af867c2c0402631f5d19261c1e1761b96890c77f5fa189049d3c7cfd4e9e367ca983e5a4615b1511f4126ccf8993e5a7afdfd99ec73e216397d050901a32ddd58e6acbf4d6c5fd417f531d65ae79ce9de3b6fadbb95fdba5bd94168bdd56eb716cc37539665d953fa74ef6dda58507364a374de39cfad256fade9d7ba157d7376e93a65492047450d04386a5409dbe1c53c27aac9b8354aa32c29ef1fb8be514955a3605bcba8dd1ce76b03cc7982196bd4c56137162a6e2c738487fcf6ebc6d2b2e2c662493fcc0eebbaabb377bfab33e5b66b8e037fc6e2d6524957dc5844008e1eacd7f760f6a4b371f7625b69d67b6a1bd779738ed0c7bca8c710b6baf7054bba25813ff28ee5acf5ec67b52d86a61e00710aabd349c93216cb0519fdfe77f0373d69f542b193a2011fee563a0ef038a8016de87773dde6d0efa5773ce9f5b3ceb6c688d1af385fda035b6ca26c7b03e0684b5bb24c14fa3a762fb035008edbebd52b0fe068cb587963991568e9eb79b9dae9dbe94fbf2106daef6f9ac39deee44e637c2f798f007100b94ebf25c1716b8fe374ce29d2401f7fb624a85ddf8f5bebe653dcb55c188d63ca3aaa71bab36f19b7e30e9df2baf90469e7b46aaa713b532373a3bea8eff14caabee038edddd4332819b46faa3ad2ba19d392c616ea1e75f8ec65f7ba9bf13b72f52de35bff380ecfcb34ced5d1a6e174ff38c8b339525fe35cee1fc7b1bdc7eb8b4dd45ad7386d2083ca6ca057d48d6aa2ab8910d564cc6c608429ffb3711bb7692e43eb77f66ddef8c04e8666c92b6eaaf14bb554b4df4ce686d61954b782297b00c74dd5eb88297bfd1c948872a2ccfa55739a9c7eb2a975b6d28fa7bf7f70b1ddf744d15f35e5a3b8332bccf1c076afa5f3d2f976dce3a5e2eec0eb15c30ab517679d3181d52bd62fcdc43eed1b7ac7a96e53afdb46af5ad37bb2514d66127dbbd87544e7dffd77765ad7605f039845e854dc1cc727baa8a4ba5d5eaa23cabd9eac6fb780b49e5aa74b63b4fda6398b0370bb5d8b2c561305cc5ebf34ece334bfa0e64ffb7173f144af1c7925f729b5e34635c56ebc2cb9e85bed56ae58837d6508d857d7228b7134aa26f653477da39da5f4312c9a35b1cdd0fcfc3b4c714e7106fb59a4913d0d4df4dcfd3ba8d0394b192f59d2bcb66adbf7195a0272d63e8b9e5b81ec2d4dc9db97b6a753bcda0553f2244b1d8c4fb0b51f75b2b673e370c9086ed35680b59d6919df9c2be0edbd7392f4cdfb67ce3bcbb6cef596795b92ce1a3c0108113ce1871038a107fa89960f622f04c0051518314c4e504a5e90b848e92be8165ac050620106959e228e60a9a454225964a9d44243c108326495a09c98bc207961c4c363a4e322c50b2b9458f8f8a81f240c4e556290c0202159293289968764b144a251a6ccc432ae4c2b43ae58c042c58214e6000078faca3a52410515025022111f2449605085618821592cf20517601011d162c04039317941b262c5dedd8992124c2693d1902c56490ac5324756acf8101421afd2de7b720dc307e0051760e03815316094a09c98bc200181405cfc0a2c70ce61286331f18bc5485ad840bff027262f485ef0f0e8b848f1c20a2c943e3e3e3431b8470c06f78095708f16eaf34125d1f2902c168ae841922eb42059244996946cdb66c2619194646a684adca3e5da6cea862c113d48b2458b1625fea9e852098361955a68019f98bc2029e1b8ce8557b2428beffb120b2592afff0166589a444f15b705cfb0b8c7644962c6884ae252b4682bd451ddb6ba9125d1832449481649b2582516f6ae2b902c9245b2c812b254123d9268217a902409c9080b1500401a8944424201a68b9a3fda172cfcd1c66e0733dd371cb3e21822eaa87ec8311812d3eaf531afd17b792fefc55b3415312e180d061be2fb6aedf7b65b013f033fe335d8d80672ce8b73b22cfb144b290d1b9f3de7cb713e95c7441da550f4438ef14ad3de980d86a3c170b87ae3bdbf0cf38d5be78559460233ccf76519f759b7b27dd6ad709aa66ddcf665dcba14d1eb6742aaeda8a4aac1ec7f5f9f7e205246edd9c67173cedf26c8a9d6dba9d78d08975e3fd4601996e238515f70621c0047efe5bd98a826dcb643834892e3ba155af6d2a3d37a59dfb03846740ed9eb639cb8d13f9407b31f8bf722355835a138dc8ec3f55e7564031c3598b6e37e119c18a7dccf81719cf3da20e0bc384cd491fd4ab9ec9b42a0fdfb8cdbe7bcaac9f6f5394c6ccf895d4e3b053f564fa91858b6b32cfbbe4cfcde7632bc9e813f62605b267a2f10494164cf440b7aaf5eff8228a5620dd963f55ac2e68f9c06abddd4b6973d8e8de3d09a387e3a1dc9b7d3111d8d9c58f11665c0d2f9b5d6f95faa8a378028adc136432388f5a1b3d2b1eae037cdcd4e06fefd97efc79d0c15fd6a1d7cfaa75ff14bcd9127809cd844c97ef74cfc54ba956235271603a6a98902d2a90addea73a280fac8897d6250d1af8a0eea3706907ec53947be1588f5a534c699eedf2ad766a5d9576b5fe33850adbf542dc207d287d3e905db0c8d20ab2cbb4180593fdd1995f3ae13658f17a5bf529c694687d0eb539ee99f57d37e736d7ba2ee7e51f4a2f46b948cacd3ed895ec78b92b13b15331f00470f0a757fc85986f4a07acd202b0d031080f85a9df16fd3da9b73de5aeb6c5300765194db2e6baf5edf6a186f8b2dc791bde6a657c96ed6b26b338731eed9e6dfba6db5c61993db92b6a533bed65a9b51388ebc6bd8bc73b6f85a8cafd56ca5f3de0c0a6c645863daade06cb3b44c8cf10368a8af35fe8d3fc318e32ec3b8c3df618c1fbf06638c7196699f52eb7dbd1a8300b74ca4a17ef69bc669af956735cbf5e956c5fa29f67ede5eab19beb69e3aaef4e4b2500cd093ee294aed54d2a8755cbb0ed659c515ffad2618ebac62dc3dc65e877158b38a71749f757877a0e25ab38a6bcd328e1333cb0b40dab35ac35a2bd7fa6bc5db8fe2ab53acfd659928f877c777d3be6e25cb798f355c7cadbd5da5b3f3aab8d58cc8e901bad569b04f7f824024e8419f521f24d2a0b71b297b031044557b44add5c60975fabe1cdfea5bd14f8895ffcd72f6089073ef05fd86f13fee56408f4f967cf1b3e1f109f1a93ed5973ae243e58c2935dd9858df818165cd698c131d530e20f71b6814b15e5f773330304bfa6ca0eae8f3b3fb4e2b9edff4b78138ed1b08a73d3f1647ddea58452f6ac55b223a08bde2671a23d03fd3c8718d1f2d44f4fa1b08cf7dd68ea7d43d29c49388b2a4fa013281705c39107e3b66a5d268660599349f2181f0da45de3204c86be055c4ffe07ee4b8402a50ca9240a6ee670599ba8ebb441eb2a3bea8ff3c2486f9a85b1c88f6e7b3d70e6403610e84cf9e01993a90c87938ed1a263a0ca67533382d4bf2fcc85d1f104efbb66ddb16865678428a080971e9212b4be23a267ff5ca5fdce5712288ef0ec2756fe9991f3f5a32cfb9ab8e322a7ee42e0fc677efad410f027990c70784db1efef8d1d25122ff4e9654419e033db7e3c5518755ff07f1f10601823ec5826ad02d3124564721b03a0a3142481902ebf5454cd5640c314248594da0a826205f5f84a59afcd71769e1ff5f3fc40813657e3f824cbd823f72d717b613ebf5e706b5b9514df6de1bd4dd586f5013256f80d8a0ee26c706b5d9a036406c82d8dcd8a036a8cd6ae3b2296293daa8a8a652515badbd375f6cb5dd17db0daa2bbb27ba970e8aaeb42739e7bc4392566dc97b73bdd8e69c73cef986e42624c3234224c22472ce3924c324aac90e497b92f70e495748be2b24efc69a9c28393c22246fa82324c3900c8f0891089308c9900c5f212cdc11b64217b5d5da7bf3c556db7db10d494da5a9405b8196435361d5ee4a5ab52defcdf5624bba70a82bc356af324c95d0a92bbb27ba970e8ad9955dd9955dd9955d7937d639774f74e5f56a74e544b1bd2bbb27ba970e8aaeec4aefe4a1bc1b1e8b67b2d4566befcd175b6df7c5b62bb32b2b9197c83af0d654b46aabba37d78b3595cda2bda9a6f258ba0c5345e4d2549a0ab4156839a6a6d2542a4da5a95229180c0683c1609aea6eac35d544c99a0a34d5d58a50edd7549a0ab41568393495a6d2581aa925a1ad34974c6db5f6de7cb1d5765f6c3555e814f221f481908dd009db9d73ce39e79c73ce39e79c73ce39e79c73ce39e79c73ce56ffde34bbb455af3f55de6432b9b22b2b9197c83a66766557766557769565599665e9ba1beb9c5d1305ef9b77e4ecca4ae425b28eeccaae1ccb658622bfcab22ccbb2b4d4566befcd175b6df7c536bb442e9112a225443a442e6c43275a75be17df9b2fb66f7a130b076076eddd8185ddde9d7073391ebbb24b53dd9c4aa5529a4a5375a585c16030180cd6955d199215af56ab554886e406d581759ae81ca1b3837660f6e49665d981951d58d981951d58d9d9a0361f97baadfeb84c94ec325170be9f243e2efbb98fcb27061f197c8af8b87c5c3ead8feba3e3c3fa907b874e211f421f08d998acd089153ab158b0d089864ef6e4ee0d82a113eb592c91ab63b37e37d6399f260ade372444e834516ce742a7900fa10f5018f7eb876c54931d3a895ca15348155a858808a142a9cca39f523f442e9112a2253617e9d8f4452e7b724d57e412b74845ae3bba2e96b46dab2fce7697443151297a8976e6ed274fa6e7e17ba02d6ad411cff834d913bbc1ce8fdef4a62e726d22d744c93add55779b95982817e33b8a767cb65de49a28b5d71729215a82c2c05f5fa46313b9b41fbfc2308aa010b9443a44ae8942f7fed0a9d7cfa99cca29bbca29979c62e514ccf582c160315809b32c306b82f5fa78555378e582572cbc22f1aa855734b64b90a553d65359512e2c168b64b5582ed6cbc4b24de0a983fa494d26b2355bad576bc25a97671a6df199ce3cbc02e92e80fd1b68147ddf9761aa3cc70270ec7c5c601365f68f8b3dd1f3e3c2ea758f4eb602118490c566abe7c8b6d93e9d23f5330fd511d702700453bd560e548d23eaa2fdb62798d7c4d186150d168d54a73484e89486aa53eeb73d099f13471aabe786f810e8624f4017975e7f75438e790dcf80bf659e7651a86070641e546d1d84d913b005c27afdac5f95b59befcc6dae75d5565952ade24efdd0658f23ec78866338d8b2571c41b1d5ebcf50bb3ac8c1551d6d17308788a3fb940aa6ec0998ea63697eafae2950da4e46d7f1fef1aa40daeb4e91001c3954aafbfbdc6639548a1dbfb3bb1d3954aa7eb57f35d61365f690c55a80eeb05d6e0894762b1404458b83dfee36918861f71bb83eeb88da17364096ad6bf60b5eae6508fb1a78de3204572b59764a4d6a72b3af178caa5c4e35cf986e3aeba5f67aa30e77076bb51229e6a420b9691b95342ba6f56138a85e5179ab514715574b27c65a7be30e7d33757daa54d43900c7cd7432f514168760850448a97e3ae7b42e157862099bc2a804afb6f52c543300002000d316000018140a8a8422511824519ccd1914800d638e486464408f8b63510ac3280cc220838031860062083004285343423601303e2e304b32a4585c59d7cc51a282d1bac5a735c2ee7f1c1106e629a4a8d531de8594183ac812cef90f117c9b57ab7bd19dc2a19c26aaf7c29b7bc7eb64d6dfeabb65eec711b8e75083390a5dd9ddbdb8a54fc24e933c4067bc524a9d56e7e303dbd2bc7a683518156d60329176de9171042958abebbb728355795394cb6a79a7b0d003a3d5f6e45c3242087f57319cb9846fe05dad016e995d39d206522d7a4f0f63605abd1080c4f8e630142a08c1b64f91af2bad6db0c9b475faaec674da52a9a8eb24641deace72833dad2603acf4b9eaac3cbb5ffdfa9aef231e9aa6bbff0a72d130867e239b491eefd5be89e5c183511638f326cec2caa308c245294cb0fc18fc8bb9bc668dc6487e0aeb5fdd677cdeece4f46ac711a06eb221682745108f240529c00b0acaecd774a42f7b0eff0235d05faf8e1577f0f207baa19439572c07cd14a64caf4bf1595c8ab32990fa931779cb1c561ee0c6f38207a41e3c9dec9dffa58287f77fefd2ae9d480a26e31326d6aee08a780eacf6d60a6ad9df070e20c213f55d17557ba792900eeb71c332f91a5d1d462cc0b22fde34e91dea5177013e295d58f7833addfe3560826f388102a632efd988394d38118699343c4c4218583e3ac1c7abcd8c081e95369d4a44a250f9a869c0604aefce4f0af91021f1a926f375eff95a21e9aa56373b608691c51d17a67b291d8ce34993e9a734474f4c67119a9185fdd50c45360e18377fb62d2857590133ce62c6dfd175efed7d0c2954c04cee22f66f0afb4c5954e6aa57142d4bc0e413930ba64aa240b9ca2ced86cc67c74a0654033d5b4be33658ca0a042aaa6b8fbafab55feee1561c872e073a2f1861a0e78cfee98425494d36b2896a43e5ea170266d763606ce615e517bfee6a451304b54df72a3e3e433bed9a8af79282d82fec54fc8e6a037963eee62060609e8805ec83012dc4ac763eee154791cccb05d5c9dc31f98f19f41c23bd751de72b0626540d11cde1f3c0540802959fb0a92b198178c43a48097d401cf6218d0d239485570255ab2af7e252505c742fd1440def016b0fe44d2c114ce710f3e7e7ef33702dfeb4fa204a4287f61cf86fc6f54340ce0055f2891c68baa43b7de75d6fc72e25a1ef5ad799b7936900ecd1a091259576b8417ca2e0400ecb330bf0c45f01a11035e4bde240940f3deb726abb472ac2f09b3dbaae9afa44a9e910d1f65f1312033b1d16333bdbcf1eb4a959468f2afb7a0eb276dbf42ac3bf84580625ddb6843704c3a9754a2f19e81eb196fa28565073543b46a5c8421467c5074d20c96b5dfa24dc0d6a5beb2e58b2a28da92f89d1a3094fe5ee112d123c335dceb5eea37aa77d26647d6c9abfa0a3c77bcfcb6cdab59dcaf2b46e2c597c7101ea3dd2646e4a56a637a5a3258ab8a0491ca1335e29a582d6f5a382ed6adc76b9c254e6c1ad37389b3f4590059a468f55032bcf672dc82c97360ae90630b4ce3e4d5c30a90843caaacaf2fc12ff232bc000d51609d91c832bcc45686da936b0000f60383bdb7f447c6e69b7890d53cdd1779d29f2b6cba61299215d53f38838d8d03a2f13327deb66cb9c3be7e116b7fffcf2cbacf3613924bd0cc1392593bcf4fb205ffbb162f07bdd185a82483b4cf589b7ec03d016240751cc72cde305ca085541d1d209f017737b9d1a9accf12de07798b78c209b1d9b1de6ec2840c9e9256a2745108f200529c009cbea4a4853d9c9b3ffa1bc3cbce79be13a46478960dba9b6a55a15574176e9de5c877d06c8ad23a8a21c137d99f2d12e74200dbf3024e51104d94afa3dea3b4e7fc43e6a3561a7c8457a306c9fe815bda42928e997c8b36dffe83eea15724713cba07a912634918a5a1590838ae5d30fe79885b3df70aa92c84154fb7ba5dfe8d7aa1e3ea5c9ffaa1e54fc3aaadcf0d79833504ae93ddb1c151f4110ec5018be4b4f52709ad1c1b2420396a7d0289028bcbeeb043b9505656f8306aad1ded45965cf2a0eeb4abed9266ff08673761758e55b3d623575acad0ec27cca67b7125540228a4322e935ef412bde8266d7e0a4fe06aff547eca2346c70caa9ecf31e950e0055b2cbdd58e281d359488e05ba69f06ad170d26a26b8bc45af5198f5909a5d6f64bbe2c5a497ccca76fbea32f1f516c3a707a331bf5f7ecca0a0adb37bb3629b8e7a454ab324867182f6c976d17b54cb41103ebbd1d0143969fc97c3e0bcbb5156e78133bbf66bf282494518a6dccacc6d6b14422fe601d0349c85e225e7715fe26d2783ce9cfd4792b8183ffe9e08df5bda69b681d463ec5d8715df86e9a9f66e4877d63c260e3666f76558bb039100320fb81080f032fd2346defb434ae44763373d12420f3148c68d1c4bda19641b7312f2d32cc6422a48816dd15e081f218ab6721526af444819a6aad17587bc09718b8dfeca072c8d3a4c6cec731d8c148e6b17dfe70274c68e36ce5b010fd518cc501bf3c27ce3f41971b45a8865666a2352741fe815b9240954429c08ca6ebff836ea057a23136b1a707c27eb3471a710251df0641fea15b1a790455157bd094d7c82cea9425ce42434f687ce588adad9af704fc9590945974c66685838d86b7238f17d84565fe2e07b045749e88ddbc5357f955c096d57bc7f374be88a5799dbf3c27e077a796566a49da9ad019a8a711492f43a2fef55c7ee4dfd5e3cc4a2c340357b36bba9467a927fd6302b8eac03f9be1f071c95aa2393022ca4dbb773c49ad4a75883d651db2995168b7fde131f34814d9e02cc4f0adda0b6298005417c6d63ea4b6a7c60c283b91f5f8b64cff59d730a304df992d6b3c2d96acc56bd47fc704d7d36f2eb1eb41b72ffc94a8d5f5bafbf19eba6be32ba7a0619147791e691def0fc3a1d2a45b99b42aedd986c11ca859402b46d0c220eabdcf21503424f2980155732658d07b96898376f0a169f314795e57e4dd6ff891381f923207f5dca0d3305000a64cd1f0a744ab90182f2f00a0073079faf88c79dd668db44fa724ed769e86193a9a8b977c8322eed223b1b14e0c89805b02844091fb889858032a034f4ced2fb865e5800391bcba85b064f628fe84cdde1cf0df162962f0b408a18b53f4865457feaa72cef382248552563769857c1f8ff88e5e39315560241fd24d0e3f318a134cd4e4e16c07204a8ff5c9ebe930b884792821460ae6871e79ccda9aad916a0fd557d81d52831b385ceb2ec9c5fbc333120b0141ac2aeb4caa355ba056816544f179c63829545e2ec97c6a9519636adf863a74bd020877bc3741480bd6e7dd45111dbaeb12e370578ec59517da777ce371560e4ae905ddbf58e2f0d60f42a897dd379273f013cf2ae88b6d13a4effc49f18f27b8244460134fe1add9d781c8b2c8e3b956cd18f5016694dab874d85797c6b578b595dde626127640de3acf3b225b07f8e8917aea8f635df05ca4af0993ebb19ee202983cf4587cf39169fed1d9fed4dfe5bbaeb99aae36c8ec7764135689817af0912bd583e42e086038cea792f6f32b242b1be439069588306be98e471db378b0e30277d74ca0e2b46b74c46608f1991dd46638cbdebb505ce3f020f5773adf5c4ae5d989f1acc5d55d755d223f0d72bcd7e2ea14be22128bd56b3505e6b05ebf09f13c065ad9cedab654b871292bf1e69e7232702f25140fee619e123f9d1439abc96403fcaf38452ad6d02599bb617bbd138906dbc7e381b4ad7903136b4d8894ecb138b522cde9987cca9c1864f155f33958c9a3af4218649854fdb4332394cf3195e21c55b7eec770d8ea8dc1c9fee903c64ba4c84f8cef6d28566922643a6696ff9f5a298698623c1a77ea58a4ca7e89a43f860a30d6d5e7844c12fe0e8107e5c4a10dd9bad223d20e20becc35a1f18b9e13c2e904d8c49f442c9217dba7cc38bd23b42a5ca08cb82acfd63463d2fcdb87890f248e84a7cd5a54be91e851b550b19c175831a53be1056ab12ddc7e79ef1bbcbfcb4bb2ab495be43a9ed73f0e0b76d6590b45455a89fb8dd95f3e57379878bc65339e76d7bebb5ddee7959e3554a7e08e6275b53674e5a88ece1bbb238e282b557a785c9944c324d7a2d1d9425a2e1d7eb077aad1912a2500b853f15675bec5d35b140c97040ecc8eb1d30af701f87ac678f259fd15fb922bd473508068cf937853f709f6d74bc037a0bd0e27d84c47a186b18ebfe91da07fc1940ff92414e75d02be779112db491bb50232ae13bf6e2cdf1b87e95a7564904fbe8fcd8f8c51df74ccc987a5465fcc7b47e559c936126b6b912b9c141eea05009ad0de4a1f7f10bd68b77a40cb29345a404ee6ea37ad13c203ad7863c1d8cece26c74e69d4aedaec604cfdfe0ecfd2c90500dad4d2f2d299918e6e3a849dc5d12b098fdd0f46ed1666e6263a069aed340823e945574f527dbb432449d6e27fbb4d75a2451829637a009fc1b10220e2091b93427af878b708782b5e155fe3f04cc66a705bed4df10fa88110c1b7e45dffe1109661e9b1a054d4c906048bbd81bb2b93dc0d81dbc43aac84f609bafdec2379adbebbd4e35884491e5610456d9acd6153ea274377735a76f3a937a278e6a1c4df6226a4a2dc4657f5707d139d9c39de5698438ea03d643ac2d0ce019290b7d0132fbc784f0b28171318e9399d42eb3d91ec9151fb7e7f6ea17cacb6fad7f238f0b54809cd830719411921001dcd366d5d94ec2f8941711b72ffb610a9b4f094b094196a31d9a34815577d9ab14d52691a00688077ba5be3116f5e92d425aeb1f082e2dc9fdd94a2c9ffa87e67d5d7f597f2d5e974148657b841317e7e7d46ff280723d48551d0bb994fc532f8166468568af288f47eb4d074f3e7d354b2578101a4dd70013b24ca9434f4fc5f19e0c79dd6c6eec6fc56e1050fbf9293f6b561c7af1315d43a0e6de666e18b061125042f49b071cd3de2376e241c25e92ad5401384e43d75ab2f3e19119a6e5a81587d8ad60f9d839e1ee5156e12d11b2632764c88adb797d15348f5ed35e228101dc0420620a6d9dfbcdb0d27a283d585a3b2380cd7cfbb6389a40426583dd67aa39c10f6c1f3202178439950866b62ec5caf39df8f689d67dc013e92cd73a0d075520469eeeeceaad100088a252a21ad17cf43568fb45b5ad0aea269f7beb803f3224074bdd0b7069de0af2690ac0c399db602e2d63c639799d8eb889ffebe4c147c11707ab04cb8e83691ea781362b53663b86e47e0efcc197ee867f5bc06786700610ec67195a80650b3d30576bad9f153388581bd10a050f88dc672237f6b95203e3d1e3f07cec0b0993dae4b1b76ba2f465915a317466236086bd237a8fae1249cd618526977379049092e5700992610ad7852f969ce730a3a1c354ef0fe90e204e4ba4cf10a1197cc136a239ca931bfaf3284b5b4c176201e0aad0712ae3fcd414581a7a095897d5bcefc36c0e1c892c0d557b37ef250651d34b0080f47407804ef8e755d08eacdc9a719b08bb85bde18310c38c2df263327353989392d29825d579fd3ad8290de393a13167cbde7a71647a8405138583575136ed2da6e9467cb27cfc759b9d710e2b1c197b3205854377bdc0d8530a7926ac9b40b484cee7dd0b72be2cb4277b161ff8f48a1d1f82d74ea05448ad2b284bd6b143ae43a4f78e43c80e86cd3856feb2d8ea1eef9362f15e9f9729c089c5ef881da6a63feca3c8600eb210b4898a27cbff7496c7ba15b315ff418ec9220309c13eab805d886a000c553b94b16033a472597ab199bf368c1d3bd6331c91a2aef28ec2a5e7b3f5613f9b7a598cab40beba0c339a85bb15b63a6b9cce6acbb70dc88564927eb3cbc3f4da1478de2fead18bcefb6320340f5db559b4b813e87a6afdadb378188e968c9050265959454985693043837cf0161cd0750ea2b9a053849ddf363f04053908b328d53726243a62bb96304a1e8cc8021202fd690aa0d7b687bb4b04802328873dadfa33246c1c2afb0fab510ffe71786dde5ac238ba499ff95dfe6701f6b20593bbb66711bb966980115f41d2f9e3c3d2788901807a367c8fca23e0051d08d6afd5d620f73b12e307603dce106c756db90aaf357f52de322e5655256db0fc5aa061c6367d35d1a49675cfa4a1c50a422c974a4147a6af465cf396d367f3f48c42619f77be271567076fc086a4d89334680e9ecb0f0991349886041d3e64223ff93bd1c2e88f4a9a9a65116f321c405c2f305e725c40ddd7f13c995c4275089edd852c869a7850fda2e2306cbb765c689ed8b6ae25849cfdbad1fe4a573aedd4d27e5ca66d4e19ac2c35296977e7c1f5fc97fad9bebb3f0298c1d066580ae2dff9a6876c2a9425548b61c17e8efe3610ff84ed199bb60a9d67b9480ffdb21acc042b1cbcc03f0a0ad4e9dcb343acfca41645e0c223a71cd7d25304c95e95ac6ffc75fa67a9a08e5c6934ccae7b1ca42bde3108852eab6d1de82141335c5d69bd85144a9e0e8a711b5d0101ed24b9beec95ca0e09d300cc3ee7448a7725f84ac83420a868292409dc0ca1f7ff84117e02a80062d707f71917a9caab0a5524316ce6c263bda1d9129c3f527ba5b73c39f36f8c19bc430ec886d371491961de1f411ac2d1a6f69815cf4effb31339b8a23899f932ccec2b063b5a6b3892d193653b4231190a8b784b44889078fe3d192055e66495bc1f10dbd4e96c198b9f18e354652a3c15ead08c7c98d5d3bf0456126fb4681d2c812e44d21529b1637795f2241e7c42893667397990ecb3e02e27b43ef14bdead86ff1a35a8bafb2b546d55bd25708cbf6841dfd4e1f568e0ca88c8d220e663fff2f7b93b5ffd2bff2c9a0b584bdc446bc1598c5a5ad9fea76c28e4fa069aa70869439080e734d814282c40a7ec040ab529927fb98f8bdd6aa6cf69e6d222bf9081cd26f66f0aa99960ba9997fd025465c637f4495994b9812d411f2f673529aa602e77ac336c11fc3049054befb85b261dd5d2c3c61c2a48b8a15be00d6f1afd13e9e6b6a11891fc2e139ebb2dcf5eba48a58e601798ed35178095002f4c608048a3cca21fde449f42e0732a8b14283f31ceda91c0cd285f1a9c1567d914782e6613a909c5e63f44050745eed29181935ff33efbf8e10093e68e96a340eec148888b628e54f6977200b950d128997ec2f1b7539057ff0ab64fb8f9fbb1fb5db1dc87ed16aed61c62f5be63b4478af70dcef7a846bb5b62e1a2994ab31efcb3cf81da9b847156c5fcc19b2a4e0566700ccf0a0d699bb69a4664092ed3563a83d28f0a82d0ce66a444a5aa199c2fa1c34ba07e601139ae478c4a76a49910726f54136f5aaf142910e83c2126664ff12cd45c70c69bd3038052b56c8ad07997404530111347a27a98f5228285d9915e66b0cf7db8dfa1d35bf2f1f536844edb6807e196f2095fe37915bf92905f2a66536c27fca79a759a412e8f2273260e53e6cf5daed3a31a4f210d1188934c1e3d672427230ba9643d08182cd41b73c6f69d300da101a492e88e87818db8ae2870378bb3d3137f15b554030c4ff67211af5b9c7c4f0bb0929063fb836601454fd6ead47cfeed80af58b0a9075c11535c3eb0e8dab33d455b0c94a3d0b442c8f60560ea362214822c283a3aef62981388b9f9f2e66b6b8768c8f9e928d52a8f5d1571ee07b305878de565c27af7ae1b42f32901aa258308523553c329fde9bd0257ad96f8820942aefcb22b9f504f9516cf8ff1c8b03621ad50181023da795eba6c0aa7eac2d77e0267c8107675dc44adeac22f6767f088b66a79d06742abe7217ba27383bbc91e22732383e63a89eb01296faf8849049df3d015c25460dec72e85c280cc742bf335d0eba2583dc22a16004b54ad6be1d531e5fbe96b589d860dfe6751a473810269b430c4833dfab7d377a596340582d504c50bd5c775387efdfc7bc7770101ad020e052825818010487126c5370447da6285b3e18c6d87ab37f93bc221b747410f8a54e5faf70428389850528e025fb8652a887d1be0ed85a08f02e244080940e10d32532c4f82dc57920af776bfb3e5b848332752d26ac1df5ad4b9dcf1121093e85d1ef9f12e5d528fb2a5b4c673e83ce159b1a994762d0fa61c0523a41c743a32461be89ba24e8fd9f77beb9a67c8aa37012e614c30dcf92de1fec494953f815a7b1bf9aee7dd02239662ad9f386f0ecb940a7526d58f2498eb100c0f7791ad3ffe3676cadc128775797a559ec7881be86c387153d729e3331058f41b76a0a6cf8e78c5dc82270b50c761ca88df5a81cd6bae3ee29cc37b14eb18a0b82823168eb9f5aeb6c8f9ff7832854e13b9972cf9f60065ff29ffb19107119825751006071142ae669aedf997999cf13be93d993953eaabf3940d45ff801f3ff3fb82b76272c9bcba605b271ffa1d75728395544ff05aaf0c73376f0fc725fc7d0025a157c16838a8b26d35c28965003ab7584b2f245c5b0a29b5684231e1c90d558adb524987dc4acc5733a6b4723b5aa04423ddac9041fca5b42de763c77d5086ea0801684eda6fb3651338513d7572e6bbc84002a8940375c8373f4d075edad35cee2d4f4cb4667ef9bbfca57b2c87215a0e4f2bc936ee9f68ba800e3402c5273ad6ab9ad80a04c1f54ee6d676049ddb88c5707e543e9f340c62695619b78ee6353bfb5df5d13718b7dbb8be4d115baeac3160eec6c48460e0ca3901e1de946b3f862e4562914971a8b380c4a2108095c96a116e4114ce81869085c039f2719f16d5a4637e50dfc5331842abd74806516b710a323e1effeb1d6771a76a8b82abbd45a22dd52f28f0e5a5b5c4708dadeff57c0dfb605b8e7b163cd8804dd5960243c2833576137441ca6b77a462d2d49f3c460a6dea197434e37d8dc8a5a48dc0f461d3dc0abd9a4b96ae26ddb9a287852e59f96f8bf7724469e2a959c4d2d8e3f95d5bfb5c3814d01745a61285605a88328766a2a38de93708fc4eada0fa773df3d911eef8e8af101dca804b673e95baee1f0d02ce90e45fe1996147e580ef81f414181a19b73d3544da463590fdc1daea6de0a28df841ccbe19ab02e8d0de26cd157276ed3ef4588263b1d0512ff84e6d6a05ca394e19526465fb72c72441c52a88895b7ce0d81c297d85b1bb43e571d803b35b6aff25c84ead0b5c5ed009838be407b403271bcf3ae404c36f0be23d4c90b1055c88724e7d0b358c524059a5196b7339695f4304c2ad5e3d111a51ff9f2c0a25e0b7d6e6fcb1b53e13d95a4d0a8cca8e6fd22dc6386082a256849adac851de6ba7d9ff8ca373926c7c2e12671c932bd5fc6b9d3c00b1e50f096ca5c9532ea162926d840e04d41f7401f1af8501bc7eeafd9000123430a6c8d6a8c4719bc26ba56a12af89bde3b5454bc47004fde6299e2b64262fa9fcfd6f8dc36f53eaba25e1b5bab6b58a17645866b13b6102436c5fbd701d7690c719feb2d51fa4150ed9254ac5e3cb6b9fe2a5af5d9d7d3c7dc886732d083790fcfe5ca5cb84cbf6ea4606b8d978a77f36a91ec25b16153a5f4637949d5d972851987ddca641fa64df253ff53cf0c81e9eba44696feadc1e0086d7a3f2ce5b78c5f6217289b280fc596af52c6e8ddce24d96a3acc15c50b9d9261231836aa0626664ea163dcab2401d33c4f10022a81583b20d403d190bc54bc40186f303e48e7407b374f559bad05b0ddfff89e8d542575ef14a4067e9412bbf4b94550139b124d685d7cb2ef158d9f4c15944972873f0e8d1cc7f6c6e9f568438488c927427b1e8f7dd0490f7aa23e9d2729c9b102781e547afd61fb8171efe1382e105d8438ad2f0f025d278873263ed4b2b131ae9f9dfa1cc8f142e3d8e931f4d743ae5a81df41d4ac052166e9e3b9ce918fb7728415c641ea8dedc70b5ac3676c7a87d34b1c547fb19b853ee9087329f89110b3b3af217502a5dabb6ebfc9f19e5361637e5384faa1ac90dc109c7639ff7fa045e4659486489553de578b712e8f0645b5f46d942bb23a89a8b49b572df9fc1c5b1fbd9a9c2955cd3f84a0f3178db7af5584c8a50b21cab34e9cb28b39da972e30dd814fcf173549124905d9751d6815cc5261cbdcf661fcf5509af6bd628999e312cf815b7368b4a1fddbecb6903e6dd5547bab9222f288fb4efa259f3aa556917a4e8f08186c19d1e9e8f71ef6b14f64692b7030526116c47ba530fa1d8206fdfe4a34013ac23f393f34b7c9ba6e169c4ff790c820621e020adfc1f45b8c7847a8eb415af110b15100e99f5440cb283b8fc0ac3bd56d521d6d014fe22edb955e84fbd783e11dd6b22742873535dc90830d3018f9227dd105c4f108f58481a2d16bb59f37825111c7af73b05977e7476ef53d691ae08c3d44c1314bdf407479f89fc3dee6502fc7512e73bffce45848a7e7c37823d50221bf8ed93256439a6f3a76fd23e98f103971c0c6490c9b90f571a2fba20ccce3766b101d8e4e6c376dd1b0448220828e1ebb665fb0c041af819f3e30cf21a2723822de5a24ca9d2b34c9390772c69a854d1cdffc9b677de81bab38d284954f74fa58617191943c94ad383a6a6853f24787e06304896e0d15f658cbc9557141b85a21ac016936eac09f96b1af5fced10fcaf80f9f455d4101ea232baba56d0b60690461d185fa814c10c82df92bc072f3200f46af1bf7d80f610bcd8d9e45f6b13f516a69c7036c4406715002a389287ea995cfa2e1fdf7d1b3f8af0220e3f039e57c6564e0359542f32b56ee6dd54ff09d92266bb7cce8bdb60d8896fad421e5da260037f559aa9890ad6ee133711610c50af2bdec1fa69ac052a060ca2979da4ce9f4dcde24b47cf108d03d98e0682c8ab402659bccab8e7196c0279eeb4390633f274223b22a8175cd72173493539c2e44f9ca44f9826bbc54dcef18d3ae55a9da5b3e5eacee417dac17e36ef388a957ba43fb597687398ad6db6b7c16ef2eea230b7979bf21d81519539428de140afcfccf3c97343cb2f7bd2da500ec35b47e6e5e425f3bcf034f120236f2c3c364fb4343e53206e47f45317b82174537a5ed7e90ca8987dbf9dd615e1bdbcdb5ce1f61bc9f0e8e4a9244d92840bc43bc1795fa189df0ae0fa85834a7777abcee0fc9f28d88af2c76963dd0f45f0aa0da92eb3b968da6f135c94120665bd2df45fe3423083ab202bf95a61e3479151a72642e58f40d5ac4fe5e1405beb2e2592554e930c65c0ac52e51d44a20ab69c85dab12f8c08c35c5ee5b96ca7132eae176b8140f634ba0e98745dc3a6261d0e011b675158a622d0472897ba3aa3fcfefa7d02e60595defa77a06ec3057010870db886a2237fe77cce69fd2ddc1c3b5765d891286da1f7013e3adaabc961bdb3a8592897f583e10663046501e47a3888d95e848bb933439d670ce0b5319ebd227e10fa550cc0d6036badc1accce3b356200968219e5259718be56d108df678d8477d7223ad495cf08b702ce67cf5e6f458546310ef631ec82b39fbbaf276785b2130fad5f84debb574339a392df56db33113f999ace8152747f1150273cd51f67e9958cb7ff94984fbb299c43e40fafa099daeea7fd863a3e472571f5c4fe8fa8888c74b4f2a3872f44dc3edd47035871aba65c5f1053ddf44a884455b4f2407393cc4d4626a37e2568ed6391eee06874e2331071f1f4df8af7d6c9c455f97925dfc0f7d9678cb0d652352dbd7027e922560ab48ec0864f2ebaa0d8b8a03ecc8466c9537e7a15d5c77b0715d2f0f97938f063a41af0863a0f312c8e7780182b23039f646aba44841674f6c75c9cd4a5b182af86e524d6a08e9dc93cfb2e62db6896fe7288d23587952a1f81202e1c74205470dd95800c639adf11300df716b3e2861d75ebfc3d419972a44044394a764ce2b470184393a5ddbd5842f011c4b212a8d15fcb8cda3f812f5475e806b91252d32b33700664624068f8e4ef0c24ef019b619238e72777b88446464a82823e75da2591a264a3bee7b6bb35edd0a35ee4998c088f128f1888a463e0ec5a4015629f606309a1bd113f1d191d7f7a1a344ff572eb4e7aeb48f7fc1fe8907f316fc782a1ba799e727d72f4a7e54b11adfee115d3273dbbfec7f41fdd1c8ab309004c1c5673893e03b7d824cc0ab528254438800de112f58a99bfd7c0429aefe77ef29bbdaaff124b4e91888043733710d892711d6132f08e48fdb32eccbfc9d1c1cbd26014fb9596f504b75f944286c460a98bc35040005206f3147a438d6d5bd12910148b9fc109e22569918028f3f11c493f401a87efee2075c3bc671739a015a0edcf393448c8a2f71b6e2cb9e6e47a251e5a9b8572307f58b77e9b9e0e2edcfa9c183e4b064cde08fba3d9ebcb1a93cd3ce671e4220d7808f1203e5e83e20f9742b8b3131d3560b077e4c06d2de3545febd153dedd7f44a4ee94a4cff4a445693a8c5534144c5a64e6dce892bafb3ff0888c27e386c93e7f1e33cd34e768c47dee0220b19b67b028cb0008ea86bebf1e295828a272633a2843235a4358251c975a4ae7e76f15b12adf64a495da05e9ee2394752e130c987df228bba3fd2aa7a90dafdafa807c157e8adeffe6785c28140bb081ebf002f5d13371a4d4ec9b9945408d365e9c29d04e6a216fb98348a2c5b8a00f1b6b4a454a66b29a0f2a5a668e76fefcc55b6ac7ceb366c9058596bff6572556ce72249db2563b06ead010e286bb47a427dcfbc56d0b4a7c5dfc29d8c88a5378172a2d98e7a052515d35935900aa8b43f513c7a804543799438795fcb5e9d1d6315dd1a95909601189ec5f2f1c7f220f733ecbea5849e007ba3d47022f959b16fb8d8794235cd3aabd63053e1a063a2a48f54b965efbfc6d87929e4e9064074d6a62bc86831f424a115ba4b5c9e10d1f28f205476a9c8d8df34bb5f6d79a0f4b4e49a5ce34af763bf8a8010dc61f0d22d716e8f91bcc5e8397ed28005ce3ac40d2ef77c02845db38e3a09bdcbce5276f012cfec4c395dee32315222aedd7bd05d10bb2244be510acd917f86db0b6240f217b37cffadbbd04569a18f77fb72fbe636a330c0a10d8d4811416756bc79689153a1377647121b142c9f8e53b71de995ceeafae203890e92cda0dcbd2861d2a4cd8a9bd0905bcea56665107513e0d69fb5a3828a085a0721ce59895bb64a8b82d3bd88a9ae579af8d1c5d9777e1ec46e464feee61d741a3d6782cfa785349ef61a5329baa0ddea55a8e63d83c0fb3facc20eebf5a485dbfb514254e041cacb5fcf6e4719bbc51c8bc52181c31244ccf35473aab6313a48cd3bc4fd90a3152237c010f330d8801444cd0962f0cb514de06148da4536edf69685e21357a98ceff0c6c5331a468f11fa7b703ccf099c6cce309a070820c8f352a05d039bd8d431840ebf13de528ef633c690a4ca54e49168253b35aa15f422266ae24a269e123c5d4d350c62c7500500bee3262004ef65d0be2ba148bcc44c1d8ae5037d8411384f31d2d45daff881d6ffa4ba4eee0e304604a563e04cd9d486c7ccbd1240164bcef6946182c12e927c4b0a1aff85913c4027ee7d86cc9efcbf4b1cefaad28d8ae369e6af4c8875892242ea241955fdf37e13ed5fbfaf9e41a92868fa90f49b5642027b130542042335c23a4a93b64890216fd58a6ca505070ce3204e2fc1f8dc224c559e43108724dc02297b290324a1b0ab289844bceae8a4a7e2a8308f7288814564e4a900d8e255c90c85be380ef94e62c3a931db3fb6b43012b1e355cd77851e9d3552c5a10f724aa5d78d13625c70c09dd199062cfa2ee7a347bfb8cf07ffe56e994ae4d70b4d1c49c09e1536772f92dc03b80bebf521498cd1f5ad2189b9885ba875f204c229011103bc381cb8e657f384b2a622d36fe009059140d21b83719cab0ea49e5110b4184e4fd04413884f947959171ff1225a124bb4bf6969aa228d6f68034a9194cee03ac0a3a0af7053c12f6998d42f36ef13dfb578cd5e21e72b395a596f219383c972a23d8e0f2d99643c17ba40770884feb57652cf7ea63612ce3e63221de72998033eec9a1d07e9de00d76162d759d7fc6b25ec3c92ffada54160a5bf23199938cfeac8b0f7c9f85c93d4ecbdc12cd5968e2d5aed6bdf86d9cbc7d94984b75317c9371bd2b4cd656e36c6cd2664f0469d012d45b4e241481b54e6fd4007237ce42268dd050249055cc90d5c7d05808c53b208021a60f39b31d8199a89be89084d11a39a40145a309b5c338ac528932c16f531f0168b1209e6c067fccac64b348ba622d633ccf9ca7b3323aeaaa2e5145ac503f9e61cfab142b013f4092bc2f33f660ebf3575223e70ef6a87d00904648a7643113ae60831cde7618f4097b70884c17978c1c868429024cc5689dc35550ee7a81d4042fcb4ca8770c5e16f5080a470574c58346d0f9468781ece85916d6324122fbd25298ded4b2ccf6e2720e02ac87693da19a0ebdeca489cc199ca7b47960904745ccc084c1b9a81543b38ee6a946ed23d083855b7410b23d799318887b12bd6273e48169373a45d5dfecb44f3803a964d1c9cb380104ac6da68fd709620df0499a1b56ef14ebae546fec07ae209d68ee4e5be1af0f81bf008ae74330d32b68e4c53097436031e51f0f23fcf7336e507ea2025075edb0129281a699259373e3e448683fbeaa60efb79d40f060d37366636dadc238172eaef2061128a9a327cc28e4fc6342181e6a55052e76ecf556d045a38265cb0fb0a3a9592fcc9d014c9c69de39e9325ab22ea71201481ba5ee4c41c0265a6ae8b44737de63e72ae0642a034b20b90951937e1358a6535b8ecb6691850bccc7a0a041a0e00307c0cbea3094cfd8022b55b90e5f51402776c4b8471b30774edba5f8e188507d4f6e1196282bd4274fa350e10cd7b764097d0046df304fdce06ad02a575c0c5b91546bd4021208448ab075a97344dfa20b2f98af6d3b067b846942ced8d61ea4294e5ff0fe93c41f529dd2cb744124c024143290f4ed0f10949b753c4b50932b05023a0004dd06d742b96cd293d0285e0af686b1902133440eb106e350e8fb704b5aad02748e5c593374ec10bf4fd204cc01561b987e8a86eb7db31c85b73cd0f46cb2628412faadb5d0b4ca9a7374449669cda3f7e9f2e1d9dfa889538ef9dcb3c62f4777f21b18d835cdbea533b1ab6cc1eaa62b862038d8647a122e84aca49373c45200436ad1b3ca37ae9a8203f19306628d21397854727041cc88c58b572789876cbf0e140c9d20d072f19df917bec78ca31384703efb43b8e3494deb9816eee184b1b5869f4e19f1a71f0d19ca250e0e13878a62f1fbfe273ed574ec6ff83c6826bfd43fab451dafc44cdfde55fe022b8a6d483af2076ba6b7968900dd79f4973aaaf82a85fb3f76495dc6fad93fa90d4f0719e86b286ac0d91efe51357ae03c4d487e106b87cff63f3b8e43f833fc74bfd7bbf387d2fffb90ce402d6d07a05e08b0be1928bab4404af273e56faef30b521a4eedf9b34b0eb760cd802d145bc7eb44fbcbf99a900703420731d0c9375d7680f7400e2ab1ab096422de5b07db8f4225f405e7eb889e967d102160ec0bc38ca2140ccf9de128ec7b48ecd06889e2ae470e07cc0716e040f5c7a43cb74becf9f0f90a20dc522a622f1fac5999152e4e264d7e529d63d0329426a400a5d2a8979b51fcba63236485fb562d90c81071936f60bfd2a1fa0de58b42beaa985f7d87ff36399a119f7e76052fa7398b7536db00185f35bd5c8ca8afcbaec6aad4e49ef8b4133679a3cd010767ae8bab444f2456b84b509f98056ed4523504ce572ad4b2e2130a5d593e0cb44f526d6294b97ffccf077055c98d088bf85ddff2743417d9206c185cf1f063ed63ab401e486e369659684fc82a04428628e6e708995cb2b834fc87ec08f927ffd78981e151c8411f7e01ce38472ad10a49826a33f1f5f72e8912ad1a0831052136274881b680dcec5af2884f746b03b32cdae00f95a1f092e64d30540c88367b47c7fa319a79abf841ac08a54a89e644e2a5a7e52a6e58a4fd5416848158f7074068de654f836a2683c38b98beb0fbbf3e48d4262a63f8a77372e771bcbcb73080de591971630bf7ff8f59a2b47669c5c10cbffbab780cddb904ef86f1e532831af503c40f5fe629c58b38be897b365dbc3399bef79cb585d1dc3b9526db085d7912ea9b1a7f07b633868af0ee0635c385ea33e0081a2ef005dd9e39f9d7ff07703bd88939dbbacc9ad7c7fba7882aef11de586e4345a32daf54b9591f1bd061907984c70b7569b7a426b85430ebb963e13fa18dc387fafa6e5e93877ce5e2be7e623d85e63d3e6e986ad3c451927418d7e56be92ca5fd77bdd47e59f5428865cced56b692418da35a769b094f70105f77c59fda6abe6a20b74743341a0df5ad194e492ffa1663dd4b8d48ed63a1474a5b304f8f9861fc8467a5b572cd1d287187c6e603f75baa2e6084670f0c12673466ef0eb0840c314d43a5900104aa740ae3fabe4e59d69b9a28ee59bdbef192883c1d78c7ded2fe01323d2f4c40cc13205a6c2b862ceab447329cfd08d3262a18b83a5801349426e23b3c6a4484264dbbd4063206b3dae4b2b1a5c518e5bed03ea7795fd6fdcb2a7fbf267d7eb4552165cf117bcde8dfda18bf38a424482eb26d3cf3e822bdefedd3ff9d022100613bf5559f44d4d59ccae3bb285bb1547c115b7516470c415907989cc745c1fe9a68820cd86efa7ae84078b9cce5c02ddbb85d1b39c158598ebe6f2b209794719d52b9ff97b865c568c99292aa0a86862825891190315916c5eea4174ba234c4914f4359b4acef407082f31328da9223f928c098d15d0b501c71e245c136caabbd262457f5a317ab7a5519ec3f10af84b196ec50df11a665a1b3f42c62ecde03658bfe9daa056710f9b985a78136e4871ca4da0f4649156573dfe7eaecb394a15e98d75410191ea021ec27cc496cf732ab63724e615c134a0aaf8bee75065ab8ad9ba9003a9f5690b69ae92856902fc194a152915c15e7ffa57f6dc4a0a339fef547c64e31cda757c57cf2defb5949620ebb7f956f773116cd16d89be44e0a2f029b22f15e6dca62b637ba73a74af034deedfa262b49523e866fcc20451904e32612208b58207f9ae6c552d2cee33b9f212eefe7fb6fc53a0016a6162d76950d1d1b4cc396950d6541533f48570fb5cec03336e7782b4773158b32c0fd423a15f5c33055e6c14a4270164e2d2f1a7387d86c8f8771ed0193e3f0332c33e451c32a5a86668b1c3bbf699eb80b7a294665c6b229a21ef3883a45364e8dbfc55ee29d2521c6632cc997ca35a5791addc6244c35695df73e53106bddc94234e7c1d4e34886e63d100e0daedaaeb5a0a4e88ebc1bfa2c41605e68438088966310faa01a7289aad2e4eea648a52a227d5ec65f3529401d0759cf0b4c014d70b6b587660e8167c8d6e72a8cf5ea4d9677397b9b184091af45b5f293e8053eec2de5ec1199c6782510b124a717114089496146d298280fe96bae1efa95fa2688a4320291ab201578ad26ab381e717b8a8021288888a590c150387dcabf0701467818ae93348f848ad55feb1f4e3245bd0f85470a7626618c6151796c18d551c299616054befb46a3444750a90b67244a44b4e51540e88b4a981f79a0072403e12ab58c43a9638ec3a784e4c4e91f0f734c36d4b7d8847bbb2e2879dc0b395c41453de47b17a5d0083ade243713a02a24b7199549188d31dc098b314059af6236eb43345ca9e68f34053e40491a357f6dc1e42a2354cb3640c282031c571c706dde967bf51912897e24f6c29f20cddd227b314e729c580349cb63c4571e104c19cd660d27626c71864525c01019715197a0742e953523c6b5223c11d508ae7bc0d41baddf0b232cfbd28453443682169370e964f8ad38b9898df66cc912565d7f4c11c4c81ff335e464c3a62988ce9807ed7e7e5f876a05ba3ee4c8ab603c07bd3dd71a1f899628625c9c876a79bc1d140302a03648c44e1f4ce2c29cae1f627da6b05afbeace3b27c24c5073a137b1a1f1e48a4283ce13849ffc47a14b72e6ef3f2a1172404d95dfbcf07bf06bc8dadafe0e6297ef9d0f359edba7b3f914995fdda44c18a917ed2b6f6f6ff08644913459e96dd62214331a0ce63a11892f4437069ecbb21c60fec4a53144729bbf6e97e9589b8c6ccf7b3d6b4bd93eb4272963568f8259785e42c2ba021975c6e4aa61bc5ff0fd6e2dc0ee9da4204b82f78ca2f06417f3dbae029bf1004f5fa4893a7ba24d6543da84037a50a4b4bec9a6ced7e59909cbf06197afd554ad2bd48f08ca62bac0ba5227b1db605dbf2ff20eeafefa2d0b53f191b18bcc20a42223200606bb2bdfbcb93e4bd489c3cfa55e9ee0a58bdee34e5e1fe01b2e2687c37e59e0e2dafecbd0e321d11cf6249040bd2e41d48e040aeba47f4c3b9237c70ca7473bc8678058d90a396e8afda86f3a796c5364082040e119d7b878a5564a6760b85aa23d1206144645a4001effde578ee5bcca5360be31c583cd3f779ca3699e899fca5f16999761e3fa85cbba86b479eee67a262b7115ede8f53f7fb04065d651002ad69bf3d2cd338de3df88c3f955c386b928270160e2f1852ff9573cecb6ae0d1a3dd002604440768022c7d6b5491d649dba35879e10433138648e0c8bfbe848af34855f3463aa228b17274c35cccd2b668514d37caa36df73a3f5abecad621a2eca50e699057bbb20f92c25eaf15a38b45ca221198738c112ffeda2ae329ccb2063c19f9664917370398e11fe3d0840c35538125d46e9c1e3278ea671eb3a97f3cc15858d984e7e164734fd5eb9be627615a8f2bf2f21a4f67f18117e1d3e598b585e646801d4071ae08d024065e8cddd52c6ce3b6057e09d660eb9844fd5bd5a3f3409dda84e565e21cff3983d245180c6a055f1b019303af47877a4cb1cb0194310f57cf826328b6fcae362ca6740832fa0bbb61edc0a35211bcdb6ed149bc5e6e195a5189f1f4a3aa55c13dbdf2ee060e52ebefba5a5ab174ff4b1e985ae4fc04f95f5f3fb7573e31d5236c782c65ce5de0dd4444cb3b13b211e1334fceb0aa7d40ced46f70a50bbd643bdebfb451589e24bc54529ef36de8b6a707702809730b463e7f1acd00d1f51b863ccaefecbb25071e54c59442d47835dd453771124c0d56249259f66d2b192340fe5eae01ea8c2e61befc460bc5f85321720fc635203b2f2e77bacb9d3c7157e9c6828a07e4f6a8c7d6ab793aec025b49d21657d21825e11be9e889c563bb7018c436bee82d394a7a6256a0f14d3d88c0a219d307b0b00db1d5b5a2b8831ed7872b4c1b5783404d412ba602f98e45907f54a953804171b253cd2fca04fbabcbeaf14dc76c24314deff42cbaeafdc1c2b9173ebe830a8c3b7a56f1d241ac4cfe24c0fbbc0212fc43d9cd7f47523033aee0971bf19b9bc6b7ea29f1cbd2c7d383624ed1a6382ceb080675ba31740650d78a1e0b974bf35d7471c46ecaf7ffb810e5031f4bbde0ff1952a54567b87d82198fbb21b5185b2ba974079de787c6c2d627533a0824754ff4812a56ab2f5fd93265c3c3c376c0d5aee8060de3f4ce97b3ae85b16edcf32b55c3154e9096fa75e346ef2d485abf8cd2aa35f0e10e29b56ecaaaba8b8b9ed0e4ab48576d41b82441286906204615223c470a1756a55f43c76efa1cebf89f8cfac0e92bf488939721d8b84d930148ecde5e842ee86d92dd9f266630aa2783013aa013f637f63531568c3623e41f5203b25d8d98de31ac78d1f8f7aa44761e857a08509f23175db866938a16a0de538b898e1aa9e5f9a763a8028a4030638a1e4db3858d6732251de2622e37e5f88b89aff3376e5697840f6194bc381ddbba64c577c4d8280f7aa747159c04cb066918f9f42c90de13ddbfcd3531d11935858ed751c06f1ba6a9064be08b3592cee0f49496d06125b0376ca993a75f9343fb7528b4899f79890b7fc9f979ec4e27934215700b663a9346560af142d914324fa58bead746b84216e9d7ae0e7555fe338e25dc3514121a113a0954bf31da499b1dccf53c43deb42ef9921b54b948a9e16089a2053fd7e727ab3ef423e8eabe5a2cff9d7d8bab5bbb6e9c1e2bb9c0475bdda16cf2325d46556a0bf4a193480818b2ba91ff55120c336b75af52bd3ebd5292ea4ec6e42b3f5759dd7365ca155dc8c55f17f1cb8d46c07a1919b50dec4a2cd0a4d922104827f2e8fe701e3a180ed83974a996fe1f90506bad3a9de16396f4d5b7da23b187b48d1598c3f9c193dd84ad0fc0159a947b04da678166049480211e15a238454cd8896a9b40b6a9e5b0cc80e9fd22e9a8448edd1f6be38b375bf211aa4919e2fc8a64047a78fe6499ef935d5ac8c3121e5790c0b39fc30dc9b30334098f73d41f83e7d3893831070363c0c58fccbe210a87017680569f9acc2989b7534997c592600eb1f30239d16f2589261815492f255b8aa39fb62612e034ef588e612a801d021ce0c6e1dae0dc46cd56d61acb95f1f91078d8408815b6c40c69163860ef655d3c93c5764ca25e0696288f3005cc404e5feb01bd9b4e0a96d558f8bf523971e0c50f938750628de65e0d3669fff0cb53780116a944d1751dbad08815db6fe75e65f4c371cb94684c7878e27af101026fb403e30e0e437b66bcdae1bc2dd13d0aa5d46134baa5a04ecfb30de8d8ea8e0475cee5b40a6443113220febd38430ba2f697f0d2e2be350a9396889595c6d725e3e1c6a2d9da454e83a7f9ed249aed03e68ab274911d9ccbec4dcf76cd2dd0c9ed07b9bf9a5ba09bdb037277357f838e77ffff9b5b34b5c32aa490fb82a7fc4210f4eb9105cff9c520a8af8f367922546f2a3a94a59b5671676d4d5bbbba2c24e55a050dbdea2a355130a867205c102d14d37cd9166ccfff83b87d7d1785be50c906d52fbb8298a483da9bb677757d9a08189ce978f1655c37bacb556f8af621facaaffab6e89ad5bc222beaf664f4d0456a8dfdaa624177d56cabf447841d725ce49d8fd099169e37ee783aff69ca60889127756214c7872f3deb5d348ad2ba53f4a6e9c1416c01cf921a750ad16888454f523f70d0b819d0551e42c87f11a9a862e6485949a513af5e414ceab688b779545dc065f2ffa0b1513a309ec271da974ca68dbc94ae2c7365c466c4b52475d4f9f6bb5f0f79135a6566515cb691a46a1cf81b7d2b5c24759095726546b083d7410b2e516d3c290ed71ea91f834eb806d9689e1275d895cda31ce77186ef91baa3bfbeb6f5e5e978bb2b4ff25530f6fd17c8c591ea93923c03f1d87bcafdf748a595a03ac7fe888d564451156467f10dc823c31cb08acb549df38ac8a159f80073d553f144eff9217311b32dc450292bdb0b616ba4ca51f96e7b1e9387163252d706dbd79837b9ff338524bb390866c57eed2472fdd7482c5d03cf1a878a23b0bf48581d68e4db1bf8c1d760c01d2403fad12fcf9d8d1e410d8354557936ab7707652c4cb79b82563d81d3e86cc5968d59918abc786a0d7e09d400e7be79200c862494852a7c94456588326d8fcf2234928b57017f232db2bcc5fe3feb9b1069b53a39e535cecaae089d611b8f994c609a56785c47e09c9f034a0a77a5572010b1a20e82ae36213e1fcad3d0c6086dabc9c885e71e41b2b1fe68e872a1685412564f2393b9b35dded1ecdfb8581c54c4329e870b5acd51e1a393823bdcd9897f714d1c9e84d4c2b3af11b9a56d7b6fb9e596524a19e509890a210a21f49521e163aa993663ba97c24aaa4b897a437856985785ea107760e24e95944718dc558e314a3898d624911e54a2391bca497ac5edc121668f9c039c34143ef4e8c650e92143c25945432e7a8231c65ae789f2390baef21a0a92e78501329c214977845052da54992333e123ff3416906be829cbc9963bc0455c5e1365fd6584c7592844dc79c2fb82c49407c70f39e71092c83beb5731e319f25226199224aac898285ee2bc6cfa3bb1ddad9a9bb5dc2e6bb973f6d8ce9706dcd98db933c3cc4ba46962c09304e68b1224706228d4d85171c5e744123c3fe29c79b2e2cd068c71aa4b8930c6c31caf3d530debbcd67eca661dbe182044c61fc03036d1f438e79c31c67464bca633d5421da52f75e2184098a6690a8c4d343163264d0a356f70b99d3b67189f88e131b670e6b8f03a8e97d74039433e784d2567ea6ace8e16a8e664cd42bcd6c9f4a43a385242e88272b5ca831736e1e53551d6facd3ef318cb6338bec72ebba8ebf12c86314e752991c51663a0182301a0126a1943f50688a97517cd62304dd3a2ec4103d6a5b9d7c3546b5c780d03159b2842aa364b6aa8dc20d5279dea2e5ac59ffd59edfb97a6290adcf6abdb7767e6a2259670bb1d5eb483df7e53abdf7e892c10df74af17fcdde4846f1db05a82474f0d3c3754e07675f37bbbb5bae8f8db6d0fdf748a81ac25b2ba14d64c3d55818117e5026e7b9bdf6e95b0fc76ebe3a2fbb7cf00df44a1703b062e9a7d7b0a21d8aec245cbdfbe023cbffd05177dfdde0e017cd3bf2d6e9fe19b18c440d6b77fb828f6ed361bb82163468f0d314e2e709bcd6f1f91f4db4bb8a8f922881479f1f163f262086eaff9ede799df2ebb68ebb79b4a720ab023c7961d6bb2f068ea60bbf7754ff794be7c49fbb26c52a51ef39454fc388e39ed23e69973844eb8710b856f5d07901745d106f52fc79b0260a58b5ea734fd9cf69c3316a6e9e71cb4c1b79ee30888ccdb4c4ec7c0fccbbf6c859580ba9681bffccbbf0c8cb2e7557af1876fbae7a149951767ac585901474dd66b9dc3450de7193e1123e79c7100792ce6b16f1c791e7beba23e679e69b0452b6e7cf982759d424a32e3036bca0c5fd2f8ecb05627e9f90cc62aa569ba02637cce2250240c1d372b6ce4a983cbf90c9fb3991863ccf33dce39678c2f5296d756668050e5ce15efc96babd7ee2d5efb07edb61a30bcf6102eca80d71e04e286e0bd7612a06ca879ed256887c0452b54d294d74e818b56a7facb25150a1b48392a26218953d59aa1de52191c162e01e39c731631a691c2f62d281a465e8779ed5048283af85ce2090e364e4888ec193245063c150b096639b4c537c3c877d04fc225e86b365078f4e0421a5a9dbe759d5eb4622b2307177cce4c32d770b29354dc3eed0f0770a628d3fbfcab5966a060c863d4aba1a7a2314d54f9e11be6d1b46bc737ae4de9a2ba6671395dc34a35ccc34a17ad318a6a18f372fb75ee7ce58a79454bbaa77dbaf74b7ac569bd3ef0f3013e67df4571cdeadc0623c433d46122860edc99cfcd3e4803e5d4640bd60b2b70d5cce76caf73205e7b09285421fbda43e05bfe69ed4117ad54305e785dcbad50812fd6b4afe73bab75313d7fbc0a0523c70bbdeee1dbc659d7beab832f0f72604b6c122b5531b3895c6b8569d739e79c6fce39eb4c6b71cda4bdd7566cb188b1088355218d5faf2a246697ab0a65b1d5aa42589b6615ba63f955c8926415aafa65ab0823d6591433eaaab6ead8710d63d173d8eb786dadb5ea259a9aad15c58d33fe1388b58d77b06aaf575dcb9d2fd6aabdb512a2bd6246e0ea648358be228100917105fab8dc31add70fb9a010676e66ddc66367ab9393d4df5bcbbc8af1e75936620854e078c2ad392d369da35f8bf17e9cf3ff305673ebac8357acecf5da76f6ec79e77bbfd842084102c6186bb762bdf75a7badc5185b8c7150881fa78d848b86a88920fe5eec178b430168f919447d3c87cd68a878f8d333530cb47bc984a392ed43f3a9a2fdd07c801868a8f478f81a126d1f0d359fdf9e71e67ecc9f942926dc0969f8c0360c63b4201b9c5e59d7d6e4eb2989a65b52a727fca4f8b6c1f130dd908e523a51d43299d6a3ccf783816432d8cbb78bc40b368e2459cb7af1cfeab16bf8c926d105c2667a6dd84c6358ce989bf584bd328f07734b1bb79bb5da6c8998cedd13951ebbe6e5b2fc1e9b38fd499b3818dd05608fd538e8ae0dbf86afac1446343accb707c39863cfb1c7729646bffbd13dce1b808fdde7eab16b08fe1829f989f96069eff1c8e39df8a7f61a62206ca6553fe9457fd2d7f0dab099a617351deb5c9ee320e3b173d071d85d74749f1a7e0d5faf9acf8e71fa98d7b662d587663f46b672cc49d239e81ebb0ff9a3f3294b1ed68c18d6e9e6e9b9168b59ff496134fbaf611501fbb807c32a641d9b3e0e5b60b1c7ccd3c469ce4c3f9829be6dc79edb41b6bf36c6ae5aaec3676f995b8be5d5044052234c18381c94ce9f19e7c49edbd7763b649e7f688db08760bf1ea76d06fb8d5d7ea4cd766b843d3442e621651eecb78760bf1e1c945898c002134c30c1d652f8c2401f39cb2f1a115309d3ce94f10f576d33d7b646e74d237f866f78d6f291e672d8e8f887813039f248df18b87fa4e160b625f0167fd4738f5584cd3b73b3d9ecafb56082a39f356f7ccb4eb40ff28b7ff5e71aae1a77d8f509f7352d07699cb971f7bb3288993e083e36fd8cc17479370e3110d616eeafe6d5b555138882f9c34078ccba36bcd3d638c4b7bdcf731ce6252cabc33799ce66590a42ba0c639d30e1cf387c0e9dbd3776793906564b96d26444d786fd75d6ac8c3376fa881b3b6b27b00edb3aebe3315a909f1f29d98e43d605c29b88846eac17bfd2c7e370685d678dc3f006966c876f3e8edd03270e430c8491b0d3ef0261f701833ca596e75aa958be5ea5cba5c5ad75f97a952ed7b897f2eff255babc54ea615d20eca96ed4e6d84af7de2e1231c73f66dd05e0e1b56d1aad1403e1316b1cb660c3b445746fe4769d23ee263196f33e4923622a9d43f62d003bacc431bc68d6455d8efd4cefb9390cbfa724bc40d853dd8e2c635eba48c44eb7b996d1524b776db895c6684148cf34a421d105c2adf4da6eb41c36c437d2f7f63dc6c10b847d1c6edd638c49eb329d0ca7bb6ab91530d6e7a12c1d9dc8521991d9729d00b3e76ed933763a3e6b75c74e97c98844122207d9eef1eb759e341460e1dbda09b2c3dc84c1dcd64ec7ae135a1f133dc761f838566ba55504ec663b6c5885b263d7e7d2c556fa7878835d76182d976b2b94196f6cee9725dd45b66a39d96711322d6b5aeb83e0ce81c5fa8310e1dfbd4b249dd86f4d66edece631e7ce0dacf123edcc05b067f0f3d3df6a4d1105e3ef84fd18f8846b1b6803f8d75b425b87a6ea553fc3b2fb8e33ac2aa467a842d94531cfb27e86355b7351ec33acd90cb334b3351d18cd84b33533ac9b3b38597c31ce5967118f786711cfb06255312bb12bb12cb12a7c730d35f0ec1d312f677db3a881a781a78187b13c29173ab82be4af0781a8f244f4d749b8a8feeb3a53c3102b778552179555fd80c126affd9a69d2fac7b55fde55ba3d1f8ad7fbb55f1dbee954d7ac198ba5b5d67e892c506b9f26a7aa5f8fd7afd73ffdd331d796679554bc96bd0eeaa0760ca4a0b5d6a216b5d65afb081fafb59376d2bacbafb681c6d16bd0a04183d36bd0d0ebb9f032994c269349cd38f23f21fccfcf8f4dffc76b9681238c948c3841523192bc8f8f4f9a394458c1602c169bed590275e7f773a18a7977a6693a59877124659aa689d3c73a98fb58013142e3a5a94acd92ed995475a6a2ac9282508290663d618089c1625ac37c60b0139ba6a94db0e0e4053764d66c2102e2034b528ad54cd3a78d006c58ba1031b1424377e3c7e76c355ef8582f1dcc124d5b7a4cc171e64c0c2a7c882b4c53ea058e05983eef748405935d9211518f56129c9aeed1b4efeea05a384bf039a1891e1755535a48316279a063ec05f3849da74fcc2fe60294da05f9e034cf9fd363bc3730374d9af6e99e69c662522e56fc799ea64f4c06516cc824d1d01363c80ef35ce3038b9da7540b376f9ae6707879f927c7b084b9fc1cb5a2c867f373cea667b74dd8a9ea27c367d8e79cb35b9ddd8950f179c3e79cb387408515e8903efb0bf2878be69c7d84eff3cfe79c735195cff987cefbf8f8f8f8f8f454e8f898e7582c168bc57443c044e9f6942f5b829122ea61567bced5145fd197d75da252f8683d9b27557451452a1cb075b6000c16638e603022844169dbd379bd9c61311ae6c1dc63301abe614f80d594340c56b328e26c00411229658094d91d1163752480ea0594233141a4f4c871c6344df356a18bbfbef8ec394711c9f059e873148a1d9f67668e0d6db02813858945901838445839a1434d143c46cadc184d7d9e311317c8809d63b000f41002c3110e292b2c4962aee68ad8093b11a541fcfdb02e0ffb602ce1f0a65d1efb25ba68078fdd02634d4eb6cafe8c1e73788c310cdf4ebbb33cab74f5d8ad0f8c1d0329608ca70c3d2e1f631bc618fb88243e8f31c650603cc63e35a71e7f9ee7e927f04f979d4f45fef4f0e7799ee7d9eba179d3b3699a5490bce905ca8968bb69a653587c2c163345219494a987c160a6bf6942e1f15a6b0da5cb6b2d517200a1a2d06980d6e1f35231cfc9d467cf39bb2c5bf96cc5dff048d3844f12003963260b89af8b1a1bae5c83c83c4d2d5e59282736f43985c89821de1d2b606a8c9617ac0133ceb969a80b549397aa1378813a513445c7400aa28740ece0c5a927a21745d121208a6ec3a20785708af2a2eb455114453f63bce8b28b9a2ffa94931511b99af99c7b54728099a212e7b1152cb22072c249f1bd9e5244837aa2e2b5d3942059a6a6f86c18e708ef14cd570c9a20d1b125cb9e245078220f85d63a9b396b5df5c860c27104a786940ca435482e827bec24a1496269903509c979a7a4b000a12cbf94129ef8f2e7cbd26d65594ab9190366c86b5ddeaaaa2fbd0e152840d0d8a893628658561d4ef00694d0a1136389171d38ac0c5e8dd71863aca317fb9c8362d250419aa1f4644f0c329fc852eeb12ccb5ab63a78e7075e0b678444ac9c8182e14a91040425235529950e143f3e5f557a52f39b8385499e17e78928da470e0398185e3971c30e30c84e83d61bc5e64135a6878eaba71e783cb8dccc89f38248d515302e644946394f5d3df1d80142d66e8be13eed20faec53a5868e314e515a48d1e273333f93f464144f4a55af6a8246ce7907f049879dc7dec25eb5765b9923e79c7346b32ee3419ea71c2c3cae5263c85204e491d95155e468ccbc3166b94543d9229aa1dc4f38966abccb2b5fe91a8c4baa243ab026b5d61b890f1690e8a1cd00850915569ad0dce86254e2ca7391b369c53d8f9f8e383d761992168fbdc34537786632c705189cc0d41893c402858b7cc509865deaa6e65d5c4ebb59c3bc6bb3376af64809b7472b7e2ebb56c23768d9cd5ace9fcb3afb9e7c39f5e261c1d8d4dafa607cc620c881074e99395ce2c8592183523352a6620f81021cdfaec796155bc4a8c078a9e835d5920b56544c478aa40853c405292350268d188ad031030565444ae7b61f8d31c6a688d2c475faec397bad5eacc86082c6d00e7827450cc52f53114902e1a639450a1f0f2924474b626c9199e61b2d40a0ba91e40a878b1770b021010bdf744f055f5cc831c31018516050985aa3987a5d891cca840f10f2909a3c38ded82012076889ccf44e1e9ae1f163ac4b1821e9aee65c05f7d4c0d9139f9bf9aebca85214b9e06a96406ac18a0f24225f0e33d6c456b256c8967b7a04f8ecb614a2eb91e4ea052551ec900f8ac725c679babcf6d73acf9bd75ca2f4387189dae3a2039b99344d57e4242de162d322ac9c73d6152e796a8478ecd69633136c72ced95a21fb654b54d60ea03397ad0c07638c9704a04441260a0f0d0134b9ca136072ee2d9576ca01a8b8acf19531a2a6d739975ba202b085cc639761b7d5496bb7d5e89965b985076d683543464f478309cb9e92c84a6f296b8953e614ecb88151070e5395147a5c453acaace5e741a98ebea37e74d945cf1ffd830d8fa31b215180d11906501de500011d49d73aff5a9f03f1434b2c95d109047c768bf5d6b99ad861bc84f5c8224d079fdda2c23c75da10c1d0650a2eb7f37ceed42958c8a26551e6f16f9ba6da5f2fcc7be19763e0a2307f790a2f0f810a54676cfcebf57208bcfce5367cbbbf344d67e05e25101a51c1a2a8ceb00cee95f52f1f91e55fafd7cb09121ebe31c3387196702fdf171dc0bffc7cf32f975d74f6affc13f35aeb582c0363c058bd444bf28fca8c8a87c1dcee73533961b0990c9fae697534b125ddba82e46086633a310fdff699adae8d06f39206ab894dd7669558cf66ac889b7e4ddf347d8779d35b1735dff453367381cc9bdec195bcd980375f78f3a68760c220f5a683303d04092364bce9255c14f6a643a0c79b4e818b9e6f3a0a49de740c5cd4c39b9e82074210e64d1fc14535bce92a5cb45205d5bce92b98be02236ffa0b2e9a80377d06a6dfe0a2f94db7e945dd12519109bee9d6c8a48a41c99b550c8fc59b6e6f985465cabcf97ad36dcfbe4628e1c1020db0089737785e59f7301e45d1b54f86198c9640ed891345863bb1134470760999c23c81b24b539c56c162bdcdde72ab9b41abe52d4f01b73c042aac20eb5be6b77aad5eabe5b6960795dff21147bee5255c747f6bd66af9bea8886fb1a0f32d975dd4e75b9e7fb5194e3e47e59c7b3d2932eedc7e8414df302f9d92a15bc00e67b13801634fbb7b51988521d83c8163c58605262ceca42fe81ae6f1623c0920682ba10ca1820f27a53c5153575d8639100f05638cc7183ca0d2dfec7061a297278d945a47c4a3f364c839e7b28e238c1d8ff1140c2e8fadf830c6186389d293c1cb1a29496e301d8c31ce398f18fb165d09f36e8863ed7c71f42de2b32c8dccbc862a5d21cc608b5e7b0812469400010aa040a74ebdf6143c100220af7d04172d5fbb0a2bacc0f7daf57aea48ca6bbfc14543485d4021ba2800746e5ee38bd6a916705ee7d737a65c005fbbf5617b17ad53bba5d7b5055f8ad76e95e8a9175d5ebb8da29db26801394bba0ca96961074a840b9b089ee769346500f957b3e09879cbb82160ad9ad921ec76bdcb4f3aef72f9071b76d55c3ebb2ed7f2daf3567a2d664a5847ccd49b2d361dee00421709d738239d44dd1ba7dc2889306a8c6d8ae058d3befd36d7f49e6a93f5c1e7f8a6530fc3d71e62d06b1bae553f35768d71d5577bbdb6059c00df35585731eb456badb5e25ac58ac5a06a735cab59b4d6e6bcf7edba894be01cd82b6a315bf89682307892b0f9e9287ac1c2908259ad5f313b214992d4a2ae2adf32ae6616748659ccabac6cadcc29d7e1c36bcdc20d0b195e6f1773b0c73d8a28c4cc20e5b3cb66d93d43b1c8f2d943c823ee88cb62891e5ba8c00ad4c1b73aff2c02ac57342cba5c6183ab2076ebcc75f00ff2cf8ac03c1735a6618d71893febdf1c672ee8732b80f812e39cf398b1f0b5987199db88f914b3f045a5bcc62240f43cead1354df452749cb3701c7325b03e6fd9316cef0d2b77d9b5cbd2aeb008c85e6eb3dc295c9bc69e75ce95b8f666d7b46c776f9d7ec4cdb414b09d81dd5960b4bb6bd3b9c4185f6ff988db7a0d252d17e24bd7c09c73ceb9962bfd45d3bf1de7cb5f59e839fdd356d7a644c7086c86f8fcdbfb3c67eefa77d1975bd7561ab863b5dc79c26ab9d9ccdd1614f42faf2f37b18bc4cbac0738ad2b7bcd38048ea9ac7d3081cfa597355d65922f5a7e2557c799d3bda68b66eb7ae9a2557ffaeb286f5de7b493e6d1b44e35d06e346da477a2d0f4145ef49b7496631306d22deddac91fdfaedc29d256b0fd076e8e2e123f3f567ff0c1072e0f366436558418ac08b06e4db04a7d6d5ed881a708675f98b9f5bca60ae518dcbccd66de7a2e63619d47afda8a02d7366a8c473747cfaeb588458c4390a057a8c09144886b1b6bb8d2505083d801e0a6d3343ca60140c3bbc768b92a9500cfb514e0b97304cfc93e969b7dcc3f66fb58d0c7407c8c848fd13c56008fc5bcc34545f0987fb8e8068f790817bd79cc435c547bcc4754a19ac71e7f30805b6d00a7e5ecbb0720141ebb16f30d5ee715bcde8e692b043d0edafee3668b06c237ede7c7b78bb4dc871745d15bf746bae872988b64cde6328f23eca461170d2ff9f08d749bdd966e4db78ea52e3a7aeb02690f80d78b0ac0d192f6e1dab493b41906d23e6a372d2d17f4bab63db848bb798b561f44b5f90f2db742d0dbdcc3ed86f5071c93cd4ddbbad97cc4e50042086e7dc4dd2002cdbe06cc2380db019018c001dcac67905717892039a8401c1302bcba482000f862d6a2a8754541053e08377d680b70910602448bc3cd731dfec3675bd06710798367f78bca3c7b0821aa10ccb39b66ee3e4db320075fba072cb05f6ea0d9bfd16e1287fc437d4437384aab17086ba0dd24b2846bd32ea3fdd08250a822683f69aed658ea7a6d15f8ba267a90679a02dc87567f01b4dc080e82368207294001b49c4712704c23282001b47a6d41b47a6d08a01da016e2dab408b4fa21d0eab5198056afad00b47a6d40b47a6d3602d00640dbd7a61d04da8981b47ff050a3a55045d03548ab055d5bf0ddaf7770a7d517002db73f00b55ceb4503002d073365fc073414d8de83da0966ae5d13c93a7c4ea72582a88093c5250d14173b9c75717851ebc25bef8096829d39a6ad60abb901b6a112d263461ba62b612ad360e60896a42a58522a5a4099cc5a6706150e266bbe24c9c2024a558ad0417564cf9292346bc634bd4ac0509124048d9396365380e68e567d014c939dac19be48b51113c30be39c4140250995912435e8e4c0d930affd9cb9f0cf7a6a5ccbad60fb0de3b460beace5f658cb9d62edc9cdef732de7afc98c0143064a92245926703e1b36a6a2a21076f5d76159aec3805548017f1de6846f3abdb0aabf0dc052a30b0ca7312d6cc1dd1dbed53d3a2d68764854766470d761bc8bda2f7f1da6846f2252f4f02db9d9f1630cee3aac7751ebc5a704d604c5e4afc3a25c74b45351fdd3bfaccfc261151a01dfee70f852c237154c795a4ad3c40e550fdcf557efa2b6cb5f7ff9f0cd04666010a3e5c511224870d75f4d17b54ef856620a9319372ecc7ca113c4592e3f7dfd75f5aa515131f8327aed5ebc2a5480bffe4af1ed62b99cf0ad862506353244bdd0c607eeda2d7fddf5c3b70d7851e1c2478b3538a0e0aed5f2d75d417c738195123a499e3ce9220677dd8575519b4528e7a2e291bfeeca7239a9a8f8fb45f9ebae2597aba90a01fd759712be5d20b0f7d75b417c2b81c4891b1846f6acb9a30477bd8575518be5afb784f856d10cc9c0624d0d1956b8ebade145ed95bfee4af1ad6ae1a2878e93ab1e308a70d75dba8b5a2b3b192ede45afbb6eb4c6545474129daefe7a2b4bebd7025621db5f6f45b937cccbb5a4fe7a2bc5371ca461f43481f3064b1cdcadfa1254aed88082c574e70416eea2b6ca5f6f29e15b079cf81072a487a60a0bce52fdf5966fc85f6f29b9b71177ddb45351acc3baac357286558876abaa94f00d04199c76c3ac222222b86ba7feca800b9619473000f100c15da9bf6e3ae1db0a866024b913acca7283bb36ea6705e4f1d7cdab8bd6a8e87d7a7a6b1a99324c5e15f2bff9973389fe7a59f5c3370a14a138922606a43b4eb80bf5d7cb20be39111b645cf042444f0cdcf512eba2f649c8fb5be2ae974e2a7a8508795b2e954acaa62a2480bf5e2ae1dbf5f9c820be15a04eb0881224413a3bdc7512eba2d6e9af93427cab70645c2933440d942333e0ae93c38b5a2a7fbd4cf1ad0e87102162648e8c30297077ca4e46c9bbe8f5f2c645cdbf4e8ea9e87d715f90577f9dcc425a91c02a1480bf4e3ae1dbbd97acfaeb648a6f26948921062b6fdeb428c25d277517b552fe3ab9c3b712484b5a00be218af3040b779de45d9454c237109ac0518187cd0aac15b8eb64efa2168a4f090915e5a2a49d8a5a3b76b2d6c81956a1d94d6f8ad56bba68adba68fd5901f3fcf57db56b54d49221f3f6fa36da322e5aab1087bfbe537cb3585855c02ab423e7a27968e7af8f59a3938a5a2b56defab8342a199baad086bff6f77b1dc4b7123a26aa183f90825bcad827f85601df0b1b36d2c0a85306775d0f2f6a9da04cde84c161834d1434b8a69d8c8b8e7f7de4c1f9ebe38d8b8ea83d72445ffd759d455b5db4be86bfb6a9a9aac4d15210324fca18a9f282bbb6c99760f223498c0b3064244183bbae7917b54c3e4492ab2b4d566d88dcc15dd7bd8bda253e25ba89cc5fd7512e1ab353515ba3c69a8b0a657f5d0c5aac12424e1425c5915a3307084ec95f179b9cf04d041d3c57f04c99c212c45d17ab2e6a93fcac8062feba7875d1f2af8b352a6a615818e28dbf2e1a89327855a8f557f72e903d3d2712fdf55c958158422b7f3dcbb9b7170ea5819d287f3d2f659ff9d7f345873b9f267f3ddfb8a8cf5fc7632a2a02326f1d67b968cbafe35ff957059ce25b8924bf16b2c2c0b9226487bb16c95fc73b7cab7656b4193ee1e104490a9c3df2d7b112be5516a414f9f2428985a41eb8ebb87751ebf35dc7512ebaed543402d5cacdfaeb77cd9533bc417c43e1d7abba68fd590179fcf57b7551d75fbf352a9a8004dcf8ebd7c8ef0e5fde4d6f092677f2ecaaac58e1d10477ad91bf6e8117ad5817ad423936eba24e2ada41b559efe0ed75aba4a90ad95bc164093112f2e5081d1db6484573e687191947b050e9c159a607c8f032a45b32e605197076692703f6d73950515b6dd66f9b02285c4f81cd509e154092d61c05c159220c30ba41c6479494e011eefaeca2768806aa9c1062c547687de382ecd12bc75d539dd7a59b6339967b2c8a513949518281f5a462b9898442e2bc9b548de4f874e3477999009be4938950a7424b1c154749574f8610b539a25ae21b99a42ef6f6a16ac2520a3267305cb910aa81d11b92a7c88425ba13464a7a445c28d92969b2c8efb19491a3140aa5609aa62d869a76ad522aa4aa50c9ec949da76c264b614d48ad7032ab5b53f192f48d634992bebd83453c34464e4825b008e25961548251b08415411fc19074e61895e4385eedf6156f5f295df566573ebf6ab20595e5d0976559966559da58482f50d5ed4c6081e7f876d2f029ef299b5d053150dd5904d6efb1b7a1dc7bef2de6ea025533a50962d6cc4eec3d3ed5991203f63ee0aa078beeb7cd76ce3c68b79482c6968964935a7fd05b6f1faf11579224f71ec791244972cb3849922465a59108aa1c514f6e92a40293ca9ef44d562f6b24b94992244972d46449525909cf7cd66aed054992243945a6c8937b3c835ac32c411a5b7b01ee1d75270ed218a4ca4227861e472b27adb5a830fae2d332636785a5e5c70a2f422129be683162c5d342e5c597dd8cf6f5290b4d8b6987f9bd5ba60947c216342a3c3d6f9c3ce9f174e2f790aa85092ff19e54a7cf6b9335edad9311bc6194f68c5a00951c99e062f8b43361a7c4a20b0c135a34cd3af8fa646388ef72a824f7e6011bb5589665c9d33ccd33cbb22cb71ec95d9aa62f641c69e5169d292344bf755f2f5aeebdb7d2ef516b92246d3c4992244992387e1b0770e3086e1c581b8770e3186e72efbdf7de9ad4fbc8e8a5b5d65a36430292484112098b44129248439257ea209224499224b5d624499224496a529fb933ea271952cc6dcf9df4bb4015b88327d64ce849435b1af49bc40d5d88df5e3a1991533edea847adf58877699ad63862da7b9f53407c555f2f2aae2841848d1e29749e0ca972c78454f00d997b88e086893d728451b65ce1f6d053559928e6075d948c9bfc5d77269fe8cca5bd4fd96c89eec738d6bc975469ada794c478ed79cbb4d65a37f9685a227d8aa88aec6162440d141665703a7dd2f4e4caeb71d45a6badf5388e5a6badb51ec751eb514529d659de4c76e4de7befbdb713270c54779d1f3d97793ff161a8384cf638baf9711c9baa3050dd6eef388ee388f4e3b8f7de3bc718f528c3b64d74249aec48921cc97124a7920447124ecad65eb1f77ef28b3ad32347921c35100c515c6824c1bdb1b0d0487a6190c423552cd8a8c843167460e0243d5d8c2b9b1dd125cd20e1f3b5209104689d7cf61082387c7d8ae3f36d2e99bbf5a4c20eaeb55dafcda65fa7ea58d9f4499a0cab400384c1e48554132929f6584d0dc5ccce7356f7299b7d7d9a61747a4661ea56490e195bba955b1ff40815bb674dd69a336a728f3bfd32b3232e391e3d5959a12755f3532babe878bff38c1268502961126c23a7066eebf95d45172ccb2441ae16a94d361d8c24499230529d59be3061fc7edc7bbb2e22dff4c0cc729de5fd42c68b1b673992bb4ac5f0e9a2670a491ac7711c4717c1b24a8bdd8fa3dbd3774e336090f991dc558e863c8751e5b6ff127cfdf88dfa48b8f7d50badc2a7868d916854a5c60e8e2c9b19e93050dd346ce01403d5ed2bbab2d9914f9f70d4743291614f5811c440755f89318ee3092c7c18a8eebf3224c057a81341df668fb1345b30fcdebe65fb77e9aeb29cf5f06120b324ef08cd71040204089071efbd79bf37e9a39be4488efa041919caf10e9e9666d2655d9522ba2246294c316f1e430c548f5ae87105cd962034e2ecb07998e830e1d9a569aa0206872c9b55a8de9a2a5d8e56c82e49dca273d6e057a825a2dfae6bf0c70c5544862e8fbcae6ce6a30a03d52d9ed84c5755d4e021a9689b3793920b54a36ca933cbec4b262bb7690fbffda4f2fb85139ea9726f1fe24eb177171856434b27acec81ca624ac3e4e689a4f9ebd31024b32b41aed668bed9db35b6c6566d54d244ba49e6142693154c5ae8256fccb872dd792bd9912c94f894cd96a4e56672a2ceef513b97dfe5f5d3e6ffc1f66b39c17cefbd7de7ad048881ea93ba2c7df411d73fd8cabdf7de504c66fcdea326f7de497cbf7ffb2e7defbd97f8305025691faecdb58df61e000d3833d8dce0957181db787efb09fc0db5e4ccef5127e9f987272fc2cf7990d9c64b52ca62a51fc751fc516bad93a47b2fb9c8b2d91003d50d2506de79fb943050dd2fb6e0b8b299912a233f23c0f3c4b7fa428d0d244d489c663f3a8a1f5de046977915aa3f8e23f002d5d747821757c40903d57dd16a4fd9936ef8b9d337e9c30e4bbc9891f5054c1217d8b470a76806276ec498701305378453244bcb9b2b44629ece0ccfaf522d9072520c5251bc231731948eacaae9fa2a7554a5c7b8f78b56929b295d6e0c6963c48e9e22d857a92337ba4ad96697527c88902d1d2ea92315af33c9e5a5e1ab94911c29232c17d4b8b5d65acf6b5d948f8643466f5e7f031e2e3cc132e6088b275c1ebe71b9be46a5664e3d5ed53367de6c3d8ee3388ea3d65b6fbd759535595e5169959c24a24087fc18b50edb1194264431505db580d37586980c4519c72123e30b1dfa21d66043eef628ee4d6aadf528eebdb5d6daa5b59e09ef9843795a6813ba918688436badb50ef25a1cc7711ca34cf0f8717686fc94cb4bf6352a4df1adaf51432de81346092a40a69c30f182c58d187444e040c99cdd8b3c548a80b17344881051c2878be1953a4a3ca2b8e0ac9cb77e9e1121b4af531c2ba95b68ed5b43392255e8335092c6a8d4854c034d6f6a06d31a3d615ac08d719ec4997a5267e6b6f1b307d53373c85af5c4ccefaf534fae84a58719453ac90d9c5d1c9f101d1c393ec014d1a832e3c79b2e654992a56d136496963423deed66edbcb6996cd76433f2b228f544ed172ec049f31b6327ca1ea190198634761dc7d12b981f7ff42dbbb78c1bddc773cc44b31f85bcf951c89d1fb5d65aeb749f58ebdc397bed4f42b6bcd6f9b53eebe7ce1f5910f9e0b696de699d8131586176325e487105a7dd14c1d839f00fb60fd736d250810791144be2bc3004056e6cf3e3101e55ea5cd9dc67a5f9c1fcfa24a4e9731e44b6cec0207fae657341d82f50032e534df4cc39b19403876b8e813cfc887bddc30759361d7ce0471baa1f3ad690a1c1a664c09319741419499b345953b514552d7bf213120a3269b2ec7cd4c159356ffdb43ebba887b7b66e80c94acf9ba9a91f36d2542e2c3889f2a22ae98d8a19ce94e0a53254f1a2c4c44a1c2c0e708009903c7a6850418a4106d858b586b75e31164beca5ecad9875496eb36abcc2cc73adaf359b6d0bf2af307b5cd31857a9e2b2a54e903773d03041a3c55dafb298f0d4c0f9c2b43b13e4e12b149e16befc0a85a78b78dde82210a4609c6accf191a2076e34f3a35192057654508200937c4370b90c99369f5d8647cf670f21c8f6152aebe85f5fa1f0ec112f9bd28d69676b5de6754e318e6af6f0f83ccba26f903714ac936f3f06a68d3879ea9029b2c2110307cc9ab5a6c9340dc6b080e4846715030d4e93897aecb21976c76e937aec217808a7ecc37561eb2261ad9cfb6b1b286fbd859d666e3d3b459979eb1deeede2ac75a0f3c26c4962af213e7788f3f9b38b96b44b4ed1ade77cce1cdf32ce673eab42c60dd16c866f39d724a08446c5100e112439381bd441220db37ec89d4223aa0824e8927493acba963a273a292ee01cb7883f08e1f707a246a8f42bd9ea72d62163680400000000d3160000180c0c08c682791e46614e6b771480106094505c5c3e1347a3419083288a81180832c618638821c818c34cd56d0313920587dba46cbe443d6e6e942f8ece4f97924babbb140da2325554422ad73b8d6b452934d9def0fca1d6609f47c5f69867f4afd4e013824e6b8429e4b4f0be994470ef3baa28e800b788ef7dc33fe5e231df325cd714b163c821050406641fdd0e19168e34ba021e22f54a2a3cd56b02d62a46f0012539b71ac13573861bdd34b72aa0ef7c29280590f624ceaf58c87dace1c596db8300747e1c3429a89a319ecb1c77ff1f55a32ef383395edcb05156e07b5d2a0747f0c51e2e2866d021c62f99d61fc564a24284af0a576652432f70c8e0c4ac82a4feaca9031a96594f6fc98d0b78da49942866f62f055822014a492f6a14a67d589a4e42fbb496caa28f4f53887bf659a804564289a454082c55160e824628c5b0f9b3525d5158014c3e982556c6d84a37782d97679584f4aed951994cd982318c953e4700226f67843e8a9c12098484e2fad0b172d424f309ce57759ef68d057f9a4043389412ad4094edc42c7e35dc823c830235ee926995a29c49fd26981165ba954e6e5d8646cb05ad53a0dcad34c4680786c5a253d299bcfc47822894880c7cf00dd9161bffcb22e5db81aa27e75a578af459707875debd40b0500a00b5acd62e2d0e8ad6d23b4c9182e44733f96149140adcc7115b3eea912b5175a542165ec2586ac922659c19a850f611becc9249e468a7119661497b2e329d4fe91d2288f0670cd70dad23014cd94562a99a2c1038a1293d6d67b7c8327f0857f8f72b3d7a398735f1d493125edc5373f2825a1b920f0144dbe800a78556df181df750a116ecf450939a2a951b0df125fbc2a54979eb7bf977c878f29853ab655727613b2ce8035a380e49d7278b839359116abfd76a41114d834146f53fdf68a9ef9995f4803c10dd6e2e8cc283b89072ae19960d76514cf6744f7583cd865b63473c9c1eacd6449009b8aaad3441978f28dd976005fdd845137ae0d20b815d6d676bb28c2a03228657a54c1b772813a40d6c23304fce240af6f1a6a4d17bcacfab22c7f33e2c4a48480d778782687d4162f13c55e49fdc7030b784abe27084984189f4591e2fc245d303a0062de1607815b8225cc2af74efb26c84e8aa5ea12ebf6eed8a121944f18684e70e349f3173c91313b9f43bba9bc888462e0f3280e241b48dae7e0620c11a761e70f713edf0e2431538a214173c3c7cf70a9c05c3549a780cebe6f32ede243ed8c437c4831b31762af4cbf4353111b1b2dbe639b903741c4c01a9abbfc39e44da0bbd87349f225ab8641082d3189a8682d406de0fd15d3bfd3cf726dd5e703aec4cda6e88dc5e44eccebdb16cdcca843308bdb717fb963710ccde97a50185c462392c16706771185fedb83db879559719d023f4a03368a1e3d74cab1fe54cb4505cc08b1fcbfa0cadcf784166885f6e265a08f98a706d2635f4f90aa898243c27e32dd69ad0d278aebcebd685de2345fb320480681a130f6a5d7c51eb7257e4b8a55c6f278b5f53221b827535e4b6707451018f450ba578706ce94a366978c2511377b28bd81c889b0cc10e2ef758787b39f8f2c7342de3d2c16df76211a1907b62c9140953424c4debb4b17fb7c75a8d5156255792ef44fccec26d3736e07f50553eb134b3b08a85cd4762163459f46346d57e8da4f7736f4003e83ccabc856686877c6f5305e941e59175e6fd57cbac284f08b4bb4dd1b35f5b2f9fca8d3db5018ff53109979ff51444a60984e71b16e315be302d437f55722aafd9aa868c595a46da01b789efced12472f26d4c7da6444eda0e5dd0b2327a2c57ce963164e456049c6b91e54194d280d57c6bee9811194920e4fc140d2f846b9425b84421f312e319ed577719fcadc1c2dbe27855ac6ae9248b77aa11f8d1a0968c7454f6cf6b6fc0dc556a085a269d642e22b1fae3b92ff9e414961ede0e276a4ed2b1159758fb1da5193513b653e648e77f577c5bdd4cbafa1f6d0357ff1645dd6e39dd3f25352be56947ab12717c42af474e3fbebf5082657bde3efc2fa207ae7958d03c3989fd734c64518c919c97394c2e3ef58f1cc4fc3b0738a3c3c6fbe40694fcf567c20891df3e2569f3159cb40812fc3f1b5bcf75e04a169938bd6d83252fc3f4ccedf8f5d45b556edf1e4818ee43c0d6e22d0116d6c9c69b73d28a19183415726d1a20e4fe6a02a33449a9f88b8425b3d05fb2e89031babe90dcda486a1fa81468076a034485248bc3177bbcddffe656f52d229f1424ed4764863c9c10c38851310e9e0067654cf85efe861a75b1ef55812ac7d8e0e2ab60bdcbb9dd82326133d2eebac0dc2a91818838175444976a5d3b8f05a53a3bcb9e7b019b271fe9f3e53a963a892f16ec218df514638b3e9fcdfafb33c320cd76fe6e47b0487768463d7fefe02c91185ea57a33e8f9a596fc299b25f75e253081b3b3cbb2613dbc50ccc01992289c82efc3361b8a63991ef218743471a4a66557b3dd15755daeb4de017cf5a3e9a6532cf586ce2a6a7b27bafb13a2dd6687f14e73db9756f3c4b8f9f8ae72ae7551fe0bbbbf0ee86e427cfa53466748225a3499bfda4139311e55a359c349278d7c33fd4b16c263c2fb0da9b1e216a8c6481a819cc84f0b4beaa64112230b79a26865189b5bca49753f3d409b18b0d2039a82bc7c6a9aaa6c7fedff0caaec98d341b72ace73a054db0a8fe7ff22032877260d26cfa08b6980e4b77739132d04bed222293f92fb9c73821122941736e90d16443d081b335c2042d5ee7528c17ac831f26506374f7456f92171dbe626796cdd61a3106beec4f60dc87d9af94dacdc0bcde96155ed660bf1bb4cabda6dd987af58381a796157c61f83dc58e2f4284e5e915ca3c01ac84aa235339e8e6ae1b82e4b1f7939c8b88446492df852f6278655c3e24d206203f6ab9671385b8d9ba844aae832d06491c235035c93a7c88c55ab52fcf2559a58bb2bdb9156842abfbd0934f6aa1168ea7e094d18c80219fa5bb993fa90864508502465c0acc858045106e9b2ef0f114972adfb0b4efe8f79648f2d11c352d4cc963c9092d113298dede558335f968d24f3ec9f514ac35055f6c52dcda29ecc625357e1d528ecf798bd912a0de986f6525845ac650344fe519084548a34a0492e5f2fd3c8130931331ae6604d3869fbc954dad4ec54ddb267b35008b24986084555f2c1678c97a668e167a3cd7273341270395eaef1feeb975ae4d44ca2d6ca230c84c80b2b5392bc1c19859928d9570bd7e092c784ed0cf6d2bc09711aec4d0e476d55bded35418f3ff43cf56ab07d2a68d3d29f516cf9c3215851244a62055a05b72e0332ff0a735a6fd3597760d6aa7a48400a5e0e54d47dceaee60fc4def27b33250344b67108336874215d8ccb6869a3e6d9cb41407a5408041b2153094921166d1c7198ae55f698cafb5bb1be8463c87bf0623e032f530ecf84e65019f8e08b7fa4ce3c2aed2ec260c007df7254e30fbde9be1f0798410db947fb6f124c8211c411c76212b814bfa555528a37247ad0c398f4df2afa9765f0dfb73146aaeb13bf03253964ca5026d02969b6225e0406f504714e7013f0d3cc9eadb3c3ee9f1ea04866efba18957538521f5ad25a73cf4916a2426d82f8f17131fed4a3bb25f79cf1bd6083111d05c895e4b54254088edc4132c9ca497de77b1e11361e259d9f8d1eec441e2c256eeb6cb74e6979b0820a5c90c0485724224f330c50d531705115b3de0795e30cb6c09b92c308bbfaf0f3478f0b00a38e40ecff94901d001617688a73df1ddbfacbbbb86481245151ef844747c9f2aeaea61205a5423a58f60459f50c6c1cfd490ffb0d0f23cf5219f05309db401a7e8f151a54e922c4e71dcd0cf5a8fd3b3812f16f5e2c30d0a11d4652698747cb55c07860da02165d77e225e07c65022b32eb8e0dc14d92c1854194eb6bc3a079af25888dc364493bd0813324838b83da1b409639687b5a7fb86b84e1c66eb20f52990a97ca98ebd7839ece4149e7bf554c493b03d82412b44c3969fcc1a665527434c009bff0e07d170cdf4ce8953c0f8be24d05e611603d42aae2975fa1b899764545c6214b102a2a7a33c19929a68e86413599f4e0dfcb662098b1040f42387c377037c494fff88972a110c2c2cb03bbe34003e2ef9fe7d004163ac6ec196f8dd2ec81fa2664b8ee29455fabbf2fcb916d57cc89b3a7bbad212a17cb29358bf6cdd2716a198ee89325be18d72a624876518163d8dec05bc98950e9c64df68a1cdc03792f53866aa04c9b14bb592344118b1b3eea30461b7e121c78d797553420fa080478a8cacbaff7c95937c741af822be11730445572056e13ae8f5b1d232f2c5ef2ae92844546263dc3268eca169437eea6e75c8e7d32105341e05d0ccabd0ccd37edf5aa498c3c34c842e5f5c42abd0a6f10e5bb03cc040af6d1daddf34817d71dce86b98d2ec6a29c58a5b5c8e5c585a4f6ccf0c9a16d02b1467693aba605291988e511e25026feca10ac227ccb31da5cc67f8947650320c7886477ceb53ced3accbe2d5f40de3ef32eb5690251821c3893ef210f34f125cb1cb8bf2a86a3e173869f93f612a638ea088a87d9d19575f4d60f45e171ff21b5299e03bf45946c912ba4003fb050d07b4d8c82cec7608642b802efb34e2b340718eb1cc5be8b6f419693d5e0d455805a6560549b45af3e0787c9d111268db25d1534a6e1bc2f39b2cce090fa43757f2efe227663d600db6e08d887bdf360e5ce5ec40cf6456c2d7388bc6dc39498ac3468c456b53fa7dd181ca03d1e03b4d441892622a4c5a290ed66cc96be459b7ed624e13f947b298df7eb6e2e1374b80cd0979bbe882c6c83cb3097a1658411e6dced13632e61016d0328955948a92c3081460c5c824e633f8e11d7d359240abe7db4ca13645de2da6174dde5e88431cca3b8158ab728df1a906cf8cdf5f1c1be378b01f12aebc29b0bcf1708c10d272fae9c6212464d71931585be1a54ef2988c12959174fae0b918e2ec99e984bf52f02da168663f9e99c9569af330ac431cff91084340165e79eb2010d45b455a9ef20710834136bc602e57621a29a1be1c3a7f24d0d3edc4bf01cc8aa2e4d707d97a55abc4c3381f163550d69e6e22d656d53873533756f06dc42d2175178a5e53f6e55eebca111e5de3e7b6e9a0b06d1acbd4449cc08d1436c62b2ca4fe8e54215bcf512e11bb38467b450c578a046d29770ee642895992b925fe92f4b296fd4cd24ae8cb18c610b0cbd163ed687c498d9a14b6ad56a98e4f441adf102535fc689a607d603568aa5c29e6b2b65a2982d63a812740358c40e24f2e9281a968f0f85eec1c4604e67907adb03dccea323fc04e26646102b19e99aa53c121a2fa5f706b8fee0cb597142964b3878511e16a63f7a77b97fa2b9e2441a3b0ac220c44a0cf49a32546db4fbcf1fe60e8d320ebb1fb577d18e33faf59da7a6921a279ffef8f40ea7138fe2d91b0fa5cbb53f68426a69a70370aab09e6f27c604316b47be3dec90de4d4342327d269d07f26dbd5548508a2dda3c7cb0d3689e96985b8ba8967d2080580d32d712500c72cd629be6d8f1dda741c3a1b733fdfa8b4a36e54af65955e2b9c756e69f6746435b7d86ff1db716d55425f7bf1317bee4068d7b8c5d20bf0d846c091283a162afc4b4e7dbe4c293c8f0589532a5834a26ad062365436e4b31e3df6da73e518a3628a66545a9d8ed592cab4c854413f29b44a96ec095d928a39aa4b6cc9c8067eb3c339aa0d03cb5e85f31b8bebf2e51b4b23308992eb9975cc193e60154a6675290f24c1bf771f0e77dcdd7a4b23edfdf041451d3c959d241d5c6c1da61c2eba5e3219e494c3b79d800c14e8d619273c5668000d74464d0c538147f4f96c35a329561900843926013a35bd0b1aabcd2fceae75d78df9665685dd00308d4f52a1ee7ccd04151e318be22a491a9e40e7cdadbb5734a51580c74aff4fcfb389209d72aebb8e5249874c34a1066592b9d1aa28276c046e948e8f4697d03b5efc8359a31ea2bb3c13e5a1ae218e7f123d8bb58f07ee049c5f542e023a02a2006cc5dfa583c67b248f166a61ce464ad529458dbf9627414f61ea623bbe944b3ce42058251891c34de1c1f935841f89c94f0d18e55514573b58585894c107e30ca8fcfc2db96b658a73865fd8a8100b316d6957d2527fa5eb31fa4de84440aa7d123d33655118b82e879208e21e65630e42d05b47907313878aa760faca617ad626ab6dbae3f924a5a84b6224daea37af488edaa50301702880dcba2b8516c90c7d3e20cb31de10fa0d9f01978c6c9f7a281cb1668cb9a3aece29c0083d114a5f83b1a408723b74d348d42eed54718d22a6a0a82753cf7dd54535d6e722e9cd9835ee91844d49835d60285d260e82e8e5f7d49cfd0cb9872bd2dd5280e3eadd1d9e4a501734c7d0b8d12f4a7a7caf767b36378358822a6394d42f082c4401875acbbb34d6cb49f6640b42c0c9b7b175f21c9205838baf584d8fc0e2ddb6c54fe1caee7da7c21c4d8828890ed36abaef32ffa9976810fd3b3e6faf398a1de4048a8cee480db4862cf1b4411bd2098a7559135c8ece659092a62fc2d4ca86615603c29f78c31ecbf672c00930716ce1a914f23806c00130a3532f7e7aa20882db19a93eeb501ef425e6e11aaec73262076bc50a693499f6422b8faeaf1451724051847d98684c3fd78fc11d761dc3ba8213d74a34b9a74c7b916c25e47b7f993a6cb784370f695abeb314a3f20018e72288ffff86abc862a1367bc37b754d467f4ae939538ddf9089d1814efe494a8aa4f3846d626c9fe2081195540efde2de1c260ab891ba07569d34bf557ea2fb0d91349889156cfa7bb014a9ea98c3be1e1933cbae7cc348c14814a40002b582d7a1ffc4fc727d86a8c75f7762ccaba2d621240a55128eb0e6ed816e02cc9906fefc9367db8b9df0c93d7b907e448862da33d4bc15b5083895d8d265b4fa8de7a64cdb6268aaa9614363e9b5bfbb79370cb295bb3e5e6930f95993a01a2e64f47336e4986650ba00d71a407a959c8766f5a13cc96b82ec9de19c66942c05ac03bb770c0f57329696571702dbd2d5c4572a4e04ad82ca7a06e2b52c7b127d0f251a32a029790ae6e339e97c40d32cc95b537fbed98afa94e10b552433b72c133d5498f98a08844e27187fb1a56355c14fb849e35f8bf2d67f69d2cae43d6009c8d4911797d00ed923c93fbb1c834cef894ed66e8d8faa9c475c78dd9394f308889718e393f3a1367a077e6997f41e561ac76921dcdcbc6b9afb786df07ee40bb9d2fe301330430697a7ce314d9030cdf3951bc18e70a117a35dff0ffedd5f51e76fb016671df0ed1629624cb4c5256e70c550a96c705ebbd4f59f1a6eded99c27f9da76e7b54a279a25a0824ecfcd00e0eb4ac5e792ae8186761c8f33ae265fd45e559f290100b7a5218684e912347d40b89f5395c4c85865466ac9bd336b6fb564bb94d40e11407d1e20fb98f545feef6f9211636689a7927632433efdb0673134dce10ec3d7594024d6e3aebf2be4c2e8e560ac187f54a3e92ba6dcb5c12132bf22d105927738e308be02600c3bca9016e12e87d05fe1d38a1c64ec4c43f822747a268b30a2da225be56d624135227c197e6d62e0edcbc48b60fdb5d719624d80a69ad1e8b7294c101edd4e8df8a80a27e1ab7e1b4a3a4b7579c3e8c12767139835e5ecb27b72621699e90af5241da10fed9a5ec333832449b1b45f51cd55e5cdc59b06abfd68245cce26a004c52952ed659493324fb44ab9a7128bb31ed8f04ae12738b030b676468c883badfdad1d380b3cf1abd5eccd03af61ea6b2b3237c83ad441c2c9a314dea8ce4ab8ae55e6304e799a0d9d733739fe1b25b2f7e302cd4309f8dc8c0aa7c309fef7552754d7e9818b07a5c6e963bb93dcf8508a333c1558332c2d6e9bd5e6aeb68b3c31ba57881da743ffcaa016c91dfe119b8ee442b751677789a5d5c10dcd5d3429756dae2a0fe402b20a3e797ef3e94100d0feaa297ff5d48528e87e51c044c4944773b07f44e90ef6dd28b98a16b6a3837a8a9b6d9a4d0f91b4fa347844eac53dd3bbf67e1451f0fc931e186bb77808e117b1fd746544267c0457ff74517fc626d51821f85f5c03d4c4c128e34cde91e78d5d1150566c8ddfa0710ce19b1d141bc7914ac4a610f5c5bd0b5419372e276c5c312a1793368e2a16bd64f95a0d5925249b480f71cceddd1aef05615a9e5254ed886222647af1652aa850a218143a0727e03c9e93d4bff22a10aca77690cb4eb77301a50444a58950a3ff19a2f70e7db140a120f426bf938c06d1107aa33522f4d32914cf6a5c72a4d51790bc2150f66c80a31fa63286ed13d404f5cb0b9e94bfc58987f3eb1ba535a2a3bc5a4e54d4fe30d6aa9fb429518c1619cab9fe9fe776d6b5403736522fd641708a4d77cebb14197fcdf27e35da487cc7d25b106401fbbf04199328614af726c2b447c367dd89bb0ab22f9b7a98e7875a6702a0678166291c59e4a6f02f5b60ff25f458371c14c673a0874e8fff49b30f8f2aa7b4f0b742acfe28eb8cdf0aafb12f4ff3da8df577bc410f59aff41d068b407430cad8a18e7ded31e463c7ed03e14d5dec20363518a3b1b80284137b95a3372cedf566aabab8089962442b4f426ea373fcc9f88adc45127deb497b379985a6823813c44e0dbea33120a2608fe8fd653286885541a38212c441e37cc88a0902e599318dbd55bee81d15354a00195578f6eab3c831d2d50cbb506c41da0324da0fb4d3fec7ace37da4e6665ae9002602619eced370148409dfeb9612fcaed134a7ad6e2e46d718b4d3c17a5c24b7ef9a16f5c5903d5797ae8efa40075692676f73981a7f1f8bfac47f0d35319b0030cc4d8a35dbb11040d0d81398afe0bd467d880532fe9cfbc24bf379d0c850ec5cced1db299bce6410459436cd22e9a4dcb944877d9602d0900e07347e031a3948ba0e444eadf7d6cf882f1456001b9e44546c885d5cc0ba5bd5003a96426b8a7f994113e9e24894172520313af52c6229124c9149a45f7a7335d266f73e6064c46226caef5a78bdc1cf03cc2b0fd8a8860a105437ef38ecade9195a20cbd38e7a1bbfd5e7e52b2dad28d69e9fe021e44bbaf92e1dd604761b7f2d62d8226938989378bde13171e248d9e71647498ea2760ba120d3c5f13a7cfbe9c052b35ede1b9ad44f08fc21e30ba56768c8e3aff977ed9116c8a125db80df2a9663c08b23d001a40c2465e7408998403c9e939a0754562d88b97cec988d253aff4e3aeaea89ff11db129b1b1f369f6ebf6ff2ad9a3b4477d4c221822af3627e1f4e1d004bb5656b31efc191a9daf6aa1384b9700acd4c43e5cc755b454102f62edbc4e6254593de182a5fbb00d2215b79b5c31437c4c2bbd75da0da7a9468007b7f7a06a2f63158d6d08a8301c378d56a582c307a83600a031e5527b525d981edeffce3112d4ff34a9d5e028ecdd2d56a6189368df16cb764837387df2de89c81b63119e4604a156013efe6bb16588508bb6688a624abdcea104fc5ddbe908b505132823b4d917b48806e292312f5dc2ec644beb8300bbe37285eb973d577bfea88aaa4079e5d146b9da4eedce7b17455f79f0314cde174a8bbffd81b46b060f7ca5dc91a0537cdeb73dd457cf0cdc87577e860aa04827796b3539a382589248d038bb979001c590e72d453bad80bc4dbcc5a1d51906c055a5b6eb6a05514fc91ff034dc0159732714d26cfc26262ea9b19ac1cdc1b660ca3cb264c2b01fb122f304d62858a71aa62748bf6abc27e5b99be2fc53001ea0c432bc5c05ebf4dd167e351e6b86080c40b3ca55b906b7d65a8683abc1da0449c5501b81006989deba3c7b0f8306cd70fc3439c61d6c867cb1918042692eef342e827593c8887db6301c449dfc155262c0334bd4d50f53d3796bf29d096d3b56e83708d7e0d3b5a42e613a7126c5e32194343d75d6cccf1347398ab82d2228d8d307dd14675f32310726ff0c5a87aac85b81a43b87de0a5376023cd4b62a1b350bd3f69136a72ee9819258f78e0144e2b7e4e51b80b8b3904ee9ddecb7d7df0f2bc0c0c47d17d30265dbc4752c42fc3862c64f8b40f1faaddcd146f9384f29e78190803ba4b2ef9dbd7468f2b2c126fecb66776206d2a9ebe5f211a076dadd16800ece87976fbf25e9629ce2e1ac67048da99a97e111fdae676beee3ea5545cc5c97c714f057b7467934cb9753a6ef18b87bc4cb80967725f00bf2cb9aff23f9988a8c3a2c2aad2a8933bb049bb7af774300dc246003775bd5f6fdf76d506a12cbc1e43c688935e54fd8fe33d7707688505ca06650c68a2e930271b1c3b06480c5da07f99f4c6296d0fee46e33c73425c6154b4518af5cbc1bfa3989e0458751b597bc2b8de6b54dcc2613003f2922ead1c6a8ea72aaf169985a37ea6707df1083f784b96a73d28fd75aae32f0845472cc941b2815d435c2c869d95b2090a92c08ba41fd30eab8b7750c01b8a9e1393412338985b0304cd7a8c0360984294109b49e4e4ac67143b8cbc6d68a014e746f34e2d6d1d4d7b5c6cf7ecdc5d71625790249cba58e409d1be013bb5cae5b7860133a6c33f73ce7ea95e8f5a6de207581a3095826c29eefd0928285f006b0e3060a0185028438c11a3f238bb6d7ed54e5b701c0581d811d79a223db5d5441b9a4402972ea821292c6b25136f5d6110fd53f58daf37b9346496aa4f74d22ba8724510aceb84105b6b8a4b43e6fe6423510489d809cd97652502c1a921232c9fe18ee4f92fe616071d1fbb1939304655715ace6c5076b4b1565c0ec94a53b7b4ea25c0de92272b459c2df6b57e692ed95f13074d71061772e1675dd8c5894d485931050e0aa5a17b955e27c9eff3b29cd8db3fa5f3866c5c3c22923e29c9f1f8bbc1cb8a5a5e22ef1258060f595995176adb82dde085c36c9a215d28e56ce88398cd6594c79fcecd16b8f53dadbe4e12e8e6e4a3d36783b49f8c5e09c399febdfdd4126340ffa3dceaf741e0e5d0d5d2b2d4800fe842e40340c05c5ce4327994609b2233e488747167f6338e38203e07cf4cdf96c077d1223f9b26fc7cce8ea535d6b6b71bcefcdff69aaf199919c751b14e26466c7cc1e82fc6fa71504a834e09b4058cafd706d9664d60f83d2371f59e20181d04e506db90ce2fe439af02d23f5f39f0ff04d7ada38f5948b1b2b3d9d2c1b692debdda4eab999ea4606aebf6b91f71f488638ea8771a2b1bb017fe4b19dad1e5935cc13292d434f1e93370e54a2ae976c2d15993d697439bcbcde8ee8bd2b4e5555bf005de4e1feb19127da1a0a9703dcf48d842ec68ef04f6c43d93ef895915021f3531aa30895824bf7c0481aefc72c14353a634faa6c8413086cd6fe09b0ce021a64c11b84822e76ef1fb422418ef1162202c2ca6af2b8bdb38920f88462f6145cba725d685c74d144a7fc2cd02bdb24d6d60f00a5e0e9d2b044a10603e74c3ba0ddbdfc6130465f9df2d34f77559f6327c83df66c0fcd42dfdb46a3e006adaa498200873f66cad5fa31b3007c5c76727172f4deaa18233926384533dccccc423a6aaa70189e2842ac8b64950998476b2694844e6b174570929ca1a5c365a1550cf1ed157738fafc21af92e3f3a03a929e08a5012fb370e2f404655787bed7ea30e2380e8f1d0b71cc19913ba5e7d0f0453a72afb0bde32b5cfea6469675dfb77bf9faeb40cbe3f2e28b47b89ddf21e8c716816ca46be7677c013961f8651aee3d72ce113bb5160e3e5acbe3799ff459058689d47fb05e12c682dd7f5366a808fc4f65fefea8e3f2ff3eb22091e04348b05c309f20aaeb7fcb59f19b0d87527f150fca393aa6c3d305de369393d0273fa706ef3189908958316a12e491e2b5041ad7d7c32db397e6c3df43b484bfb6bb051ff4bb6d7121d645f09ba184e92b4d26918c1016c10ed04e27eca526f4ec8135bec4a9820490007f8d9f369c6a3420f725a0029ed477e435f96625db192a6b91703d5d6138a3aa02f838d2b37a60ce072fe7a934fb547d6dcaf57ddf4f3999a860f6d848807857605ff299b678f88f97003a7131fc0d01ee15cffcfe53e9ce25bcc221406ebaf580320fe763113cfe9939e0fb1e086a9b597e3460ecff187c628d0af6ca1034c24e036224709a64a839db5f5396c0a31fa34823b06c05292df4f8f0998f9ed9199ee8c5b0117fb04c92afb5f15b2fdbc1845e55147d6dac1f361c0e93496231a573fb59f547652410a8a24197bd440f20812726a28af52c04118c8044dbd16a31424a07cd9a961076ae18fc104458c167a6e2c565204d31867e3a235e790eb6e8e21a9c59a1816f8e46cafa05a649da2350b65501f49db16f060823bf2d9d9964301e7b738199d26fe490015c498803074ce6999c522504a87fe044a7402849c05f7ab6d3009dba74319b5a8b7781992465788ea704b80ab17d1be5b3fcce1d0358397b7c29a9d04c2cdc07421867036cd7bea2be3d657bc6e255cb59b950b5c45102f11e666b40eeec10d5b8995ffa8186b9e0196cf2c60b45a3e309c822b26ea9a7302789427035b27345863486eaefe6ef9c4e924d3a1acb9bd4483d1287a683e322eec208543dfa1409fbdbc8774a0d8460b6ed7f878871b101a81ccb86014ed74207c38381148956ab280b4c8800345e508bbe5766850d8ccd8fac25043b6f160b32ba9864658087bb5ebe91633fbc1a24be926d55468279ce5b8f61909f4d41c94c662ebabeecc3397918d5c499e96abbb4274e060a850e565a60b7d4a5d8b3c9fd1c7d3297f6fd66b395ba5af14d08ff3b59123f6b32273f3d793266ff48dfa61d946e9eac279833ece966f7fe56b37649d1e831319413121722009b808c943f3670c8220cc3d3bc0ffaed0c0f695c2fef37e324e71a84eec7c85ad534cfc2d8351e18ef05e62c147c907e3dbae24b5472391d67ed74e072a5d49137d29ce2c119f72e699a7b9abd5d8467f2d7f728a79f14d383daf52ed3df04eee1ffcf147b1bbf000c664cc34ed6051a4f516c4610c3dbca4b16d1abee89cc3df119d462b3cabacc06bae403bd87a762e54760c354c566d5cbb9f7f96c9ef0df4a1a6c3b2222df7580a274987e19c7c3beac34cb78f0f74d38519527359185fdfbb404ffda9ae73e5dab54770bb98ddaead457dc915d42c63bbef8846e012b94073c677a0c77fe82a421fd6590930da6fd4894608a9ba1c069f9ca8d5116ad1a2d5c43245492009deb4b58288ae8a6b02399b603342df2f63a6d800338b0ff1ae08d3dfbc1d0ce27c132a917787d4e1e1ea3c0cc176a19822448f14428f0dba16b90ee119caa6fb49b4db1272158bc3b61b6f7ad0851e5cec834d873b4793506c978f14a9e23134781df27ee29dc4dd8e500e903065a6a464cf62c318446c11418c369d1bfed76a9e222958c2f0aec919cf3859bafbd9774ac5e4041445b78ed78b9bfbcc890f111fe16d64838ed8ed26a5f48f15848f14191db27a14fcf7c5ba1e0b7ce3b0eef97623517adc8c7060e3e5349ef5fd8f01c9b67f08f047f2f6c65df1945a3897963df7b913d4e2e7d7356b80bd91daa99916d108f8f650cd930600ebba836fea1948d94173e149cc0b785d60991d0e87bfb963f62db1be13a1dc4bf644c6cfc54ce0972e1171ba5704ca59146250c97785ddce0b558daa6d183ed8c9495c5d04494abe49a25b75ad46c103fc2353f1262c6d77dd60e8fcbee962c50adb6f89906c04b030ba35ada49daa2cd1cdd5cd21c61274bf2df4f36867cd11d60336009e6751dfb48ad50861df01cb320654bf8139f6c9e39c009381ef1adc4bc5b81682da2b8191d10739d4d5484f1defbb88f78ce7f7b46f62e54fbd9a3dbd3d0192c54a31eb8fd17696ca09800f18a614e0537d93eaa0c7a53933a073090751621e43a1ca122c94b2f5847be71a4f9941be93ad3835232d641c856f72e3dca72c1d51602910f4467f75adc57a31dc9004cca3fcda21a2af2bf5349b16ee3806ab037f0465a11d004f6c99e1cddc95db5f7ba6b7f3d6e4aa4740708e00e0d00382ed14e4f51f5cebb212c23ce201f2173c9f8b031d5db31b7a1cd708c43e01bd92511fd11d034ffcd513744e1ffbb377942775819fc030959198b57a5d7fee16f0274f7e5c9893ab569072a9c18622c7f2c2acf60633b8c4a84570f91e7286f3bf5fda1f9b1065b80344dbede8d5a24d11d1544a07f3650c7c18f131942af934c53350491e6f26ce8737ec016ef953fefcbebfebc3a556cf843b876140e146565084ae878befbe472e8f8067175f51b5efd597efa603432d4c6e8e29d38230ffbc40926c8a2458047671e2267ed0bc89ddd7a63da1229add817a64acd96ff64990f02d68d5354e446b51271bbabd2b254e855fdb6a9c0c8635692871c47f5178c7befbd154347c7690d678869401a6c3cfc483f28b3c81114d8934de87715dc539266c6807ec7f63dde32d424abfa2f9ee82f851287244def86a4766e872f27dedd418e9aa834cd53e586e85b7c9a7a3e16ae8878ccdc64849623c4fde6776a3824171267c4e67bd7005756ca1f2845989fafcdab757cf7414e38914a40fdc6aa0c244dd33c4724fc3aa28f865f2e0fc2a048bfc94790adccefa21e6a419d601b10089f0f494a72148a5790210c8f06d1fee7a95ce801c09708a26baeff11bfc45c26b51f0254d76fe20cc996b5da2cd4f4e32157a3d47db16d9ac714a0d209737ef52585fbdb0662b1a4b4a63282fbd8f3fdba4148f2fe5ebdb16e62f1e878425b420c3e03ade76e2ce9695824d78ee5630c164f7db4d304b778586aa33b689422f5b1c41f7a5cee47c385b3cf3e58911d8ad505fc524a433899073a0d4419a4604372a3dd7098d197c3c09ac197527b8301e2bc4fb8548b5cde97cc962176232d94f69e36b9217b995ea133fa0f67c8979e96a7440b3748b251f86357f24ccfe3db33e1c9e2b0276e01d3476202189c073af616b9a3a347bbcc0f1c6f953f04ec687e31fad7086eea64bf865a1c4ffdf1de51a197f8a74bddfaf8bd3f7a53d63976ee180390d6ba48dfaa31f36529b2653378a4922b7413fdd23f98c76c4315088fd04a363157cafc29502dec3de81103aabae9f260dd8c313699c7633f853a84d35452c20d8fd21a9ab6143c562408c070c027c1c38fcd685f96bc4cb30e56a905da90a3840790371dbd63827944f6cc78fee0ce5aebbc66a2a73c215dac06ad60733abcf8e6f088e977b47f23d0599a6eec263b5b407df5d5abd341061ee6f305bc85ee90af1dbe202d5fc11e77dfef01a4129bd0e17421d76737fad875266d7c89df0b2ebcb4f3d66cd834368a7cc7602b32726e321623288bcfd35ccd432c2dfb1d49b03bbc90084ab167a6c5e2b8c779b8230acd10125d658dba15366746a2118dbfddaceb028322037f34113d7844e683f57a8e985d2f2bc871b86fd6b614b4e114eff02b981243deb0ffaf38be98cf1ebe0501e0af04f503d0f52a8e94b52fb062eb5161d058e450c144cd860871fc5962a35d07cdb6962e63f9e0782166abc095da0d5b2c1918b026c1c7bfd9a285bd31b319b510a6acd83ae0993bf05434dbda2225484e1cea8345ad25d79ac9e2bc1f05317c3ecef40bba840a926f5f05588c0ed762b508e06815b2f87aa1783c8271253192a932120a8ba5f29ac4a99775a6fc520e918ee6662ec0b8c36f0ad35d3b58257a25efc215203c9ebdc6a8200838d784d4b3b77bd65968605399b791227546662137e00b421afea6558e5e4e6ff081436c3f81861c8612f02b097f96bb4301d4d9794519fa7be48d77dad560684ae74923c8f418f319590afc59f226b420ede6f8e9fa066786d333bb93768c7ad8f640ddf2469bbd469efaf896ff3e0cb7d83946ff68928c6afec60096b141bdd747e29d0c16739d56942fcfcf5e9ac35d39e24a40fa39273e38b4318c8a5fd000ad5d8268395029c23865d5089ff1500e6b7fec6110c7777c8c035cb81b0c683ecb6fde3152ec51645a933f6058d1b21f187297ab9556ac7458ef18b16419d1093c060ee5d012dc43b42329bffc8fd8d311452dd90c1608cd772277c9672d13e4c8ed2840130812132763e3a9cb22da41839de0a1c6bd191e4e5d10e3d7ea57b2951f32ba89562574807e17cc63cc043acf6ca5b9cadc40593dc348592219b9506fb0921cf2c275ad6d4ac28ca5ced3070fb921ec232710b0ab24dbc6ec599c44880762999fa6c0b231465edb898dd302029604c637a43b0450074ae61f1596446b463c913500f651d1ef9d42a7837a8483962c526b0094333642780c0932272a4f0dca5c4a3ca71d0f56b344d19ff52f48bc8b36a2c4b6c5db96595a68ebfa8b1b09adb1a5782ec28d3b348c2a1ba22cfb5bc9ab772485f5a9e6c5fc14d7f9e0b953689731124a6ad48799339e2cabb95708d758b8a036ab4a339fa351b940acbe6d7a111f826d9ee087ba0a953f38ca08593ad75562a043a4b8a2381c1e68dea8a2a6f312122ca53e916c8c9c3cd1ba054b824443f83224a0d554f977e32e61940f3607eb0f22b6bd3dbbcf2eb007110a055800deb57ca9440f2336a548d7b1557fb89e0fb10389e77c1802163c0071a024eefa22b95e1618f00eaf08d1d3fcacd28e9fc1f6843a65ee9901f4fd84fc3ebf9ea3a6da50a5bbdfaa65e7349d61879fee165fd521cb5aea671624b2cc2dc034f9c2671a8bcce5eb544368fe3f77a06ebd636d8d0a24e788a67ff9d6d93af066a5da956e07c97b607ccf2eec3617d0408a5765450c8f5828479d25eafc396a26f15599c7b109e47caa4afd9ab1e4f43a0d9c744dc2e60796b9b7ca3d1709b95e1d693678f374d448af88488fa4ee0fd8aaae5f44a4ed6a62f408580f9807fe22dbcd51373ba82e525a5f107b2f94aa6d923dde28ea54b814f8a48015402e354f9561cf2307b137dc8b88f42aedd720db7297814e726644e82c2d777a61efeef784d402475074c250c49648513f3e7108d27004432434786555e8050007dd539423508b59ed5f16a71789c673d0889a53b97f941f611a1e8f38372c566ff05c216efa73fe1169a37ed39157788618068c89031b49b2b1fa7d86f301e2fd53508d6eec3f31bee99b239768a5ebe8ca8b3970acbd50a2db97324351d237af1c44cfe585cc3132a423a0cf5e94d618ec458f4b231a369321686a0f22bfd8bd80a2da4acca863c1fb4a9cf06373cab37102a5a9707bde86df558e60741d742331fb73fbff036a11430b3591ee4ce6b59f2a5b2cb0c358d9687a93d9ce37292e474e7169900da65c6385deba2a2844cde208eff017e60078024356b6c31e4cd86badfcbd6f8acfd6ae2fd6a1e0440aae761919c64b832d71191ebbc31647fa0f780044cd3a51f1de83ceb0a60f633d342d142c3365aa05401a60c7ccbab65a7bfd6edaef60898aaae4b61c7734f946e1737c7ba77d2f6ae1b9a579f4f5b5929650044605a998625d0bfbcace05a1893b75f3aac879d65f50021233eb0eacc01b7f5cc2034e50f080fa80a3bf23513136e884b04969566c4626821a8d1378b7d1146e10e1f417e5fe75cebc35c561de1592a66497d9d81b6439cdd37f8a508ac1d1fcd6f199b5184d2dff6ad8e41f4c2d25b17750140e95696d5215d1c57cc8f686222298512eac15fa69ac1901692cff2692a40940ee52d5f8ffcc9b4d37ac68cd2e5ab8a84ca2cab453a655d05f4c66d764e5f90b5d6792545f154e664d35ecac89d82fd9ffb33fb4f50304523fb155bd8ebd9ca7150561aec59685885031319d18b551445baaed1cfad7d0967187922dffbededc37e9fe1cce66615ecc41b84ea93f4e1056460c77b4a04f1b3c4296dd76af425cf50ad8fec019f050f4f16529a77e4e2700930afe3a797fb9a786e778feef17cff8f49b9300936ba21b55f0b7cc39dfdc55467021f31ff4c00694d1d29f4942d1f3c261f0cc50ad7b109a690176a4eb2def7aae404466631e228af6f929fd6031fc331bdf15da70b1d91cd52bc5c56a71a9f7ccb26dae799da2d702651548478bfb5158c963b134d953d7d6a76627a70001b6392ba88a5a49ca0c29d224a32f05a52486f24c3cbc5df7f34126daf5c27ce0708f89f2baecbe7a0b58938de0515cf4deaebfb53fde41e5a1cebeece430a7c3c272728e1a91334c4d0e4d0cf4d617aa81305bfeb210a5d159185e8c6f79e8b30c76d7a54a743b7c5dccafd4f8f9516bde67f4f3bd0f818b21f447f929fffebd72cabb1dd30bf55a839891109d779fc80d20995cda5e528134e3aaee36d39d28cd28c8155f746f25f557b3c17f4defde4d3968f5d8ef4d1ef1eb7c5ed5fb34cd82156447528014f88148113061c9a310b7f14683bc3ac159ebce493219b7dcca1a6b001739cef1f5b78ecce8f201ffec7737a0dedeee1d5aadc4101ff75d033a696902d9b022c97d08840b82aa05c2038a6cb6110168ee540aaac9c5fb52463f3306ee373ce0e0930452d1bd86c4a7a783297ab28e8fef2c476a4ee3d4ddb8da6bb767eb2a0667401abbbf91d4c1cecc0c295c53431b40b75ae8d47fe6024c99c4a3c9ecefd51018875f313e019f74d7bb4b7d8d7218da2a33119c73a2ecd407e77dd3fc289e3a1423f649c0e682ca0fafe19670de0878bf87d189714b4e6572fb3805943541a67a0fdf383cc0df5aef434b13eff103cd3b3547cdf5e2b3738bdc43fcfa29564c31e5b9885c37c0c5d7c85682f33a84511f264dcb6b57ae47b256e32a72cf10a48d99d5f836a7b81973c29ac6e70a77968bac0015c0615fad59ccc4e8ceb739cc401285b84b7c5c63c7106f1d9c6468b59469085e43345b1183e17858c170bb21acc771e23f519c81df7175a69cb8ffdf1c69c1fd32c29d893ecf015d8d9a7f5941f675e6941b699a6f46e4fbdd6d53803a2d2f7ca6ca2167227127054975ebb4aa92086b5d4ca789cb1101065eb3747b3757edac6f94e6879535f7b0c45535b132cf5814c730ecb0acb3e5c18ac560d212bd6f32e7cd00009d395745c09dbcb5cbda656de9c366041ad82b894dc61a688d8c7ff3d2d310e16acaa439745369e4c1b23889f54f600701cf07d4aaa7e8a612a2dfb920c5a4e05ced114639323741480e4393f39493936b9f9981509aa524330cf475a9173e54a60e496f7705c589ff5f5be8bd7ee6ac658b42fb9173f0fe58f2735b7d82611b22b234fe7356ae5bd5e764b304be2c4de4d3e05596a2ea739d3de0b4dfa34628fcf8fa1a4ddf4355d9605641c2d0113787e8c34e260409e11334810ea97fe07a32fc31a9dc6633e47030fafcc036796c33dac25cad6e0fd7bece2aa374cd7b23064590d67ab4dd309641c2e9bc359bc35fda7b900865f825ac9d0e359e9151580528d67aeddbe3402f8815974fa9b7c98db3a94d09e1940732b28aaa107f2d660e3c21ae989e78745d04be367c0b3160a5cf3452bf931f8e7ba8a4d60f9c6ea517dad4f69016f6124cb24cc6879a1b3310798b7e9439ccbd320531bdc25fcf04b14d696632020e204321211c206fc39cb5390d4915a85e31c0293268040b50364c52f538c859820a993261df3093ba08859a146e4f8a12b920d0b2443c3ec40bfe890fbe8583d6ef6106153b4fcc76c1dc48b63304d298909756c27394b20c3ec13650404f1658d1b51c604604de0681431e7be27a5a670f7c400d475dc8ed9b16f7e0491bba11367b700e3c2592bd46785f3640d839d439572199662b49616afe6362df0861db7e921cda483db1dec271149f0a0b283a8e703c53cc8340d90301bbb9dfa599b9d99469cd310eb1a3f0e9aa4a9019fcd6e05dcdad812b8b1d46068f3f814dd587b145ccbf871c2195cc785316d515c5dc863f73082822d135e60bf03bf9851a3e3ba67f829d62723c8a7360d7082d0d279cced32b0b8a8ee31f685acf07f48cb775a0d4707cea3aaeed0a3b93cc15a4750d53a05e8bf58f39ef61c5418b0cd5c22539f10d5e2c8c8e53466e2c580145f805c206276c14b001bbe8dbd6e8a191f0077a86e24d975ebc28022b43a9ce40a415ddb032f6f2f0a4edfc0d324acc75709d6f1d5842c19a70cb3a3c3509f40678a557ceca5a41f0e04e0d691b770b35e1c66c2b152482a708fed0993c5d10f80878e01a3a2b98d592f2eb6112805299e0a12b3c7c56ae578d41cee41f786d2d01ca4dc2b8e5f53e6c8042af7b026fba152903596d3ea4c211b3833bcc002bd91846d95e4bf48d5ade352881bfa9957ed7d306e87cecb1163feaed83ce9c6abb41065f0e70b5122aab8d0aa7c125c9ab8896f7eb22c467a8bbf7d48f6395bc290a5e54c9f65498a7c40e57bf33111074edc045b6dbdc6a52d370834db2865ffcae31eda9bbc87a54d9290c0aa2c6694194a3ef5f9a1d3d353c6c4feed2df8187a089be855ed22a187c873830f45980b22b5b86c2ae87a34fe5fed1e69e99cc1a39c250d3d760f7e1ea6f91fd80e14f68e94822f04de53aa6f76b6ad64739cab207abe34f056a8cb7356151f6341a62bf0d5a4fed40ec41b6904b69fd4b4f66a51cd56f6881f2a404236650f319d6fda4849f60ba472b8f36682a7a14140d17f00de180136a0778092955ad9d733186b51bbf75ddb605559079eabc361228ff3fead1e78718782abd9575eea05057810f36751d3173da480185284bf70a9d1e078681f9e9b5d7ca27528574e72f68a5330f89c2a049eada54bf865247e1bf26435811b05930e4dcf154fea4f4b8d4adfd75576661e718acd546824e6c40149fe1add82a7a45759d422d37afa02b3b59ca17239a8b92eb5662a07e4fa65818dfb317a347998dd27e8925f438d54655e5aab18adf5a53c2352133df1500c0e8036c9312808f915a0ec74cb8c07c0508069cfe7ebe3191d51a112221911c8db6ede7b82078056daba17a2826ca7add6508b134234bab03cb60d70bbc5514c6147f7299192e31650b98c8d2c316f21ead07462c2a55b3d26e768aa2a12b80cea00d0b4123be7390057e28155c84f000195b56289669303e32ba0088025458421181d074bc5db84a8f4a02d25a43bb6064aaa2d64a7ce78203ee56f4d041fae16780c0f7313d255f82eddfb9d95ab321ce43828ced5199684d89c26af82805cddcc9b669268c10565ee9fcb303ea159797fd080cf04b62dcbd5adddd3a3cce1d6789b1e051a4e450911e2ae46e1aa87db200d4b41e219f385b242b207d405ac345f38a1344c4ce6bd35a5f2d3d5f027278ef79da270324906cff9f1af283680f7fcbc702e087a153a821eaa9a3424fe5062bc984f11c2e6cf52ac84d0d20b3e16a30d3c4b1b46615ef07c297ea06112da6dd2a3506705d397c90c3c0212ee5d1191caa3a7f16b9c98de953e5fea087f82ae28ac0ea3eadb1171724b84f9ee1c80f41670b65e7246efb713bb9bf4af884a7bb31d23f5aa5d8e8928d01697b0e7894ea417f2064bf721f2706ee33e8341bfe8634923e54a4f2602acfef25928d1d64bfe966744e72785aaf4bb696b7d101198e794a35823d5f4bf8feab50f25e4d7654a156b09e15dca41b5b772a54daf0e028463fdcf141a042f5e2893d46da06d80699a4ceef70ce177003c114766ac9e8ae3358aebf771ff5d053c1bb3bba0dc323d7b4543bb49ab6672bbefa8e30a568a04dd3aa274ec02fe0ec176d8102028453a42074a0e22c6c14c53e8b0b7208220f1c479ef30192de412d944829865e586bf084536e9626ac024ead4a9333a29fa36aa254d6c009da0a2004c223bedd4c8879e9399e3001e5706a354f1723b5f06206a25b00b43195a37bff53b9178757480f717a4b3964a7c823e8503952143dc5d0715e220434dd6259395f0d890fbd0d699ceeb54f80db8086c967b98e24c0f1f40ac4ab53fc712f9590d6ff9f9c4990b1e01e685efba17ea8b4b80df00d0d004c74036c32a7c04dbd8809504ba572387f4a9a58e0e5a9a409c2a071fc8cf990650c5c5045ee6ad466257e264bb33cfcd7406c899feafe8a4bebd50d60f6e50021289e6891453e523ab850a0d911b735aca034c56595bd7d3c42576cb165f277b96eb772488876daf32bc2f946f6003880e69da7a9e9325aac02d4f10228aa8cc658c8d799128d93aa259e5417be08070d4fd2260ba9fdc36267425f1c35b12ca7417b41550d2f0d79118f38facc33d121174709b20d7495ae724e383b0bd3fe66db01c80987afa9970f9a617ef577bde2e1db2a15b9835421c556c836ac1fd3b4e648ddbb2b86533bf7da5f80d33e5e61681701edd9fb546da39e9ebc1a925474bd26b6dd39f3a49e64d45d76f8f4f9bd783f7f8cc312d9bcc36d7b6bf54d44aaf7ebb76cbe3739cf292caaebbb00c89a66eef72827fad3c2ee0a1da92eed0b9c61278cde5fc2c0f89250c04fb70f9be41b18ef7ad9dd1b76fe07071b147f147b54671ae8a4df834c1e02d5397de40a368399d1df05122c30649bbd98d0c7c1a64e7d5aa858015cddb541117cc513e48cfe0e401082d2b6c6fa8e61e0598fedfb530d82d9367936b6abf4bd130bd7584d5f06963e2f33e3df889abf9ea1689078b622cb0cbdc0dfc6632e5a78e4abd40c6174f1357e5904084b25de960e151b992acf015dc62f445d65fae1224bc9700e888f168c4760165a3c5aa6d9d0264fe159a2d24e058f2e47bc02c0e88d9a7d2b1612d5d2266db266afe58bf7823a346cd4b17e842c23b9f34b8cdf598bba1ebb625183e772e4775420b6cfb355dd3f6078bea60fb7e71af873664bd92824062c49331cb5207ed840759f9f1fefec2d763a78e38a597a6a1a5e1aca9408c4dbd00383730f095a946d1a321c6b38fe6ca57de709e68ba816be4db78412a9f707345a0fd32ffbf28b56cea4710172f002c41d85f1c8e82f27167b6282c54688bd4926f58586b6884ae43b2703a5a940388e03abde2f2d9e62b46c6b67a1c513021e0a9d2d9ec42003b27ddc30c501882d3c6d52e79287f5171551b5a813e6cfeda321e951a8bcb358401f2f2db5d8a66daaeb12b24168ea5a8f8248f6b9da9cb13aa7e39ea78d14cf7ff6568de06169f12a74d10f6348d9cdf7be53bbd29dbcdd242a897cf1bdfe900e3bc5f2d35134170424ae84ba26023b9b1f20b8e47a9c08b093c24460b377ac0372cbfccf2d4be50a53a0bd7e33a717bb8c6a566134a52c199ff891067a36a1075012f21b09bc2b4fd1d720ea85a5f41126206cb499700e2fab914e880c170dd0c73c1e42113e1d706b6846d88f2238de896083660350f98849b7422270e5a9f45253c1440873b679e569c59629bf0b3b2e63dea9a0a853b28b69a44b2ad2db27007955a7817389f100c3c4e619a0a12b2c53b91cc20a2f2f8b36646dd2030627a4d0181c6455a40fa961e4203539e47425c58652527052008940163103781bb3f235498df47fc7661b341476ecfb91ae3ce799a7f685604271e0c25e5507e51b3003eb5c23fe0ad03b9aa38191ce990298d0364f8c4d1ab5d06fc1db7966c6d44cc7d5196005e2637eecb383f279e628c9f3ac6558cf83f870e769bdee337dde7b3d3b4ffed8872e6c1b701058a740ca6f54848d6135e8377a11dd4f1d1ad494d83e2710befa81277e202d790eb41042f0b0aee68f3961480354e7a7b2ca4969893220a41cffcfc1af492318efd0640d6c83967d8be0943e5926ba082e77cfb23b8377c0b9f493c45b3802bfbb94eefd6666d64dfbb3ec6ee1114c04a0af091faa4f0613a474326371402e73b3b7420650e832389418f6de15896ae2cbc888ff20bc9ddfe566bf609e31eb996d70dcc2fc751fcf9aba13e5a1a9a54f5f1ee3babd5bef403862824a7d94b41284086f0c03d40c46c1ce97f57f3230fe33ced7f62c818f0edfc28f416df200c5d6d6790e6d1da234059b25751505ffb08a9624a562a0f559668f29b4a103f6e0aa6c06a00df12082b5d53b381cd2d28266b5cfe6a6097db18f762ccc0fa9fb9e4dec959b4c837c764a28fa3327595516c15ea04098bd2ab3905a407378913c5aee8eda00774d857df624a270b50f3d31d891a2eecdd806d46dc810697a2979e3951049da2f8978c878dd58eef10342c6bfb35a745d1195724ac1af3b4df9f0c78870632912d55052c9f3a798513e66cd6d716af7b345af26a0c965c52e833bcd079172d26e50fe11a173f6d10bba28138292839014bb6c52dc02c2524cb91d8f7cc46ac5ab84f8d38a07458265ff2c2d360c402a4aaf3f6bb89c605d003add09447b15316deb33a68a538d2a1629fa4131c1b3017460bc5f4cda017dc6551a53ecc1e2be849ec1f0f673facd241d400232b6c3f0dca2e1a82488f9f94a62c97b7fa5ba70c7aacab5335ac1b62a2dce4b05f40480e57db6b4cea82e05786331c7fc61eced9ff27183cd0aa2f39311a2a659b84b74662ef09b3f8da802e543ce6b9150f642ebb51ab97153341a2421888c7ee059437c67d8b572f38fc9fb060bedeba995fb526642e24e6dc5fb137e182bc23b445a3e04c99afc67bcd30a9a7b54af3596d74d97e723b18262d7afeb0ab420f99cc483c39fea626f60992f9e3eb5d7030c73c1ef09e25060f808a5fe9b492e0127f0b67422f6367be1edc87f0ab02b12265ef0531dae1f9bcab2187403ca7cdd968bffa0dbe17556ea49ab7ceb33d26ac92175ef096e8166ce3f3d35541da82adeb981088f374037ac2ccd4a032caa9197b80d6b55ee4d154222160b75812fc4c23a34cd480ac4ab28e144b87065b9fbac496fd9574e56334b17b0e5e1b1885a9c860878ca859760066d659f5b8958bb5e353df1611515f57dba3f01231a08d067791c21f94979db058bb992c787edac9c3e4cf8a32bea02579024c93d51140bbcb9261c47ae0251f755d495c383723a945f661621ea6a8ed12d5f14d75be43141c7dc684948acbe598c93e7ae91a87e3aadb5f2f84593188424629afc1267bede6daf879807d35becee2ebe4e1e65f824de83acf365991dca07c8ea57a04a6578f6459cc87ff55c1f99e02ce9786640c6f12cb8161feffece1858c68122ed658d17300de39e4296df3924d3710017fbd49dcb44b1cc8f2dddca4ae1bcc7f5189824897fba7663183c92f277b4dc3bab177ca00ae607e4eb78fb7f121cbce5d6506cffed0aea70ba6a0ea69c4d1f234fa5c178784b2055966a35713fd13434800d98e4d072552b1a719a62a0bb772a91e132d93c688c16b7335cae5f8ae5d110e277e5611f91de3b5998b836d156dcb24f4197e823d75477e519586e4f03575c858c9417e94143416d24c52951957b1b2504648124af04c4f5effc40fb7c845c6f52d1a426f497ab16ab9fe90c255b63e2b2bbc1afeaff3f2b85a2bc05824b1e1bfb313d68f9e9c6b1e4f7ecd7b626f59099dc621dd29abbb0da3855d07c9aa26e1bf202e89eae0d71dbaabbf4731d08637cb516816fc6e76748d10dd646cc4bb4ea649143f5b79ad8dc241d36852abaa88e2a96a04a32354402850e29941854b263f8b00a2f8748759ec1be5673320ecf61a021dd4c2dbaf449c72b7c251537c4221b8478c61edcac17328ca2cef44a011bdaf2ac6b77947b21d97a9442e2fc4751f158d79304d3b4383eecd1327d008104323b3dba033fa0dfc2e3e983eb8f7f660d2bab4d40b9ac725e011a346127be3d5558b891b10db2552ab72fdca9528e032482853b0c90642e83fe75004b928bf4d1a1eb181c8487d14b9f6507b9340cfa1ea0927c300b63bec2d1aa2182a86adb67b35b2a74145c2d50c72a8c4b313654c0ff2535ac9a446f1be910eb98b60a8c674eeebc09966c013fd530b4286d850145d7eca486435294290ce98cf20ed959c050f1f624cf7259832ac30e19eedacb4aef3c7de8713bba1a77e6de8d9e9d70858bbc01b448b6c2c8151706cb8277cae006a38c32fa2ded7305f9ddfc9c9f03ba579bda11c6e4fa8d02605f0abf3bc846cfe2255c26bf90333149093325c7614305a0eeb2d39fc8db55c5926862bf558a55fb83b09c8ae15619a0076609bcf389740cea2cc481a6d56866e53d9385b2900a46d154102d3332db4db2412ef03e52ddb01ae04655cb453956138352a535e15b97417440b5b4a868c8055599f8d7f2335442242e673d8d2ea0da977c8a52847b5a9e23cfc4120f1835c5652117a2c6d92259df70f0289b6ee74c50620a522d21c43015fd9568caa2cadc9469bad978292c462200312a966976d428c24540abac757369733ab36ef2dee99e9b87cc70be8c3abc49602c2f3e2f908ce86f128809d4369fb579f45a289368012355234ed0fd7252fc74c53db6d8764c28234d21c6abb5be29f45fd8a7360b39801923627f2d2d619d0f6b03378088f6fb98d8d5f0412c5de5893b23e47d097d9bc97697db711dc55bc46540ac55bc53d10fc20c0cd100450b283efccddb0efe6260a94b979eb83b376d4013e8e759267792fbfe35cf9b64b24ff93ecedbc188bbca5a8bc0c0c3236167d3828a0cc332937c6bd35d888ad787b46a561e5f846bc7361a0fcad1ad836fe966e0b06b34944ae5477be107857c80838519d34ef079962d81be64a92a1f2dfc113b1c266de22df08924113794c0419f77db395404e64dfd2daa119a64b71355b4e3604333493347b2f286e1c15432b0f3371e50522e33bfe68933bd06bc75376530a6064b07c21fddb64a8e540d9fa497d2f557b9919373bcaeea6e18c391945ae939a2e87878d742b624626e581c5d194cac13842b20f5e73383afd1ec62262d42b0120d1837cfe18e95de520028b71732255d0bee48a9413956e96d2b93d344855d975da8c2135a69bc28e4dd5971c85a0faf33c510480893d39c7adb55db7173b060b74a887bafb8007cd59fffdc88983e418ebb891e1ca701ba45e5415d70ca604e3acaa21e02cb5977d0f340ca749fe1518ed5d4fb3b41daeede550f3aea7d087e39d27d88fc2fe79c649623391e1716b00996271eb6badcc9d69c5c350d26de27ab7e4be250023e0c0660fd307bcdaed40f4bb69432d16ed2482004ee03a7033deeeeaed0adf0219999f966074bcda64248858f7e87545a96822985d3eeeed2a5b5c8bc32292b7613d08c0893891d458f3966774f48c95a422e6b48348251c91367293352871ada7b7775baa76386f6394e586293759cc49670031d28de9c2d94337387a10d3a24750cff94c0f415196e8016fea69eea4a0d7f52c11ace0a6a48d48581268b15a1e4cfd0acfc299d110591b859e4eb73bbdd727e4a0880716a4804e48533a39980cd97d7d00738b72e97dfd4ff98086df70f86f293837c414c414e41504155415abd452a33333333b30d1f1b3b1b3c1b3dca43bac51205ccccec73f241f9aa7c5a3e2fba126b92749504465bcc58d9dddddf93d8124a0183f50756936ea18801a9e245f7fffe3987d966885293ed8df16eb71b4d0b183b39242ada552ebbc3a7e0b2687242485088cf06ab4629a84350582ad66c44beb05bc782b7dbeda6850a8d8536a2de13580d450c52fe3f47fd873f87b321ffff2beabfbdfde5b0056ece1de6b0c94790478f200f6e405c98664689c38698498261815c408659933d2858aad2ddfdf4f4f444323333ef0f1bb514233e46764678467a94527a5efeb182024ad5ae8a57d5ab1aa23f7224d8cfa450882de14f95029aa14a2fb69736fd326dfa6343a5e4154e6c09af70f84a47b3e9e8f4304991034b49e7830c180e4ae979f985ec79f33258e5725230b125bcd520b8a553149a99999b082ac7cccba35246d284e409891412a00d49b0acb0d3810d204370469010c201cb85e2889080514acfcb375828a594d2285d944fd42e8a17d5ebee37a59452fa9fd2ff4cb8d59055925593d5d3fbfd9f97cf4e3d34ba2355d552692d95d752856d91975d4ae9df74e9fea74bf7ff7f4ae94f9952eaa453295d4a6996d066f9b29868594e364a29fd7fa71894c9c01fb125040231508806f4d9280e0311355234bdf84dc1c4fc92dcf6ed6309cb3233f3111db125ec41f1538f0075c7ec54eeeea6cc4c97521f5d95967363210341b1407eb60201ea8db90a825402a906570f170a5329f5a994524a29fdcfcb3537253b4aa05a5465093d600b03f5016c662692135b421d5a89f4d874382cb1c1539231358461c30af2820f5108271c6667da31e76c481c4f3d2068cdc663c783474b31d33a7a1f300e1fa19a9dbc63a764539b7a413654a626285de5d1e3557748c1e06a361d40594b6853f7b1ddcd0195a38a26e203cd6e0fa9d71e405ac92b302ca02c39031a006d14252fa5b0a597a5dc92ceece4e9921f01581b5a36bc6c84dd78b9915bd245e1351b928ed81222f530120a1ad28fadc45118878243604437221c110e090926ad66a35145438b86178db0a0170a64ebc9423eb125647282da40a8aa697f31d5eeeeeefe41fdaa7e5a3faf5f5885f24b6aa7634bc10d96c036c071b335dd6eb79a25265842245f4f6560577577dff858206d4b96a2986279efeefa90cccccccccccb3f128a1d2cf43d29980e3fd734dda8a78a6798997b7b459e6156c0ef080a105c59405972c625c4b2729cd949caa29b56bbbbbb97e4441d1ac9559b4bb7a2d2d5c485a3a524e9fe082a285fc1ddeaeeee5e92d4dddddddbdddd7d987f764c7777f7a9482537119a06a574f464254f74cb883c7f0dc95a425ae393b982dbff6bb6244d2f66a3970f3333f3aa98415d7777b78fac0bf7eefebb7b8754b2ebeeeeeeedeeee8671fecd39d893b5844c6eddccccfdff7fb3d1166ecfcc5ebddd9bab6cf40506c3025543322947749c4149066597a147cd0c98210a47660d65b89aa160b296903374d1f4d62d43d80cd76c3e624bb8e3c1d84cc67ad299f119b1e1044c06467a31195c0573190081321920993193c111608c08c44ec913ae76a7d2bdbb5b04bcd52e495c7777773333777777777fff10b86663f25a9ad0748b947ab73311eec776352c12216cc7ccccdcfdbfff16db2a65f4a96191915ccc470308b5df36ddad80da32926af7ffeeeeeefedfddddddff7bb3b25a0cde6e370f3d99f66a58e4c4545f6eaf76333377779f9999f91d1656f9b2f24551baca33b30a4550c0a7580d4f171d81aa2f77811cc286b10849a732586fd3744020c24643efe6c7c98bb89395244385b213f0630165b6e4d38c26d9913a2895853656821b6d6808355944da055dba6f9ccaa7472d26012eada19452da54e9ff91524ae91009242a9dcccc2c4347e5f3f720fc7f97cfa58b69bbf6ff1fea29a5340781181aba273f5aece8a0e3a428cb47293d5dba43614a4eb928b84361e62438594bc8cccccc15800044b3bb1b34d7025bca8d41203293ab294ae612f43922ba6cf15c90f8348971e1bac958954ceaaccce776bb8188a15269d9eece9a6a780475ab2fc96daa9377bbdd4ec474d16a365d0d8f4610a6cb52f2e61d9b6eb79b0b1c066e2a026b78e4e4550ffcffffff3fc5553f6b7eaa10253a8051448415f44561a82176b8a1a3f7fffff7f6b6ce1b27533bf235f5ae4c89a8e0c802caacc9ac152a9bcdb26e249d1a42fbffdf76a4a9fbffafe406160edaffac21594bf8ffff77f7fffffe875f49fdd408f5475419ea77f75fdede3dc21aaabbbbbb7bc4a77129327a6435715652d653650a3c0cd5a09caa8939c7cdac6633f204d54103ac1e974dcd56641744028d95140e27551442125c10a743d5d3891d20af97a34111a9250d8ce88670d0e00aa775b31a58e1fc47424e7034a8c2e92495cca23ba9c3a1af0bac724936f54eacc8ee870129889508394f53bdfd42a2a958b39500dcef50d64742d8d479a08b094c929d0721202207ad0f22345050a4c5d32bf26eb75b07a21710465d0d7d604dba3aea2a7469e0e9509aaa5a82f375747362814411a26d737777596b5e0d30f0e6b220994892b2d16a345acd56b3854cabd14a3a8260799574815b991f05a861910caf52a470355c80c88b1424601809e1133fccb868a961d1cc4b4de98de2910c913a2b71005e4da142400d8b6684545a902bc82af0026a58440353596a48c4d54413634b28a7e491daee4c4658e5925cda7d0e4f6a2b01f509d1754e0e4bed48a7eede767777f7ffeeeee248f9641fcf57b9ec6666669eb1fc5efe6f6ff7ffffdfddffff9f834265a58653ddb27b777777f7ffeeee6e4e0c145acd16c4fbff7f7bbbdf6759aa72ea5b4aaa2ffbff775798d8dd7f55527e80b5282c1a8a53d5ffdde69dd56cbe13bdfab29b6714c1ccfc6f6f7f85b090be18ba7e3f67882eadd992c2fa394bb36ddf53d237c3e49a6de8677bb73fd93744ab72d9cdccccdcdfce01d2f735052b97dddd2e785c01acbb20d0e9f302dc16bb0010f184c565951b4183cbea76242cef4e2adb5ddf08a0eaeeeeeeeebe777777f7dbcbccecfbd01bc17c458c7ce0f3fdf0f0efee773fdbd864204cccccccdfeeeddede870876c02905656655a282a613a42ccaa258b058c019c939cc4da652f02af7f62e5b71a049d0fbffffddfdffffbbfb6f9fd58659ed8a27e24b1622ab2746ca4eeb90827a13b2274c2e6b39310cc0a90edb57a12ca40517b492989999b7babbbbbb6fddddddfdbfbbbbfb7ff78dd468595240682abdffffdfbd23709c2505d8b4bd32d9c89311a93e8e36cbeab99085c24477f7c9b09bff779fd66ccdccccbeadb0ca38ae9e7c554317b6a42663dd9899999999f9888e999979db6744027c77ffff4f4e2c5effefeeeebeec82955437bfe6ff514401bd4568b166bb7064684f15bba085f393efbf7f013892f04511f1c8815f6f861ec7dc45bc63aad9e009985fa8ea8dd8305e254d11662e50dd6a2e14e915c9e580497825a774cd6893bc2fdb28a54180624b18cc2008d80d87a3cbe0c987fc106566662babcaffffa5913152f8f1944413b432810a299cfedf7d1a26092458eaa9ffff5fe834532a35a31b38a609d22618c1d0f9bc459e1b4b68c4412ac6fb99991fdc2d8f881526726a2b2dc254b0d08c480075e31c66e6b673bd94ab18e1e02dd2acbbbb8d3c40f56166ae3bd7834f51babb444fed6e212cb39acd839fdece69d19393a36edd44b9afd929a54631bc2a97ddfdd84c86493b9ccc14dcd80cccd988c58e99993997f20dca7577f7aefb7ff7414c780f1dff3c1a41dd2aaa0684396b36a32a1ed877c66c6ad42425f5ffefedf76b6a6c3333b311915ce572976d7e761b9446f8e0a104c385792a1bb955361253b9fbcd0ca3d737e35827e96a97ab2399bf3fa30499bf3f93cbcbffff4b9acc39e9d87c9b2f5c9ddf2f3015319c3a1e448d8022894b841b542eb357e764a2ab73bb9a7c8e734e9a396daa56d06870314307e83243a8737abdd40a6585ad16657941925b0b9e1858131914403844f990f10b31644eee13234f9e73768980c636eceefe7356981fbb7abcbbe5055d43ec627eb93e74a060ee72e5c4d89ab99658260586e9694bd261021a6d2ca70421ad36a786b18ee338d7b665951b97eb6702170d1c96a0099b151039da978a19952f9e4cca922a1e94e0cbce6cab2b87e4d27043b9a0767aeba98667dcec07997f258118791c26d187d1825f50884edc7277c30d35f3d79543fb7d519501c891c968e31e66a79605de58af8e6c4159e182f282727451c7b1e4711c4b0e2ad449019176cc389e4fd4711cc7ff349903ca1063592bcb2d2f50a9615109609583d2c28f29a3a94971040c38655502840bbc5e7e4f9a605501016d7500242364333485b523881863099090214739493654220c1e5386a147013d00a8e1afc7a2a7a35dd6837f9a25bb864741286823e198323a9b479f8e19b71d890e2e6254bcf8fd7475471d2d6916d4260822b7221fa41076b24af0909e7c2caa210590c300a914187ebcba5a78f800490be9e82266bc18e1064fd808a65c5614415da41d4833b84b90cd24f69474c7c9e467c7711c6bab61ce12a66d4e2631ea9c73ce716e0d7f5f5d95ac1cd04a9e262815613ac0c10271a30adb4df55cc86296745c42381f247e6a7cfc7889da91834586af164d642f89e238d630330fef2b628006d110214274481f3ce0e91a660a1f8804d59031c4838f0bb3a8cc3c272aefc739abe18f676607d93fb4b00c97ec8ad106d311e91c6bb9dd981b75c78bcb7f8e8bb7e4a70207e84493cbee627ccc1d09ebd183068387264e2bc056ac540e4a0b2566e8a487162e86d694541251858e6c312693fdc4f71ce7389b39ecee6aa83b97f7cb44a92e870fc428da0a3269827ae1b229ea26a9fb7182ca416981c7121972566677771ba586483f8a4a0872a40334e5740385a881de910a191f2377d7869967a22aef8ee38e3bbe20cde050a1218341f32b35449aa151536a8834f3b332fea4faff67514fffff25d8a84729e1c54e50c3a212723e64043e52662e5d8fe36be388d30004885216538ba221279e7c6f5a16ce947d6f4e7691365a501b63c690b97304b0ea818387c6a7d44134f1642f520b649634065b4f6616ca0bb6b678cc9031abe53387397bacec4c4f04192b92818de9c083ad9b1a1ba8119666c4123437343cb7d9dda5117144f34243f637c3eeee96b6c9352322adf0d50935445af1c28b66930b16b1ca01da21fa78b071d361664948c40891c4f26154866e4a7c78b2b50564c44efd88e1391c1cbbbce386302b57424505ae9a7a828a30e1c14214812346c6721b62eceeee4e3018628f0730666885e4b70426078c278718c2086c06ed912261ca868b1c582e13449d6506462923b099ca5243232660321f7320811a863eb10ccb06c842143104b4951afe6a5cd5ade1af28890766109bdbdd1d31541769048b5aab2151f0761996016a48e4244495d4a8d4ab37d98806a0802000b31a04000140612008a2b085f00414000c22966c98fc645022934b033128181204411084500803300cc4600c436118cc6229e201209012e103858cb1fd08b6cd0efeb97e9b0d603f37f54d3122cb57897b69c404f3e4a507bfbd5dd93da5e41ebb0e56df465090047fcb1809deef47427c6bd7378432f87c3038bc321bc5e4ad2728a3e88b1e27a085a533466fe04416ae6497826ad727c261d6da27a3fa9cbaa7d779c5356cb22ab5e98947cecbbe97e9dffe0cc83f0d5017edd7788ec90494cd0df342b99952c18d9e777b2de2c5df649443e96cb940aade06ca3df10f3ebd714e2d4b690d69ffe0b0dfcdc2bba7e91cfa413135da9b9d2ee7ad48de6b7517b415aa7f1ccd07e7e90f1240feda68f2391f4c387a498a15ed1339d7ebd7f382fb12b0d22e1d2adf725a44fe1bb45ac8aad28711893ab7bab0e18be706be18f0bca0e4483b6a65040bdf6dc16b1df209ce2fbfac3447021dc2cae385371ffa032e32ff10f3ea37fdd182ab895a9eeef00f27bc5a3b36c2485044fd25b340fa6453b4099b79cf6324f822b9d98b2852df279f259f4df653edf941af49af378b2a4a4ac964815ee83202e8ac0cf41a63fe19d6792f5433c349078cb79418c0044d5cc5ac0ed92143f07dc1036e82753234206737ebcd1d446958c394d42ab47ed60d0eb808f6d98587c96cbbde7810a13163487015da1e5f0039c8fb095f3fe5542703cd48d2cc753a8206fa0f94d9646d87af86b24f95f5a5803ed6e88d8f010660d9cdfb5e90444b731dedbf261436d9cd966d1d9c14e3e5367ced671f77465c8534ebe662848996498497050106121e887a3518a47fb709418b1c4836e50e34bdf73cc9a0a36bcb10360236b1be086c8962d16f958e160c63b33a760e2d1e2b2193abc311fb070cd4caf86d1b357f0bb5811f7c9259c2022101a9c9308c2cf6b5a551cad75ada0f0326a21974f07e382e4cbcbf80313e612c7da421b2320297023e5a5ab940d36aa90dc070cf83ea20b1ae4250a3c386b460f4a8158d2510f7a882a58f197bf6404a04f7a1f0c1e838e08b96da5948c11e392850e8809f9948facf63ffcf5e25681dacff6f554c4e7aff26d8f46a4ef81cb5fc81fd198da40a5a65020134ee2296f251cbcc164b70880c9150825f441e6c995eef3b06ea1572bd06d156132ce83e1151c53d8feee791692e59e70f9d0f9cc8fd377f899d82bcee2e8bf84522e92561803a7877078262e9d96b950de2c68adb5f137e1c555fa6c9f94c8496ef4ec72dd59f5aeff0410ea467779ef64b314297eecc086cb42170079ba0497b9f92dbd604889006a8756c2fef108b71745b3e4548bf05b81d821ad0b05687203720f495771c27e8b47e667f84119b06fbef8d146db4f1d9f9d5ccf8c5c8d3a1d12c1f9cd41b2f4d4e5f06eab959fddf3daba026635741206f359b94b2a0c20d237e2582f3c8765fb3b03eb1b36492de6b35b873e6c60f390e44910068946a99b0dcd143981d55ed68ce9055f215d039817d26f358ee8f9c4e0866627a0b4e0acff70fd3ac5218df859268fcac65d20d0fc8f5d9ebac54103790368fc8ca5f1da49fa610d30d11bb43784ca45cc729ea44c9a10da2e373237f591fd41ea8d0b7574830e97aaf457a53b2d22bf7b2953da19d21ba9ded5eb8276e4cf382ecdf233a45066c9d5a2777a13c64369a38a05e8ef23fc5fc08a2e0bd6a056e5260f2d53413a4022833176ce185ed0e7a4bafdbe290f6d9a0ea092c747956aade8b60f52176f7a3106d3503adf36afe72c2667261b13741cdd172fe636249b6fc2ef11191d3b4f304b2c3883df3ec4012459a65c20a741267e0e574e05d7a74194b263a20e529e8530be4def29115306495826a61584b3a74ab74a01e229ca65b5f41141aca4928be15ddd670af4aa04e50b61581ff352ad3c50f034ab7619213439ca36c9102f920a2c7a07bba5f8a3d88dec39a070fa2f5d7a6c6db0f3aba7b177d97ff84c495b3f1f703baf1ab40c3bf4b4490a12bbb586f5c8a18d9c4d89053d60c9641bf84252466645c9e0277f9342e402e37251aec670f33ba85960b25294f6eae2cff24a2d9c36562a4c35be52f1fc8132a01b2bf88d31730479c85e2680dc353e46b7f538568d68918c72dcee244f21fd80d58ffa46648014f2ee2402735328e8dc031cff277e806a23cbcc56e3ad5640fe25e4401f01bbb09e722cb58fa6ba03708981545b71301f83c7550404853193f9a1c1561d7c4e65ba16bca415522032c97475d7313883f7ce91b103ca66a2585fea2b81aecbb4b804483550b25ae9fa7cdf29ff57261d98d06b975d36af61f04a5bb4f82e47eae613860e3f886a7a300dc68c61d8ccdfb95af2679b49549c9a3b48cf1730d4c60e4e8c43e22282da7f807e926e629bdc52ae378aa097fdc90871ac62fc79e2ded130f44d5fedd24cb10bf53acae5a837402f3e31d8b289c29d1088d633255ccac919d582c482cb8109d427c479482f79520d878f610f4207c334fb6de433887f8466f498ea243d4218371e9d83a2c9de60338188038953be34812c8510b70fe804eb97c6c6389510091cdef08073e7cbf2b566261445505cdb476304a013f15088e9bc206d3987a20c0227cfbbe9ec0e4a5d829e9e7b602c5807b76a587655845a871421aba2129108310b42f434cd19fe1f789338888ac89cabac81627d61d780023b68c95adc0eb10157d2f44f6663fc0ec97a4f072cb17f3eb13d906de83b2b94258949e94c353891c471df7085c0f1b29235736b6e9f9c8debdcf0e0070e0c521871d09e3e6156b4607cb09a8decb6da720a8fb88a8961d210bc8deeed8aa08e78f58e076a5e7f2ab715560a20b6c4375700fa54727dd4f9d2364c133a861cab66915e2a865cec8fa16fc5a9b72b1f29a70551bc17723081783c449e6e0b15ea3ee81f815d69b9e8a05af54ae094aae1512ab7984b49d9bfe6e5d6c34ef7a399845fd24b19eed17858f3b2693ca93e05969fb29e9e765cbbc7a3634b7115d04dd931c855fb4b5135af591991e81197ccbef8a52c2a740e2f122e03b2e729948cca181c32c9d92d570b2204db033f043e47e9eaf278260e0be3f66788aa7d14180d7789375156941e97f982c967030bcca78044f8ee8ad763d0c4b94e5fb030a2578e86a8fc4a49e17c3e961b1672f27a45fd21d85269085e99da22e85869a2a626b5caa948b8c1af88008056b2c3d5a10d1f58910704053ce832f4aa83d286a45773fe7a878f22f878bfd3bb74bf621fae55d1530376f4db46ea41850ed777875bb238a70d5ceb99328db8cca71911af95d66d68a8e76c6a339092cf149b7648741ee817e2c0200a922831d3afebc070ef6cd104144bc1f35ae6c6cec42d951a3568b7630a6026c19b42bcb51887044d11371f89c16062b055ec7d883f8ddd16286169b41ff94ac67ff20baeadddd7006b2536633e879bd4ddb61920bb34aa096ac64a1f110d35fe000b458dc8c6a215d2d008f4d09f13bebf90b803c8e36f6f993e7e714b5862891ad769e5569c978837d3c1dee839ecabc77c3ef272e204efa3ed3cb6b6edadf654976dd0efba1e12e5c4c3d589232cd54bd41c1fb4e61bc8d391307d03ab8d82e259c4d52393ebcf6f6c6af5cb2797cf81fa676580b80712bb7d68d2b8d386c3ae9ff8e7b4e0139ac97e4eb7b60dc46d1fe6c86b0cc85171f7277a50ba28747bea0aad187e0f6acdd7cb9da5bd435b3ad115c7761eef2bb5ac11aa9e8e960df4859e1b81e8a1f9b6b25b4f9ad7530db1e755f0220636d11d8ecd9d9883623362f5d05e1e4b90d5b8d05c371d00c5e765052229522b34ef5557776b1b46ef87a16138d09196fac33cbaa7706e551b56656f5540ddd629fe74057c142cc7ba2b0b4cb882eda8eeece3e548e33ca0da33d61041def4def41fb25d351c530dc82391bc1eca6aaf5e156d16629f49b00866cadaeef0389197ba23cb30a2b044f91476715c3544d197c6590f8a1804b629fe0da152182fe19d5f9ffa6f431e9b48e897412a156617c42c59c945fa1f57808a7bc77adcadc34123ec86b5c04ddae89c35ea8b849a95207b559dcc81f08c61fde0e8495905c40c51ce90cd21d99619b71241c60fa0286c3d2b3dd2109d590c48a5b8ab7a00cb43bb8f3bdda3886be994bbc076381132cd55b0ce0a8626bb934b6c7f974b8208f9595f58833569adfaf2c8debee7e44291c410e76f271545373b6695c90482fa75b5e01a5c4e13524b2dee2d95816d3f75ebf8e8784c0e6e0ac061e68839163c5a0d7622ecb0c4ed1cd2597c8be6b6c91d6139351052ef923068af81165789a665aa3af7ff9a9a6524b8d26413cc7f0b766f696cdd68a2ce2bb4dbf6b5726de72aba0e879a2b5526199647bd985ca0904ca534cbfc8c9dbcbfae4b30b778de345a9504585f9c19ae48f20003dfe58a68b3e49354be97b9515a783b17dd2eb6defca7cd515974b43a5cdee659eb439f77f2de044ce73966b3c7cb8b61699ef1bae965ae1a9ad5d436d1b47c4ea2990ee5d8ba283813ab2cad9b50e8936eb67615e45efaa8161185b79e489101d6c6f5b1d2c92d9754a63c9de52b9bf43273d7ad190b183599450aa2164f8f4205e38d1a09de630118b28efbcc2f4e2547e3cb6d94c2a1557078f516562bc670d4bb1b5cad2761e62303d2d9117751222b62a1ca82cd3d06c6e1c0ca7718d8adf6f53e5a2c6a6f148303475c6052c0a26a17a9d2910d601891ea56a93e967407042a69f5f03abcf4a2cb79431563b6057079d7b29b677b6957c5c79d79e1126b2f726ea68a4d3345680d91804178bb8e834584514b806fb865a8a994cf6b93f958a314f282de2b950eb17780a8ec7d07a58e6b3968e0d709c5091e45d8663c66879dd23b51b52aae9ce1b4dfd9a8825c021b1d7807c69fae88b281dd47877a4aab1f1d283d8ccc488a43978140fffc9ac4edec39e0fabae55edf9ba9fd81fae302d51f5af8a2897b599bd70332ca045d21d477a5d4e8ef7cfc591a9a153feb99b29bde662eb93d94ef5c08b5f7b8495daaec269bd147b465d00562c9e82b4403b628c509a7ca52b9eaaef67009f4b9a87c468ec32a80f4c8b97a18adedb91b942878ec7317f0c624c1e615d5b4b5e7595b72aa94b8748f86190633f75483ecf76a2a9663ffac21784ce93229d9585099837518c34f83063d5deff76db698383e8b9ab5a34cc7148e1eefb96e9784445084f116ec2626a5ee61a5aa796e042463b68b3c90c7eae423bbd53046365a670df9a0159976c1ab78f5af23903e357726292a1321ce073e1d2f5898a4d3cdee74415b8148afc4b4563327db8ae2d036b372bde9f22168df85324e527994d4ae9831a58394ffe4ce9eac20ff2234981f70e88c52fbf983e4b1ad0249ab91f74308515c8b0dd702ba597f575c941c672fd37df8af20701217ade2f7059bbb516f0f0cc2deb0802438f2c37cd0b8fb7b0c42b26548622937a114b9a7bf5c0520edcb226104399ff0390cc1f0976a60e29fbdfaea0acbd902c27f4e0e41c488cafd86c94c1bd53100aeb484bd9cdef586271f504fc374119556807779d4cb6184d4b49bc44dc311f66e9f5dab25dccdc77d439d24720e0ba79b4f79271f96a7aca26a128814fafdeb1d4b596495951590c0fdd991360f42d0c19575c845ec85fa5135e8725e681ba51f5c61354d064cbac28d89e832d10bcd5f774e61a8319ecdc25261ed361c1970a77b44da3c1a4703bee34bcf5b4285d20ce8f298f397b37fdbbf788dc55dd019c68ee5aca9eeb68030115cd33c924239a2e6a315a80a0a0832a04f4bc5285e6134716d64722f43dd17d41a0deada44bbeec831e48be944307eb2f3ebc6478f687549ed24b0dbb8e41ef5339ac449df86ac61decea30b9f09704eccec95a9b44dc28c47033f18dcf8bf422b165de1127801e0e5c3c917b49de49e5bf2380ba9c0eb1fad7fccb811f576137a9ef7c78b8076e419ce183f0cf526558e6e7157be05f1839fa88a7e0c468e3de98af0daf0512253d161b3369d688461f8370d1534ba5f8ef8b0c9c92a0e5a7380ecd99df8de75c4c70060ac93874f511791bbad43ca5e7086f2d44372e541469390399e32248c7832d3b83e14ae1edf986886859629be06fd6a487d81204b6842b37216751850f5c05ec65cee194a1a10748bfd0e69abc0990f8c30f6d47db3d14542f54f1449dfdde5fd99c0e95dd966a9b4fcf2742f8aeead5039ea1208537aadbbd72722b83b0f120e4d9b019646d4b4b41191ab3b1c1ed8ac6758c976624a0da36163425c19304e6b7b773217baeb05c66ac963669a9526c9eb67dc3031fc52258a83504160ceba48c0b0e68ff58eafe13a471631d65a52de5766f415419507ba9f9897a0516c33b00f78de58c35ea195fa0ef602ca8206338ebe3c34f63c3e2ae53165aead7f8b26bbff537a6516f25c76a665b7c49983c60a986a0e3b3c3e534ac6204f92d2a990910a332898ae58fa88c7bf3be346b24f4a701a6f424ab80153f13eace4e0c6a365492a2fc1353ce06ccd09eaf0ac46f857deae0b952e9f48242e6f24a0627aec1f09bb517162b9b5f7cd16c5223dea27a0c3a013a7a71b87bb525a1b18ae20715c22d5d68e87f62db760891d23498d20ca83d8506d787fc76bbaca0b2d01b6c0da74b7a1a6dfa9d5265bafe0853c08ac28b20ad29f34059e647834231ddb0861adf43831c5e4470c73e8b7f9d0e824043cd1bd2008e7c5d9c664d172d843c2199e8d89549ef7667e98b03ae964fd10d0ddfc55c9a02b3be8da4fda5cb96dec68bc55072c045212cf4846f33d703a82ae3864188865b931020fda356bfa7121f6a8795e3e213782c2733935b7a7bd352a053a13e43a8759496864ee2e6abe37411c404aa8dd204aa66577d61a40888c75a08986073ebc69d3f4c327e4fc65c67321560527d4d38a09de4f58f484e7e8d358cafc2e91d8766e7f1dc533c3dbd22643d13ab3741065af7621eff1f54c083c1cf3616d3a59b340001ec078881d4ea12819c337373a7244a81321b9ca2adae2e3458009d3005ae66b6ce9b6857a8d11e10b58e2ee3cc74de4da5cd7b1e5446130ea78f2407cafd14a17740df658e9d94c47b2a1d17cab2ec127b2034baee0b0aecf14babc8f00812360f419104de7ee69054d070c4f3a373a3080a9c30bb351b42d0158206540daac033785cdc68b7150baa9a85c8b37f6491b713617e03cd8449e7bfc9d841db2858a73aa897c8b08443c96769c9e00d2015e94f79c3d51d7ac46db7e1f1a8357b8c598c2c6619cb12242fd267e4740a4cdd4d87b51dfa768a1705948b4776d8d22b0c44c52b70b5569b3e4f11338a125279c2537452418acd20f68272fbd67368d727fd5ee711bf1263feea6fd7dbcd067a7f18c80be762f283bb359989014e6799fce8b6d66140c66da894bc3dabbead1d735430249a6060c0c6956c123b663ef6c65509e1e0bd83c4ca9608f68e2fa839ac7a54a39a0bf3e21d80cab2243ad58f3733c4efe910d2b23e9e7b5c2501738f67ea801ea76e56e318f286df38e7529494765a3bb1086b1d902baf8b8201f02e58423932944047bd52535d2427033a8cfb81a88a8a322a4171594e8751161e11037a57103c5384a242c3497ee1f7f30fa868bfda2de2009d8204ba2515f2a0cffad87507c0cca8f1dea3b5aa94630dbf9a3bd725b49dc01602100ef982d3df5580d03e829f34663ca10fdbdcc2624e7c7822fb4d32673681181404b10e69ceba2eeeb571f9db79c831e5f82ea0c77a85de58f09b33c7005707a83022debec9659a67d4991e7b723280a667a498002c97263955fcdb227bb7d48bccc944cdf36e7d244d730a8ce30d484f84af28ed6f32e11e1d07a52386ea6024f34bbd298031f983e87dd332e3042bc52787243bb80df11d83d083a80d3d4b82d5eb81fb6691f5c9106628e03074a6be0dcd0c714980972c07c60c0d0aa738c0f098a041b8d30f477d36c2cbf5f05faa538a981123423d32b2709b76094a00880e043f4909c92f8d2897898aea9466b445f23b1087980db7e404605413f74015fd436a64e4c366f792cb097b970d9b50c5d279350b0ce2f5dc58a41ac464b163a2e560f2bd919c8826676fbf3d901675e27032554ee275542f7410bffc9bb59759c68bf33136424f39fd0a471731d26f63ef71e37db9c95dc639f30433d0d0f3a1750304370b1fa9271b59fa9d67aa832142b09de7d2270136dd8b9fe070e26831722bcede6f4737fc46c3f33de4cb6b9e7d97c3a36e9e6de381f3114587b496f018a246589caafa16c08f9b70409e96f9331be1667b795619e8e2495563fb3631c6c63b24d6db481fe84bf7d23a75bec26062a07235cd9df83e987caa2c14eedb05a193512db6ce9c31828d2f483c129ddb8363caff21180f655490809ca5c9ce41933e5519fa1d9d88613e49af95d36ae18364688a8442783a6da4483b34bf843facdb006ea21bca55c1e0677812235c65de42362f24d093d72918a3cfe0a5f963286e5bd9c0187d58ddfd79d1ab5b652a260ee23377da1c8913ca63b01fabac602152869a875d032d2c18b6c29126b049851895273853c08cbc02e7e0332ad55bd3baafa08c0426399853c230c08369f7223a05ae5e9ea3b4e615f75d9a5a02f24829a9635ad5ceddf60b703b6df81286a53aa5d31fded927a846b6650ebd86438eb649abdd8ea81a68f0bfabbb8f1275a33a5260c7c5ea041348aef84f3cf19676748aa45531a71ccb506f957d6b7037bf41ca5b7ae3ba182d6f6056d5a5b3504032bac6d16a1677e03b4e5046548673b52988fb60107a756a004d04d00ddc930526cfb5e8688f2eb87fb15e4863628699cde2190120a401aba2e1c8b9811feeb78969b03a76406e984be5276fd7517c0e4069f23a660f327678c6b2f6d342e10b351c784212e0902831ec765f0b22f83b01fe0bb631db4f155144ee9d0d7e19be132d78d7ae23bbc60ab33d5abea7b5740230ec622cbbf334d9c27113fedf3aa87d2357fc88badd979905060bc815c026b90ec3281e90e5a61839c9af58d3b0c5c90dcd0c31c73ec13298e0f04c90c25b4d0c309300929dc4e6fd175c98d5031c7702843e0b22aa388b12fb853afccb89952abca314bafb8eac1650e60d1ace1d612988384440949fc872a15e6a3d76cffb05ae664c4ca95be2b84ae3efb405a6a9bd2fa7f009a7c3841c8d45bb9dfe1c66357842b2d3a74078d8443e252e842e1b1a00100f3648c7666a3303f6431dc642dbee34fc69d7ec2c02a5c9bcc7bd3be0718e3eb98452111aff869eda8b9bb961dafe76824cc432535a8e297fe750bb171b22f05bc57fe6087145b59582ad184452b03de70e43f7f4a18fca31726bbd4640021a2fcd49c5000ddf3ce7b11f95214d374cdc0a526be35b604639593f3fb6bbc390e141f136f74789cbcbe2591f33ba50a20ff2132bb242b8948ad5eb0e0064f816dca83758dc0944e36c9253e30dd4839ed606eff84752119446833cd19ffd8fc5b601bf63725f954a033febe58c8bf432d239927d2a2f8c042e47ffe243350615be9e42e75541b7796d9858c422826e87453c22caca598acad07b0beb92cc2209b326dc23f9c9f152f117e0c4fb63156f43a4b4fd8e2abe2f846e855ebc05157ef4e6feea3d55d3926d5b7147c6a9b360baa962dc7f937a0ffe9d195b57ed00e205ab101fb623333d3265ff33342300c6e8dfb7c1b49a7a541914ecf079cb17c18ec37078575a71b1c3cb2b4ccf8ca2328bff6596053083029d3c6ff822dc9939191e98349bafa19901860ceae999a140bdfbefb9abd303ae6f8103673a98efe7c66f75d4f6f34898afcc6e2b5fb764f115072c3399ef4075bda9c13209db96b3251e66c4acc3de6d95e049f16d22f02ef09e32ce1c59f8056fadddad87ee44427c231b8d90e3a82242eefcc4de6e89bb1e846e4ea189ac921cc637ab6afc8f294b6b202b5178d380078a38dd84822ea928ceccff3a9ba1b35f53cf7d5ea19c5b72d54037f1891619201205b2c1fd1bd5051f0317a2614a4280b3214e09e923dd0287d2b3d0930ebece31e9e6e2bb19073a0eb6bb50c8148ded740d1819b21aebdacad9acf06433a05b3c6cd8e2f91ee13f08140854a5619f225e29a133ed38637115a82ce115093c8792e19461b75235d42db677cfeab71d62310b63df379c72b70b119ddac2e89c8d9c85580ebfa98e45267b210b0eabd46176aabd3a0524f419d78f5f5236ab5befd1035e7eaa5f7e7f0108ecaf7fb88d6f08959cf49b535e5f03f60d81562272857cad301a8ef6e387a2a329b7c889c21abb6bd3e75b959cc1d7dce537796b6ad05380bb4a12c9909476d5e6a1cc815b616104b811f07abfb99f792355cde0f3bda2fe31b36f87008adda3f2ebae9bd1f5da52fba5c8938168f57d474e05d3734002558cebdd793954a95ba176491cd94765cc0f21cd7c138f8d33f1b0d4ad205e11a265d96de25e87fb0050f27767c4faaa3586226eec0ed4b64773eeadc92c840bba3a38c1c7a8b28fc8de440ac787f427cb17d1668c135d2cdf162f0a8b002552464dc10581ac010b271309c282c6533783289fc611b9713d25af8d141e2b609918441a0992502899a56eb7a3d737cee763c73d7aa886f24a67aca5eab55fcfc23fbad18ac79c40c39f3d6356b1b6ac5fa725dc6c2fe4016ff59ffe4c59dc1dde8c018072e0682a17710ef1d7367f6a8787177ff11c98b42a97e5f1bf69ece705c9a40482a1c1a0b96c28cf4168288e72a5008bdf63773f146a23913e5761f548c05dc51a3d6a1ce3ee117971927892548b1356f5f706ab250b693dd60806b4b791f45ea7027c88d337ac0991a192d2927e25130ec5d8271bea18543ce0538165838502bcaf306bf285006f64d81f93afe212a906ad194b0762bab0e462c4d07245d7e9c0ddfe406d2d61f072033caf5169e300ae075c973bfe6848824c84be2faa2f0ae4769e7d27dca51ef8ac5530748662909d398d7a5170224ca214bdd88177bec7430170364ae9d8b7e79d02f39013913a6992a781039af33fdac80a88bccada5bb12922bd2a3da7f8d9d22a5cd83daa6828966549ff8cfc9ecdae7bcd5830ded1995e32d3c863b992e6981eef1823d4abe48a232ad0efcd7cd65b23cc193fb49a102cbf2cc5adbf9f9304a6f71e9830e5e649ce7d0c6b7d8410f88787df2f650c90cdd1f80688975f768d20a289fc0ca610d071d2457a3cc226d3bf8ef7c680bf267b58ec3fa67cb20921675415ad737f408eb2807e367ef4a894a84b9c42b0370e9199e2eb402b4d37eebc7f6c43ddd25aac3d8759b3558b665c6870b8dce9f39f2e98f63793481982228905078c61b81e12946a900f3771486d9d3803ca62e08113c442d5f2e2ffab752469f1071f9d9617d3b69d322c4645cb3c5705e928aaedb54d4fe221e3babd8963d76cc1badfa17bd840db9c9007da7871ea04ba992a6e9b02f12e4ca54d944120834824ce10ee8b3c81ddd75ba17b3e0fc854ca735ffe78a044e22e6a663f8fcb11e5144fb9028b02ce4150b9ea3a7c40a80ae2ecbb7dd12dc79ed2562860f4d08fc79b17729406dccf6c933df57aea0419be034150230280f0abc941923a753c8738b337c60ed698d7709dfe83b256d1f25ff737b75f3d6c4a1d054df5246f55414ae0ab515205fd69dacaedee30157ec021a18e63c96158704e3657b1504f7e3de7bc34b056b0b18f832a9c6350c7d2589931d69358bed6ae19b9f4e3185cd6513f2730233f3bc98464b945676d5406673a74949ae58519441a0e96a2c529f13c292ad09db8b3d84edeee73b385b73a83d70975902f301d80ddfc183e116e55708b2b6c53d3df8e0eede47cc0e36597b6a7979c99e77b4e01e8aa40171b9fec3a918d5ace7affba4cc94ef72b052ef49a8be3ddd2556476f4ae5c9d5f3d03e46f50528c12fd92a203ef0ac95ba6510657fe278189216b16087f2e27de1e10453afab3da10f31662cc34dc21e04bc0d0e464a8c303d21ec947f0bf7384b31118ad456bfa69e53bb850f2d2ef833b8e008bd58b51ac8cd2b02ecccef94adabef5dba35cd297ea2dfb586ce7b926dfac85ab0700e88809bdbb6c5985635c5148ea60f0669048c0e5b59b5eec770c30d80832c0ed3ab52642df17d51705725b4e44782427859a23046301ac0e734f42c7cc3d5480c92e8065f507e45de8a6b229a0959f010c00aae0bc11478b39e021ea4cc244c49a85a310f9562991d3f90a594898449c439b2974b6f5019174e0714e1b8fd8740b9a1c114efaccf4ad38f5d2ecb7a44a400c578d9575f96b1f5aa7a089cf36c245176dd98dc5662988291fc85961ef01577b2a047992f9a6184e6a47685de17c5aed9db3cbb94e22a8ae7f3c51f1216ed45cb76069c96a9f583a98d7c80bfa8687db9d32f1a4fa123e9b3ec2d403238b53ac084073ece13bd5934a3477fce7a527a542714437570e7e4cdfbf33097098d203388380c929f38033042053c79894493aca4c826604be39c0e43638b80c0614e94e192eea10474650015b5676412bcf493306e80d0d090f20d3563b92ce7922626729a1374f3035f4480430a17d1cf072705d429693171424c95dca63a1bd4b81b910b78df636dd6406c61092467edee709f10c1b639c5f4d135e637ddc2a4d142c6edb7e2edb001a310df9bf5acd5adc2139dace5274f9c4504307aa6ae0e99f535514b9928d650f7881cc9e4a5d92909eca4b327a8075eda52bfec3485aeacfc634b5d731cbf1a9ef8cd5734dd345906f9a879072a3c2179c5b605f11d397c587bd88714c9b7b4a7d86cb8202ef7ccfa834ec4ae3e34df579c5fdd8e9e830531aebee109904372cc593d1eb6653c1a0dcc3855dac61d90d61eb39ca0dd9930c620644794351a059505be3408ddb6881537960ba78fa093872b7b525e16a5eee9056216e17f1dd8af43972277aa42ac00081cf3b65f8d56cfba0ad32701c4fc83d1d4a18fc00c33dd95d4d3f4347ea9a80782dcc4275de6c3ce61f8b05518c92155624d2239ec83559d328482d768f852979477f25e4ae653fa5d3098c025c05345c37bba4a1ef63a969c4a911a2b8ca80aafd9836c13594ef0bf956c503944102dadcdd5f5c400e4a4e07eacb54ade2ce21c99a1dd200556dae4a0088284a2da599304442741ddeba9161f6888ed825d9ba68bef67fe27dd49cd87140c14227e9a694b9b909800295adea2e5b0bff8972b90238b76d12136c42f6de52a624a59432e905f905ae05dddddd5ed39cbcd65a6badded5d65a6badb5d5ddddddb55d78adb5d65a6badb5adb5d6daeeeeeeaed57677775bdbddddddb6d6eeeeeeb6bdaa724bad5dadf55aabbbbbbbd75abdf6c9a37b77f78b0362adb5dddddd5d5dc9c99520fa3252192a3921011322f9fb9d4d06952953acb5d65a5bddbdbbbbbbbb6bedeeeeee6e6badb5b6bbbbbbbb6bedee361060010b63bcd010c4081992d8542001990f6050c006082426c0545a6bf51f2345caa0a939b1e608161289ad091e59fc60431624564a70645665a8acd617e9d452fa4536abe5eeeededdeeeeeedded947e91f48bbbbb7b77bbbbbb77b753faa5dbddbbbbbbddbdbf7cf94229a5d4d62a04c6054ba610d1421368bec850424325a3f2f73b76e78ab75b6ca79b65bde00e44537a59f7eb5432c214570c5139e28c10258e784208284896b01266861b4cb0048a114f94929a8e98e2e5b6dcd2850b1798650d129b2955646982052e4c45b51a416120f2c293305ca65059a1b6b4e403143adc9045992374c8626967830561bd6badd5b6b7f7b51d7e75bffdae6ddbeeb66e9be89aabd52ad52ddee170945305831a8c68b1c2110c257841902d5582aa5861a786988d8ba1898eb3b6a8d6aa2557a22ed5b6556dee6eadbbbb7b6d6bdddddd6badb5d6eaddb5d65a6badb6bbd65a6badedd5be706a4f406dadbbbb7badb5d66aadb35aee2ee35f3940bcd65a6badd5b2da8fb8bb1315a9d67aadd55f40592d233744819a42b5d65a6b4d014a5e56cbba5dc2651561add5dd366a088916549429b20609129158cd12031431d4dabddd5fa8d59bcad860486f3bba3bb74de1167675d63604b76eebd6ba059a5cb7cbc2b28598bc6588658b23f2775f4cc70305ec90365b9228b61b2698e87a30e176b5d0dddd8ba836a8abb66e5cf783957cca10cb0f32252ead0d27112e56442005113b9cc08919641154d4a800439b760b11c0972b4660c4941da86801162a90b237e532543ae304106ac0d02364947870410c18144c09baa2268b9a265be566a8b4066887b37573622dde64a8ac160dde144d0db259ada6686c90d4ddddbdbbdddddd6ba5686e9093524abbbbbb29a5b41b07092d9a28325e965007552419a3a4c4c90a4792a490620d4d698d2c6f192aadd9b283825a6bad4b80e45abda3925a4665a8a4c4892b91f8ea318d1210ea9e86cb9024869c08722f2b0d1599cbdffd0ed2c9e92f1c6009262740b2a187362ec45c12911d8d11d99bae32549ac24cee325452134497d4b6b68915d95aebcab63681e2eabc36b7d65a5bdbdb2b7d012f05e2ddb568c6796bc36eadb5454e64eb5bb2b5d67e770bd1e53cad9b146badb5761b628b96c8d6da221ab2b5d6fe9645b64f57d65a6badadb5bb6b376d624a9190259e68c10d25a8e18c135ed39cdcddddddddddbbdbddddbdbb9dccc561b5987071d1ddddddddddedeeb5bbbb0909727b5b2643a0acb5d6d625b44910d59d490e2b777777777777f7ee767777f7ee767777f7ee766f26339c50ac568703e744cb904f94278a00cd9c2c5519620d501725e94e2b27448a84a03a562bb1d61e205b273354778245b6b6372faaedb7eeeeeecd5a6bed13d9568f0188555b6b6ddd8c5e5448ed09e87677d77203e9ee188872777777370cdd35c88c492293a1411a8ab595dc444f72887ce85c8068d2244d0104509228468450620294068a8e2188d553487777576aa4bbdbeb0b50d4daba240a94cfeee61a4877b7d72ad4ddddedee6d851035e92472e46575931260b0640894b5d6491a0a5cb1018921e20a22110c9122083923b7e6053ac8637fa805e0e866db4c982468b9b613804a8104983523e80da238020c9120c6c0e8992e48cc90437d99599af1f0c47af48c962f5a8c741ab06a49479c2068cb80a219c2044f4c5173cc04e1a50d191c0caaa8e2a505311ccb053d745942c572909ee1814b1426dbbcb556eb8e26523142885cfb8a0b371156ebae26eeb0a4e4ed52441d94c6580dba5814262cbe0774ecc861820d11e44bee503136a498f836fe8ddf8afff15ff177e27f207922538e6f23be08f173c425727c1df177c447218ec931b6b1f4855aeb14304c8982872d699894d002041b15b0325462d3c5063a77fc039287e6f0a60993d75361a74d18764520c6eebb4ab8efde347b6ad7346f7bd38cf8fb549337e59e4a9330f927168c7e1cfcc9e060c39f0799267b7652f8f3e0c5c1cb8041f11859c7348cc98fce2db99f6caa5b6801148292db4f2fae7fdfcee0d27349eeb7d1fc3f679249b3a7be7cd92497668f9d4d7b97f02791706bcada8cdd3f79dd46db9ab2a44104702809c81c9b6cc2b6a40d294bee28251463a494522e8708d96089b420b2dc9a78c86636daecb1441326bbd423d95aedcedaecd95aad9910d1ecd9685b0ae3e0d667892470611298a6fc22c3a4992c77f234c5dcafa7e7c201941d2877f374bd4d68f6dcbf783b9a30a9faaf75127a2155ab75baf76e1bad36aba9d0e3664e0758a303186effcdb7fdf6f56deaa7a702cab648bee4649ad8ce7e6689ac917cf558a48f5323dfda7b5b2d24896443da30f2256bb387532361f225279b30f9add7efbc3ed869fa24522c2ecd9868b29625773461d232d999107696a5ab84fba73fe11faabf0f63ddf57eb070fafb3e2e7695a0fafb17ffe05ef530e6e3f4dc4b548ed343540e7f1b52e54d715d967cc9a758ae448a0f2fce7347383891467abd9f58a4f8fbf85d600df9dfcc46cc2839a66d8bfb359468245ff2af3763980bc1ed9f7f39a0cb1d71b2d9f31393cf21713388809825c51f17f1c72d65f9d773a609a34d4f85f83d6ce672e0a2c01a40f793484812893b823590dc6f3b72324e73268fd6bc2ef2881a4868c2b6a369edbd3bdf76941dd3269d1da119a5740bb79f3e17317734745d2d18f225bf96149256b2a44bb0867cee85fb714754ce5ebe8edcf8dfe34410cc1fca6dc0033dc917dd617a3c5859763cf2fcf63e56cbe55f4be6caffac91dbfd3417b99fe5c1caf0af09bc647181284fa638e4424cd251ef93b31fb22c2d8d49088a50518b0543be6294360af1a03b5cf936a6f578b08a047d11a8b31f03dfa0484341de91574899fc4d2621639a8884099294e3cf31b32947339c0b1768f6d8091b7255e871f3644209d841d43284286b19329424c7efba3eb1baddbd568902c14eda006badb5d65a6bed5413e3064da178d6e48b8d34407c59e6c69f4c92678ce48934c9f3b38ce48914e3138432c618e5cb7b217cbdbe9865a63ff3449dda5cfaf6690366a6df758abe0d09610d4b9f0b924965cae4ca92afa006c8f79f35c9e3f87242deb5213921777b2ec8fdf14523086bc8c7f66d48296759629f4fcefc87ec9333ae851b69f983ddc7d7018ac08c75587eb096bf0834ef67310f39d35193e1ff55c17f03316f5885edbbcd0b2166086b506ef3b295f379c8596e0ca1e4895138b5b93fc7c8d79d3d7105088b3fa485244620aa74270d4fa62d17042ee8420a9403d4f5f4472c5a00253921c6187378c927ebd656d942961c3f0ac524b227358485991c1f463639361016466a4142f2178bc89808114b5015393e0992c7796616810875c38dd4902d2061f13916ee072103644057c0a42b5618390dddc380917541b8f205ff67c6589b0980f395e1d7ca70e727f6dd321152ac42cca71c51f6862ba194914e216772d6c95a00bad99e21892d4e5832ccb468d11b149940cb0a2c8c062e5a8aa82f254a5a767862bda32c5a821071ff044b96329d06ac264464e1b26540a358a9618a9a73594a80c852840c0e06517e28c2092a96a361044564a132a50825453960b102005962c48854400fe24fac69734304e7eeee5264f720b5257ce86a915abb1aad7604e710cd165838a112459224552841afd49a64cff04a2d098d3374181305c9102149ec90a48a20a66a6badb548123422d0ac40288827311793dd565babadb6565b6d3581db3427b7d6d65aabb5f57ab35a6eed10a85997545a6db5d65a6badb5b6566badb5d6ba7777bbb5d65a6bbbbbdb7a3d4556ab1b0826433b1b16b2c3591a7d335364c5a25b5be19c56a766c0acea46a935a2812d8e9ab6988162ca10288082e64875332cb8d57a0775779b11ca4d2bad94ca6a664d4ebdac3e4364e5547677cf90d39745cff4b0721aab0cd9dddd4d5de9c8649d3941ee7b8606e4f6cb503a7346a7a99392821c96285103ed4b123266447002ee548fb823f142162ba8e24252192b310fe3e44b931b1a35843691a1d6eeeeea356bad0d10f7a0d9b1093847951be3ea63e7e2efdf789f8bbfc969e9b45ebcc8d1f1be9ffce25daceae905e631f34a55bb2afcde7fff571876ddbcf1bed4dffcf5bed4df8fe6a6aa87afd2f9f6befefbd0fb1af79019fe8de7e30f7387f3d0fb6e9f729f326caac27d5fbc0b2f85995b3e29f8c8ad87f9c6bbafe3a53033c43ef5617e91f278f4c8f57aae1bf7fbaf3de1e02f669c9b7781f310fbac60f7c7e3a482de571fe775cc1e79f3fed283127683f33157d40d99af8e098bdf7ff3abefd7317ba2d1f63aa22a55ff7af5713c1d29fcf9ac56d7fbe0df1e2dcc63e6faab97a81b5d76adbe95bf55ca67f550a26eacf0c77a1f0c1e3e7c49933c10fb6cafb23df2f6d0e9b765f859f8292c993c1ff82aa83ac1d8c1f7a383ef03193efc7e32f4be2da75458d256de87425e559c4f7d073d1fd5cb8c63435061ffcde24fc7eae52bf59d4aa56a2a27afbcefe62fe7592c181f5120b8a00ef93a41bea2fbbfa87f531f46148e9877dc3cfef06bf0e2bbef3dc4dfbf06aaf757dd583d84aaededabda85836f6c18ca97eaadeae1f7afbc6ffb9c77c0fdd4db900f50a9be1fc6bfca5bfdeafd55de8742567d4441006257eae15b57ea37ec4ae11b50be50c82864f8db03c0faaff0a98aebb80785f116fbdc4f619f17efdf83667fe87d2adc394f513858ef3f51375e608c7bcc0cdfc53bfe3c4cdfc54bd4083710d79bdadfb0fa4355bda9efa256c72afcb9f81e33d7166ebd8bb72175c817083a5fbdd66be0b968ed903c2df8107f2ebeabde0e1dd585a7c143540827e8b0540f3d9d776fdb74a0115c7d77e3f57d285f385eea6fbccfd0f1f6edc9fcf2b57a88ba31b3ea6dc81b2fe655345abd0bfcd90c819b8355d847e7ed0d1d6cdfc6dcdc832a1dcfa2903bae7c85713e1acd68dbfb701e00bf791d8859a5c23ef0ed4b140ed6db87a81bf02184b63d146ea830f4be1802fcd4db985907e733f894ed9cc7c13d68b63936661d9db731753cd66be0d19c81f7e5c8390f004fc70e773d84b803f1060699b565a836d4b47ad5cdd7b6215323508f09507dea6d17d15cb8e5284c96f94816653ddc90f16482e461b156ab15eb73be63792678391ac965b1be1f07f92acfa57a17afc2216408a83e85b9c516dd11aa22145537b451aeff0d15ee8c541fadc8a5d913346b50cce4f8f148f224c55918d913d4b2177cc9f1e318d903c318492993e347d9b4aa116244e9bc40e1e857bded3a140838c8af281c8d5ff59be7ea8fb9dfd53de4c6a368245ff5870b4780efe2bdf52acfa75f85a30095b75afd44e1a0f2b5fa2fe6d5eb78304795677fb3f8ebef40ccf671ac4ef3c0f17ac857fc179e077cc857dc215fd587bbc11aa9871e8d1da4de85e7b183948535521d3db1bcfbac0af30d065fb164922f0c3e070926e438bcefa806dc7b31780cb0a4c957845fbf3ec4ae7e98e1175d960773d778c7f340bee20e1d6a010a4ee7de87f3abae3d9c879e7d1c4ff51005310e107fa786d0c37995a77a9cefef38e8658b43f451fd2aa21ac7db10e320df4a0b7198aa873bb819aeea71fe8334198410deef220ac7eaa647b6df5eeaa1b7b9f79d70f4a7b00f942f140ef83773f5ee598fc729af1e7a2e1ceec2b1ddfcf630bb7df810fba4de3e76c187b113244ce5824f33c43a3819ba7b164486371aa5bc08254a897fe4c3dd2252b4928d82228e084bb09051063f4216c04c20202bc8d128ca87d1c83fcafca36b911b1b458921362aba2e12a8a438caa2d18445a3974c6439266388c271354e2166f8724c964c64f9f0a5377f42940922d8c01f4c587c1c8f6611976372bf0f6a19c600c1e9270310cc9f482500a683325a36de813bf303c903f3cfcf3bf1bf8348c917522c4ff20561926c8343cbf2bbf933cb323c6a4f28d7211026bf1255c9b22291d538a21b9f3b923c11bbe4d31eeec71d1d8d00f24824f892dfaa65b944cb52882cff3bd1a59defb6feb3ee5121204f354273219623b5dc5f35ca63248fcb623942cbf2a91729ad481e48264b3a26cb25f227b36429b9a3598d0214c88a226892154e3ca1b369946685494be364ab5888b82b5702c98c34d084322346ba9407a580a226a9d6ea510d37dbd2c50c0793b674d142b6c5cb931eae3b7daf29c731caa8edb9a99c948aed7f9ebf7f944dc751168f629459f8a27fe39d3c1684d1b71e85376efe7ae41068b638051f797b18a5c8d78c47b47ec5761ad1ad6bb5175c41656c986451936441d870352144aca035929084315a21698abac928162de8242a20837393349443376b5284180e459b6caca46a6980302295818c1a6101123ad1b210524555a342d6c98092a062654dd260f8526730b0e0092a95348194144962e1cb8dc964832aa012041493f9377f7829fdefd5c19e49046fad32254c1985b1cdf45a0c252a46ddb7dac95a80d2834f5ac3028446b72a85908e6202628e09a0af82fc452b793ef5b8a4fb4da21996365662cd05176ef2fc4a9f6816b58cae04a9c51c99744588cdf47294273d923c7304999724cf4b2f92c7f3fcdffebd7cfeb4fe477fc3f248bea68cca997ccdf7a158cae4eb35e59299ab0245e2ce79346593a84a9e6dfe69a3de066206e1d4e66e797ba854822819a21ab0d11a942d37892651d10c33a1c8a31ef29c4879cea43ca7973c67b71d499e2f364929b3d622a33c271195b9235f1ec8ee2785f2944292a788f4225f532ec9d7fcf9b1299a913c8f44bfd611a51547841892fc24a294ca886495a89fd69f47f5670572c5249a8d29e66620883f5576310a0b1d9cc0855a8440c99f7d0294e75b9ba7842f6362e028c7bf2d189287e5802e766a9a720f29ade41e327f7049c950ee21b3cc1c68e51e37cb9f5e076c96f847c608d4c1035c88050950864a34a8e120432c4361aa9050eb05230d2e4198047f07f63453beb4530ec880190af7aca54116a1887cc10c3353cfe46b26b3c42e1cfd65c028f7a35e4a4a2557bf839769422ce3c21c34e5a6c3a0be99a4fcd47ffd37b867cd24bfdfa77133c9d72b4af9ea99f41ae57d3c4e92c8ddbe6792274c33890069eede86ecb697de779212e57518098b8f8231886adcb3149e343c872efd6f32518ec3f176b39b5b87799c287d486dd3e4d74d3de36cb85f15a2cd9e4602c2e22b91e393c9f1a1c8f1695fa4f56c32f56c363149c974e5ebca9e458a675dd7ee2a24798a481e78a54d911cbf2265913d9106594df2821a18b68b7d1f1493be57feaad0d09022f9f320f6dddc54da208a455fac21c72f3ec9f18b36e4f83142c9312ae5f87116e5f8df2422c78f5f27e92a397efcae021100bd8481913f9804cb98f1207f30096211d4440af217937893d77ad68d94e37792266aa21c7f12419168d264ca4bb3681a4d258800ae86ebca41cb4b13166d68c16849299fc8a497f13540047046d7f5e2e0f54592c7b5e3c14eb7047222d3d9bb3ec81f34adbb897ecf249eb9ce5ed09025c7c8506986305d7a48ea3294e39f8082163452a0c42da57ab823b65af7f65bfc1a6c4ea50ac27e78551f8d54aa5a16f1885be1ba27ade0030b4318be8e003cfdf83be6cb2f21004f7fbefc21203a4423887f489074c6bfb00f1f3f3f24d0788a7d4c81ef43c6d378884980f988f1b0ff897d900663d2934fbf8419ffc23f5e3fe3855d70c6ff70c17ffd4f475f33de055d10bb224083468c87fd0f194fe34b80c5f820ad02afa7323c97c7f05c4ec373c11fc0ffc4609e0b3e8dff89cdf05cfd0178192f3d57fffc18df6d50c36bfc06cfc10b40f534bc017870c29a03af86e7ea17c0ffc436f05cfd1cfc4fcc7a24c4f8f92a2f0231503426a4a8a9c2080828e6825fe37f622ef81bfc4f6c831a70c6d3f8194f830301c05e3eec2706837970c2a4ab84187b18fb3185840d1ef630f66303ec824ffff530ec82b884d7d37f611f535c395e2f01187b61386125389b2552c820c31210500cfa1092b1d7830088de6985880f471c51e6855990ffdd19de4f8c060d6f86a7c35582fc77234633463dc92499ec84b99672fc227e6201f07e625d3c05c08313168da40e17c6160063312683a3e17e9f21bd7285240d31399db8957baada87f8bbfef95bac43be76405abf8f378eaff276c0d7215f3bfa4f487d7b3b523a76c8574442f254cc019a71fae39f2079e0471568c6c13ea9f72416a040a85241082107b08f5c7924c8577f0751f0d2d4a720ca039624a8d4eb5a0a6a102aa56600000000004317000018100a070423499044410cb3f10314800b5f984c64682a8b8822f2280c62488882180441100010600c228629c49474530300af83857cea04a3cb456cc0963ba01f9ffa5e69d823dcc75ccaeeb175839d4a7da76851f2e0ea5c4f2b3c88efdf606f1d61028e707441ba404757d3bca821479606f8a9f04dc1d3a6e4e1825680c6da973b772d44df864cf80303e9dc90c2035b10348f11e4613bcafaf7d29df2f6e143af8e5975c074da37606fd3b79f29502544ee5fd12c2fc18635d3c8c705fb662a84a4b39391d59b19b058af05d2e67769526540bf085e02a8be1bcd46eb9be41b79b23cca637f21040c510216d6a1090841fc8514325eb2e73dbfc936c3776b3ed5cf797ab76cad36aa88de3889546c0cb39ca5ba77dcd8c58359d34abc0a4d0e97448ba6540d82f3b73db21d0ced528d258a49040708eae32f9b2fb875477576897d676cb621d210e8d78463f67e851c76fdd257205e73a0a95f8ab3c563e83a23a997ae04de18c8ed9eabc7338ea809cc13456c6b00db35b188ddeb96b81c8ed735cb722e7571a3a9bafdeede1727ca07e639c8cb38cbf486140d5e9979fc59cd55f5b060d4a07b84758c59cd531fc25e2483d47cb7940f14853a56fc13f2bc44e8e77db510315c282a9442abbbf96d5f0304f4cceba82ea140494c30a6eae276cf32ea69eaaf65aee4143c56c486256eb81f93283872be5b888339be6ed55f263b543c963c58e0db21332862a3247832615d117ba35255bdf16cfaf8c0ad0f54ff852cda1a7df3a29b52b4fc02190a119aec7a95008e8848e4cfc7a2b0f39002c032a4ffe54708dc4a612ebabc5c5a51f7716023a2e881e0ce2fc6b9a96826e18eb3ec6b12ffb593d6c9d32c49059b2afd642e9a1fd2f3d1b60a499c8f8dea3c28a1a884fabfd204aafb338b96ecb4c49ffa991705e29a6c902c0ef3ded32951f012134fde04e35012f89b532e0d7305fa8a5735674880e3316c6007ee6b6480b821428c396bffd5f1b3640348ecb80aa8e53429dcd3bb6757abda078504939abf19ec167fc282462753e7cdeba959918a175c41d3bd8491cbac6e1953402b3c691709d33232923bdd22eb109a7839f120011ff6216bb3594a10e236446e14dd51db4e81534da79baa05bf9f3afc46ef0ee046719ba66c20d438f611cc7fc3911e1696a7ab061bf2ac4cf4d98cfdf31809cf11daee37a051ddb232c4a4c3591462f1603656575e2a5a46ac3881cfd20dd78f40afdde909bbbf752671e7e660880a68021244c706f81316ae3595f69cd8105be198bb6e07fc69c53e371058fda793926ce6ba1c4d870b916d5909706ea699f270a8d509466a4768e63571a0bc18105f152c4e3ca557a7682b30142aa9786169c1795c052f6c10be17e6cc476019aaf2996878b6df9fa3b9f762bdc605e622047a3cde523edd504c7ab21a4228c4fe45063df3998c064b1b7356eba6432c170d8521f48249055e28bd82a5b781f0d8f62c14be138588ef395c405f20ac4c4d99063c6c759d5f5965af104806315b2ebe82fef92a68058fa1753424d96230bb38c8a7bff3893818a8d31b3e5678ab824d67369849e069c2830bee8ae0ed1e74fb7d6b9b841dd1db820c689a43dabaa71ce3c69467de85dacae9a63f03540b325af147c94fe845b2391ca8240fb58096024070c25c7d7f1bfab1a2604a1d168fc96e852c535216828e691e5d7fd0bc1a91eb7534f6f43f295171ed262f0956b9f0e803300d5d61230d0f1a2b97d7f12711f02449b9cb75baa9105478851999065e9fb8e980b8c1804e5e6be31d2e57c2686d1ca3216461c2cc40807cf51accb8ffe8440b401ef30e05cac45550c6e58db41a4d9228ad848535ab6bd035963241b09051d12bb43a68ed403c398d7503f53c1140e00dc97674717eb19bf77a0a9d279bab86767c1072161c1ee04eac074c2a4fd5380d2b56648d6a12e87677c60a651215f15eb9ec3aaaa70cc48295ec4483228f7ee080ad1f57853300f5172c7a00222b22e808e4b1606eef27e7a489abc61d64ec70e73e81a2672e48ecca5d46097dd0512f8ed7a247624ec45f7da773a82d9818042dc046b94a18be6f9cceedc2662da43ea192317bb6220743fcd8d6abd77ba931a0cfd697122e44e8f7e3af6e650324ea95e457f9242f12c1b02f1e2588a142a4da368dabf2b27f0dc17087e2201d5304e9859c688209d9dae31bf40b80bf9f2657cf68382364955feb46ae93a5bad883b43ee90ae91a7b3541a451c92c6e8cf987c513574efca37269e98e7a7758ed515fe0e86be666c9b2a5da3665426838f2a5c013bdc18fac6541e7787d7f454d54c9f2f2223bdf46c47660c0070e00938335082cff93ddc3d5452cceb3c86da7830beb68636df9866fa73d6f254b7078928e0958e9a050bb01b25c407d58521a9c55ff1f0e589e7603f265efdcf565c95615570aeed457e43ac23bb4e01de382988a3aac33b24c22feffef4fdf3eb423d286244cd939a4844cd212aa0ffdc6aefa5698bfc1aae4de83e0ad870068cf1b492b348bef392a1a8a0873ecc115c373e6921cf05643fde241a0aacdf1f7175f2fdc9cae106e48e633b5f055459354f2967f2ac037e5bbb575dcf66216622d054ac135116e145c165959960be1e1c9715ad18221b75e04f405f6cd747f6bf01081217accf955c1255088b3df963a39069e38a2f6af90dd05f17e485f59858baee5566ebe7694b9ff346e7f983e0f33b1cd7299f8dcd9708e0af5de64691b8b09837551d07d0a2ead67a29bf83f3c21c62e03977c5bf025a8596d3c56f90cbc01c5252d96656660af2f26d7060c284fb3b9cf2261ff9125281a6bf8441abaeac8ea2907cb65d6e56e88e8e8c23692a7e8e45f6beab8dfb75047ff29309f980792a9e77e6ca91d4c780c68d7872315f84a194a6eac11b3253e00177307d51fc9f41898ae98a5dc830c3d3f8735b243c3dce9ea2f68cf98ee2b1ecb13527d5c9e1fee1bf08f0ecee15ce324adda3d70e7921bd63299553f15da1285d0ef210e9f7c23abe2c706bc2b41c2fe8ad05982a1dc99596a121c5c4392ab365aab116ad08f368fb28e6d375f01eb328edd723037d21bda501f919c00662c7ed40273d785c38fdf7a14eef1ed3790526934c065e8f772e30ac6b890c71591aaafd84b15deb4635de02a314ac92338a095dad9c35d129c71dbb9cd4f22f2cb6dd0fb8820ad1ffd4bfd50eb8203f05e3c60a6a880494997054f23afca19b7141b806e2613528b54554b218ad7988c1818ef3e391168bd52076c97182e183387f9da17a833f31738132d0739b99a5b345cd3bfe8ceff7d9045637656c62cb50651b3782ac6f28e95f5e2304c34620d14d0e942c5c4e5713e662d713244bc9c7ba1480d6b4e55df7c41339ef540331bb1c0162120aa6910b61341497823ac011d48993f31a9c9f0dab34e3dfd8663705d67376fc510de64364dfb3e2cda78d0c945f2886403a81d01086822a5c4089db5cf91b079961b10ff5948695a674c8ac067e6277272f8af11812cbfdcdbb1e110d452c44a821bebdc65124c0c6ec38966c53e72bcd4c767ffc408dca5ec9e6e8c32a04a16df81a83723350a3a9a15cdd3aaab90e9a455c88c1d76badfc156f54a13fdd95edade4a1cb5548ca9c32c924a42449db47578496655d00732c6a19b75fd9d456b1cc0d6fd27e8f951f21e71ec8fb07782385a79a6272dfe0d34794bc02714b461267b0f64994278f840837083c105d8ec23bbc6eaa7cf48166a09a711c2718164126196b646aab141be0a1fb15ca641331ace6a3f8b18996bd9e363fa3addfb4d95e571d835290cca79448b35d453a5f46ec54ce18c35728d9b1fa981050afc8ec603fc1308c37b5a4f08b25082e9b0782d1a82e114b59358b45e10f0b2a16294ff7d60a39c2b4027e101d03d1ad0e08a01028524a1b997fa96731cf61f08ad47d23bcb2500bf9814a83074bba2cfe18cc96a256e8c20bf8475b347cabba05ee901109a82b292099206a707875057ee6a5179d4e539905683c94e2306c3f9200cb2ce8b171f6e6631d4b19f0b59ea4da66c06c8f3826b5fe9a087d6f58948bf2124f185f3300ed2469a3aabcfe64c3cdf095a09f1b577e2d10acf1275b781ad3918a90d61f689fc79c7a479555bb4412f33077bad9b119ddcf0df688a9e009fd62c4ee1f61c40f59d8f6e2c51d8342a56f69cc17d5155a2f40c27d609deec3a34fd46c46149884e589de6bfd24e6d5af50e4c06a5823b29991a83b2e0fc849180011295cc5995525e0815866696be816f256ba60c89a768faf75a13a1d171493030b66b02e3b6528db46d16f856e837bb4b5700fd742fc0591f7e1a83073ab4022bed472388c64681e47af49b91d27d8805b865563e6831afd98cb6887493f9b7ee97ac541a3aeadc1ddb566493213132b08b465f0fb5dc569122883a4834187b7479206102bc7bc9d485d423c84bb2d28c94b81670757f67c49127b0185d2c17aa8dea768446319d129c51f063f5dd51d4202cbd8169a12560d0678a3f8ecdca39a5ca963d80ed98f9ff98ca5fa700508fc2154b2c77316af4d9e03b69768a235d1f6d36e04264aa55872c7cb39bef29eb9fa0ba5b716df3112f8f1296ef621a740a94c341a18b09e526a0527267d4990aaa4842f59a028a39c4b7e30a79db1e1339ccd017962187d5684c31ea0f6d50e8924781d0c43956f7296d90cb786fddd1240973ee3c90e7c744b853848065d159954d3a591b55fb83dad6615d03b40ea3c6956c7a941e7e6d589a0fa911771d8da971ae9422baa5ec77522db841ac608ac34a0c248262155de0174a98722dda80682aa5b84e7e11ab96ec03360d3f1bff1d7ac25d3d809362ce11a9f60fe5f92b399db518e9e8016d98e9d8c3d280d2992ab0f031915a2471717c13598f4ed74e8774535279061cc87a3e26a203de3cd09d7b535250946206748944fa1fd63da442d48eb7cd4de3b2857181049afa89b4cbf9394aa13b8723405a36c3870c855b6bcf38d147673fde2c85221326264a5d8c719ce866aadd31b9b018f333e04d2413615ade8befdd06ed49679569a6a833070278032413c17750e9443592ac715737d02d5f1b1e0f39d592f118406ede73e28f8044a94d3ed45bd78ab20f886021dcb38a6d86868a2407b84cf441b51c4977cfc8d23d6c3e098df69ad0ab6afcc7f0c2b0176b7831c30eca06aae26939bdc6e5340a17cc81a61367c515442cfb30676f2ac2e70feefc0377d470a9949e2f469e00bcb9a6ed19f456d9d5273902381e2123e71225b4ec1bff1b2c5929241000776bac6100171a7f6f92000eb5613168260394245d2c72b41d9e0cd8c06e9633afad8446038707d92d05c2e9b187d04d65883ae691cf661431114ae0d6161cc56fa49544a35007fe4e0fea341f82436cba0bdc2815e54b4090a92cd22e51c213348b2f54081987f0add56c7880bc5083098a8340f2a6c0dba93b784ea1a97a65d97d1986c13f012e90b2863e21f32cf65cee04112cfee317e5f0238c79698773aa70fe6094a3defd406f3cef073ee246320116a94db15252472a45276148f98ad8a4926a2cd4b01e2bbfd949abbc904819da6223890cbe9aabf2a532cf4237ffb36e391ff3be75de8abe21b1a5cb7580bbf948646cca978b7a3c99df2fd0c16d59309d68ca1228eb4c5aa03bb8a64103522cfe5787d6a866091cb84645569dbc1fc5b17d95b78960f9f630a1bd0c88b16406295d1a8ff00d765931ca098899260de7971dc3a98f28624cfdb7ece3431c2ad1be1b6c66a387c2666275ba35d4045ab823a354e6c424309a40f6d5b29e7520dba73cb3109af3f164ec9d0d93ae7b3fd8990bb1a85e2f4afcc32b1155f446a839ff7a2b91a7cb247c6590025571f7d1957d546bc82bf1cf572bbd6edfd53665262373728c26eac6f46b41d7d477161afc44e010a28cb214f447e1e58caa3a5b91aae61766ea3529ef8b9702ae1fedc840ca1dfa8b2e30089e7b502f032b6c68c61662c6adb7c1f76452c020f815b57ee48905aad9e643ed2f73328ca6c4a8d0c12d8476a6f715981e2764a1c8c633b2d0fde8232064b1a4c40045b59f5d572673693aaac99881345c6e7840f96c2e1d95694576249f17d5333927dc146b9d275af8ac4d2bb3eb8ca75ccf6f074c20e5a0ac49a992e5251683ac0856b913fdfa9f2dc0e6dc94eb06b6906ad6c038410ddbf8145fa0f78e4cb826d5d6b6d9b3db19bcfc8fd31db12c3095afa07952fee985849d50023582d9a77218d3edb1c4c57a27c3700f360e0d8f08b159924dfb33915ea23345d6c32fc0653c49c10193375161bd8515edb9baa808231e375cac1ea9bf8130d46889f9eb35c5f90095825cf16a1ff4001896f5ee0db319168fbcde615a539d0c1dde0c85a1098a204963b37b09270d824c13896228346a9517947d93c8f339255c8d04845afc3b9715e35ab9af830c9b0407af5cc47fa250a73c4898292e6849566981bb36b1b3ee54c3e2bd21f93f4ad1b46937663e097c8c32dcb27551a6cd0d8d465e4255a89010c9784abcbac062d29cba70c8e828776365a2f36e8fc9476cae019c35ac31714708a1d90eae0cc20c8f65eb8b2b44598fb0ff6346b829fcfe0332ef86cc5361ba18408c7c81abcea48900e685c112a915f57eccf6aa1c2d6f730c9879bc62dea705f604f4b33f233c5cb71b3827866ee362488629b1ca8a06a0bf5e043ab9212adf5e17f143b4610cb808aac1a451430519a1e9402a930e0a3e2d3149616e5ccd8f9844f71a678462289683cb2cca1c04100ce75a0efe1c841641bac6468c0da62012639853a29ab0b4ddafb52aea50b80b77ee9d6a8c744c1b8afa110bd199ea956af7364776add7dc65ce5538cb878389c731b3285abf8431457ee76aaf039774b9364ba9afc9e01117116296eaed9340ca4fe19b8f96b21a06b6ac896749f70385024604892da43563f09b512874f177466d2547cac9166b62a859bc11d6ee938b2263bbe87bc12e2ece00e546f4764de11918581eec1c37b5401b58c1b4ccfd9b5e2a017de8fddc942be1e12473e2bc51915829db0465134bf4b990cb865ca0e29968aa8ac5590045455c89d09f819b7d45c5521fd67286e11ec1b308c0ea973c1eec2638154e7721e0b38ef74b81514427065b1ceb30ea854dfc094637c911505e04996085ea258113cfa2e0e80ea3fa850edb83e683f2a978eee250ccfa71e77f9954f62f5741e5b6f79f1ad2de9f590a320de5b178eb36bd018d1e43c632884825ebedc4119c0a66e2009b5403f917475221767ecce48eae38f141aaf11a41e83df110c1b6142970211ffc2b18f48f121b82cc438060daf144f767f55bda0f445a16fba61b2c6b99ff84ce9c85e48aa904a3f745f9d455832714da8ef55daed0e08dce67bd6b2744031e7029ee50faa7980ed22d544500327a3a86a23805cb012a9045cc2e618c2b5d4c2ceb612eda537563f36e3cac51435551c9d61978e2f82614c5a8eee142c4d248b3dded8d9a9c264a6001a328bc988db6829e14af1d173463bda7685c965ea1d9c2b50ed2e2ede486101147a18063ac7e971152438f6e5dccbf2af9eee229611cceb42b775800b7704551c74043588129282b38796bf3d478aa05a0c92abc22864aac7a4ff6eb679540b2254966295b0c639909f1919892c4ba19438dd9c1b674162b62c19451380c3ad1a12662a7442dbd55c3c1f83f62b5aa316e6a68674a767c132cadc9dcc8e286311b987d319ea053f70276145d7f0517b51dd8c7e012816f3e4eddd47ff101cfdfe5146f92bc82aa58f785eaf315b05ff5a02b2b29514edd2d4e1a6f1c62b81fdc21815722f7c3a9fc33086e23dfeef313020d961bc381c2224ac19a307780e99ff44d984731c62d977e810169d25e0b242e4f5dcc988976c3ac2fb677825cfcc302f7586729e5c5490f3464d3cc54cd6c7e8807066f32c8eae11ea1c594427eda746f24f30175a2888457e41eed8598f9b22343bc888af4865c09eab96e4068430de46f489e82d80d5f29700a660226a334f7708be20c91758d3ee28e5fc26b9b723e57540dcb146a110d488ebd2d2ca7b0538c10b4a5dd1d479b721e4a09103d93160ded211a53846025915f923019357c9420c52bd4285730a3a200a130e6383bd565508b2649d8753c4b6c31fb1fbf83cac725d9b21d5167d440e25ccaf0f5287ca8cffbac962023df9aa038d1c64481e82ab6441bea19d627c1b25cd4489535001d5be546a5b28e0720ef9007323f6cbd92b8e2a80977994a148576b732fbc525cdb5670f1435aac356006a7b798cc8f4ad96977015b84439e61465b0a1d89315d5d7f3094574445c2e879aea138631b77ed25c89896dead1697a30133de693d6f7db0a6365db14bc0bd72bef97f8f1b0894098efcdd2e32049f90b6df9ad395cfa060058ba75a25901b2610784fbc3fdd238f51d930ec9584f7261c20b4445e44b0d8b5ea081a1043b6888b975cc895076acd80b04ba05559cbe51090b6747c95e5ed8467d4d0027920a0b77b921e4d5beaa844a056747de032bf57099a2dc032d974354af56f8da036542ce67ca14dd46c7f266b5cc02d801c0748247511403b9cdecb5a124700f074e6f174cc9739abff8e4bb2849841dc2474411a991dbc0d158aa9ffa8c10098fe5d5e6cbd907a00668c703da4ea332ea3676ef1d97804237d2f43af6405de7f66c31df396ae758b15b77617395a1ff19c713d764054da60135ea37e0a3b82525728f54d03a7bdd0d718aa856de3f6fe208814c744d662409bab5aaacfba6630ca9d555da4c79a0d3529bc491c91d0f59b8ee5f524c6c19a9116df0c44fa65e2db8b4560371d4a47e5d1f851cc3b93503db0e0c9ae03b5400a7a5a418581fb6772499dd1ce7903c0ef50c56276de18f402c2c1292cafe8b7a1d05f052e37f6a67225e4340e83b93520d83308b1661f0112ac57fc2c30b9e7b29bc4f654fe143a4bba070a95e37da4c8f69814ce9e0c6dab3d96170638d8014b0dfcbe0d2ed106317028e3cc53497fb915daccb00dd608329d463e8602d8fbcd966187a620ab86a81938fcedb68d021633bdcceb5953786395060e4c3281015837c9fc7afe38ffac0287ac1b902cf46f2fe8479a998f7054e9e0dd55e66bbb5bd176ee8a73b985db592fa8d9ab042fc12bf2c7420420ef747602fb57b8f3e5bdb80a7f19b3f5e4e80a5c036a9122b5102c3a0a44e190a11bb114b4555f130569dc362b788076abf4129baa7b1b4ca09d13714f2135a315bda0384d3a4b8579295aff209e3ed62a0d310672d1f8d2264587d24e063cf0fbfb64e5ed03661285b9a834bd631e604c52a02bde36466edd3107e030905d2704e41ba73712bd2c4c9999706c2fe636e80ebfd01f6b9b0a97722b9c6ac94d6310b5e40200f48429b05b47ed40a448e5f296ffa5e967bd53f29a9fa81d05219d9d481d509a5106cdf31dbb21d9609d5053551585d4547acd65b342dda20a018f331bd78235d75352c1d01268dc915adce6c345758333bbd26cac6db7c454c2bf92612a54b88a50c2ba2311c2852af34c253166095e820574fe8a60bbcfccd50e08296840d975ab3bbb7a6da4be958e0ac43ed06a44487cf26f3b6181dd5ebc50bca5aa16e46ea77ef995eab1130ca74d53d4d4907bf38d88a634be4909870843990b1d3080500c48672018c30f22f286e2baef4f4266ca2f552b454a9a9d96a0eb08c68d82e6039e9a818b4423183feb7a579a02c79458d928b2fa3996c47a5e831c6a9485f63613fd22e1a2606ec9aa1c80ca91a0666704e5ce032add51d0243c464726059512519bd311846e2d9c8469b2f36e9ce5fa93c72b2b0aa4c07ac23fbd0d430afa8909c0e8de24810baac5d5d35040b65a076f636e990f019c23dea239846d3cbd998354486ae70e6506caade39c8234a0e94ddd0541e15626624063ec6dcd26dbad157ef580e696bbf1d3e0327c170cdf0c54b4e7789662dfb301f8de56f9254ea8094e5600351ce9b80af920d611c78ecc9fb258a19cde71b5fc57b29aecfacd690bc26cd51d66f14f06ed8981ccff9284ace5a4bc1bdfe342bc9e820811beab6ae0e44d4640ba13b0928f3d0c8f11efc1e769998e31ea27663a1bd0e4d29e57e664adc02e7e2096962e8f04c9ebaa73950a1e4725d4f2064d3c79c19012ed22f63acccb60a7b3dd4e03ed5a13f940f35e83a04df46da5d5c460eb4e1c8d74e8b229a63d40b9ca87c470f591bf522fe6c90815f9d281c1b8888367de3c5560732cf53d28effff012c3de9ed8e938d9de2d0fd524e153e25d49195b8ca38bb1e7dd1cdf115daecd79bdf844fd878004f8a8796bd999df8fb9993632b8cb3bdd4a76b76e3f64084717e524e72cb2c73d53a077add03bf66a09ced77e97aff5307290e82bd93a91c0aa732c57c0980c82104a5d4543d80a96e73384acaf942d2a06f76d5d43106f168a636928552b0ba691bfc2ddff3ae924cd9586407c53956a5720a6da823f28af71574375a077015162b671a25315a4e5a85a9baf68358f00f803e1ab0e78aee205fae167b92e650a15800dfeefc2cf451f13339a0fb2743592baef681dfe2c22504a5dce9b8b56fc60474b916585ffbab816ee4001b613bca1b5d0b9d44ce570b0965c12be0d18e4f4ac2482f72facd0a50cbc18aba2e3b16a8813781d26ff610fe1ebee053b1a31353641348fccd3ee1afc3173e7c1d79972ede8f65312c5c2bad63897af049a450e6577d5575e8c5d251d42fab2e4f960b72c2a8d601fd0a75642e9097985ff6b04a4bcdbfbc4b0cfe0182693a32a6971ab2a814e91f17bff43cdafb6bc4681b942f731dbc98a2572f979999c456d6d18324e26429d4e3533fce1d32572e0ad17b3384c7bcf95da804a0bd550e2da82c7c8ee60c06f71978585f944e2580265f8710b28173ed2e14febc0a164b9747ca9b5760dd464a05ad8b7348dd938818ba4213ae661c70f1735b6e795888efb685749122caa22f6731729a18cefe2fc1c387c2b53528660493f5190059236aca2a5285d340fbf8630c211c352002e68adf5f5b818c2874dedec9ca5fd2e251934c9da61722dd7de70ae07707c0fb85e86222a61edbc952cc7205286e600a74a6c5885225097e10539bd80de808a904f2c014fec09eee5cb4005b1873ef5ae6eedfce81ea8e4c0ff8eb3085bdc86788fa3c2ebb92a1e0e57f558a39302fad7daa9095e49101a118c3b0051be242c1874e73a108cbb285dc42d290416b1d1001dc82172e34f50f8b0513898180fb5619303e91f345a7f99309c681b5765e222740d0bc7f0154cb02542503682fc122bbd2640c611bf7de35d7c36de029518d4f46501fd6a9288aa32a6eaacabfe23a01950ecb2a7a65a0ce60d090464a9a42716dd83e9fc7ca715f2005fb69213c1a6bf03eb7a6b5b4e774eb3ef6f7a26f65316b84da15ef40980c076f018c42e0d6599eacfc183e9e9e85bc29f6aa392d148cf7f3114d1c5f346688093c50cad0e27e99204d39b38a0d24bc136822241c2312694ebc0194bf7a2dd7e42b05c456971c8c012989f24721b17c71cf903a678061c632443d9baa9153acd409d221c326169055f59dd91c8de9410e75938823bb40d5d49d0f1e6bfa34fccf47255f962dd1cf5db5d2ad5c92a790346acc72d20700c99d15a42e33c45f964da05480d6acbb9f490aa278a406d89b5bac8f15ad31526bfdda4c51bf74761e86fc5a4062b057ace4c95bbecfe9fc790849e4c443bf607a71477ca3f9c51f44fc91b449a7742e10019d61b0180e6631b1c886d7fb0e15bbee0c32a11d2cc4ce7e2cbe56f3c30a9ed177f4b46eef0027241c603def68813bd203fed2492cc2853a254d9aed8a2e8c0b48796f65d69121e5fee7b74946af9f65bfddc595984fbbe95425476cbf46c746e5a45cc11c31f4442ca2bc596047d7a81734695b92552a635b46aa45730d09ac3bcf0bfca7fc6da30e07e4901628b14608277048bceb55eef505c97bb97723322d04bd20f9f0856be08146e60d048d71c88fa2a7f026ada6e70d81fc945e6bdff737a6df1cf81baf9ba5f4c7db25a3de66f1d6e336f0aca13308bb8eade10e7358d28546c0cbfeb6503bc5d750b64ea08b4f11f0532a59187726025abd3bab9b06223e625a7eb8a757f26edc7a916c2bc7431c0266d83e896e5da5500c6a17f988fdc5ac4d5e5fc97a52406326c26b5dfdf893ab7c54d1c2d8888d9f82402ffcae1e9644cee438617984c25bf38ef9add7a65c2f998cc81a04daa4472456b6a9ecb84dbf1259bd51e8f45e967634c09a22647aa5cc85a0c4b942db7d8f21d0370ff75fe0873418ca5cdbcbb842ca8728160c2f1fa07a9057af1902ed82b0d6e36b554402f3d907d03cded84e7df7fa381068f61c15b0ccb833648dc1fce5a72a010151f8a8084d22d077625d931e170ac7b2604c8395c606e07009e5004d758c47f286a4415dbeb95ae563fe4be599c14800a4e6c564b3e9d6682684b5527f9a4b8b259ccdfb087236b2f344da5508c586350cae18fafca46d74fb3e8098e4baf46417fd64d7a6e6f33c025c91593b0d551342bff2a1b1438601bf87489e7ed82d54a9e6407db736a3c751887ff7ee5a11892fcfaf5fa9ee1f92e0ec7bc8b5801fb16a7acaaf9128dcb24362c8c35a85b1afbab236a77ecf53f1c773cd61d749cef1389bf8c6e1e19efbaedb21fd43ce44ad78ba625885f1f08d9699912dcfd13edd5b0d25bb95cfe2e1064b32fcbe376587bef37d255aaba8482dd8dc9cb1f80d490715fa406f0e16e5376538c2de00b90972398031f1e8ee8926dca055fe266c10202301af28b1623fe73b0fbaa66700a069bf4c5cfc214cc3613fae04df1bcca899d726dd4270a2a464804b6d8a108ec5b49d4ccf6de2a1ee0953afd4dd87ff3dada90856a0b76be0e1ed942760ace30df6ebbf2611031cf52942265018a9b20c3c32ac55af78310450759dfad70a64061b5e092cbc4f55daa1ea2fa0787f453d60c0a06a50ee3e00ec575a55445c77a732ccc0d2144f585cbddda7fe62c11ef71a74bd807e95c32e231698d218780177050532f073d805902dca29ee37f55c68fe0d6ecd5a6e004565c2f5f2bc7616f71483dccbeedf5dfe5f9b7a6f0834dc8e95849b700b354855d1a834318d1713cce83e209221950d362af1a361c3b1cfa05408c01cc5ab368592661062be53b696da4dfb73f9b3bed3e49b0f0cd282c8a7dbaf2bc0f9cf6326b814f0a062366946caa290221af8dbfd647e8765aee6869cbf74bf8807fb4285339976f5c8b92f5043b81f85e8f4ca80b9d4f89b9d839adba0a27bb9d41e2e086bfe781c0a6603f16d4fa83026d2ae1e397705a085db8a6a62b9c20eb7856976aefb84e35798145a22039582c7707079cf28212dc0964f5206d55b68697ac68002274400bf0c4e009cff49ea5846b41636224fbed0b048a8553b3b60acd894d06a90e08e0297a427f2b15213eca19435f7617545cd5c9517e800dbe7677dedd27ce2e9cd387603a4fb011fb8af8a28af6b91b651071716d4813a2609c4aed8f4ed4ae0954cf765196b7b7f6abda07f069d0cadcfb77dd6cc6ce3b7d9cf3910890e4dba858e4051fae7f818d0067c4b2f757c559fc3f6dfd3de61ac4e5a24458a9c41c88d2c059a5a0620350190aa46d4a01b2135ce6d4d09cb73d720a42b6cf627f48ee4b88add389cc69d45d98e344c119d974059a5d32cb89a39e3b1ccd86660184fc905ae800ab73c3917bcfa156db8123dd13ac6af56f72fb828333e5f8f31c9b5552c1c101e9fd7dbfa37611a232336be2dc7a91a6434bb1e8bb296249e11af4bdf5c11924a1e753c9e36559d8fe32b940bbbd1ee831c9c5956a97d3b3098212079599415261ab8ff75f3165ae4a3fb5895bb52544a39996d2bcada8c9393f9af64983ea2a2dccee5295894e52dafe145c20a1f4d47780e23f20cca8805a2aa56eee959db516693789ef5a3ec6e90b8d246900cc92887a4003f6806445cd00661351b9a561dd517be0908e44f311b3707bd04cbf87b1ef2538a61e1a9000e7e1a519f19a1c02b97b937c840b984efddabe130d4568c8043d86f4e624d61a1be9b7f34565c54fbcedcc791c5305a3ca36c67327bbd2add9e496e4b493bea671d2dbe8c6cec4328aa4bde49b36bc25758217152439c874ac0f5fd39225ed9e71499458e0589f9857be8ae74f0d61fa521e4aeb00828c6aa2fd675fed9703740a409d096ff4e511081727f29415bd7d257eb44b8857925b72beb2d7c8f8cd7930d80bdde543512a576ed346b00fbe938cec8a20af55fda4ff96c1aff1c74ec5f4fbf021a54ed77f9bfce904806ff40aa01fcbc79af9653ca3e0b5afd30cb6782379f559097a1562fbdc9dc9dc612f799419390ec395abde58e624d1dc9478027995e900db7dbc384721646eef33c00dacee4c2d76652b14a958ab312592a8aae5dd5fd2d3c458420cc9532736e54f7ebeda20d003b0e4aeeda06c862c94fdd712ae80fc66fdc2104ed13a87d912bcc31fc6e6e74eb43c1aed6496eaa6b58bff6292c4f24e6c1aa236f38590a722fdcd317f256ed1ae15d993fbf106fcb60b35d156a2e53f543a068e861aa5759e7edb29a9a4119dad1316d83069b48a1cd456d03c463288706096f718e5f1c195a87be4f24c96e9bf5eb4a19c9c2f6d738e725383b350f9d5457260dd83f0b72da3928e074da85d7b024a5a651df32ca187c0192dec55c50b29b2ef870d7808dc375250aaa17c42d06676ca2a896499ac0eca8257b82b826ab184f43cc80e640742abf2477751effdecda09010b1f2bb522563604443af54f157b1d95f4a091882b813f54e96ff87d5e5721984e3d223601237419fdb1bc5daedb788cd4b8fd20555202eba515ac70ca565b8692e4ae75345de265ddff2b667960a3e108eae64e760481114d842c3a79f2054aeee00a4761cb1b09c462b0a475c4fefd726d5ef52dc665e201f74dc770b05bf22e7079d7b36134545f31a8507a373e1351e141a7bd4ca0c5cffd0ee30ca00410fa2dcc5b1bd2ee6cac577f4e9001318dccb95ab942cc549b60da2729d688732f65c030e50dbec5b574063f94d97329217dab7d675b8d2d29db8b405062aab959264bc89cf07c506c85be5020a37839c10d8e1e8956c91f6129f3ec5453e4552e35562dfc53cd9e31ed3fbfa34926f65d57467e54c4df39053feccbbdea5c6550c46bf952f1792f21c64c2a0bb8e41a83052466eb9fd478b310f0493752b5f46be9ca0fb90aa52459aaecc7cdbb3bb8a7d587c78e53c59a51b1dd114ccf25aa35b857a0e0516eafb2858854bc13ddafa65d5cbecec0974d4b1e1bee631fca0a21447d7d58a137b579e45c0aad9ffaa2ee47b9ccc45a36c14e5c49cd9da1538a5c01ccb4221ad63cce7d74ba71ea1c36469bdf36845ce99adcba97ba60a075e62c1c741f433fb9344324101c206d140b7a830a033c1fe10b6ccafe822d68f1c655a898f4133813ed0c097bc961498aae1631434a0eea0c0de07145c268bfb936df569006640c39326981a8b05c71ebc5e043c7d5c5fbf470ab8c4fcd82f44cea2e7107b4186170983cf4ac9adef4d8ed79d9c2ea973fe4353e4746d9f847f24813ae16c17154cd3255721ef59815f88b3c79881d7890d45b05e5985508a1ca1324143c3e0b970d3ab8ff37b4cf66a0f94d39e431cd69a31f87679bd982bbc82e5108a28744158e93dd62e628006293ce50813ce4aae28b3ace463a0fd146e8454a522ae7ace8f5477e89acf872e0541e227f9a27c3727a5c9c6951181f251612100a17943c7df8121b5e6a77279e5a7a3db14ab0a5a2a8030bdab6a5a057caa6f88fa2bf9b747c2710a3fe8a4e95444677af31c37909454780ec4467d4d2f89741e1cb0f5bd0c067c68fb415da903830606807a2b18581cc38096730ab1d2a209d6d7bce009c8062260897961807e1c95fb4e198104594ae40f10beaf2b8e7a6383da6e4918c6e46b6d9d4f916ac514c379fbfbd81b2c54a74569725ea79095c4a16e88a7cc4985716e65b741591eb8f39feb6403ef562688402ebb4296ad2a0026e5a19b8d7dd5d02425b3544a3b2467e0ba2dde1cb628372eda1c80e3a6fc3eb0303604d5559590745d89fa5f29f54d19fec1451a86b1eb63ec2f9a983a0f1d75a5412173346ab66b4d961d8ed622efd6027e7019e724fffa1bc8db812b2de509b6d61ed2293f729e66b4087781e242af7b6866907dbf991f06f181818a039596905622e0b342ccae64f8261939dd7722f71c7ab6fb3959f4fad59fc469101e761b1d10793e206c720eaf76753d8169b53367a632885b5b860755a68cf1d902f92d31c900f0e7e2f03af7502e0ee73f8d8770b3db25f56e238a02a22ed7c0b6b1f3184d31bc103c0fc19d068061814375c301b0b1e7833f54a59a0b0f01b4cf71229f84a018f69f59ef59c6786a4c47215026cd02812e53910538bdceef075bcc3286c96c612ad5128e821753030107d72cf74ecbaa19aab29502cf1c1c4591d16f23d8131a1fee486a3529c35705ee7a6aefc28919de31be3a7058e4dd567ba2841cc1ef50214a1b83c50d982536a71d88bc153de53928e9048be376979b1f8f5879ff203679812f16f8f50767f106e3db246bff1d6e9b026d60cc3db7963354be8ec384b5fd9d6ceef0cdaffae30f97605e2e65cf5323d66660efe3736120ad44a88605aed1951f0476fe02391f17bf7a5b0212762c575baaa2ee3c51dc7957f16f5ed44bfd79fba5f018a001d787ff727b1f3dc62e45e4514db609324252bb81e4e37bd81f29721465d99999e2951efe252ef4c68794091dc0ae82119134eb40da2c1ecedb5a9c0ec06472d11db7c3b7879dee633a4b137897c06f02920e3d52888fe0f6a69c0d00aa9205df000bea3bf42524a4a9d9dfdb4d698a12706517ae411a2476f84f4770383493c94577bd0f4f1b5edc0e683ab9d76de14371b397a7014d4dee7a977a38dde417b5a046d3ec5caa734a4bddbeb39a9d04a2b0b965a1927af1b0de0f12de40c9aa8fc87b6e2d3c428870e95479d7e06b42c53671c3ea1c43c0b50122a862eb6e5f0b443882fbce176a168698058f96b460cc06c11880a8882971aaf43c3fbf8d1bf8a8845f2b233b80547db05f4aa4751664ec8496e5fc02828ab1b8c79a387d58e360c8f4473fb59c4765d1fe65e8c0cc41a32cf2a896ec0fabf6f9db5b4842dc2fb2c36636bfc0976edf17f47029b02f605de88be96931b777adb2e4c3f241f8826a1ac3796047fc5ba913392e08e787ab2d6949236fbd33a3657db64bda826207e2f914aed0b8ee490883192eb4a53140f58ab92e06393dcda065b1444a21aaa582569aae08847c057e9f044c0e58305c15271dc932955eafc78de3ead83db6ac4112e1e6d8ba54a24823a22a822ba2b419be1700fd7059d108c518b0000cec30600084d8ca1e41219f4d81587948cfaaecc6e066c67995adf86dcdd65a4288b44d08d95b6e19180ef60d250e21cc8ebe1d7d45ef2fe2783c70f4a97d79a1a736b22c119c8ae9c7b48da1d6dec9a172e861645d0d7be8a344e2b9d8853e4ed52e05eabaaf63b8771a67fbd5a0769d5016a961ab6ecff413da5b46ce1a98d4f66d1ef6e44d835a4a74c914ed9b0cb4d32feac814edfd6934f584a3a9952c99a25d2a41274a98483bd63c270020e20d407589b1155b2d1d1695759098ac63bbc6cc991bbc32efc235b4cf193216580a776a5fe419d8a76d4ee1b368bb7ce9c229f3265305af10f24eafa53fcc33d80ac1ced602a086f4cec993bbe5e34c26038e99e5e4639631dbc3952cb750a314aa0f345eecf1e6e071ba01bad84117c31e8578207b8f7985a84e45c494f698d2ac4c97ca2c8661189beeef6c823be1e8ed05555e1e26d5dff6821a0ba044091bd810df9accae5995eca391599969f3593c9265998a061d3683a1a0b69235ac41e7b61ad4705b270d69c06850e35943031a92dc3ec3196e27318319ca50063290e1f51ac318c4208630840109123080e10b5f9899a9d67f88804b4883c602e4b7c36b9bb867e60fee01f58309c1ec7c8c56257fc2618156a5a655497b2a2225ed0b112238050246928a57319254112919c9c031113d3072b98a9a292e172e576173e4d21e342ac4812557c763b41c903fdde056dd693920ed29882b6d68832f128ce4c67380ed298878e3fb0b9c79348f87661eaa65d8f7d5db438342681829e7093856a936b28c696cda71da1a97643788819c129391d9f8f0930132662fe56c25709ce2c99d70c8c747fbd26f2fc4c7afbd70e3f936aaac1bdd368f87b2fc1033ecab0c44bd73da1d4a5029e43c820c10b48fb5bb9b9011461d5774c99513c713cb17815d5a1f4470b48fed588a999efba3f58b57c9e831ed719e66bf88ec8ddd877c664ff3d1471fb3f10a9e117f9912279206e3cbd5a0c935448cb46da94c891d75e2b401c7a355d77396117a58971e3bccb7ed987dc1bed913bfcc477b6298145399421fbf89844a77504ffc8db76d7be47c44eef34574d889e3b713df07f6faf99d787b3c8ecd0711b638eab1fb88ab4be2f77441b27165a9651b9a4c1ce88ba9b8922b1e954ca15781184983942a6990d21daad320c55455e7521ae394e9c378f3e2b1757a1871505e5fe8313ed3617ca3bff844a78ff4165fe9a09364e9161fa74033f4947e86e6524bd9521775719489cce389f7513d717bb4278fc7937943c4d46fe7e89cd8e7fc3c8d47a827ecf145608f766ec78e591ff19b3d35777c22d2b48d33ecb98999b6c6b3f286f0d4c8147a8f8a029c428f05192f5c4a069a3b04cfa0dc76847a9227694f14e0bebd08eedbbc8fee9c2a626e9ff62491f00c7a4f9006a967653d350d6ea1869e9a4b376b844c196208996284caf7410447fc761ff598adc78ea3e2d88e7d238253455822f1dd63b0739f363471112abfb31867c388b130feb68f864ca17106f3220e78067d7b71c533e8e71136205788b40d3d4674d3d99ea41dc2c53cfd10728553f4469cda13bf85cea5361432bd857d11ddf497d14387a121e3cc2235f680dbc4842a451cc2a594060bb846bc9402f3a1e3980fc5cfb7c501baa941dbe38ba8c7ac8fd0eba38ddfce292e7a43c4947e6272d2e8a279108e06e9a4177d2ce9471fe93bf958a694bed1c729510a44e967116ac838270ac46f37221a118afd575b1c33ba640aadd42322a640e7e6173f9c537f1e2695736aec38e2b14ffbb28a363285fe85257db4a9b99229b4cf038878770011dffd4481982a221e3b164615a5d5a3baf4f5639129f4db473d0a740a6469c8147ace13d9233f42361a7c96674df495656ab32a3285fbb20c6a737858a2794203c7a35ea6cc9b640aa718bcd3644271c1d12b2f5832e604cd385d5260f182198711dc4c726d94ebce4fafa56b94fcdc5ad0dfa988e823857946c894988ae7646629cfe0beae21702c239caabb711e95731e97c7ca1c7aed98196a28735c39dbbd2687f08c4d85932ccf8b34e891b155b1aaecf03d0d11d38f0fdd883d8c3acce219db76cc4a9d4b9d2b77b6b74aaec8c815c9fa7c7bdc912bfdd6dd24ceddb6ed02b15d8f95395da87d4399d399405bb440db93c70243c894ed1feffd22bcb7f5410447f6be0fee5e11ed237b5360a6a26d954cd92e59db375648b76362a8d5ca9b06b74b2b6d1adc8e85a1623677bbdc8e21a9d4820d6ed7ec1bdc1eaadcedd816eaf64ca7c1ed590a2a5fc6746c689736b865f6e4e186c84e04a78a486576f3a20ecfd8be15a1ce77074dcf468c89c9ee3d86fbe727cf418749755fd7ddf30e645f3eb65732653bf717cf6e1cf7651fcdc9f3ee30a997ed1905b273c7919dbbe79c7d21e2b138b877f64526eec894ed2fdb33abba1ba7381d99b211a16ab7c1f79e8751471597c07874321e46ec2361967b18ffc5934c8d8ad654b9c66853c5c53e5f1bd58f316236ee48c6c167196314929d3d23fa8463bb77cfbe7436ba640a0efac2d9f8922952a6c8222611314559a6b05c39e1d8aec1a4341cdb35fba27db39e2fa6a835c99479f084835f6052dcfcc2de099b155d7225469cd87251a1509d6ed81b775a66eec49d1977aebc9c1e23cc8148aaf82f068c172827172d4ca51313d24814aaa08fd7719b876a193665f38cbe10c9b16dcb18689aa66994dea6b4b16855c0067180ec48b9824d7599de5c49551d571798731c538bc58a314656d4096764f5a38e5ce99c97ab65ba61994c3ab7b15683dc35558cdb10aa76288268d5d52c86f3f1baece37558c63536e8a1c9d334edbc02aa378654eb3e0ca751481aec681be3e2178fe11c69b0a7eba686bd735b984baeb04ba51a414caae7ccb93d7bdebc6ecf32f810656e93e0f65dcc1b62adf6bc644aff83ade46bd5ad3055c58265d8c02b9b8c196e4d7dc16d6c05b74b90c5cd0b57d8dced26c3e2b7231bced66a10b342b6875b111eeb0304f29ebfd07bec89b33ee83d96c8f428c0a94973e2d68a9b8c8949ad32b7db094c601eb6235bcb08a4bb5971fbdbaa3723b47846efe834d89f5454be1a129fe7f57abd6c3a0b5ce38281573a4ec9893e44e6410b8ccadeef2e300a7b9b9a6486db97b30ce324dc50464371fb5a9d76033225feeb946a898689d8c9122c8631c619dff231364be6d4fe4ded87f3f221006ebca4fc62293a46665d491b6c193c235e5e11635a766a03dc8d737b5ec1f527276daf45ced813c3a49ccfb029bbc8a8f9eed6626590b1f8796166945de058c64653f9bec0ec094757492083550a260593aaf6257e01095860a55eea97f0e1093e60a588840e93ea0e93021d26f5a28aca619fac91292631b2c8228b94c9250231609ca5b98a22c731c9906e39b1d07cd82d99f9b9008902490dbbd592b78f342a0e91f38b71c523de30aeb020c22bbde2141c302a2b0113cae085abc5556c1df08aa441d1fe81ac9134b246d6f0a7943435f4884be329f35773f667a65bf2481da265b3d5282c30bf45bbe7dd92d91066c6cb8f3a2f266a185fa37315c5c9715f1fe1ceb2478d43abf6786ea3a26621cce5f66c58b78730aadb23bba42338c5e43bd7e49c0d4d26a736ac266f1517bb7967a4319e534c6ea262f2cc9e7c364a247af45a44261f8d1ebd96d12c525b7cf4356c169c3456f19ae6f9b2b3cdb655ec565cc5d823bb345e18913b73c8723d34a60a084ed05f7cd2b899cacd404ec9aefdc507fa3e9f87be4776699d40d0d9967ef1c6f8b8482fc09f3fa251946a9927e36ccbbcac94c1c8327aee1cf719b1042969c0b0210d15156fb3215bcd86269433a3fcf4d5297edafea87f1a8dde2b4a33ab79780bc1788ccb228d82f1911a3cdd02d1f730e48d64cd61e648afc4743a4b9648560c1872a65161efc8273ecde369795a9e9694f9644c839e670fa5eacaeff49246796cbf9c20575e78167b6141947e6c7cc56be33733e20294722836e4c0cbd1b81c77d9aaa674c52a34c29f4c3efa4e1d16dd32f9e8f1bac86c7884c9a5d7c263fbe8dd62dbf2d856ab0a6d3aa186bd6a4ac35e891ebf30bbc80673a2efe4e21382d99366e32a35e7d45983e8cbee42fbecd6e705f497255e96c87030839d14c812895fe2b4e40d3629cc12c9a13dfec3fcb00776e7339c065bdae773cc7b7a60573be799ef23bd82c5219d22bbd5389eb862429d73e2c880c60b9de76b1b4969363dbda2a9f16aef2143e28a456abff3e311e567407170a5ecc1952d787b2dccc5aa7ddc47e2e524cd3645e7cce358d1a85087ca8d9fff9cf8ce06e5b32ccbb2ac651aec1f47aaa701499688e1ebf6682f9b6ec979bd405ff32d6c96659e6b9fdf0f0dcaec934de622c7518ec69651748abca4c9a4681c66a28993b3f49c430db955e3d18688f79955e5ece0e8b45e2c978a25d39ab939acb7401c959006eb776633e3394d6eb2435ed28e182420da86d94d6ee2128146912e7ff2edd06ea3af264a22922c67fa3865f2c5cb45cf6444d2a6a665d1e4932a936ab22346165964714d7a48a7c8c798a451279767b9fcb6a1dcec618e4b2a77d2882b1bf6c86e7693b631f97ab529a1573d248660c986a00d55e2ea216d1b568fc6ac85475cf6c4248de2ffe4cbd123bbf1ab46991c359f99603d32932fc624b2cb362691a39e217dfda341f99651354ac634ea397386a6dbad887386ab31b307b3619c9a55cca212e2c0f2f014ec851b959ffdd028296fd22cafc143e22393e2b6282a7659b3922b983de1c05ea21a864086550ab3722553e461529266c6249206756a9dd7921a4a1aa9c9f82a2342e52b1353d86344e00099983a65f684bd88cf41d607111cd83ff694fd734e15811d74907d59a208153a4861f694d92140c7ce294e653f7880b49906e533db320dce22481a1c708a7c0fe810aa142b9e81841ae52aa47166517364e7873a788a30ae26ed8c9bc21362cea87d3a788ac6c9baa584baa2dd204d833175ee689a2667a2a06559964d1ae9840f54acd48cb623def9fa3516b27004566a4ecdda2454cbddf7f239a6d9acc18695054d10483a382e60c10c0b8b2864dd0ccb8930a8587208d203ccd379a2250303eaa951411754d0861c785422089d3579b64ee1f2c86e18555f8c5109a961ccb9a21fbf2cbbf6792de7d80322dece765d7ce2766729b090e2c2dc2fec2e17c66f74b3a1123037f69097da4882c843863dfb68b4a18eeeaabc6b185551d5a838537365e2941163e20f2fd410bcfd1d2e237afd394194d91972fb2fb453312831d3341da44e09d5196ac83b4ac815954c1d41ed36c5dfa6bd89a0b2172f57c071a3de316e97935d7ba8070476cd661d966197a39d46e5e5b6cec371ddd6711e10bc792827613a624e60afc1565ca8549842245243ac26f2c763de55cdaac18e37c46ab020d10a9eb16a14739cf6c4b6716ebc2cbd35513319b9221f5f8d83e560368db2c213580d16a4573a8515b97dc5156a5bd160e734d88d23e78d5c91d186acd338584d4b9bc9c8942c60359ace651d2656052e864816ff107b66ab0923993abbe725b73f2ba9573ad55d19b7513c5a7a41c82caaa97de0116ff482e02cb2e8b01a3dfac6201c7063334e0d2be5410d2b0a9a45ba3ba8613c1f3b8ac398e35222ba9048723b5a1191dc252c63f45aba063bb36174c5f9c59c06fb1cd64aa25db3648b63194ccfc90dc8151a3a738c4246c45f0100cae51525644a47286ef7f932b8c687f2cd15ea2988996336c87c593adeb8b8f99cb3c3bc162dd3a46703743db65fe1caed2291877ee522970bfb15e476f461b68079e8171972fb2fe019fd30062162e107ae17191c999c9b1cfb43fac7d7c48eaae8f3ec1442a3503d76fb64b477cf02a183ec12a722620af4980259992e15bacc4cc5802e029aaaa75f4c490fc74c85ac0842004a81de298fc700dca5d7d281deb1015a8afb79d82fee9eed064b71bd47c9b75f92060d151510fc4da65a3f2dc5e58e84e99dc33ab2fc78ba8f790637a368706a932602309a8d7977701657db805c9129061b6c70b26686793f666e4b8c74e9e70e2a7dfc7490eea467aba3c1ee5887deeed33137cff621d1dfbe01b9d27db39d4ee5978ec6e1e8874483ed9943a53ab887bcf3d23a6ddb427a0fd5d12df49e6f030dca5467e74aa66481456edf800e24361bc6eb797b2e7c3dd4a371a0353ba7c72e2a590db61aec235da8d90cb6848b2996b185e08d8a4ac296e9468551a5b2e2c6f44aa7fa89dbe73629d478255fab1aec182cf455a778962a24703173884e409f0aa16d7f88ea62e4f623c056b02be26008110d9b34662cafd9f861971a9835f6993c17bed3f6c0aeb467c2051cabd42aaa3073fbef2ac8dcee2aac78dd4ec1e1863240315115bf05572ac61b5420d8363139b3ceb296d6580846a05bd3ba3beb6cfb22d0292e3f34183fc4467b4caebf215c22f05dc06bf1582378006a67d1e2cbf56ecccca551d8e3233044f7e34c625ecdfe30afec3e6d5ae3690d071ccbe03ad565be8c2362d81746999071eebcb37ff44f37b0394d189513a333a87e987d32636da7b5e1e49602c771ed8844833e6caebcbc42ec8e31dad6d14890e8f4babb9b3d02aebbd875c7cb9d6725eec482c0bc6ddbb66ddbb66d7d83f40c4dcdcae68695a392a979d16a3a886352a101aa1c345d86255b33392c9a53c3a2352f167dd9b0a80defb028efb0288b7aa49724075d0eba1c7439d038fa6d3b79a2d83c9eed73a53aa99945a6911f33d243b71db9a41f399629a66bcfb19d3edc6e6c96b5f74f14a551a104fbb36ff7d05f40bf6e9a8e927e86c233e2b96fc67c536653ddce3edf45a69e7b416c96c689e304ba845ba12153ba77ae447143f5a2646949a34116794c6218b52cdd324a1a2cfd821f72c681eb0f7b285d573b762e02a1bf88bd349bdbda4aa660f462581833cc62b3ce195f5922803224e786342e7692e9623cc5c5b01d2ef619bb5b4e38441d399c70d0130ecf8b0726c53242173a97b17eec23ac110d8258a02940add1856497de941f8609c161b8d1e690e7fbc26f7041185429edd1b3e1e282584aa818bdd8cc217abca3c7ec13b2c99f4eff9448bfd8e7d2156d7c5f891eaf7b7a14e2439217fd924ae1e8339a30f7f485dacd0d47d7215d5774c9b78f5ecb67c405a4d722e539d24da44f93231a6572369df469b974944f1bc6388cd3e7e75388ec7decf1636f64d83bf64f2f611388b77496965f88bd6dbc9dc7bed3e935424c7b3a61ff5cbe317b43892bff79a9e92fccae43974e2efbb6394affd81cdce575481756b293fbe8d30b427479e9dde042b687bcf3279736e4d9a0b4610cdb43b62701d349a4874b5c92bc9c242f8810fbd440e7914ca49f9048d2ce68c313d2342159939f18d120e933398cefc4c484a73c8171f680b84083dc9d630954d1fb5c7c9675e7648ec9a735fde49ce99bfdb9fc4e9f5ff861ff9c6c28e5977d0a513acd3d8927f3269fbca2c139852859db7d149b4566d8c771f6a7c43ef985a7ebf0ec4bc2e6f08210bddf737efd0ebcd444f9cf5964179e2e43d2dc70f453bb606ec7db75a2c3f8e695f1854adcdcd175f8c2979a3bba117265a648d6c6fad98f5e16e2397b9e24bc1b26576485c83cb5d90b740a9fbd911dddb4e69c93e3da75f39b14b525e508e78e6ea46cd4ec384cba44ae46ae6c0d62cf02a492e9db4e229d904a2612e905b7c3e9703ad8c6c92ed660b466c41ab546471a15314e87d3e174402cec9bac06a7a897bba39bf8d38e784f2e184643aed433d7bbd1a87674435b582bb626540c0355c163629f5fdf1faa945d8775ece2dbce9e055abc857d892e581284124da9a614a451a7f34bab4691fec9b806369a2208f3c09fcb651fe8460d274504b3a08b2da1968ed9d4cfb9e66477227da38e5372639fd18d775928a68ed3190dd16a4636a3d51685d1ea72cb74b9d2e27cf0825858106a4985712f9ec12d8e3dd370ae942c9d50e5e3295651e38743fb665fb4b614f0a440ac0d0a35723adb13aafc9c2d7e8b6fdec81456ce6c192153f8480d695c0e47525cfee43147adcbe7e88bd1680483830103c6c7f7e38d50629ce340a0175f6946a6b4f7060fdd3c5fe05062bcf37e685477be8b5cf1ceff616b42ed1bd2e8340e3b0ecf357bc2a17dfb86d2208f6e26caf99344ba39056990bb7feac660fcd843538c71329aadd98a71792ec677138a09c5740e792db24ed3a7a52b9606617ca78fd6d8a0d6dc908669d5a87014840e3181ce7d471ffde42506b1463792f58205627972b6903cc52b6404bd4053805a8d3a718174404a404b7a85cbe0021de18370222671a6157c29716a08624594af34837349dfac16ea648e3d94dc4e17c36da1898dacf8480d6611836229b288b93c6235eae4f247397225a692d49c815f3afc510b9359773f7806bf3fd014a016682ee95431717a2df3a68feffc76c46b522969901f3fcfe934c876c4b2dc0ef68d8c34c8b38b6990cf2d6990b946d8b774661f4891077ee99d4ca3da0d97dffde01af1ee346aa2b02c3b29fa30ba611ef8fcd14aae6cd68868c3be21e9f268353bce8806fb18861d71c230d3cae8c686a7ef88cf8806f9f2bbc073e68db8c011a78fafe7b5bcf35cf81a218f90a056831ca9508d38e2e43c5bf5f21f3bab0b3b87fb19dd700b4b3a8b94915b72f9a52fec4c70f9275f48afc917ce4bfa42fad11bfac2792be81b0591dc1fd5961ab1640a5f2aa162d7669f3e9f78f9d817efc8c8e83552c21f4dc1cca39ccb23d7e55192cb9f4cd21ac666f4be91914e613bbae1410d47372cfb13399df8f5e594342a5ce2ca67717e22a79371a3a66c8d73680d0dc2e7b9b52ab78424534c2f4991519221973f32326a8d8e5c3e57a1841aa8525c7b2d369541ac0b34ea7403bbf3d89db6e32ce4020512ec86201688d5289eaa38182157b49f8478346e0e36375e4ee7f279b6e611be11fc0b702ab57dcc299382581f688a06d9030a41accbe7741a158e6e9434ea971f732a77e71ddda05c1b7458298e6b3432bfb9833aaf7d9cc9d98259aae3da11ab411edd34c8a31b173ab361a2e665800c0ec03007c89094b2fc3cf2a72d649dbb6df24a34aa6fbff4773b0ee9c722bda2809a18d328a6420a321b27bb0d12884674673950a8f421b332ee4a34d89c7d89aa069b776e04b1e53871e78f762e96a5c1e61d25e8999b526a32fd32d68fc7bc18a98baccc0731b22c465721bbe93fe9fc4e45e5199affeddf46957753f9936ef68dd4ddb22fad896acc62f9a15177919d7491ffa151990e52f7298d3a48b7b9ce39b1e06bd9e71bc5576ef1d2635d582e8b4ba35845cb6c48e34acb381b15b89f9333da9e1d6577f76c19e5118e7f39c618555a3857dc9861fc468554c6fc9879e88845129888b90ab89c04266a2e079224db4396b194313236aa46d07f2a5ec69c9addedb2c894784a6bcd9a45ae441a9a2c8f96b6a70b2144e6296a4fad5921f4f4c69cba5da6a2092f48b186a61d0888744bd3cb291ad7362469dd97a48b591a5b0de2e5789e115f05bb90e80e79e788d65a7b820b938f383911e73f62e50dc732421953262c14a38dbc9136582808cfc05ed8a367c383856cc4e11958b422a741ecd1469c06310c0d58cc89387225a6b07bb9528f3dea740ab063a0636f15a60306b17320d161525d77d0717420fb42248a5ee416b2314983d8eb37535c77dd270ffaba7e765e0d62f2f545c8575b445f45a6600f7dda658f8899aa36ee803e5fab640a76ef639e1182b7fba40e18c58c1deb1430881ddbb07bacb46910c322768c5a6c0b4b6e86829a92ac08133bd20c0baee7c03262c3a4ba234c2afb6447aed1d1884422b75023119dabd1902bd5f4cdf350a5a52aeb980635d0b1771f76cefb4ea2cf475f5f4428f46a7d10c1413aa77c7c1e7a11de49d607bdf710bd771fa17fbcef247a3d4ceaf3511a7ab52ffd903d895eeae945a7de43f685defb4be89f2e143aa5d42e7144c8b2c814adbf93e82af53b892c0f1cf52490084ef549f6e5a55e3b4c8af450856459a674b5eda9ad9d80ee43c89438845e8f7d5ce8834955d1e947451f57bf38531fb22f2f512553b4232153b457ab69df4104a7e889e054a83e8c3355a5d9c41a9b15b509630d7dfdfa62a307350cb9645cf68400c0fdd8906b47bcf4a21f8da226f4ddf99cc9e7bdfb422f1b72c5b8c917865cb525f6a171c90de7dd80c02eeddab38172d043aa904e6dd50d7d21158cafee6c6ea8a1877527f4baa4c136d430140a8566ac47a64109d4eadda821ef46adb59444bc252bfaa1a4d2875d4b755f5c63f4edc535d8503d310f45e7364f02a31ba5531b3d214a0f2569100026ff42a52f89784dace84783ed5135d81d13a4d7b5d6102ea1ba610f7a4387718fca13037a74c1813efae86db66b10043aca4bec5119aaa3864a737b74ab6b718df620b9a487584d77c4895abf3df45c71854706f4956ef2c5db2274479e3bfac735e847a3475ee1d4e82dbc9691e604cf68199ea153abcd415fbfd9907e7be90bbb0b3a47bfad5a50cb6659e4617cf3665fd837dc3c4a6e7fb4bdba181f0fec862157c4094751d0ff5cd6c1f8a68eeeca7871960eb94248443f76548de2ae359a01afd9d0643259db895ca328ba47417a34a4898c8ad4ae758b9073c32ec9d6a5a1869da7fda0ef5a946e569369b0673a01fdd074066d46472a99e9ecd71df9ba56c7ac997ea26b6932dc1de914ae9e8b5a140a555a2ba5f4b6d6cff3d0a7a36fbbd60d849c4e4f3686bc96b8da4ebf01b9223a3d1272e5f41845a34a9701c0a597c1354e42944bbb5ee91979e923fb506f220f7d93d3d346914ecf5c6374badd136bb687b1c623e3baa0d54df4a1ee441e506c5825c8cedc0ed9b035194d06f45310f4a1876c8e794493695468c80d75a3d148d491bc169393bc16d2499e8dbea373a4ae3d1ba01bb25d2b8826b3922b7227fac01279e8d71836ac30ecea36d7b5a48a25fac0ccc3e7b57a52f561d617b15228068c3b5b21988bf29e11b2b3657a8162e7911cd41d40f0f4162d1e532d4e2d5c5c746af14eb58b1a12b5b0cc06a830b7f43e0925a1be4d8f926fd7aa3664294a368441c2ada741434505047f93a9653a87955a8d3a31d910a6f431cf38b1b3d560b5f3c8170abd1a1cd9900b07359c2d08843a250af5431ff38c6a67ab87166ae7914fc8158692dc7ed7b578cc1b6a32b1a6519e37fdf6b81d5940837d1a5d4ed7ea701aecb06b75477450c3d96add7964d4225b22c2542d2e61051c2ba032ab083b97594458728bf0e3725c254665304b19bbce23e3623132772c0d6a9aa6fd870534a85966ea12638c2ef13fb8709ded6f87065db487524aa979ba047503ef5d1ad5f173613966492ef1d2b2b8b8fce082861a326bb2fce032df8f80118da24751424ad2dde5c6614bb5f0e5320bc9b04fc8b43f744a93a086f4a2a20ae3867061e8d85986908f88e7149dbf1ef3924ea6ecb2d0410f3121da392c742cf41c58e81de98ca7ee7c397ef41ec618637cc54f7435f87a45fb62666ca2a62bbea22b22119dbff812a9c22ebee67c74c5970becf89db8e489c9ab51fc3af94ef3f3ce9b7c42b624a46ff4b5151dfaa2cc17633e99a7342eaae4cacf50c3a892b913ff78df31272e593523a32a6583419d99dc56545254759ce9c9368c3451d55ab47745978caee7dcb8904425913932a3e8b85e9c04c96f9b649850a8261201a53934b7df1971014e2287b07cd123efc9b0b3b4b4d94e7945bb94431a5c79ac1c7269135756da58b95a491b3944dac8d59c2142cd647846674e642aca32675a998a73e46ace304e7f081c516aaa28f92c9d73e53720573ac76a988d4cc9321cac087683d96434f34e8bd5501bfac26aa8aa26c88683b58c02bbb958ab75a49264304b1bc673bf62bcfd6a97ab91f05fd1f6abdbd557a8f15c2379b978c6495ecb54990c4c8acb3eecd339c96bd8ce95d97160cf4e445a1cd9356bb19757ceed21b0964ce98d08956f832f2605cfe879962d9982dd60ac68c3a9c26e6ad8aead0c95761a0b3650e33ae20aafdbd74012669d86b8f3d25ed958d3608c354b6a8dfcaa511293524a1b57b1a6c1200d76ac89c7e4ac611b65e24c4d7ce22deb6479844947055ca0311e61bab3b339ccc971cc31d2bf5133e467a6b999fea198a63df62ccbdee781dd1ef3c6a952a95435a9ec5da6d96aa914b1a966b3d86116982a1c69cac64083d222b7df8198993b6bba89aec848551933e3d1124d6d026b0c918e4fbb063b9e3d9da595d6063b7a9e471bfc2aed988b5e4b77b7af459efb5ad89ee4e30db11beff14caf029cc2e2e631d188343a7be6b508c12c4aa7b4a9a565516a02100e4b6b3c43d97fe33d6793090999c2d91909b6b5415327a06bb3326d8a90743d671bc66bdf4c50b58e5e7ce44cfe0a4f480c639e93336c46d93899d4dec065671921c91533693a01bd71a1869366469f07cfe8ef98359baa92988666d6442bed8c823fad8a6d14185f4e9a06bb463e9c34cf216d9c349e1999e6c79a0669bc2066140dca1492ad61fea4e9cb511a4a328995d25a4d266dc67a4e6cf86373d26ce02d42c5153a5a0ab415d41d4f1635f486dc0ec48f26fad04c78ab1db9121ad2297d7e48c37ad2ceed8786f48aca0ea08cdb10c5146d484f489809eb202157ae003b1daf76e12707650365642a3b8c70704638239c11ce0807675453e3393906ca4f4ea8822e693faecf0ba42259cc62241b24b806dbace4cae934c476be44c0a4b20ed9c81598102bd4baa7b86dcf1e9f65e7eccba95f4ed1f2208253a6972a53284cea2ad1f2c0d1ddbb675f38ac280f55b014a740ef1b4ffc21644ab3e58123fb762238e5625f58644ac3a49ee19c7058221c10720ac29e62aa592a55ea146dd451a96eb354aabb5995f7ce02dbb3e3e0fe792112ed4b4c6de75814e094674f4574cf9ed9d33b3b6b644a4f282a1fe5fbe4749d8b16a6330a8a15d51393936866762f484d837dcf7a333285642357482a99d2a7b456928a644352916c48aadb27d99054db76726143f0261b9ae2a764c32ab2a11645b59d36c464d2b490d8c13e642ad63ac03592a8373ebe8fc47c410b78d250a1ced35391ea865672654469ad26d343ab70840393c2b41b2d08c6c5b84da18693664641d3a8b0c3612f88783e0d315dd74855a2c3f1641a1cd5d05a43a72236eedb39c59aab49e30304dbbbbf74f6d4bd6cefec66bb1d9942e474045f0dac78d2308f747474582c9668869e5413130913cda06166d6ccd56471889ed89056131b56932934e3bae045430d3f39ab908b7b5f7b62645b644330546d149f20de87746091db37a27d535524767007683a9c50e88349856e4238260eadaa1a3a1d99d2f5f5551d9ea1d9d05bbde8159386268a59137a5c3309f514756c60659a3471d2f43b9bce2676ae0d47ae64973b72e5332f6d48addcf9e4c47ac38c0cb7cf9f1cd7a409b599b96a54e871795c565872fb1e2493268a39c49304bb9951cc9a4993c5210df63155f6cac8c02bd12653c3ed0c0eb735263e391dcea4c93e397747a6cc743898b539531bed098d469bd176640a5b39d320ce0d3d2e6d66dbb2504339e3715d6963cb197b8a4348ae6e892c638014d2c6e6dab84c283b806288c422184aa3e8c31d2e4f1bf24313dbc7f94675186f6ab0a345f9c2c9c518b96d8b5126f2c091049107964a20891186dab6f96c1a2c62c26cdf34181f4ddc46e0196dedf943895f1bf98c93bb260669b065106a68aa8935d22648b70b79136d6c58fd29622b3ef171545d29985064186d82f4ca2cd2293d8d2cb961b491360db614ea8c35364bae2cd2603f08cff94132494d92115d4839694417efae51266f93ce6024b63395489d4e126f94b111498312498b7f9e8525dba36f44024434c1f877e69fac0a89f4175779615f3ca3cc29269b9dca953e9b4c1f9d44b77f564777492d3eb2e1bc9f7f3f7d9d1b2a8aed212fa9c5b78f8d1cdae725d91c2dbe873aba5bfa675d743af554fac986f1c795d2647394da0b82f47961b3976c0eedd8959e10d8d56cfcdce4d97762b27152924ce73876279e0d5faef7ec9397f67e30483ccf3bf94867cfbb4cf4e1e4e4d9354dd34eb8abd9134d7b946191da277ff2b1b424ddfb4c4e1e65488f243839e9d26b21d958fb897be279f345fc71c31e329e5e702d3ed33f1fdf169fe73a7cf6a5efc359fa795efa3e254a840eb73a7c9e8fca9496e74a1f6db0c56d8b16a6b367c3f41667e9cfeda7c377748b6fbb7411ea3839b1b1462497cb3eac85497edee51792b22c96ae699a6d61927c62431d9f0f16c25c0c7bf6c50bca6c0f0db68be61693d36814e97d8e639417ffe8bb74f118973684f191778df33e4dfbf782cb3af682285dbbf7e9b89f9377f916a66b270fe9fd9cd850c73d79d6856f0b6bd22eff094f1e3a9775f2cb4a972797d9bd2462dc0ec0dc937ba4fbf97c4eac7779efd2fb3e2f7de1c9b7635e045cbc74cc7389d7c5b52ff4feb19d1baaf7ecf59c16bd09c4fb29b928591da4fb614f0817ffd81c2e5eb239be6b3a48a1677590ae0b3bbf20b01b9fe5db1e52b3610c3b61d81ef2bef8e9d193c08b934e7a91659284794184daa5772e2369cf2e5fd8d04796d9e9d9f02451507e3a4b933e948fbe138a0de325995ccad339d2e9f48d7a68b04db09f9c8bdae567f230decfa78b16a7de4de73e975f462addfba2f7c54be50abdf4cea6bb30bd850dabc974930d7590aec9b74babd91c263fb1279f8f35934f9e3d797269b221e97e9e796ff171839ef72c73e1c286f47a362c7d7b8b941636fc7c3b8b2c7da18e5bfae733699acd2183c07e72a265972737c9a1fd24ebb0a854c61b6af71e962ebaf7e538791b71c3ed25ab83744f1eea205df9ed218c76f2999c459a7cd8491fdfd137afe80b7fb8db435fa8e36e57912b33c551d0bc202b849ebd254829224960df3e158ebbc7952ff1722a5fa8f2a14a0f16c6fb781ff6b4ef37fbfa3216af4a0ff49be78b5493510641274f694d4b344c36019083253397a9b82c05164cb81c08e4ea1822d9411e4fe3306b077d22788ac866431f36773bc7752afcf8cc82fc68a3cc7768b055dcc3a8e23eeddbe7798c013b012a9d00eefd1d5438edabac02825668ddfe0eaa981e22c7a0d795f54cde572ba9f68c0a67a3aa6752180395a58889b9e065294260e42a892aaec14410da6d10b8e0f3a1360477c0d107ee1b90b1c606dd39f6361b1ac1a3eb112fc71dbb7793bbf0bc8f1b3479022a76efec71666a9427c4a7224b2196d8f450ef1ce66198f72b596240c8bb435ecf32cf98e7c229fa42d3ed7480d7db4eef42f4905eb3747bb40d46295416627b0e36f93ca7719dc6d9309a7c3ac0af933aa8a4b325912c5fee479df3dc73f0ba322e579183296e0e8a709fcfba11f7a3b60ae8a3af2ff783bbcb2f806bd04b06b006fa26fa8478ce659de8eb6fdf3dec3de2edbe5dfb72749fe738eedbbb8fce73f31c476783d18a0afa703d78f1f401cd0d4db2aaf4c075e57b6099b9f228bd125352e5926e689a5c092a183912d46bf22995466d0bb892a7b8f2288d0ab1779737710dae91033bf790cef9eed817c63b314f08ee939bdc59dac3ba6f92b46fda8e366ace19affc2c11613259b5103972e478a6cc4ed49059f12e2e587e90974c2b96592c53e9c74b2870ac52752073f9f2cecd2edb26beae496ce7b6ce8c3a32ea50934ecb1885d88a4e608e54b81d5bad231849c8edcf39fff14ad7cc3b6705bb8b3dbe381928a43b674ba64c250db604c27b6ca4b6759ba7376bc02b5149a7b40e6ed491a961ecc9fd0961301de0958f494057daf89a37864b5c6eb06da88b6315e6152c74331d6e1679900fbf9b5df461dff6ac3e7c8b9b853c28d24319370be3499f47c657d0c7b3221bb2d1769745d62f8c01a2f57ef2ddf6f8f190e75ac6fc6ebcd4e1c66bf6ca9961678fa57b65a6989b4a3896119b49b17bb033b14c02f159d75e1093669c7941c4e63a4e1f441fe2e5739eed597f3bd745aeb123de24e8edf3d432ec7e1c68e397de386d486d67c1065b40377e932a0b70c171840e256266a25815611dc9f992a835646f76517b12901192c0daa0fc959eb67248ed1b665c07e1e36607bf4d2ba3c124e20da310f53e5e93546691c5e5ba2efad04c741eafc573a32f37a784c165cf468c3bed8e18d36b99d73ef046dfd0c7d5be699fbcf34369d308ea94f371b2a671c697729de78b1a273b0d08ec8b9e674b3071b373a19cc3cdde60a3bc207ada6810501bce478d7a42f467f6b5112ee6d970c09d76870364ecf9e940df24b23bdf12a50e28885c71027b1319965da650b046935c7182be09ed54b34ed0541319cb140c7b1689846a835386ba06a7ed2a43d3b20b8d91fea469171a23b3270ac49004e5321562c0b9a1504b2f64e756b72d140a85425ffdf6559391c918948c2149cdd5e172126292d08415f7bb9c84266c2e2b0b99fbcb2c392cb1a20e1181aa899d2488e0c80d45ae46852123b7a711a9821b86928c5ca1d5b6854e87dc7e901ad4707bd13cd128d4f9baf05a5077a149c0f9b6f05a1270179a1eced7e4b5f470171a049c6fc96b41c05d801ce07c4fbc9603dc058801ced7c46b31c05d80a89c2fc96b51b90b1017d7e0cbc3f98ebc161eee0224876bf02dc0f98abc9602dc05080ed7e0bbc377b80b9016d7e02be37cabd722e32e40585c832f78be20af05bc0b909fefc76bf95d80d8700dbe333ee32e400870be9dd74280bb00a9e11a7c0170be9cd70280bb00a1e11a7c0770be9bd73280bb0049395f8fd792721720325c83af00ce977a2d02b80b1015d7e01b8007e02e50ec700dbed7050a1daec1575ede050aecd8a7086a385b4a3eaf063f49688ae870f65a74d0e1f4fc69e9d7350a040aeb29f4d039257a88724fa3f32dfd443a8790887428257d3c655cfea82472e9d4ba895c7d0a21f9422e912b14da5ced44fd15e984429b0d453bdb452e3beb89da90d23a24043514b942ae4a236972402b1b3db0bb9dda2a81ed352442126285acc8257a750240ab57a38c346ab3424e6f910b0444e84fdf98a8218ed2ed9486a80e52dda1b45693e90741159516509146519b63f41212b754b2a10e1d77749a8411c4dc50e46a142741044b6e5f8444a4331a6da552a9542a954a4aecd8acc9a90ed2a5070dc9411f32791c86d8d86ca8dbea4dad37f5a6ded06a03343b1a2a72bbae6ebfd2c815110e8d0847e4e29d1b865c53d0ac685634456886d01469a26e34369fd7e58a8271a159354d0d4d0d8d8de845b3ea15918b26481456d42158fc88c3901f52b0a146d3348dc686a608cd9006f96a5e8b0b4d109a9a46c1d0d4d04421720111af0bcda4a979515aabc9f483a00a0d1a17abd9b66ddb3e391e299959e34fcec7f54162f2c8787e786454d81594d66a32bd06ab51a11153c3ae55830a13ce8d52ac0675481ca87821b94cc56b8a8bd5c815ed0719acb8a1264305198eacc4edb58582c4683a2f250e58dd68467a2586e288a104b743ae2766421bad378d0a432e238d9229b87d6da6bb1872c99553284948a73b7da15aadd566b41ff2a68a5c8dd26914a5ef8b908c548d3ad1f30d5da4043444b4531b3c854e210b44df9046c54bc9ed1bda68b65dfbd1a8ed03818a504aa9e845a91521d164341a4d0b420da5ea36ead5a8782ffdd194be144027b544017452a7d3635e0b35c21123afabc9684e700dfa3e2704bda1d3f704b59e262382facb2c1a5c7143acc6c5f610ab910141ad093519abfdd83e9768321ba6aad9b61a89846a85ab51b747dfd05da0c8097d2e50b84060c3058a2bba46857587292d43cdbca285da584928182b5ca038d2a8f072d1058a23564081130323b7007504495cb0c4054a503aae285e0b3d8ad7b2591728ae7809e7a5db665986b68da29cbc0eb940d1d2645c784268596491c54ea3ea9246851e99504cf461c88b6b308e5ce157b7f399a25113a7d3f1549fd6c7c887e525b95e8e87a4dfb5ba23328dea3c9fc17edc95d0922b8ee07c3e1f8a028b3129b94d73bb2792db54bc8adc1997a978c5dc52e9a673d2f33ce412b9a8c631a124c6ce925b1a59fa8515895bcf2694766ea8db4d3801782d27313c17be279b0ddd84458e3e2d005e4b6763adaf064b7fe1b9f0adf6856743fb0ed6a68e4706abc182f40aa7bad2971e6235d4ba5a4aa57fbed2bb96915b7a5b714b8f71e4960e234e714b47b9877e3b0700af657bb1955e3ac720b754d36029c667923afd271a25672e5fd4e742f304cd09cd8f4649145cbe09f85c687ecc98ccd0c4344a9ee0f2ede173a189a19121d1c82c699434c1e58b80cf05c8121ad5c873a151296994fc71f91ee07301a26447e4b900d949d2285982cbd7009f0b90243a21cf05880e924649125cbe2a9f0b1024affabaa251d289cb9787cf05c8152e90cb8a464999cbb7009f0b102b723e9e0b901c20471a254770f9eef0b9003982e3792e4070a6689414c1e52be373013245ab6b1969946ce2f2053f172046581cab48a364cce5fbcf0548919bed6648a364082edf199f0b9021361e9b208d9220b87c09f0b90009b2a2ab281a2599b87c01f0b90089a246f35c80d43cd128a9ba7c07f0b900798226a301f2a3519dc5e59bf2b900f93183792e406680c434aae770f90ae0730112034466029159d2a896c3e51b80cf058a254054d27301a252d2a85e7295ecf44e9246351697affc5ca048a2e302850ecfe0eb02059246751c2e5fec7381e2c535a20b142f9ec1f7c5b500f04ec5e9985c3507000f399cdb2a99b2a236f546c535c12ba591c9498d3a797f5bc2a938261805fabc8190db41220f36587130e015c7025e9980562b43963ec451fb179f2a3983441fb657e4a13f835cccb4aab91d8e60703b468cdbbda20f9f9cc843df6343938d26335a8d6470c3ae0c37b72f8203833b9f488948479444f412217135289203a7e44416984c80d5345189f0f978dd39f636fe80315eb2e16fe97a37a1d4844dc08b7638e88270c0a89316173da4a710ebf30ab15e2116ebf699b93e6cd52834da425b44a2b9e5872e61e42e6173e9b9413a79227169cf38e767899a1b46d785f1ca4c774e4e62f55a4e46a34bcf79ba9369a38d4e3e6db8d7e7f5798d4c2d4c2773c6e78e38e32380fc42af5092eff3f911600601241680cbcfb17972f2b07e9e9327d8e91780cfcfeb8749ece4e4dcc91780cf4f349b6933577335874c9bd107f4198d48a451c8bb3112793746a1d1c9e8c4a3f2c4bcdf792dd4823ece1b7d3444005a66da5eb9ec292010c86b81715007fa46d74e4e4e4e4e4e0ec36b39899b4eddb6d77a837eab1b57b7d1177640a0bc7eddb76f00ec496ad3a850587768770ed47d03f8a85c71f1ae2e2c734ae92d282d7da7f4d0047ee3149ac52497f4f1881c66d2b53e1f0facbbcd3363ea4db5744e554be764077ef16a19d75cf4eabb3278cef34df09b2acfc3a98a69b0bb968989c949d6e423fb4b2add7af6247052ebe9b9cf677af799dcfbb4cf8ff4e8c1588d46a3d16834aa377d9f9b90be798e93a85cc510d5d5fe7a93c967baf69d04e098d71280639e005adc1abad5736b7d8b6b3f3929e4ea1a3479e819c1b8896bb0c9e85d2bc60960351bd201d8b0de183fb1614db1a1e9c6989e8d5f8d14e326e75c782d2622af029c3add641443fbe8303e8e5ca35101783d7dbd89bd9618ff3a3754d361bc9e2b99ce9e00ec8dbe3b90b887f1e849a03b8c0fc687ad6e985e6df48480f1612b6c483d4bc3886177c4abd50fab31612bef0600aa0d276df02ccd305a50724daf5948f9a1f944f109f2597d867c7e7c66e487e613c5a7a6c16d0ef547a342ed30def7cc342a8776d3fb1e19ae11e37d8f135ca37e07e830ae7d31be78a72784e9d5f47aaebb5acfde8d7ad3593ac6c7577b77c4f475385d4e7745a7f44dbe0e4983af2e89663b2b3a6a3c3f21cc75a2728394742b08fe2613f7b69d7e9a8bbe7e1a95432d3dd46466c7959edbac8c06a98c52ce0ff38c5f4fbca12fa41b5683d99625ab22b7f405dc520f3bdc928c1085744be70ebb5bea975a4a3656665d4da69aea4de0c886570165d752b9b485450db7178aab58d5dcfe1601be5d83f4310e72a5720feb8d5c8929efd548afb468d4e86dc53d3dac476e9d42aeb4b0a0954cb1ab936599e27926e71846e8c57d3aae3de8a5ff782d30fef15aa8ad1cb561ab2ead1b85038c87be50e87543ae06bb445f3f062337ec5a8d622ac650642552318699d0652ac4b0240741b680e4dacb556c8175eb394e55ae820b4f5cfad2398ef35a366b776e6f70a8a136faba230d9a7c7c47485857dc7456705cec606ec8f343a745e852cfa52b5dab9e2af124502dd5a1962ed9766a0ead47bcda4c833b35477d8f784d1e86c2ee737602787796fe7cce09e00bc0ec62bcfb02208000f0fcbcfb7cde678c7fb419ed096af2b0be3bb7bda1c66b63be9ea54dbe1d51e7fb9cd6180faec2a8b4ecf3a64d903a85666404010000f313002028140c888482e17848a2e921123f14000d99b4527a541887410e29640c21060000080000000020080200a4a2ec761fbd76f04c60e78dc1a2593f6e64c2d5ce2aca8313368838663336109de4c3af91fc5d135954b7294119b881397df3b8361b3a50e0e18d146351acea78e7fe998465e6dc30b4955c50a18bee3f1e0f57b404002d75040782927fba2491757794eac3a6b393dd5363a1a2ab729ce9895edaf57818ac17f6cc687095cbad764fa16940ba7b6791ceca9004b8e9c85d6461773e3964629dca7942bc06ccc4460b8a25093fe4382fb518671136a8686b6d10b01604fb291b30b7ea1c203a7ed61ad48705fba83460619e3448213c5b873d863fe942b3a365256a4d10232733e62ad6e843df8cd89ef871da74584960b43b6a2e1f4105313ac41a262be7789d4bb1500a84b372a55dddd88f9c25a3ab4661a2edf07be1e907f8622e9984bb184dae99847597df5a6408ee5933bc9e63cd9145c2e67607474aa8d920d158ef00cbc273f211c3c0c89a0ef4e1b5ac01a3c809d5d4552496a9ae8e40d46b92320dc584f47dd75028c0cbd813536f4edf9708a5d31128c1b8e09637640602d1b903ca8e6a1aceadc7ac3ec917d3858e875bf16808b3d79c6cfc9503cdbfc0f1d83a62f3c5efaee99dceb8525868015fc9d9d1613047ef6b52d375655e55f602a38fe69837551b3659893708753f8680d8325960c873f3ec25cdad1dbd7949995d5b1ccc1f9088f5328a5785e818835edab9d451fafe54d7934dba2a36f38d06ac3a67f3f4150f7d931de666aabb59654614a8bb5920cee1ad812b1ec034eaba1b0671184ce48d48d810d576c019d7df56dd0bc8db0992a8e7f9facd2846ec43bb9ed77417ba25a271c9593c035c80777f1cdf8f2c89205219e97ed0f21a5d1eb8333365a535aecfc4a49c3afe381ee4a212f90d5cf030c2652d1ce925bf297844a77011a0f5f6bd37a9b46a1465b4d49d43d5c7a32e5895e31a3800b013917c07288465c930d153e4bc3649c9797f45788ad9b47b956810d8fe80cb8dabe1a28cd7b347de5bb273bf471da1099c1d5bfa0ab05027f557f464523e084541c62b22877f9a8f573591ae3bf526d538634a4d81ad81f95ecbb8a4c827fa247add3a1095e0041e8aca3c485312bd7de32fb865c77300b7340034dbddd341fa2ecc91def376b27ab0bd07ca6cbb4004a48bb8e195a2af342ca30a2a32e5339227f45f22fedbac3909b79161bedfbf6ec8f1989a73173b4c8a3f54e429693a6e62b2525c28fb0677583209f6d828bce79655ac66dbc5d59b9e59eb135606007f3002c95d107d81ca8aa0f1bb9145d22a9e34e27106fa842333cfb7c02fcaff116fd0c9e0d7ebbe3e707ec976c240eebe83573dcbc8125e064fed777e9d9b298a627aedc7e41f3ab8bb06649e977eab08c3a9a7dba0cc8f66bfa42b760d618a1cc1fc5a952ce76bd3cf5c6eac6ec0e4d69a23e545643cb23086c183be682e7a2c4f1b55167c2d2681db182c2380e1c9a9a4a1a8c8dd2c2ade69b72527c1cf923072433974707faf410e8dfa19f698b82111d08291e8379767615e9cf995c182559df8ce34ed8e89e041850b6ce25b13d39c20fb22d1463170ce33399066be16e6e1eb736fd7333621ed4b3ed6e7325b75bc56a196feeb717274256e5fa531e15289f3acb9a95d230414efb0fd17d8f5ceb217218e34356cd2b7f12d376098899cb143bf7fdf9da381f8c38247e3f5255616448735247e8fe386a04f451f766e209ee647c6e31241009ceda45599b56ae76641ea882c48f3d02384651f21f01a3fee33a9caf6765b37f1f886100496e942826d1f4477e646fbce9383851bdcf5c845f2d6b06e7ef014544dbeb9eb34b6c9bde71decf4bed5056970e0c48ec413db72ffd87700e9eb34f408d088b62cf26e2dc51c68314f086c55c4aedcb47a88ad263273340f67f2cd814de119b3609ee02ab1df38020fc53af7934a24422b79c26a4f004640cc12b52207d159d4ebe5340b89e6336d4788459b16d9e0788b4f72922c01e047f7f5b8b9d6da8f787e42b50a642ba80ce91b9f2185339e289db3c0e35d1c9fddb316986334fe20e4245912a651e13e5decee22f65fc3b3c043ee36bc8e4957ed4ae6f1e7ead07823b7701f3eafe7e25db0e27de551e08f538b489425decd121165a74a736793d5561d19935bba1ade8ef6b6f230eda93d47cd2d01e7f79fed24ffed8a689418e6141ce81d64d4b8784ac2985a49ba245bf3ddfe07813e767801f7458cb0a16dab6600f1da1a2733069a679a11bae90a366c2e1725b0f3ebc5c86bf8af6be5fc0df2e6d1110cd2cfbecb3fc7c56a48a09b3b73c7a62d330ba2a093281185045c6a9f474b21c4b69674953b837440c45e3ff53360903801ba233907b0db6e6e5e6987c8d60f15e0f40f0acff27a4fbd225760a50df266208adbd6518714d81704d9ff9f80b6aeb63a44b0054c64e8b632884a876e488813cf2eb31ccfd9c8f2e3af90ec9aebb09ca5beae9ce1de34d5b3da3e333a5ad1f933bde7df48b86293a6258289c5c7e74dd7ef2fc59a8d215a95841a636dd506e46d1689c329446b6044379f1f062e7aaed3c6b00e4def8d2dfd45ce70d473bab41c24b1f852aa3935f6bddeb884236629c1eb04dc67b4d6e6c9970d80d594bf64bb2712594d1d7ebf62d4a05a9263844a03d5f8d32b54ca6ecdb0e1e82cdef6009ddb94b190cb1ed62f9616ae60324378f9f7a4335068b4ebb0f737c20f3f9a396e532fd730477e516edf223dcd03161b297086688fa8624c1d2e1557f511a0590d794b5ace2b168ed54b87969d27201a0493d62f9ac2e45bceaa05c1c4d91b27ec6ade913d739ffaf70c2d17710c45e061a79692fbd33faee512c15d09d7d869017856be6d45c87687c070f7180f00ef1ed1825a75f54a86601840b3a95854b61168327612356a405d4c644408c86566ee6f331d7c0651016015e0a3d7f4d6d5a597c0934c239367b3cb1daee972549b5f76e9598b42ce369d597acaff9e1c39f2a7730aff47b1a1b54537f9ce4c35d1cac1197a0ff7d598fed80ef3586bdebaa614d64828170fb34d8337f465ff737b14869e407d903d7617c0f099e287e8a31700be8fda5cf543ed67da8bff61ebe50191b4033936f934e00f5650652f0f7213d30cdd434d28b15e28b64c3b2c6a6a89c5de50b5174064ec75442e4c7ff3d02702eaa51565eb8b421b93f299d1f9f38870a2f7f6ed46c6cc338a5e0515e48ecca29c514404823300bba87260bd108d0bf1820401b5fe199f6e8bebeb96944e4632e5d4d63e8d3c1ece2005b8965816d9cea026de67924df1db0202863bb4e923f2bcea7abb2f9087cda418f4b0f44138a608de0591934648e9ede1904a10826b84331a2c526d9da365d85f154fe7d098ce2e1092fe7004990c79b9158756f21d685ca3428a2419ab3c1c9efdfa32866e5d75c152172f2199e77b8e62a8e49ef91bd058d6a0a583f32c63b18282312565bcac182c1f458052d2170a5338c2a0e592d1b329ef378f03999d0387b01bf7b24b2e643d5397ce2e09a2e9922a37716ca5e09ea4848c4c681ea22cbff457a7b105953d6053c7adaaa832c5c6c0d550aa4363c3ba3af514a5650f5e87a93fdcb322fb2988ce9a2ad5fdd64a0e9caa98678ca3bf9692511583f56ae7d3251d21b8b41444454145093ffc9b5a81b5ce1dbae06c147b4fecda7ac21b674ad58f21744fa4e0134697eec25dda8826a3528c04ad0a21ee35bcf4609434b9fde65aee28a67062d118c3c424649b66b263442fbfae67a5a74fa4bc4922d2040e82ad3fb9393c5b73d04061d8c1a6c6f577b12b23151f1f7af00e6dd5895bc6e00ea9b275dc64d368f64aab74a5554aa5ca6cbd558ac2390744af32da66be687cb546d933ada7947246fdaa516ebd4a9bf2e577553729ed170db8391875385038d22645cb6f97dedbfe5c292e1fe9cd12d5fab9fb07ff7144e2825453d1ea80379fd17fbacf20aebf4982a7a04f0b6a00a41c956985a795ffe6ab019f17e0e8a69660f4091eb23fbc6eebd2c11d067ad82c8fa6696b284f4c9e67a95fc5cb84eb4408d6f8fe4a2116aa964ebee91d727510de285ee416ba40bea342e93e343ba04bc49a10faead080e3ed75496a1ec8737cbd57ebcdf9226e7dd4105f491a46ee15e9891a619f0cb309b9dfc80ad36ae37f3101f69b5491afdc36262fc9331f5973da2ff23c93ea008890095d49f4282c1b8916195d0575a95bad364d28952150e01fbc45f442b301e421e11a72e2352b50996db803875fc0de9694b6251c753e9ab34f3b9365572a5dcfa8e5f4615f007d02306be1a5b23e6cb7984c9d9a7e16c05ebf4ade78dcfc632803626f2cd4ab63403604295702f746bdd68dfb2ff0bc0aeae75bca86ee79061caf6046ca5b22985628e44a879bb01cfc27bab42933e90b3c700a900fe3cc079798df5dece8735654a9929bba1362e48040522af83cd88ab50f8e4eeea8dad7eb9c69618eb4ac60117e47d955ce9b8d3f6fc9954bb5f5a00984bc9f9b810dac82352e8bf96e64dd72445f3cc66cf3fccc98015c809386224961c146a766d122bb7f9883ccc2810f554a12bd4898d7044e443af40b3d884ec5c68830f4ea40dc5422ff35dab2a8f00a0c115ebc4bbaac22849d7c71cd25367932173d3e07853587a189c9a3bc7b662f90f976cd6436e129ce5185292d64ec80c4b6f82236881d2a71dc1ca746ab71e86adb1705fb5494b8753087ec07e7fc0dfab1e7cb8be6e280d54e041233b0cb89d06f9582eb56cda960d6f537de08c3e8bd5a3549c64838e2e2a5b30fde6044e579af9ef1cf88ccb90dc69d0e149e6ffabe612b63b8cb8222b0dbd5d5fffd878f4c2f7b6a2df3e1f6e1c6a21db42331f5edee4751024ed10cca826528d7eb83eadd1dbe990e111047d599ee6bc71051738508a18c8c64ce8f41555e0d4557ec64d2d39a0be5a80cbb627bcfc1c5d751d11c16186cea78cb5c465063dd2db892701b33fe27bdeae2460d3248600679fcdab86c9520545a7da8852224286a4859c667e68c8f7d199a8766a2edc065411fa3b116a8e7b0bee218faf938d9a88816cdfe8b76b78c2fa3f9980dbb096cc45892b03028e8b651ac69e1c81807fcc0bc4021ff2e409d53654f1c00d4915022e74089c8ddd922b79b7fe07cdba2667c8759cbf58d152a25fe2478c96c49ee044aa77bb53403204bc48c33d9a5032e8856c5053d689380d478f038983c7523873955758e862cef5db00e1c687856408b48a437c6c7d8eae0518bb622e80fef082cfa4383b121bfc0d00de478079c03d801b6bc34df3129489d0bfc1ff91214a260ce88aa4cb024fc5885ce8aad0a4c61af04c220f5118e117d73fb871c6c2181bb7533c1ee86ff04cc6cf28a49d08e0a9505a3d11b9cea7f75039c8d2732c2847b020396e2d72c071216c04fc488f9e365c2c0eacae40171ed7a9ff2c755098d6503e0581d0004dc1ae8d8c2a3771e9999327809686b38179647c0767d5aaedd54469c1958294ec0cb982e3d14f5443c0fcb3744635cacfe4377bc216629be29f3b182ab8908f734ef91f6939176d27a9040874005dd900dcb59b2caf21c1d3f4fa906fe65c88bb7820c5056f738b22620be7288c066d1553196f702f2798b0804af34d9230b5f8ab06a535016023a8a9d6c59361d7c43319862e04fb00b51974413e5ae5411150be7cc89ce44bcb833c37147d04be4408628699f86c439b592355a458fa6110ad90a86d1a930e0c644cbae2cb003f0670aed66bbfe47a3d6a7ecc748e80d6212fe0a40d13ac5fe8ea97277d41e958431779324a19bdf99fa5cdb5468e91356cc181fffed5d640240b2a964c3e0b290b8c8ae16d628c70c03d89913836231f1b2b6d88bf48616f3a77aa46911bfe9959dd50a3c51b5dbff0132cff2de9c32a40d2e9fab74d28780341921539912e1118ee18a3b440eed855986fa448c21900a04fa6a7f3ebe888e9006b7e6a6d7d4d1250e2ddcc595c83a2ec0e0ae291e03f123ec46aae68c2527a0ea686388fece56954fb32e70ba9ab8a9d04c6c0472789636860691359e9d8994ff02680b6a4a1015e2fd7af115bfa1f8528a7d43495e902805634c116a207492369234491b491ac94a1b088aa4086d20aaa2361455945255544a45d54c1a5d15dbb00bc5140af04fc33a825dfb7063ff4bd63b4828d85c1fe3029bf62f838bbef7f4df176a9f3870b8490171044a5509314e4f8a12166b33183e7556f759577cc2d2e154871b2050facac104eed32b6b5fb4854329d8c32ab63701cb066225754b5aa9bfc78c9084c2421831e53c741b6f6405a475ad353f35e10a161ae4ccf2a3a7313b080757a6ec36bbae7a7fc117939db3497c7aabd16a1b917bbc190f78f1cc2f66b335387fba19273c459c2727bd0f521cb424e8d481a6fccf65724546ebde2123042f6802840faebaa2a90f613b3802d5742aac398fae1ab2ac1d96c08cbf2c5d4506f7912721860f30480c359a34e1cf3a05e197456e7ba18cea7b42152db428343961c94a3559664e5e99d202ce8d6a94754e7dc2d4c38dc207b7a4293489f8922c4ab80b2920d387ff003b91140369443682eec9a4216d9bd68b556661ce79105201641e83550da2a484abd164060f7a64083c1b9b6711faf705663bd221b070f65fae1103e1a1f813354e4776b74cf6183d60190c6bf9cec58381664c84be79541492674aa2479f50a002e202833fc7309cfc28cc73200b89ec491fb41020d70eca185fb78913d7d3080a2ea6daed992a3539fa191e25e6d3c8bdcf78445210ba2e3cd29bec9601c5e625ede584e962575f96497c20e27ae015121de650178895bb83f1e522c82cf64449cb95106c80fc014e9e8ce88c9a1269c26ceb9fe8f39380a84346b98a42048199b4ca3f289b9a7fdf58512bad2c369437af33e526e28d345feab5a1c1793de18e6d3b8a3778200662f716b83d308979172e5d0101391dee7397ba66876dca3fb75f1bf99210a294815ed66b473cd21e11b7ab517024410e51ce8c3d8123b4d1f3e083a867f3ca1abb060285ab53bd8ba0ee7ee3153ef7b513479e640cd1b86c897051005ac06addc0509a295c7e4539e0b8ffe03c4055612659e968a188f35c62cdf279ec68bcfc88080d0bee6a8422ebe9be614409ad2049986d3cef03f2381342abfe2e5de33d471ed026e58de66170841bc0abeec15a59fc4796a4fc0bdfb8adde0b6a3676f9b40e40f16787ad873cfc25ae3e544043e4251ccb0d59348ffbf041df1884f2d5cc9cd4dbf19a25add477524af87f9286dea20e98cad8bb0b1d81b704b2cfbb5a320a8f2e8312412e002dee214b3a9d9849b1f36923dad107878baef41a6c2a9bf1d9c25da0d794833214c4f55d89c78e4fc1f552169126e7e4f57e52b29b3d78966da7e15634b1514d3f0400deb2d083211fe5468b2f0a46c6f5c231ed31d9df45f89ce2d1eca2cb71813c51366a65c491e0e71a90c5b2752275b3310344f86affec73dde5e532efe951a2e92b679dd3c42e45e9247f5ca930d1bc4d82b42ac0b33e7e263ce2aa27b706e8f089e437839e2ebaa8bc8315fd5225a305db72f94d4fa5cb32f0372ea12b6150b07c22a68956f515d07a9025e22c011143f341ff5e4b2b065632b7e2780a3daa733482049ae738937bd65c3159cf87158d8ab0f36933727136882a83b1dbcc72287ac4ad36c0d6f2d1bc7804bf285fd337417a404d935580c2f52f903d911222b5f57ebfb960bac60d8c3101a7f73755e18fff5e3059dac16b8af3b1b35fad4bc6af5a140a3a7c11361063fcf7ff4ed8f45af3bf36da2cbe1f7633be06041a547eff6743782ce1f8dc81799da6bc8e03414fbbeb04fcf35c342284f499544b8fe8a32d2e3cb91e566990e5c37108de44b9991f5039423bc65aeadce83be77a10cd5f6faa63a750cb5dde18b3bec0405779d68fb736fbfc20b587c11acd7dc9b4596cda354e124246149eaab829bb6da751734a7963b8f70be21a27f69e5a49e641453dd304d95cd4898697b1853a550adbd42aece747aa2bf739536663396f720fc0cc951331f015b25e1906979853c21ae579701f5066ab4851225086e85d123ba6a2a926231d0e1cd5358f743c8b02c8eba47cd08cd84198e75020cb3bc704f09314aae9887bb5d213b027bd776e12af9980bdccf43a1c5909d4052ebb0d898a15cfef743dfb6e5712ca71eed94ea773a6d4a80750c0f21dc92a4b1ec37be21505fecf85d2b4e21fb03942ffa742f726f9cafbbd945a6d43ee55df58bc36f781becedf4af4739437354dd85896913eca496865acea4df3cbb1f4e69b346c765fccda1f50993bacb6f0e67b36dde127ebff1b417f4d5d104e0fb020c715799140516077bafe19f646e98f70431ade9f79d97adc723d14cea153515d5eb20f8ce036154ad92a2772d536261c8c9f85d3d4967c348aa5cef4fc8ca9a4ba95e3aa06d688cadef8044b922aa72a06c376d7656afab0952d64098d93d4638ad6aa82a214213d7c1106c353ed8bfa5f6737579d38f4b8e1719e5beb47959edcbac82d2e50437c4563fd628dcf28d9c0517ded28ccfc1807a7e3974e4ae182497e79c4a763853c9572edaead50041b6bf945e16a0758c8321f30402d8892f5d07cc0cb6309a350f86123ec822071b57ef57e2f7f2b1dee4a9d36b638f17b6a63b0c75b31023c91b62ed330213d45206bba883e2e3863c227b56b36b10063df3650fc0c9cc97d80a61fe202b88d88970e2db163228ea8d0eac60db145076374e8ed881c383c440c00e342c70bcae2aadee77c82d15d6395a403ff666cf4daf9dc8bc65b4d88a60c8a3f81bd63ff376d7ade5ba74cde37635c25f8a849695d93ce7247710792cb5fd3d1ded664810ac2013272d35a78246adae883ad3c1083379f4b8b3dc7a4703f11e2c11088511dc1d3a75699750dcede81bb3370a8daeca66d97758c6f6df06a2d7bf62d3c1cdce24bf4abebd9a5711d4c78468b537fcd08161366731f2cbd0d09b20943309cee9ebc4b9a14332c0f349ac1f4bcadde38de82db1141c2d1868fb7f2c421bbb6651b9d6393b11fc321ba2fc5c19166c7720698016c8e3dc882380106a4f72d40c6501acbf333b04bc6bdd227ba3e1f0b60c609afef7c635d212c817765391a6024d89ceca24e81881bd1159841ba21930c6a3a8d2b39e7a30a8ae215cf529f734ee25c3138cb65ae392b5398affaae2aad58f69ffe7adfee9a07940327e9bb92540c80b346e9e7c8ee99ad562e328b98b85e029201d694f519b1366947bb58792711df41d79b7533468cbc1880cff5a0fbd89c4dd24a65489f284fec4cc0ea0a257a3e87bb9ef98a014a21345b49174bd95c814cab4e788faeab1348a40496db57a86c4f6b128b0d11c52d71d3c01a29ab8c22707fe3a5a9da93f3cb0ca74022e8a19982b03093b83eba707ea05a224088a4b720f8387ce72a6771bcc1bc5cb27098c6ce554524db99f9a8625e750b8d8b44606950d0a4d1bec1c001e94ee66a517efba3522d03862e0a278302659acdfdd7b9c0b78656194282aa84feb64ba8fed48a6c2424407a78f5d6fb6e9e6b49609e428063cc545512e29055398c01ea105672dee97fae015f22f70829788e15159685b4c1c66378257413b1c197fbef8e846a011ef9940ea18ed3556949164f6545c721ca6e41d98935547b88a33d366cb52b68bb3b269083462de1b8986aabccc8bb569819370f4fba0139d76804c40cd1220d7a884fbb80076cc6f542d80948ca30277bea3cea9460d75068dc39b6e50b4725a9860c47e65584b05a43dbd28bb1c0f747c9e1bc8d8459de9210be4fb9793ef78c55f67963f882810f047f44933150813853b54bcb2ba60aac1147060426a05b5c21423649d68d7aebb9c915c58225fca39fe57fb29e62999c951049dd4d8d41c26b32788310778554df0d23636ad76dd6308d2aafcd8e7f8448ea02b6dd07504bae1ae56692197e6cf56c6718f529fc9f46600e02c785ce41a86dcd80902c871926de315462f864f2ffc72e5574031215cbbb6080063800efbe029c342a704456ed999949c10356ab0c4062d23bcdd2dc01791aa24500332b496ca4e0aaa9f47f54c60efa50c6981bf090ba3b8c243bd9dca630f63f05cad1bbc4303370238750c8de5ed5a9c5c6de70a3987aedbf70b6fb237c4da0f49a9f8848ae1ffd0ee9155151346792b24a669bcd1870f0f38603f4281cb707f03097b7f3d096401cd2cde57aa8e5be9f6190e2cb17bac04440ca284f257fe06768b03eb2713eccbb2515e3a3b3c069935a97fb4d6b6cdbdffbfcf33573b5275842a0ccf589ad0da7f53492bf39062815a62df0b1a60ecd6774b3fb4b842639944a7ebea20ae6982e10856ca10da2988ff5124b487cc87b75f0f6adc1fdb46fc3d3b1ba78329588a00bcfc466c77d57943d4c0516cc11e64627f3e1b2b85464f57bd1b983f905f8cda8bcabb608479f81f9968bc9fae6e2e2ef00623620f39e9bc3097defd28c1473c799ca17c40c2b92f0a2621960f71623bedcf02aa0f9ca4856225111c96a4457c01637bbae1c30c0087cf0c749f61fca2fb7969d0cddd1a3a50663c501c9acedba3ed335a82935fea283cdd5f454fbc2f33dd4fdb422620ebe6ae632bbc64698d781992cdc5a2beab6604bcc3e0ece2fb5e4ff863f0296c8e44defb8d9202ea2d52813600b6bcb1a71f84dda73f7bee2fa3e5f309c7f0f6209d5a6dd19629531a1d1e72d1eaab1c1f3118770b50bcce588db35dc73a35c19296aa61d628abb4ce24a89825c843b3743588850e19ba0b8ff18166ad4e6a30448174f27a98755fa11010e8475455a4e3723e01b0c5ddea4566fd5e9e05b982b11d3911e0c5b8865dfed03685d241b65880c39dbf19006f08d487e7b4102c82e6ddc08fb1ac01bf318df836f17df0c40e1c0bef028195d80c10bd0ae603ff50effcf0564a0b4190ce4d2d1ac7e2bf7d6a11a7c5a4d45d0a91309bfe94de2df1a4113509108c403f4c04137228d04820967043a1a631c8aa56cec346946ea56543866d65bc78805cfe82f0cfcea15797b6578306446d954650e21bb9bbe6ee2bd7937f38085ed3db23b6f42ecf327e46dc3a699862f08a2e93d020d36e0f0acc44c3f5afa9df6c46629109098678336679afda79a1a9a83f1781dea3632a018144f0f1a61d806c238219ec593656d616359b3c22c94d90d5ee83eb1a3cac481d700c861db09edd6c1cd846e836f39a2066d38652bca88f816bc9a1885c2e9475d1eb71946a5c919ff22f18bb65fe791cb6f24601d1d62a586582cec339e48177d3e9add93048491093360a274539c59852b9df44e573e69e64b7977c2d37f8fa5c2e47aa6ea332f35b9644083ee71a99bd9cee9576b2b70009a4823361ea4c7888479599acb0ee249ae9992c26f169bbd15d786c8f08ed61e99192194edc55f511ed081a6bc32e312c4cecdb097f2d7e2975b84901f215be6fd703ce31f4cab36890a0c6d06109a7340724da9df56b898b9c7d7d90f191a60dab7b3932f6f86011674c7c220113129d25c3cd425c89392c21bae3bf6583dd99066f433ba1493f9e0dd7f7289df22846021314e53a5bf960b7d71d044aeac3f9ddbba47c4275cb3274a4692d3860b2b91e8300dffd893bfbfd818023c82cdfda33fdaa78674daf6a4d4cd907091e967f3875374cbed2c21da2b0a288d65d5e5455591affadf00d9819798326338fd49aae063d6366e695d1bb6e64a82770bce859d14b63a74d439af562f63e69eddfb36dede38aab038d54819b2adcdab7482e38c012ca866f5e0f97e7283dd347744c23f97077eca7d6a68c0e716cb25ca65f27ae030cb85aef18d4639f42bd92ee1a0d66c0706c61d3c49021f9194d3f0b477409244bdca9ab8fce39550da3cea183854fed490f32b093c1045e35f7fdc9228653db110ddf036698f3fa9d128628641a0d120e5335a7dae06d8fd3c3c75b80e02da0715097c37c9cb72e96ae6870019e3be990055b66473c6f842261f3004294525bedef31b8c7bd5fcf0b6998d7bcf584c2e232f992694eed96ce3f255956d3f1815ab1c3cddb5993132dbb2988f2f674611039e807466144028a51d16243104192529c9888196c94518a3aa6a3468240f83d74b928f2c14735b0ca8fea5825f18803c776bd124dcff12b37fdb9d7af8438b989f1d98f4a342e0ccfa08fb7b9beb61563e652a659ffc501872bbcaf8008f8a86276203177fb0fedfd2d91f800a139c6ea9ca6be99c05c2c689b49ddd1de6dd9050b35132268a4c2f832008bfeed49eccbeb1e025f14f52c1f70c51506254d3bdadbebed6a7ff044dbf106c638091f34621a0fc45d1011579ac9d49e38d50a3ddbf7b62e029a42c35e9f4cef267337e3edd89504b58f4046de235c00976b294c5f6fadc2d641f4a43b5130d7ff49c53569d5ec8cdb58d3cd3b0eb6d40a2d0fe9a4712e1d232ba3a1b95b28e590ef7128f71969fa6ea59e9e3f857fc8962e9a64cf58efc839675bcd49526a2f8bdbff69db810f7decc8760a509439722823d3c03a653f6325ab3d84191ae75cbdae10f9bd02b5e4221e7d5ca2c9d325ba584061a11b6f62e45f5a26a9ca431baa62330849c35b534a94f63c4317dd016ae71e67b92217e7e71c2f4ee32ac26985e28e47a184ae0fc162fe30cdfbb94d3dbdabb8ebb3c0546dac5c0c819196f1aacfda1e6a05aa36992d01967cc0caedd9840a935d86cb5ea6e200d935177b90596f6eec0d940b27c39e9080fcdd538fdd48019fc4be8258f6e2d624de102fd398f84cd3bf2c37c2c7e00b71b33132a28e22e1ec68af1db0869727780810f3284a5f655bf20d50f82b022e4510bf3da8c43ec8482f55c303f890336f5655cbc3c406bc6b34201f97f4cebfab13de9f0e37c64ad3656973eaa52d71bf8e44297527585b138be240d7b621f58ff8f5fea0acb3fa28e3f1a478373b6e57311311d823c71f9fc3efabc8493bdf4f2796a0fc6b487c8c010ef5a3f36a4cad246e8e1f9363a589d6fe96773afa99461c9289242b8bc4a10716f63a017be8f90566976d126ad9ca4e7f59503e1ce67cbe8cbbd5e81cbfa1f3ed60d81e174933b52fbfef4b7441825b661b568b43f717a46f02143bbfc0fcd6716e367783b2745ab6cc931b839cba18446151b43f745955c6c95c49e789d2ba6f0346b1b6ef1c4784ee188116f5c4799bb614151661b51d86a72eae087c6dd544bc7d1690bc9314f703ce6ce1127c8d8ab3bc3f04cfc77f188169b5c1ad7df564b1b1ef01e95176eed85104cdf45bd7b406eec1e55a0bbc541324cbd204f3e938ab640b114598f1f00548e978ac33771cec57800ef248917761433e66f8782ad5e7d35114fe1c3b7ca27c2286c976558108ebc048d7c2a6cabaac75a3e92d18a61bbd1611c724ef20eb62a04e5d9b6222b220d069189d0af6d3d6ac4f03ade2d4536ab2a569f0c41f79f124ab11408b10f052609175ae7a3e6f9a39ae199d361f65be399576465715b7edd56bdf4701059f6f944758ef0e994e1122d95921f17c24be5b07c88084fa94667f3839f5c5e0b2d8bb80444680e329f9234650b4f2ba775770d45c7a08e1967613bf3601629ab053f386f1a11506c32b4ae8849ca7ac1817cf2ec19c3347bcf0013fb742ae1415559473fad6079c92bc1a3159e4506678364674a1cda705eb116bb3b6de88b5e0bb92071ca702ccc70896ee67b105e440facb1b150d0c9775a9be47b2c3e66fe46d6e328d25949508235c4ce3e22a550a8764945fbf304d3051a7667402fac93962d45ac99174bc3bde0f460d962bb5dab097ab93dfb150acb3ca73486d380a1684a481b446bdadd7aa48711f15b086b5ba176779404240a0b3e0f862f4f178c7a6b6a2d90066e8c463a93c411671092ba05d9d9d4a2805014ca53347eca9c3e898769fd382d6864f6dad46e746c420ba8021bab84f43eae34c02bc562d0bc8a54a2722d4c82b98233d8138e61646892e722f50fc0edfde95cf6978c0a50907a6d6b966c2e3fb0325e5c85d2231f98a3fb86ce37af2646a4968daaae7ba4fa266d4240e0891feb9814e964920310aa515242b1e6cb6b7cd36f1f6b821092da60098a13183accadc4365b578107c32b605836483a4b5fa23349a99278fd2ae6fe3cf3ec3b75097a40c924243b4a348c3bb0c05c8d168088b20aa75aa3c2facc119bc9e00c0963a44aa938bc35eb019ac31df403f7a1caa55b0bb3dd185b59fd93f1e7c3fdb4cb346e86ea9b14c3b0288c71706249ca7e2065b00ddd20732ff972198d4105b83d42aae3e6edef063464a682c4419b73edf5cf5c38b1c9c1d3c08784e23b7aa805f80d9745b68245d097613f8ae9d9c8f7b872f2565e7edce2f93bf86affde06564f4fd41c5ce2037b0fd86324fbc74f05dc076ad34c54b888b17c6cd9448c25041431d29fa4fb3a4402e48f8df081d09ecd1b8da82d7e9aea8ce8b08b1af0e273ed7f096c441798cbee7f5f5a805b725ab61825747dcfc29a5d395726915a4b203e50c189c8454ee701d9d9a9dddbf3eb02748a3db3e2f0be2366c6298e8ea678a1312fa552cbf3098329a3b8218e85892d72ccba4949c38de28bcc6e6042c868c5442055112267f17bc8a4c8ed64458c5c7b77c5ae244ad5b794eab48873ed9c7ec109b0956035d851b6563d4b51bd943e1c4524434e42de11ba6105f69f7b8c1750071ecb8b5a3608e856d90e382cefc1513b5bf22383893299694d35d069b9681f9c06e8e8c70e3022c1dee6adda7acd01bf3deb70c24b0f6cc28de17ad0775380e2ccadb255362a40e33970600488eeee73719b0444015243cc7a1cd07d2b55c2f2259f50f320e3718fce0479dbcf74b3580bc33bbdce530e399eb3e62cdf079909cf260f0a22bdfc36098c12a8220f4c7f716d37fdaa4f7d1a0e39776cb0c8bbcdc4d81a34b702e178d7be8754365860609b21a4b00d16d8fb5273334229b6d85a3d6621fa999148df74b898dd082d42414ec8ea23b3ead9e9ffdcff4dc7d043ab49f9cc133938143c548a71bf76a88fcaf1d56e0fb11da50ab4956bd8bad64d733ecaeb359ca3a5ec350ba62417189ac548d8b989bf942b2f801eacb04716177fed353df619606c5b323218d1cbc2f815d4a1e31a6a9e3c58fbe158134bc52ac48cb7653ed07ab3f72f25c36771ef99b5a4fca069e4e44d8a9e473e241d1ae16b3255f51af1217528085f09a696a55ef715e8b3db7370910037838f7769ba029ad505303bebfb37ca1bebafc979e0cc8108c72662762b8677f8bdbb9945e07610bf83e27775ef40e8c6087210839902f9517431a191af7925c1aafac56f1a4445306b46ce9e2e556a1353321cc2907d28284843c26c191601a702354135542a7a619729cb1a017c11bfd2de3fb9ab99f7652be9918bded1677f93e6675a7f183f50e472580afbb08a54a43ed4b8e6ae58bc00e135085562b74c9643a5a487cc6db082e9b6d2436e4c36339046848987b67c00a6978ee56fa03ea67339184bad83d8fbe5ad62e919e66c24152154ba4e70e39cdd207606e0e628554fe86f2c545e32993382b4f6dca0d2a5f9fa197f4e5a2542f7eebaf64beeae66a20cd45762d8361174c8a26fc5ddaceb5c74cf3f06ba9118d1fad2ad101afa587dff33e25705ead00610c8ab9e24b2bace69409bcc4e3a120ba477114bba1eff5ed72e9c6eb5f8e20291724cdb92e572e6606a237eec113954110e9098845ab3056be437c1a7b45aadd926c8a0025491bd89fb52a5c24bb8604b3c7ba6d68b2b9281babf06dd20f295d61baf0053c4e4929e75745bb2623d6b774e38d75d56e6caaedc8ad631e9d0817574e4bc4c29081d9cd70d871c9e682d0fda99f33eb963a1aa50a238a61c6dab762bfd47c84057a553db51ad64a84b52e151561ae344599f52c3262f0a949a36a7dfb14e88bc7060b0dc2011c8743e6cea7c62df325ed98ba6c76a7354ac8811f868d62e12eb642cd768803b0d05458d0d6f4bc9ac029710f86ff14adfd55983792031e2829dce5ffd4761bc2c895f8a0549a738de054c7105c44ba8c8e835a04f65a40c3b5051ba4ee55c06764adca988436a1d2340791437a2e5bb76db5f27f9410fc762679ecd6d3733154434d75b93d77a55e824751ba62844345aa280ec50b44f912e7b1eaea55b80aefd1eb9b5173bf9e449081375a466ed72af0a69b477aaa2a18d8deb06f82e73d3dbb3a4036fcf7a906e722196e259d2b1ca480670b4bfd86950ca8c9f3668a056f5c43d35c62c20cbdc2158e52917d9124b3a2065e3ecf48b4ccb48e443ae9c3a3b0bdd69f8380deed92d489be6b98ac31667c5fe0c11f7c524b64d0c46c33c00a6543b2f470fbdf5f383c76e86a4b1729e725af276dcfd2cc38a9a15859d10f7d83e6cca8f2e96e4602ed24e81df1ff21dcd4e309848426dea8a2fece8e929468519b01e5cae7a12a2533e506b5a1c1e0ea4a4022d811a08caa277df48caed24d70ef649704a2f244ae5251eec6af8850b48e3d53bd086d5be6fd687baad157963bc1acc45588c57ace944201ac77a7a76bc9641da02014568a5f550b01dfe60b83c3ea67f3fa705eb4254bb2084e2dcdad1adf6033f75406a5faaca0e72fb2a8440301a76be56e6109bf4f135c566e81c1cc0276814d0881aed6528e4a9528f3e22fd50ee476d6362938eb7b17ec698c06c3cb1cb0be274c3a8424ea2c43ede6d55d46e444929ab34a60c93b18f3aa04a4ed2d4fb83848c27d91778b1c5008a9b5c14db2f8bd538b08ed0758b42af071f3f423ee2bdd87772e03efe1d71f8dbdf715182f39d2a25bd43643c427bfb0fe4d0bb2303471d81158c6c1f68004f032ac1a1f2257ea0647c95230a99f3662bf5dc3ff59cf6d950957dcfe48ce71e3dd9821e9ef59fc2e02e4513787627742f0f1c12109661db51a4afe73fac70bacae2fcfcc0723db067f68f44bece8045e90af53ea8ae3a5091dea7bcf129fb9bba2f641536cab4bc10ea6e4a07cc16a0f4c1f35a96e072f7c3980f667ca5f6a7e7e9666e75e050f6db2d7289f2f19228996e5609f678c33b83940f07e9b14c7a8495c7e2f4f8b47bdc031fb3943f11ddfc85e4947d433f23c4ba411ed97f31f18299e19c1f43f322b57f222fb2716d8dfc9a416d80d470f3cd19749557689c5e89af6e22936908b2dafeba8359cdbf1b802b3e9f9ac5b914b2586e6e881cee254e622fac933ef6fd63e661f21878fe41efaf12c6b929b0735ed2d3305396526a0d185b58fe737ff1fd3526cdbd80b587054d361cab66a3044633a40b8322349e6136399f7a44cb8d85f698bff620b5ce413c5a6ec2e42f08d7cd503a873f7fa8318b930d6014905861050a36f2af444f0c9862767784ba0f92ed45ff78c0d10c6d4293d83b4117efe7642d50332add6721be883c0382e48eda95eb5d22366114d9380f9d0389ce464cc49e07d42eefa4f4ba8d6d4d5780ebe7a20d9918d9ad10355fcc9f2905207da9efbb8cdb2a4e9b7e0033538636b64f2453433e39ae75c790f3ae4fbe3f561554257f4126e2ef01af89f4a57cc712142837a4130d644288d1e483476b256ffa1f8bbe2b3023f7a63d4906e81c0839fdba3fee087e76d2cfd1a7c1dcef7d75c49634c16e7805bfcd57786e34f13750a2271362fbe693593d49eb38933d59b23d8cc40e1b15120e65a305830c47f6c92ac5b7a240a07a57efc9396f340e95978aba032d1801405be595480029b986cf7e9fa6b4254c85d338214d6a1d294e75fc0ec3ce91b4ea26905db2d8dcf47921f63fc294bae062d29b7d50ec2c3a90581defba839f8b3b0a471bf41bfb9b761308ba81d2b21f2173d9188ed808cbcaaa0c9a3cf7d067f7beff7bfd19843649a77fdd46477e2a8efd0a0e1175affc7492db25ebcdb263dd973306d69f70f69b82719ff764e41ee6bb23f113a6621415e49c4ecfa100e7cec337bbde794726a30d2b1110b33f2e93f0094c7247b3068d0f5c78b12941a6f6879e566cdbe65ad57292f876585819463c3c4166364f0853b51eddb2467c917c193134b8419e3b3e42fbda7cd275d5f438281b73e14ed79eee02cd224d7dde9d4d2f80d79040888a2502da8efd5896a393fb656fffbd65649ff45343e1bdd67cb494a97ad2874a1ec9419d4461e442ffc9eba63163846e071ae11b4ad8de0f1922d77e6b395e68d13272d4d02c9e101be79301733b402fe9dfc7cfb25fbc84ba6dadbc6ef4cf58a67fd382f3cf175b762236249f5852ff04fb045ae77526adfe23a190a711e20795f9eacf0020b946423e42fac0d184996da89e7eb142eebe84ddffc9e471cc3bf791150c5ed6e9afac423720db4876a33c6f08a8599f84132f567ec6a8b501611271db0b0588fe0266631851431e632ec2bf324c06e3a34f67ba2e4c4aba2a2248f805abe6449bcd8540b678c155026aaadbbcfccca8a4b5ee4f67702a0e6fb0b4e3f386d9813045e5e52f202b4d9733267c0479a58c72596f122146b1916ca8ebab5716f3162f226f486f3d0e8e95c1792b6d40437906dd3d5d7ad7bd2c9c21408d20d5bc63ff63ccc170d795b5f65bd0a59dde470df9200f69c0520ac15d2f6a505217e92d9d73faaad0182fbf2e24ddda3f96669ff51baf027ad7e81ba583abf0826afbdf1002039a9c825bed9f987c7f765962bfc25583c78bdead22ccdcd5b04228dd5580029f1b0e1c9ac0b3f459818202f0f1922900c9deb5f13b5d7481f93758a4d2770c3ae9505dbb9bf4a4ab1beb035481d046b1cb98ca3bab24f414b6017cf8482409b1c248497f028a420a67ea2d5541979aa5b25e5f1aaa1ad2a5acb7ec250dd50fb161b5c191f9f420a8adedb18907c5232ec27ae32745be1fc0b255a8efb412a4a15c2e7bd75044e694fbe37c592e6316d74e51226c30ee094352da5154ae570de3fd73326ed324a8ceccd886223dc6d31d6c9cd97947c596a02ce177bfbfe88d0eaf5c26a3815f6e424dd34d8325336245e8f151f8ee8ee31c533f05909b4e413af8ee80a0500cffa4b61480991614423271dc80c01f0d13c04d6e0c131be75f38f12859e573bb82d80072de98b0e7d225835632bdc011526c70d16a00c0e3f6f0149a3179de86c58ad74a2bc8c450eabf12934d19df8eac2334c0a4b977cb518463eed79c7156c2324f42aa7892a5a59d67234e5f93e24f1d01a05b51ca4e8a1c37dc0dc040196f4045474d6d965044e85271df9eda6fdc2e155943b0b9ab086b2ad29fea55a48fc2a67c90a948e14500c45a81f35c50c89770a375701586896ef031400960b756c0ad3b3c5e135079eab7601f52cf897cfbf941d423831dbde2872be80feb3d5a6e8e29c7f495da2ef79efb8b49bccc6f11fa116c1c4ddc88d8c91c196d6ce8b6e97191b2ab5a13a9e000d0ebba8acd44ea15aa249878ae7a6bc1265af2a7316c65df8b687766c85a021d0295a12ddc9254a7dcaec8df65b3f237f368d86caecdd445898b01d219f10d06df637098289101548945f0ef60385da5a18c50bbf4087274b3a6f8e83fafd0d6491fc6799745673780399644ddfc249d4de9d61eca7896028d2e28ae6f9280ea43fa6314212b6aeb20010cb0e96e774c3272031d7a1a69e37f7bfb300b033d6c38c63496a81591c86381c7b2ea29a024cfc505232c19420f432aba3f21592896078acb9b09697e2c38d7d23cfb4407cd657ed73ff04cf97e9900d7b6442360e3904a800e2d50ab394ff8b8667aa8d2a8d7b45b7bd80e517ca7a9a66ac2054f93869817df01d18e4e770924bbf4e0543d5182d1ee909a3e20b07b2109830e48ec3ce1b9818081ac76f8e29a800dd5dbf9dae3c87dbfe08303cee0c4f21216dc3a29184e8b3d4352957ef4c9125e85bf17d70a7baa7ded48afff25836ae2571c8a12e0ad32b3ecc02cab9a392920d4613777a2494f708d8b4c20b5c8a5213b369529e516172b39ea327406356a9006cb91782a861fcb3e0bbd8fd0cab716d92d5a8e17478753acc0064b13318177c418591c1de29f828bd86165286901301a3e89300d204dbaa79012ff7051f2497c23a8a287b8435ab612d64359efd96a0fed36ae45880cedcd41fe7d7bc3fd3d48d8b4e6a60877e1974af40783ec68d7d843a0ca46dda036eb264e0e9e6b9c7525ce639a9a174999afc226378d2e3a1ed5824861260df8914aa39f1d876644ee10d85d9dfc090283732d8a11c2bc386bf13add93784608c89fbf514187c345dc3f371b4600879a300f7136071487a417d7d500c5fdc3c86e7f4ecc8d527d3d48e688d4827adca421f53a305fac865329cacd69bc05ab83cb724cc37732266ae39474d14559328c7b48e4ac4aa2613d9a442ab2eae9ac8c54b8d6dfa7accae677f0f0ff49cd9f6b48628fc93dcb95677469a0d1effa55c7e03f97749a959bd46ff42d0f1f1846e9d54a74084792c7877a1f30dd5c23fb0c5bfeffda53e70c7cf73949fd654ec52c9198e102ce2cc809a552bac977ac4d93008480c4aa8d9b49a2cccad9ad493609d4fcdd0681192adbcaf42f3e8cedd03d29f35502836a1031f137e87be7032757fdb9d68c4e9a4c7137a26be2b92312c76b3b824825f1aa7a93e2db71bfe9e5522a63a9a836bf570342f31aaa536e7ed86f72a299ff6d033c153356563fa7f03097bf81632a116420ab3233a3e634e298117175ea88726ebc017f335f583fe4f0aa8687d008a61041fa3f446d32715cddcc2ca071d924d614a2778b2c1c079d8d113dd8d3b462f7a861ca48d3b0ffff3d913cbb0e67cdd4293e569066cf2755417bfa907096943f2b8bfd332c2507dd02d9261d90e6a784c6c48dfe88d2b3181467edbaa9fc8cdc96f21ace9a7ab5878e55d626a39bf67aa2c0ffb867b3c3c7771b121039e56629dcfa3d6fb3ca6a469e89dfa0f8d66316121bb1077b55fe855e748bf37a5b4f664d9f59877db1559888f263ac78f982f894f2aed713c66801ca12770b5b83673c647c12223dcb2753c6e0568b57f39860e0daaa23a3598d670fc35c6cdf9b52f862e24bceaba0dda74c78a5864220dfc556ba8ed3f27e03b4db8f868e63209339cb7ab2542b67a9bbc9832299435344baf635714b27e9d9052448bf01f474dbfb0c718b3744469f0f9a5f6003aea9fd3bfe76983a1cfcf911b5bc0965f515497a1893a98fa150083e49dbf0005004b56f4fb83d62fff14f0bb37f066297134eac458bf3bc64b50f7da435587b3349b6d1a8195a8c8d4e1f4a236dfb2089bc153cc419553166fe745eb7208a8307089d38d8637a786597da803f07604ee4d459a56c17511eeaaf817843ffe2b6d096fb0de4bd5cccd3adfcab60beb6082f4e1e3f1ad9e47c9df665208a42ca5eb001b5a89b129feea2ff2ea40b469626c1b07c60c61bef6107ec3e52d6f5cb32c3c977d5c6878c79258c22f523f957ca7419717bb1d1b694df63603371e356928079d65c6f37c4ff4cb667a749025d4d38544c3bd3b9b7d86844b8cf1eda4113271cde032e3ca6ea34d04c40776275540411726059d545ec1560c5f95ba1824db0cbc5917d48f13d6fb0e2a950c26de6564b87760edb0c9caa926c5d9c9de49e9a7f3fde7a250820aff32aad80e28cf525ab5a67f85732ae4840678fdf700bf410ab436c6d52c90d5afd146bfdb34a94ebed2c16fd7179fd75a09e2d7e896d3b7d0d35e2a67d778671f9a7af0669a8477cfa384cfc0c7a5f63b98661646fdb3e8b077f500c86a0918a350677abb1bda4ef2477728053a5617d360252db21e4767e92f34148daba527caa322dccd45de06347c56c12bc6c1bda8474942e92b9ddc332a1a7be7db79ab578ad23cde9ce48ee4182a7be2c1fa7f9f72e3b9169c2bc4f2175eb20dff7dcc95b5d63d22125b0b7ef5edb04b20b89a84c885f97bc26e88d109706b9b38238f253178942212c84a777d1f439b949d511ed9835a0f85747908ccae3ae638e805ded1535fdf6951006983cd164da91a9eee2b5d4a8c854b2dcc702d756c043fd04afea41c957ec441b26e22912af659622a040ef07e9305945d4365a279552d3003a85ba2f756d93df77202cd70619091d8fcccaaabfc473b04009cfc9be5f73653dc21ed8fa8c5819fed1974f4f59da49840af6a5c1b5251cd7966aa4aa22be811079d8c8cdcc113700102923be93fe540680e3054153e690a9e14fa59a3538fb937a6602138438aa4c5de1b1f517559dd83ceab49b4b59a6ab5aac9cfb46856f624d19fc9110bba0ac92242d946c55f6848e53ff13ab0f04aa3df18d9f86a4528b98d4c1e300a410a852eedd3ccff9f6e61a26c88d482a49b797d152e24f12cca3c702a1ee32420f39576a34b028c9c36d32f211180033ace557e79626dcaeb4b5397955f26935b57a12d9d3d37b0d72ca0c11c32d74edc3477ed9f4805e725ec47c74c4d6051304a6e98b829efc4d4b6375588bebfeac1d1cee0056d7ba9ee3a853c5405a9f1c318a68c1dc99fd9d920106773ef711d0de8442ae8a4a66e29c14cb6afb71fd69a3578effa48bf14dcf36cf72e86233a6943fa85c9c98a4e9c4a40f28d07c14e99f84051c8535c64103fc439b65fb8759c23e2b846284a745857201bcc1547b52396804a86b1a4cb814a74a5d582af73a41de3304ac2f3e4c7cfb40ab90c9fcb9681655741da3ec9c214ae3ed0edfd0e712b706a7414292a1f847073d7b5a1ad414057e2a83f4ea83b813e42ec3d7554165e9c14c5dde86b6152b2d33f68a7d7897944820d319b3bcb0709e90feda3cf107dce0c944f3d349d22eb3c7de0955ec8a19dc93d50bc4a0fb6eecf9f630196cf86eeb90ccd366183461a7a872c1a83a96fde4f52d83b342e628286bc8074954846300b7e5ee1d26f38bcdd58f09229c98f9794a5d8db8c1767bf500e4f51de36303ae9253f118139a2227846f908def1992a5f5b282432840d070708bafd527be7a345aa0804e9586d635472ccd99c2ef8ccf715b541fd539a5a9eddbc37e0f5d3848c4c8f05ba5ccb0115b8fde909c1ba7fc5c91af1949f1fc121dadaa221bb0ef282373497d7823245a80ac0465570144a474bf3389517066f20cc11a9182b6cf1f80556f0c066ce603b368538a9e65ba339e15efb9203fefd56afc09b6607def35297346f75363839014a52581b8df91c4d84b4019fd818773af26a51dcae6b9708a7565b2883487e5f768ed1337d264dc50832812e14d8e751cd70d1c996288bf8699b085abcb098ce72574d18e031862c9a66148c99edd429e6eae10b363c5965fdf8babf7b7053f39118761edfec4e00b3c001664417d8f6682169aa2598d0dfedd91ddc7750aea49fe74ff4e2bb300eaa8b9e404dc32f5a05b878c90be995d54f26389c5e1079caf0551fdaed714b6602b65ba1aecd9ab855982099c0a833f0efde88c9d4f0b8d6eeb3cb85d36e175c5ef72fc4be0d111b3bc84c5ea04d15916c644232739dbbaf95d40138ad3d352f41291e51acfd874e3f0ba69252f8367b444c1d42268c8a7793a056f6025ef05796766f9534acb545e55831ad42c50a301bc02bc29e8f5f4494b2bacd49ca0abf4049d581b5c41b6c87a34f3caf0cef0d1603bf56feee1a58917699b3a8d5c4d1b77c2c0ddf358603ae509e696bc6f799302bdfcc54837378200d1ce92943fe776043b759fcf74970f646b65366a83b949250249821ae18a736f1305431d2e5eedaf5ebc192c99d274ab2ec608713756b297acbe1ec46d98002f5af765865e75676f17ad595c7a93cbc902c538ca59ee3f400ccf2fe6b5c10ba285d4f1c712ac1d6d2c3ed7e88a0bde28a1491dde634402ac80bad1b96eda454f26c534d8eb881c91b7dcaebd5fa07fff5f3a00fdefb96baebb8f977b8a4d51db823e88622d841352aa5295a8a47215bd26d2d8562cbeee849d133e956ac931c6d24d8bdd988fa32939a9c75467ed9cfb95523eac39b9722c74fc60e72cd5d78ec7dfb7d86fb9aee552f9e1688162f13115fe58c5a3f6d1e81ffd47053ba7aa2bc6fd13f62618edea0198789f01947454328f52b85fcc38e0f61b25ba6ccb80a186707efd2e93683ae768ce22199c735205f059efaf1d630a587265093e22e8c66fc8ac4646bffa28e936b938229f174be3c4e27c86ca98591cb72cd3c368c994d79d72d9f283d6fb99bb3479652e3b875914d970dd698d6a6eb6c6d939dde75cb11e7cbc22431e82b4ca99b59ec964998d6f11859346e21279ffb1a1afa89cb7e8999b90d9f691c8ed644aeac379d04d57d0cd55f2cb4ac453ab230f3f5c36240c45ed9c45df4c1281e489a81c4a0d55b567d7eb2b37911edb375417f59d4bb2c8ea08a6465c4f13b11cfb289b6fba8adc158d4c05d455683255bec58636a5ea2f97e8e55d8a6bf9290eaeaab164bc4c03a582379ad1c38ab4d1de922f821ab43d66a8e50bab44231b12069d949467113cc08e3019f9021ed30ee7c3002a8de20648ccd85e2b67d0a8d1f04082c5e05bc2e98981b30a6296d312eeaa9ffdb448cdb329ecc71f4bfa5923528dec4c8f6292d065dddd90a7d46cbf71df1a796f98d950d830219609e1b2a87baa9a30d605a6981dbe143edf3e45492f41dd266c0a86054a995d5c2b8813ee70177f4c217cb2a10ab58f3dba4540dfc368d0de54910b7d0060140cfe410e9d4b326fe761df61075540566d5c4c4f74442359f5bb70e854222d3ba9fc8c4647b81ad9eb69b0a2cbdbd909d353d5ab37df09d98f67c6b7a061b9e8b211de9dcdba40e8135eec3e1b257f0a0c6ddc9b687bc5feb39482bbd873cc2aae90c5cf32692a201973ab8726780238bd7b2edca41d9b280a448c489d7e5296fdf16bd2e070f1a9142060956a678e5e07a0ad1ebac04687581d9f1ac6af858eaae73a55df3ed74889d0822c8b3b86ce517be816abde658003c0e9b7317ec624368489b11513cf0e0a584fae12830aae65ffc52f8bea91221423502a3814408dfc71316c376768c18a9fffa0bae63ab3d7ffd1e915b644a3860f8321c501cbab069b3392fa106a71f0e119505528c3bf62fbde0ced3460ad92d7ed87b3c6e42c088bf0f39e639eb00ec2e4a4a38b84fbdc1ab725c2706d73d7a41f1a3f352150cd37182a47b52813ceb20ce4a93af41b7e525f24f4a54d0b1e0d229bb238c320a3907314f566abbeba3c724e763e041a9bd652c3a55cf9359ea565f01139121bcfdc0dc1921c53edb851168de62d3bbefac81284b96a885d574985fc307e55b2345d61dad43b4307e41944260e9c4121b1571eb01b688c50e5fe5e49d859f25e4374e0f348912248dc056b56cb74a33e534cd583f8af3b659a5f4749c30eaad1883823ba810fe976afb74c2c4b53a108ade0bf1f99174b831558666310f81c8344f0000155d837bf1e60b228418c14c39a710b3b0f31975ba5ace7b2e123424a746eb7e597518be449d22b6de15c7be82d7fd01803a3a8053febea4499bb770bbd054c2e7c270bd4514480ddaca809d1310ff0121410be39a97b41a3871f9794439cf08909411c6ced3290c3cb1d1052608c1f522d9c75288622132bf8bfe14bef0fa20c32e7da24c01628bff4751f7f0a82665b4f43e5b82c96228bd02a24a602513c8178727c307c74d3ccbee4a4af796a2d467038b89b8438ee4d1ab53e68759b169b9e20bd067155434f5c2fb9ac53e3d397bc6d12e73310d309b24615360287551133ab02c465efa2b3b22a70751bd290404899b78dd3b98e7ce9bbb45be4060d12deca540f9e652374e3b8611bdc1c60adf5c6c76cdc4b2148da16243fce69b50a50b2ba83d097ec2888126fadc2fe046a400e9127e2f8007be02ca969d562dc04be4d3fb1c632e591c24f3acf77d9c4f5e99875638a2cf5be2961e72154a22522ecd665ffc19884feb968f6f216ec410d77796cd48e33ebf3d77b7788a3f514540eae82c0a6cd8e0185d18d0907105c86ce1d44b599eb7115d27febfb5310dfd52cc2e02a0cb7e58e318c79e994ad786004eb3b1f523ca33d4465341968af631f1e02c3ac3460be7749fa6c7ce840e1f64e8c5cf596310c117515541f2f570ecc515411c27e28b52db717996fe6544e60ab1ccc9119052a067411dc8e9481d6dce1e5926cdeca9a780518b5fac5412063ac3ccc0be46feabdda6015301f18c91e6db445d20a0330225715301a58483b317551e812679863ab31a55600c734d0aa4e339d129cf97ecfe9fe7f602c271d6112d9f83efa596686e34723a35adfc68f045238d67bd4298ad5cc0137468f2579ccba1b00558d9efb7f257d8563341d1a1da2581510aafcb2dc25260260647444536606bbf07e437a6c476f0103c4ffc056aa2b7857e6619eafd0224ec3feeabe37ce3d8321292c6408b05d2145062bdebf13894afa72c60c76264ec9930e99a26f3d64e787b76bee103dae9763ff55eda634967625f240b788bc632fd9d7575e2f6aba24cda818b5cdaf1bd5744930e0b62c7af400b8d16af5224092020125c82a22889dd982e02fdd0b82422f135e3ef4420b0ec3065fcf045d59f91e86069abadaa689515b806bdc9987fdc7475b2f92c017241c9a3ea0170fa5c6b05098fdf0c8045c9e3113ff226239e43f34f231f2fd11f0373be5b96d43e59c7da20578a8da4869c95a44c90ebda7ac37d581404f25c54de01400d796f2e18c322e3cc9419b4ef5a2bb5ac9bfb0cf2ff67c3d329a551bbe7cc4e578ed0c95e684eab9e17c9ca75172503c91dd432960d6f638dc4ebd6d2360e48d3cc23da15e3e92a9edb9be80b0169780acbdab3a9ffa81ced3318ebb98083f17bc45f0c6594f4ae7eee75dfdc8f8b96b24cd207b29bcb9f954c5521ec6e0962e192c5364cd03ce60de1fa66d0b84b7d9bc069b66f5f79cc0af4aead4b85dc118741bba15fb21ba91bf0ca39e6eb634ac645e0fa02862bae8b4922ca91693495c085e0807d1b811bc053bc6c0e61633a1c89eee79893c79c2128504cc564fe88c4fc8809d7f7a28e494062ca026785dcfb64681901db2a745b389ce0f8503b043bf2e10cbc1fff723d4a22fe19d574b4543b72ae73580795686c74a171636053888d84713c60983bac7a3320dff764f06c948c941fb7456d2be01f29c58346b3361263733f003cb5dbf316074a40aa1ed7c62c5ab20058da06fc0f1ac826214564cf3343ee167b1d53930934421d6fdd703ac4f4e84457fb52946871ae077ed515c65870c1d6b5e6ee4e880ff384bdd9a651408df5104ba332c924c85158baffa6e2ed27bcd5bf5b47ac4baa5c9ecdf7290316f89a923c754e86043defd63355396208fb9239ddc65308a19d8f597ac13903cf3b6df33a8d3f853bc007f45376666ee6b65ad66af002389761bf02240a4b1f515d8cb27a6f03c625ee4cf9dc9909d6e0999f737cac88a8ba48f4becde299dd03bb9a7b761ceb554c76511964788412f0608e151359f6852b6915ce0d49abb018b9e10a4e6d83d3f72a2fff86c5f7cdfd83af78f91af0f46bd8d9dae9d48fd9a90f359bf2e93f57f1505ebbdd54a029e58f6e2ec23e07a603fd68356c11e0eb5f785a7ba23c87e8bc26f963d7caf718bad5f0e3d8d05e0c709f5f9281b0b3ae0107d59f6ecf9898c287e2b8961f6c06f7c3a760e90a50eb7b5ab6e0aec2fc1a4d8e2db89e9261934dadd3f19b85e61c4eae24d7191d2adb27898dc945136071057599976091492dde44dd2b86983e2537445494872e220fc9741a45360191a7f5b320a7b8bde8ba68b6139a4747611eb065c7fb6dadac758c97fd0d2ab1a8ef8604afff0fbc3a87d35462ec8fabd1cef0408096eb1c9631e00f0b1d9e2bf494a8fd85bd92237c445bb228278a7199faa86fe1973d2251693cfa28e7252dc56921a20d41f98c3750914257de52ce6ac24089c8406fea93152b9c79647918897e73130d4a1e172a6227c525a64e46595cfb6188abef9866dd12a2a57fd28081099c7d28f5594092c07fa83343f4307ad2eef66cc89cf1f7ae99b30b644d0da3780991aa9446e7243364d74dae8c320e3f848fe67730ec1ab7173f2e4f911c0eef7f6b48d3ca537885bb73e62f284fef7a480c406a69782f9c1318dabe8e154f51c6ac35a54279e941af408c12a24448d9062d6a3f0d077e482ca4c75cb14b1a8eff3af92636b274a8ec74e34999a4537d159b16610bdd345d4052bd9d3aa7178a0c15a55de2519e390eb729a60dfe9c5d5ed5ea56606c42c752cf0b603693828b9cb3a7bf412d59a046ed6393748d32c2e8d66e09a486cb9c9a81864aa8990495fb7e88b0717b65444c33b104d5d1919e1aa1ec2c14050d9180b9351677f10cdadc104aa90a96dea4ae64b94e5712ced02abd756a1f504c49c8a699a24314420610411df780dc9530171470eed253cfec5ab00b57b43edae673570ba708f20182cd29530dfb4a42c0c8631abf31a379e6043dd6d05859a39f0318b1e18aa047613f8139312abdc810228ca66e2c1ab776a6e4a02dd13cc8c7b3115221224993d406c32287de42160f3dd7cdf7e44cb7b25425b848337b14fa6081011b8c483db0acad2d01fe60533394b5de281b2d8c49682b5eb1420e6e45c7fc2c9150f6c154e97d7c89370ef7dada95fb3e5495d984c1d78899494971cc893003bcfa5834fbea2d2a378c6f17c80641b7302e48618e2a66215a3ecf8c46b26ae4489297cbe890878af1c4c44b8c0a3f689936d9fbe50e28862ed22788fe28086225931aaf6d9efa2b35a4bcd1654d0c866ae44cf32c0ec1f27678fe6e2837f52c6d89bde840f1defa46662c97955e3d79108c2b91c8478c491ac5b480c149da6e28d11a788cdd46cdaf29092480e1faa2107c58acd5e631170707271214a7833eeb814ce3e0d6b878af78106e446af5199291af829a9300c6e398c6b8a8a39238eca0f9533ac7e2fa84fd8843d906d839098a113404c665ae8c8571bcac4490b36a9d06f8aa31b61ef30b986682d3b0b915ec416434e3b8f9f90e63499dc4593b02c1c705e1d9563800f995145008280792e1e608b3dfeed25a587ea4a540314ffb6e0db7bd0560d65b7c9fcf942fe456a6b0b3a94fbc7ca761fe93d07ef53ae1ccf80c642a349df187d30eb749e0dc0bbaab4c98d6e0cf77f35e90ab447d2899ecd1223674f645477197d674c82733fb092fa2977034ec10e0bf7e0eded6c69e80033983d809ea720972f498dde67270abefa2830eea757f3124c5c8e907433664c35c2407c3d115a5164b28468ada6269690776fcbd1bcf905939ec48405569f21690635d97a0e2e1390240515525843a726bc50e77fbf7d3981097b8104e0a870f1fba2b897cfad373010f5699e22b6dbe7b4cc12eefccc85fedf2b7af33dc5abebb4bce4960b946f13f82d0907d703575d470eb035c66c3c54b5e77f486772301442aeeb881420d5fab9fca74e363933f6f0fc439d65fd81e4746e9e97ddbc5ef82f6e25905b703e014b2554e7fb0ce8d1b84a0c38753f89c046b2cb03575d2086a59b11203ecbd704b4abfa064f4c44bec269353a3a252447fc81ab032857da0c0cc040042df053f328104fd4df271f8c3fe226cd2e90296c9c22d6c9effd5e95fa34e5e2bad107dd200ce0852043ceb631ebdca2df1889f63ca59f4c439019517b3ce41a447d530e661748433093309296c723529c21480d8417bf0e07bea5cb48a7848c907a99ef922730042f6512dcf3cff6c889c079ae7fe8ab16b0cf2bfd0d85185cf1e32d1370fc593402b534ded39cee19d17f7ed2838dd9faf8c0d0224f83fbfec9f70598b78ec53955f9b1c9c261b1236897f386041b554a71536b963665e0e7a518c09e077b68d52bb15b8abe90296231519617a983a7cbe66c5a7381bf298342e81a560753a60db0327ea4ddbe7a4e29fa617489749bddd43f613799a1782e12535e8809640d0202fb589278d3606f8a135e2c19106a72a85420171b45b6314d0241bb1e51779c7f929c80cca7001f83b0e659428b59bd355faea16433a27bb22cd0c76d524f3aa9b825c9386b2bd474b29b0afb59ab05426913ef47a9b915d0cd328f130af141e98674dd7e2422e19710d36a371f5aba743f60c51fa92432b90b0848ab2d8f6a27bd20382e75cd0fab6abc7766a691a1138643c4d3bf1497c037d17174f445fe764a02e812f7f22f9c55a1109f40528a0cbf248ba749ba1ecf7f4100b3b74ab9cffc6934eaee6137cb71f142acdc673f33212694df6d142b24c7f94d058aafb560b66811ca3d8814a05c75e926e5cd587d7284c9ca42706704f18f48a579ee7e85d13f7b94aa25fccf876cbd080026f1359063f2e1d889f763d94d75417c0338e98d51e8ab6d1867a60c1c5fceb6c4505f3a926b6c9ac1d686f757347d928c996eca7f8148871da59f440a2fa1610cfa41ff3d128358556df00aedc124a891f4890cc59765a91c6c6477de6f9117d4038788cc9f6950b29673db5c1e530700b9f414356a5523d3aa807e110610579f88bf95a7b64b3f927780ccf078b968a81209eb2a90c7350de29fa30d200c0392cc7e8674e68051b326ffeb6949a0023155f40f33eb478801896304b974b8c3f81138f05e3efe5a1eb1d6538770b021816f8dabd2d0db397d913f68927b412c2caeb067e255c0c8bc3ca74dae9c6db9329702aa6bbb2a5c8ca40e1a83fbaea22c0dcd0816a8a2bcc9ad76fd8a7850df4ee1113f5ac0005562fc3283962ede07e341a725140bd2926b6434b9429f58e9c8d81f0c13578c8f171792502e8da59c1c5b624677633141da622400010053286f19829698a55ff459064d2b2c625d38a87fc39196901a5ca98155fd49cb8fe228ddfdef92143f57dfecb98f70b2073ac83056114115edb943f6687f1924aa0d419ee1f1889ca3100589fc13b4f73a79fdaf1be8b2fe37697c441e0093eec712c3d2b85df82d272d7990c9f95c55135df7e175900e142bd66a2a9da65bcf959bc9f663204e0a53f036bfc9f810bb6299422f461ba20a7a6568653204f85f588941246c785d5a7567a24dcbc98f4a42f196e7cefe23d6a4e21dd01b2a5ef5511077cdb87188737e5c634bb29428923504a2c66a5b20a4d2569e5a5e8d251e981fa208ab92c5f67d1823c131f6c0f95abe781eb62db4889947b55b6262f5fadd86e92efb19d808c4fe55a6d52e3e1917ee5190ac0036ff71b7033e58f0866076e0af5a4f7d1f24b3dec1621dbce87491db32595b91d223671473d26907785f5b3e6fb0c476702015f4d57e71fac60d622c21eb60c38a56b7a838224d197adb6fb9c5ca4314314c996af8a30db266ba4726f657449f559f43e7dfc44412f76d02a70e7c3d1b7de8bea0552c705520d38b511f224aaba4358fbba7b41df956ca370c34a335309ac5d9b58c2ec2d7a4655ac630a01efe44e3d803044465af6adc062433a9908f695b93904cc69b76ba1ecaf9bab1eb35deb656b711dfae940750bb466c598241ef13a3471033b8b136a61d07303e10565d540e4ca440c9d48886bdd5c571524ba0570c78163c066867a68673fa4d63a566bc1adf5375c5de99138c1ff87ac3279b8e1e98000545a61be0c36d44b1661a16a9ed7c7e210f303038d77fc89879d03de5622220c2fc51040ab0b34d844cb0bad9b0702ac66ab45105cd326c34f45a4ac92456cf349322844c078fc3a16f180ed42b53abd388e21edd784f370adf3110f6cb1cbc50fde71e6ae0fe43686cc6cce5373340d68371b1c95b9c7fe9859a8cac1efdc60f2535b019b3d77102a0bb6c6ac6a76919f7da7801678c27d6e3371c214640f6c98122cc21489a06532fe817db33f586381e8ce74e15faf1314b5ea99a45d8945aa6ce69c65444526bdce522b7ae38cd986e609b908ffaa3b25f61ca15a1f0f25f84cc18434cea660f1d0091dd24d18cb9539aee42629d72823e2a55cacdbb347370d6d4baaade16181c35946e3ced44d3891e4f2bcf7c27da3c0809857443d205d1588f8179878c61c153088126a6c76cc6685de2146df049ac66873a7a009b0341869a31cde3467247ccc760887b321ac4e6e92155745162f4e32525476b60a45590ae8bd83c28d3f4a91466f64b090b779f70ce125742fa51045bb311cfc92b6b12c603ee2ea06785a015e18777a4721174bae2de948ef530883abab1cd680c75059836264f8850e7051d0f654824230ca79616597d20ed89d252e4c0bbdd0630df6f00d1f24a90c4093c9ed0fb8f28f3113491c09a165892adb761f4ad8a4c54e6b166a43c95f470bc4f1690656934cf978385f44872fd23117a49ae4a8391f742f68b53d5be4730756fcfc73b6c323a13163a4777522178c3f97fcf0539b8f5eabacbe1a35fd1d18ccd21687eca49afdd9ba0cb246e92a28d955333c3e245d83a48d3fad394cc3b8f09944fc715c395e4b84548c1f3bc72f09033ef8c79248cc0368dba199d7311db1a2fc240909d63898e40c2b1528d46e6a604fc60bba7868576f9719adf92bb9618e848cadcdf862a4fe080683071fb03669adc2a4e93cb6434a52ad954e38c52a0758610669f653ea1827c539598341825aa344da76f8f28fef013227b820e8aafff3b155cdb4da9b866117eab93e08d368cc79211a2b1e57aaf10352765da92529bdbe880de53ad6efe638586227e2e9bcb0c82d720878c5d64f977f4c5947f8646ba2fa4b825c10700a411f8c0943c0a294537c119c5696dc75283a9f15792c40507addf4a32ef763a730e5026139baef8414f186b146f150d94b40e0f9467157e385264ebadc84034f5556e6c1fb5cf4b1dcdb3e5efa51f237e040a75772de7acc6eb5c6074c575e344fa0fac34eb37e5791a90c8000f2b5736296651a05f4c5fd63bcfac7810d8594a2f8b06b359f8827d35590bfb1b5250e0b828968b2a338fdfd33ba7cff478627064cb38f34725fe939e1afda5a7f197de8d5f7a357ed2dbf8498fc62fbd1a3fe9ddf8a477e32b3dddb865e6263ae32fcac35cd3edf149cb5976bb5547c1b9aae9b122c9764c9c4ba3096751b757919f46b5c273bbdbe952d6ca7735f7d32ef8148c944394ba4f9c5c0619b7d440e8ef2a938874305e0818de24bfa7988b77bcbd4cf7cf40f418dca344bccddd73469aaadc600240b6ed9eba6dfded90d011871db0473764efbd6b65ac1ca1aeb5bfa05dfdffd728f46e03e0f1dfc1d52c4cccd11804630b397e886c2fbc8292926325274470aa2789c41040b0127ec7049442e9e52fb00b2978e0f464bca5ee1f0cfa191256515ed62a9f6c834365f6e67e4bd3f7fa1cdd4a62feff89d7b07c0223e0db0662055450c67c2188f8a659457c35603667fb219b3ef1d4a0207a52756a1481d50918bb73fa43959d208f1d3c364a98d6661a2560233f9e637c9c9ca29dd8413ea4281f34e6a89b76de5e929d63b685f10133cf71dac09038e0a925e5693e9c973ed516cee4c714fed62262e56e918ee2b262db877c53ee40b99af6cc84043b9357f0f5736d8b9bec414fce21adde68e0af1a525be1322e01f73d08f4407767c9072ef457af6085856ce4188c5027f3244dca6730a707629f23ea7f0a18f2515bf5d993bdd9387dfec591c85321fe6d8c1c5df0774facecb62f03f0e0475428a17d3ea67db03a725965fa30f01a7c18f1dee468e6cbd79e71edf42ce65abe05f5b781216de429de5d5b197eba808e61aacffed3a469eaaa1c9480ded2630f561fbebf89131fc766bf545dcea9035593782a40760e46399e14a1c0a5fb1efd49d8cd7b32bb226d052a949808bca821e3eec8f71c04d359677a1c81a4813c661a7069891b8d7c0a49d12ec1440b52a742268bd1e9f300c4063053c9807666a13060822c81c7c1201819e13f67c42e7c712612062ab010c503a82c14023e2fd3d795b6e178f9fbf629edeeae0550adb38e178805835d87f4f2bb649ba1255f041b6086bc011626c05cf3f61a2248a667a2ef330153521326a6958a89b55ddc9f1acc0d8d4da8bc746517dbb05ef85ae238f0b163727df9328236427517ddd95d371d7560d183db7c11641175d31970d533a2fdabc8b17c05caf73280c9ad2e9e34bea4b81b7045f8e2d9963c5aaba5d7a99bb87e2a68ca8bf523bcff995466a254f8deaf47bda8c37e89adf9204eeb8223c93ea6a5956c984619aef4065cd2cb06d453a4651596e31812a15c5b8119d880d20217f559e3a77fefd298051ef1929bac062dc240a025400fa2f73e6e6fa9bb879966503cc09a23a1a916738872cea33068d71c3b0d05ad2077e0d59f8c94e7ef9bd6b47046000a2f09420177ac309f75bfe420bac9fc7cdb10d68a89928f06a38e1a4b7f35a84b7d31cab1748ff6cfb99fc07cb63987a29b7b4a6fd4943e7f24f32524462a2cfe6c895114ba705c06db285077cd1e83196c891e932ca059107924156e4e33b96835f8198f165631e335088f5253fdc33bad0f8cbbfcef459203a25744dc4a749cf79e88ee65b90e7de9436441c38646a4087a7a7d409fa8b20c211cce0e4e099610594e2abf19c2af69541da41a555836d066c11729b213f8001bc896a03393a2330e5ea2cda06ce10eecb709b254a3de461ae25f028808d66a6247e261fd2676c27f429eaa3ab91f4e2e67cd1b65961983bca549172bd8cf852e670a889fc2992e6eb160b72e9ba011fd71ca72275d9044a2323d2dbead4eb84e25d16c902d2792e41e5f62c1eec190abfff02b663f366d5af4200c03a519008b1a3ed2bb27551a0728ca56b5f6fe24b99a1f3c44dfe5025f182661a642c1ac1defaa5c521bbbb4694b37bac8aeb4c15642a594e838df0b3f3cad482a24e328b63955d3bfa47446334875e21431e94a724dea1c09396369adca53e656bf99e43af67418e24bb7249d3ae8f3ec59baae491ec67cf5b6f222cab227a626b8f75e89bef67dcff99c93d0c03d245e5be0f4e4a84540df6e52eec8ba59e98ab76779c700611d75a0e77ddc6704d47aa92290a3cf66dba7cf14c82ea66a95d193fc44709e0186826e61ad5fc17c4240becfbf81446b771386e073a59683ec60986aac82f702b4d0329ba0e489894f2bdab40815adb2d4b822742456f5291a4d06cd1367359c7c4c00fa7af15ec3a433962a87b1375ea2a18df9087ac0698c2baf9299e0956205d3d1fa0f808ece93b8223805cfde0a8bd635e74b63a84d12580c8411942dbe11f031ef374003eb7c30323541a81018a7a9ca4910772b6f8825afd5c3ac0d6474a9a09d4581627a27534397b65449013095ffdfeab251cca624df67d8272e957a3f6f5631ef09e8dbc8b75efee9032c57b999425cc81b2eb14d25409fd42dfa0d368a4a27500a9d0053973bf39aec3c6c7e892578136b1f9ca5f789a5037347714910e18a0f091d55616a7095e11e515efb6cb9161bd5e7f586153a996208b69e84753ba88696394522dadb1969f438bbc7218d5759759a0bdfe8525f1adbf5af318ec25474a9574b5ccb76be20111cd846686a4ab6393da5706c1d5d0b3b4b2c41cb66767478c9ed143b68e06667295fd35721913f2305f1f25d73d476e81acab751e1b729b1a4941cb30d0a82246e636a06cb78f3d9a565b754a6ed3e9a29ad73e5320f2a2050259757bd7f94027d6d18ce208a319114ae8b89e2356825c369a3e484a499c4a285feab50fea39d9a1dfbf9cd98df9ae01828b53d908f50a639228474d32808813cd02633cc9d9cf2b4eacff366b07d5782aa3866a28d53a4a5c99c0480c5bc366609d670aab351403e84415ab892367c77dacad0c4e34aea6c644b9e66871a0d181979946212a50de910cfa4a55cc7f3db1cc83154296bb666a42c20b6c3506b42ff48e7e53cfa74188b35ec2df0f33c9f997d9a5a8cc414314b9966590b51c8354ac4aee97436e1eefb36fc1b5c1c0c5412f64ffa861297cc8aa8b243cb2b29d64f84950c98ab5a9531e84792d026b121768a642e53493387262ccd1f464e60558aed7486b241e78670dde278e97391547dbe311128d5c1d457697a185f6eb467f6b4095e3da19dc64276c29ae36169237e2074e4ee53f15ad8171c264278f8fda0197b3ba8a28e4770e6197a18cc89162cafba8a71a1d78db96a9766534db97d4a1c6ddbfcd05949f0de005835404be3006906444392995f06c229c9c86f7f7f40f4888260bcc0c7bfc8de59154b8c1626534245727ada2c3a0bca73107ff3e0990d77affda0f0ee1d39ab8c957d39dbbdfd019c099be7fda2e5497408931e5fdd30ffdcef4999283b518252b0a0c40158fcb0025acb5b4623d33903809ec672911c27eabf14b0daef031fd72e724c8f689b00662f8e281f91be76901d00998a945abc69cb6ea1875399e927f17bea84c9d42054215a7bbee56f72d206f1e08ec44f4edeb55fe1d2ee0001ec9e166a35c6afd57872a35dcb7774c885ddd9142f1fcdf4e6880de54c6795dac32a145a172c29d5e4f0f39f03a3d346c4a40626467589596096c36cd43ae5bab0f1c5a9d1cdecf045de4435019efb62bd96cfbbd05825bb7bab7f3cc12c4321c7fa43c9d3673a29c9de202b5ee553c4274c37b2ffaf564fc37ada49a4c61c4e5121c30df69cfcd98ef1f9bfa82302cf6d919d1b1e1ff3c449440f247c9ddbe6183f172c76a7d024f1e91c09a238be09826a3a9d45d7d2f39937004c70806c31b94f27817a515ffe94e77b01d628827ce09d20a5e0929b1f7a37fcceaa3b44a2018a6b60d7001848116b7005a241be0cf84ac520067385d51527d736060a129489fed463b88dd3721bb7e9582eebb45dd3691c86d33a2d8d39699deed3e91445a10b00be4d10750832a1dd77309dfbd92db174cd63551b6108c33a82a550b788d1c60726540362ad5cadd63975fbddcecb271b89d3e9f53b93d9b11df6df80887cf923d74292af85f56ce20a9d6616e62465169ce3c9bcebfee5e68c06c120d315700e111bba7f4444bd52a87adc0856b87e77f85d8888a19849bb02910b89a3e4580e515533d67cd2a1c5fff4eb4f38da001c1707d8eaaec1944a3d3e2d4d2d38b42b37a13a870a16b3401d8abc4313f428e1c86abc8d02393c85101ec3696161067de3a546553255af5b4ded7a11e68a5c4d0ca8d49e94e184a591c4c22fd4ea855c41ff5e845538bf4f4c4c20458dc0d9f546d7f7fe40c4106906575a3bb87cabf264ce40a82e88119f54b5be148d3037d89eb1cb3f11e0d35434994069328bba49fff454967e221c92c368fef0a35e59346ad312b6fdb2de77fba572b6ebe682e6087235da10fe57e863ea742df03c42235c778b2ed2c7237f49364030af6a8a827468509ca8a7d48d21142008f60e10acee23108b19803582d6d707d4f3312c974322b8ace1b2c329f21140facfad5b26825ddd69da600179ae180dddf22e6afe5331d5ec7d5b21dd862bb947a91dd32ce50ca2949f23dd4f96ff49c16150e6a8023669751a3b6508fb5c85ba160f1ea4862009ca4a42b9daf635e5f6b6385ecdf9a771f7cddb2d541c327a137df088a0676f850c6d69959a4dd1e0a162d30921e3681ba4c08829108b29f8ca1c8760baa9b5acb4e7b41dd8015709da95e098201e9d8bcc27c65e1014c9b23233690f4662d0450eefd08776bcb10a0649f15f594c8b1ba5500c3fb1625750621c64bab86dc7129ef84571e3e804dd7a11f10f4cfa19a1354b8c07995bc390749dfcb16b6c20fa8af41fcd980f529c2e03d43b9c129df4cae835d6e2ad7e8bc843b9a079c06195a2245812d3a51eeb4cf8a3ef3e21c2e98fa3f360d05ba9ae48057a570d5be494ead02a2a56d13d2abc7d9f40ae719d6904b224c3eb6c2495e241d7f89efa479707a7150a746a11cd3c74e8a15020ae356107f9ff0b5dbb3ff394b7ec1412d69283c8a72955258d0baa6a26ebed3e9367fb9de43ca043b24329a9298afa393278f43a4bca22870cd5eba0d9245e6a2a7bad66d83aaec808948b1ded4b30c66a08b0a4506a09d23e0c47ebb0eaf481176ec3a9a67a264798eb7255c7c28428e08d9a39ab1f1d62661252c1d8fdc64b849818fc6b97db7b7b9e810670184bc3721c61ba46bb60fd2a878a1524431628e0362bda3e406e9f8a98d5e18eb83b59012ea7c4c2c22478672738373b4434947e6d3a31b14d58fc8ca045b1d3369aa885be489853eab819d086fbdb7328477267dfb846c08cc2c5a6004f96fbc9c809903830d821cb55f7721b23b5fb576b30ed0ed15cb69ab7a582fe87a828d8e4b5355ec1ec991b29adb8b9cdb0fbdef72d683128e220d59f359897db3ccad708c2f6c59d95b9fee095fe80f66a72e679f77d8861d6a4eb4eed1fc22c7929b851e7c56c35492d4956985b7bb2a396004233a84e9e669605797559345ea64116a1b2617195d1df2aad79950dc328435ba213e7e54ef66c8fb3a13afb02d437608e7348fcf885eb896fdd2589f9ad744f096f529351e078cdaaf902c73cb22c7cf1e61c8634777df8e84cef4960d3b650f45c64efa46a85285a77712a2ba0bc07980c75c0f62cc82019226821c835385500e2617d28574da8c4c4f76a1cd197016d9c270f832045335d497c76916ef53348d9e11733c27c0e0c20fc41539d35a636d1a79ef5a2811d083bd345a09073341bb52f851c07beec9d13c2d1adcae6c45c27e035c7044989ec9cf5314ea9ce5e11fb95e5825288840951ad94b22ba66647abcc9f14c83e681f06bd39c356c9880c6dc32dc06bdd1ca4388216d16548daa10e057b62de814f5cfd1789366c9f3f6bb7ab78f6342f5b592ac0c345fa455b3d42a163667f84899dbcfa6f4fe41fe11b6c8f152b9f23a5b3b2c3105e523e02377716090e0ec642dd8448d7113915a0176f668290475e99bafeb6aeecf22470f70f9880bc2fc8e7198e33f66127b92cdf01816483b541460a7ea48466782b29edb10f814e9017fd9195fe2336c297db76d3f34a7e27f6fd3676af0b6fbdcfaf3da4c9c6442acbfe9baebe79db8f4738bcb0ef904ca1204b8100b5a83cc654b901d8bc21e292ad3c4730561c8e9c6dad5a6e1c05c5426a9a29440f7f52c577f75dab3216b058dd308c6af04b28d58aecc9d5f91f738623f118264972ec41ca1a435607a4dfb6d65b14c01339f2a57727ee754b19f7356755f8c4e96ab842ea55c2d125ef7dc3b7287c56da147dd68a7fd40d30423bf8c54e76b32e0b75d7b8d6dbec1b8c524f4aaa0c67a18d6b0f3725638c6c7cba0af62156b6627fd722951f81ac37c5b667d9ab7a1d10376381087bb2a5ac9fe144137cf54c002d43db153a1ab7e0f28046f8356b50fb34fdbe1212be6a06df3c3405e34a09aa6116076836d6ef7b98d608f0bec3437e3ebc57676348a2f3a90e2e2332ff74616f314a6c23764f549a6a4216f314b191a096fdcd3006f18f73a0e4143d017cbc2b84a1adc2cf4f606c109b3849afdfdc5aa085406904b2ca041dee3b8240dc4fe99a1b549c830d884043caa7ef923d5f08ef42be68fe7e4abe63309a517cc21053b1bba967842434278785b3491b917acaa513c2e7210f6a1eadfd9d5cf3de5375069047b92e857cd32ca7aca5d416535cfffb23413f44a316a58c1db78067e5e84a1df30c61cce7f42c27124c80a1bd60670a5768cce3666252b420aba71a81480e23efe74b1444e53580e913f4eb8072544472e9075bbee8ad34e8d01faf05f7110bde67443d5dce9673db85d8373e8bb48008c87a9148d90fd975652f52bddb5045d9e657c4492c35d60bd347de1eb2d51de012c30d5ebb80397bb14ff0bb8c39ce4197d0813886dea4b3b49e36b0ee58eae9923e2256485ce2954b3109169f5f3d9057dc3f84c58dc78548b969772eea441627046b875c97f9e4c024a0bac05f9a3eeade11ec0961833683b6bba7918ba9a9f9ebfc7bf675f632f33a7f599b88cf8a0cc8b0de1e6562e7a9615b2638abd4ff7e841189b0c114e174210a6ed0c7f15668c2048ff4e285ce4e2c97626b22572725870dff9380b2cd46c66c3b5a050ea393b5fc980f1ea4062c229cb1c80accaf69d5180268d0566e55aab794c8e9beac30e120eba7ec2701c884c3bf75a71c7a1bde77bd6d333dd890f29bface5ee7f772bd45638863d4519367a9d303e0ee6c3ed84197ba06b93aa76d10d9534a791f05a789873fc49cf4436c58e3906998e9a64f20a30daeec5795f0733963f6ee3fc3c0eebe6796483be33b1c0bd797a73feeb58d3ede8f5c1af4175bc147ae8dd1ec4a0352937c4891bb291fad52cd12bfca344cd0b2f571801d2e3af048efe73f28c5a066b19fc71fdafdffd938739c14825f613b6dee232d347082e854227bbf324e240a3085070a2b2cb3861fe873ae7ca72f71d74f65f06f39a4042e0d84c530b93415a5043ebfe2e52b28c16e9ade4df4ae082ba2e05414d363d1eccd44ce5487ab0167f9d292d1ad0d10b0318f5dc494adb4a913d4d0c11405b7505c2916e321f2bade891a51f22cb522cab1156d8483ebdaca96e0cb0b622f6f2eea0a57c3e64a9224ae9286d1f0eebe5525e0085d1c93a49761026ac6d8f004883e9e8714ba3301c074cb7b9317d073125570a1ae946858a98bb14f4f701486e295df7765b4870284a7bec251ad65ca8777abf03f7eff035e11df53116f8f8e2ca1717e68a2a2e317e89a43a0973aabd16ca701f4416cf9e24f71c95b76b1ec07a546ce83e967e1c5883d0b480e3e3ba09323ed9340a8e28deb8b10432e9360440c412b545782bd2b88f62a63c67e0874db38110c8406a3cb3c9c43b4b19c7a77ec98a27387d073b91eecaaa45569108c34368521fee05651e07f13445e7028c9308d1fd4ee80e593c591b6208328286c533ea989709f3ea0270118261292f02be8481c784187ae0b30a7dbcc88d70baea262b96325cfc767cde58c81cd8724726625ec7ba748ff731a198b27093f8a6d9113bfa3c54355a9160e9171d328a16c0b041553bc5cabfe26184ff012257603d563df3647c0150e68aff8cecec54c38ee2206f48a0916e93f5e1aaa07b871c398e024ae856ec00ea45b9b56dae194c779ae229bf54faab09f4123446950a34e71cbcae5c8b456b32e9cd170a58e5450e60edc0e80708d18382d820f889971c7516e6c5122173c871a5ecd05caac1161204870cf9b8d8996ff8f4a1fe992b4ceb436fd40d7a8eea705d23b06de4ac35f87f91824c0ec2cd70c8d939c08032b9e3097dcf8cb8c61476cb5cd2527621969503da51297c8b8041c1fa762676852dc24c0d9568f5f893f2313279ed04cf29992b3f3e9878076effab9beb77def2fe1f11e9d059755186897f80799942c1dee754d6e68b4176f2f2bfa0df721855425aa482a2455c95528c040552dfdb2506e7e1351299b6c27c30347f683f8a37244113f43e6f8995a43a6d4041ec167c91f12560cb219a9ca17e24f9c8ecff827b58199b9fd0b5d182ff2126b944610bc5dae1fd0f1d57d4ed33465684363302217784f266af3b2deecf64cb5e8a73b1e84b614a82f22cc788d8086df3adebaf72d92a74c8d09a61d8d7407af31e258525159f7c1120f7388c83d89012cc2b7aa0324d1d029e07162f5a84aa4f30a2bad35dd9ed60e7fae2750604b31372bc5280f25778e9e850d9d4a724339aea47a72ffe3c1be949d8ebccbd836a4b663f6b4c8d7820c8a6a4a39b613ed6af48f26a4aece81f2a2cadf0f72bc70dd421809272db0689d19625fabdaa143686e9952080778572483e08efe5df8a0d0988333b5bd399d9850355caf0dc75b4c9ef6ed152befff73cf9b0511a41624363b9c2de28caa9265ab40a76b011877ee465e6883f308a58a9125f064b403dbf14384211aa62ee306bbfa243c1e142f67911ad1f8d565d48bf9f87c15ff97e9d306e4c6dfe1e3804c5d6bd40b24668b69cf2cb81fdc44a2301c07039655f7acceac0a4104caf6735f126f06e25725953faf92acc296926adc41a038ed5a4a0395e2973368d03680f2e56d2943180ad5cc21cfcc221643e0e0ea8cd0b852ea4c1aeff398ca5a320fb38db0595a5d8265eaab3344efaddd4c36674ba38b5ca2d3ad3089476ac2cdbf8dd4fb6b8c47730237e497123425fd2ce32343085d55a9ee4ce903b8ee63b050412a37109b8c790e4d7f18628cfaab0c51f5c01f8402db3a793f693ccaf76166e5cd1bbb1c943d521301b5c2a9c84c9c4bbc5acad6270932928cb41735c7d2b6d6c4629ae60b0ff2790c49fc31648a100b45c3ed87c7952031c38e7fe69f2cf68183045d882cc5f3793490017d8b0d36a6ee19034a2e06554eb7834c4e9069ff0da055dea246cce93cd9a19c74634bf41e9599c5d8870929a80193874e7a25fea66804b7095da4d351f7bfc04cfb828f34c3e8e650333ab8bf44b16d09761c5c8f4d2ef0341d86846b3cf64bf0b8bc3ef8384530a04fd3ce7e878539c66f1bd4b8cdda78a9505e068bce52245546292cd7d42f5d25b5725d2deed7e0d25a618acd84ebe9727eb614a2dc5fe775e576304d0f7d83e3e9b147121d6248833af463f8ae5fff2980eabad83a5ead2db194db2b3bc2cf7e8ca43fd0eff714cbba51cc15ee5f2c227d141db036efd425a9b82590de0598a00dd7aa22f2e55a9bb6455f11b3f7e6eca4ba7dcee062b35870f09bdfcba64a353bb8c66c519fa9d8ebf29d1d84480a9744d711a3dd292821b5ab997fb391170941cb6c03295cf90b39f59ad00b43cfe43e1d7b2142f1a02de4882e74ed60c7a51159f42afd7b2513d83814768bf4b2d74a7aead3d0c01d9b60b032a28a5e97e8efaddb1e7814761f4d7f1ceaeb34ee040aeb03bb55309ed5241dbf2d916c810205803a49e2f43b46315206d7c4b72d41226b1b410b2a7045406e060c22daeffee673954a8b3d2b70e8c7c5231889da16563e7501e7477bc163debe8a7e6bad6d4236d9841042f6de52ee780b9f0bb50befed5a5a83a7aacb5bcb017d92dd9c851608aa580221a433a0ef10bea7c00b7e52d0be33417777431b38c8ef02d2b594806e94638c314210c02702085b96703b6c905d1d2869b86ece64973a73a10674a3f73d20084d628c3142182928d2c1d07775375797d6628fa4eea9bb5d5a8bad69ad45789dbb39edd483992ed923d04037ea3a26374a354a9f2e5726e64b97f66266623c05064db246b897a884f69944966050454e8c31c618638c8f31c618638c31c618638c31c6c811c618e319c638030a1f63b48937d21c93044147cb5c8ba4824029eac5dc7037e003e09470c35101b89000aee18bf1628917a3695e40e785d69aeb016cae8b4d6bc04ca2ed045a5b224ee1601ce5186374324a10c6ca06ea9a208692cb871d3972e4c8134a34d078a6715e74b813aeb0b94e8b9c2a2ecc755a0021c93d8cb9fac6a4a4a0d45b896c217c08e87bbb16c861f463ec378db8e37e947392aff7013ac5957eea8a0ff58806c3c6719a1bf188830a9ce6eef6a6eba66b898f05b292cecaeabab94670d95c23b86eae9b7b6171dd5c37f1c5f71e637c2fc618a91a2315e3a9c679efc5cad74d2c7960e24c13cc1b374d307126ce9d3a77e2b4061bc82425acb37bba5da41fe44b3488f052461fef6d5140f907dbdcad66922ce8e600d5a3e626982758c166eea6a8464194588a528c51ea47bb5df0758f009200de3ab3cc489f5e2456efd9836f655966ac57f7615917925dcb569608bcd58564b7b2772f72e104026f59220c845f59227cfb3cde54c3cc051898087bf4c0a0c2a01ce53aed6683714360a7206e2a150bf5217c374aaa8f0dee25be27ee25be572ea67128b743baa83a8713e31be7894494de270f4ab579eedb54de934b32bc9bf3590a7a2418f87888f7f8d706b7230e2e463efeb9c18daec7ec6eef89f56dc6f49edcf8ab3ea74d97757237a6bfea5c8ee9d68c3bbdcaee74f92e49fa4a6c95fb3c2d9a4b8fa4c3dca93ea9c7af75ae255a9ad884a9364807036311695efeebcaf2a3ddad310a75341290be5e73e05dd709a83bc543f0858792dde06599794f0c19ec7901e98627c2bc02e95a5a8231d2f08b5128909703fa7a09d2b574b72c036de2c5b8279ebcf7b408b92b7c130ae0ebec131726e1c840dd83f1e10eed23c329ae11dfd3ee6fd31a29d7cdebbe45e876b8dff79e32f0f140470e51dc7808dd9c81468cdcea5ca9312e14e3c2334f3df8cf4d24e229eb587ef0e3d952175a21d975b7c8c47c041d102c0156086300c6ddae5b13390b244a902841b2e4b5118ec2c47def2b88e8be8ee2ba284fae806271dd5740fb1b5f71dd5dd23777ab996e6cd185efc9234aa6b8ba2f5540ed16a40f9fd5f156d0af3292a702ba399deb9c4e24c22445f81ac2259ce0e68a5a631de980188ddcdd65863782054e6abaafebe12ee48de1587ef4ddfbce081674e1de8eb1a064652b380704c256bc4b0acbce560091d7638560f242b8c1db6c45642b2c869d5e56ab6ed7b5e0b9ba6fbe7faeb3153c049cd80a0f5b711b650aa8f58d32b9f23c1e0673272c3698db57dcc90aced1e7d16cc5153de24f920394afa02c49214514060642d810761018e804291d33b36376ccd6c975adc1d61cbf307c71b9b87dcee2f2a72a2e7fd202177787ebb4d0421577abe1db971225419ece351eb65cc9ba45e3d6886e7c0dbcd2a59ba4ca75cb2a062b755dc79e710ffefc347bf0abbbb36e452ecb0fbed71022f0b2851389e9cc6c1df5379198b6698afb607f72140dbf4fd98d4f5d521365c581f65d1197d6583275ea4d4d561c28fc5403e3a589925c74504876d9bd30ac4530ae4a209d6c07b82cb828dc025cf701b8189884abcdc585ae835170393a0a509404b38d6371709abc26341a792f1a79d1887b79ff9c476bbf4884c1378e7c15be6a2452b4d6f05585544b7131bbbd23535481822c2ec7e03a259c208c2b6575f17cafaa877ae805ba3b33333bee41f40aa76ff4abaaaaaac3ea22114529e8f472ca503769765afb56ef3d8f64eaa19ef7085f3f0cd677b1ba51764be26e585555afaadeabaad9035e082dd723cf555578e9dc8eadba25a757ef564bd13843a26d9cd65aae15072adf47aab4149e5e56b5ef0fecca99eccacbc7ceaa92afc7d257f6555596997737286ee8f2958f47bf4beb465dcf2d0fe8c332f3eefbbbcf6e505cfaea738a9dd27b90a04a30c1cea5d713fa7cb0ecd58df97a2690eaaffa7bf455cdb03943ab948b5678899832f4d99479ef55c72eabec557d5885d5e9b452d9ab2c11d4936534a39688d63865cac05ab4d63c9618746b9c3ed2a3cd73d0fb8da447349e7fdc8ed0fb8d02d03dd704f2f9783ebfd4be35cfb37f2a8de7f4d6fc819dbe9a331e4bdfe58ceb03f7fa46dd238d2302be6fcebcc946233da2efc728a28ddb3167deab4b5a5544f87a0e956434f4d58cf9832f2545174f24b057d59ca1afeea6a39acc5b3d85aa71abf770aba6ae0f113df258cfe9e7f4d394f97cfad094cb941a0281424f0949223e92ca00812e65d4947f6a7c887e522e2385881e51cb07d5d05d8f40a740353e4469a84e0755aab5f78117ce1fd9f55c7eea759570822fae43c3754a3001942b572e0b0addf8b25c927a9fea7935bdaad45ff5fce3b18ee559ac3ebb9ba64c7c565f75d3b14a9d65ca5496881abe34a2d6de69d488d8bb92fb35b66de086aaeb99a418aad1ec6a408c52afc6dd1a87bfb88d93c4dd82c0dc9752e195c238b090ae6593bcb8f09a76e263285ae9a07f6a8ce25ea43f6631ca9831d989a37dfdc20edf212af9e23a2a5ca785121c971e5e2e07448ecbb9dbc3874b373417eea1a50795f7705d140e1b73e672699933574b6b94d61af5e8725d8f972e631592ddeb95af8df132882b461bf136461b31c61cb14a986863b4b1b5c4ebd7751e789832d7755dd715af6b8a3156e75e6a4c206f3a0fb3c7f419973057db882e1249a24b25352694a426528e94b4e084c6599af4888b1e39a1317fbc4f5751b11bdfad87ab5ccaa2471bf51a972e31912ee9c820e60fbe2b52888b27123b7c629933d4276daaaf2ee7c5f04e767af73ccf2611445c9ffee92a53e657f924e3776e070fdfa6d74b1f2b9f56525eaba835ae55c65fab4f9587af54446cbf8d4b87487a44f3db4b87386e47bd748802b763ba90ccc65f6be53bd94f933d8faed55d47846f8b6511c2379e08bcd38564342e8d4f13c8fb6489300a6876ab5b62d00de2481c2a6d2c3efc36ae229a406c0bcb0f1fdec37bb80faee5f636cea3b9874f9f719712f2d0f89e33f1f64d217c5b1e2bec115f1a8fd3470f8f97b1fef01f78b8ae7a1bbfaeebfdcf04625f2d11be2df74c20ef9725c2f7768b9f7eb02c3f7ab80ff7a1074bd352c3d75a9affb251b7bfc6b1eb73cefc1aede8612f49d7894022f00a1192dd68cfc361269077b644f85e76933e3dc704f247bb49af34f5357c7f6b692679023a55fbd6a89f07bbc5d7f89c3f76b8f46bce442b6a8dbad48f9d15b1506b54d7a8546b34ec769dc5f29c5979fc7cbb620f37d6b831e5c69d1704e6ae1cd6cb0474e5f36efa5891be5da3eb2a5554b758871a4ea9d2250b64379155f2a9512ebc94f362621ddc0df8155c788fdd4425b8f0d46ef403173e93722edc5ac9062f4e6bf0486bf0b204145e826f1b282d183bd60e84cc51a27159b2b435ae9280b991a29c24c5d8c23e90413a1823b40fddd5a1a6d12dedd2426c445cf7eb03ef54c730d137fa8fa2313c36b7f3de5b7676fac993cbe3c53417b70ffb8bdb9fc0d8dc4a3fe9304a40b7188d7ceb272fc647922dfa86bb9dc44814bf3c5ab2d676111b15ba2ee6484ae4f6ca325d5a119e80b9b88eb3b8ceb563e76820a3b8fc7e17c210c24feed6ef374f992277e9d1bb0bb7fdc61da5f3f9d2f4af5ba125c2fdb62eadb9c8fd44caccf548fab710c5fd755a68e18b33bc64a40c461ff01d9f6bb90eb27d3ff79e752db748e42e03a4a89e96dc1dd769d1c5912be1159d832ec617238462c0f749921effea7469ba244d522572b9b8b81d43dc9d7b912ed9adc8dda64b6f92d83dde961617f7c2cef514b1c905d021f11c740c39cb28e6010d31a486baee5be8d3dffc411d861eba74950875853c318cdc343bdd9a58b9ca7ba356aaeb78236e356fab12e12ba5a5a1cfdef307e859263f2f25f541abf49a5d541d8d7c463f4f7f55ec5d63dd9ab0deb7dec7acfbac3456cb7bb6ea33eea934593ff6a3bdaccf2b5b036ff64fc657241255d0a719754be27e2e03da1ce2f4c885ae9c46b81bb235d3473708642392d6e03fd00627cb0e3d877715ccb9b0edb3b9d0a635d839ef063c843b17b675f86ed5ae9f36d6b93a9d03e1b35ac377de5359e2ddbd2ebb0e61ec5d310b6ddc0ba476c33edd3aebf0931ed1c34dbb8886716194ee8ea2fba6fbc8851ebb1d2ac9eca65d99786bca50f8ecd3e3a7cb4c74452f06dabc1bf0146503854037d185b4a1cd7bd0d9fc526b551aadc180529eaa4fafeabf780f7d7cbcf422b7ebc652feba3ee731ec59765a37ab5fb55cacba287756ed5ed5258a6b5578ab5a61e151ed5e92d0be14e31228ba48ca33c01664946490d6a29ca4f4579970a3ebce39283c6c33ae9b5ccc6322ff983c239c23b60d8ea04347cb0cda399c233ad935781d28421d32dd67f3a2784674e0c0a1e33874e8689941270c6be75ed421c43565463ef810f318211e848d0f0047cb0f2d42c408711c1f40103a8488a141dc46109452d09419511f7c38f5c1071f46948e748c46a3d171e0188d70e8188d70fca0638e260e1c7c47d55d973afaa8eab806efc4f11f70c8b458a6335a2abc3c83759c9a332957877d36adc5e3a8cf8815e806775cc79b1ebdefb0482b2d410e5bd4800ad7393c447cdbc08dae4e82eb21b40f6e7c47d1232f2eb3d3362786cb7f4cdee6ca70790997833fc6651786cb4e70921e49d7ce4ab80ac682b3e02d54e2cd34fd717659dd6da2474e4c17dc917f9689dac40da88c4db4163b07eebc1827ae2ad00deebc9d2494876f0e8a179f6ae7c09d6b6297b59f91ad889c262927293b109f78c08d240f119f84a80b3d28382dfe08f2080f0b2334c39df8f88487784c38477c4c3936efae275c59045a03af8b5cf924df55de5386e53543ec90a5c2305a8b7f35e2b4162f1181c21d08c615f45d4a13cc57ea0613c38059b94bdd9ab82e97d3e529b9bdc35049b2b2af79c4a5bfc3acbce5f2bda7729ae9d255a64b9f241b365caabb302db7617f384f991e2e1df5e16eca4030e2753957454b8cf617edf252064710d72adfc7976bdfa83bfa4808203e80eb7897fe602e552ecf1388107a89b0dc0b14b92a6751b12c2ba761b9ca5758ae72161539bdc3d44de5369e0020cea200be403cfbc3ab39725c929665e552aa2c2b57b904f38dba2c776d5956accb6960be721798af1c6645e5ae3595abfc9de52a4fe5371e10397eb89b4080f8b334409cc5d2c4fc5da5d640202c6c6df429e636aea36ef00a7169fe68798c75ad8de47df813e203b0b03521ec7d389c48bc5c7b4f245eae5dbed40d8aab4d93d42ee3252f692f76db0075655306c7354db29b0f9a0c42b341dc87205e83387cd2a320ecc657c371a972a9dd874badc22715eeb0806a60b416afe170b964954b15c781a85b131788c3298323c7a79800c8152b5dd60906e62c563e07bd520588afd497bb0e40a5fa86fcca69de59be6259fe72581cb7a1626970dc058775398f0784c3a182c3e5126de20ae02b01b864b900aaeb1b2cd30360e3b26e40fcc69f8a8aa591eee2e2a2f295aba848d2cb25bc54aacb7154776954ee227de5d2592acc657d57e553dd9a907f978761f94aa5919bca731c8803e0392a8dcb3b8dfc746959ec1277b371206c0dbc2e77adc997dbc051dd5579b15b91eb62711c476d3900ea96c4b5f11b756be2da38dc814faabb129b323f58a63f54787da8f05e3dc85fd3879476cea4dc161b6dd4f86408748b4f6e3cdc01033e815060941ead3c3e46152317ee5841b5c80192bbbd2b209317f38c30a9dfe8153d2c9e4e8f243c0f3b77da3a27e71979d66e54b5ef3752c397e52a95e5dd4970c7bd5419974a280f76632f2ecce9263de2a27376b09ba846e79c86a5284a677cc6e30d4b95799f520874a54e6f923ea9482955a4a4d37437a547923e555c708ee952bea9c202e7982e5dd22dde456be5e4f5ab9c48292f3aacaeb5ee6208a7d421d3dd4275c8140faadb14ffa9db7537b8435f068b886f6267a32e9a76a376a336222e025a46679b5a76735d5cbbbd85824ec2e9223e40c14562aca1820c026566c3e525dc0ebe6cdf45d26e226a6510687fd3a28e1e31ffdd881e59971a6b53f5376d6d7389444e3c26290681ba17687bc991897a992e7b40a54fa1ea38741f7d43a7a11075ea3252422921dadae7a12a6aed13b2576b9feb32ea050719f7a43c242352140c3523c36ed7a56ce8a0ba15b9201932a80c19744e0a4b994f79e8548752dc0dd549519f53c6a59c53c874a9f368caddf9948a3df4d055b7d0fd50ad7da0fc4c6c33a739518fcef7a4a6359df608fbf490a847f3d369683dca3ed1693a0692a0504a4aca7db89b92f299f2f9143b2fe3d88bdc50fd7c4ed5ed4aa93d4207519f8c522bb38ed56bda8b9aa869b2a696252a8a9aca2029e95415c297722fd2650fac6359bcebdd50f9ea42b0fbe88b7d306cfa744f8665d8a701ad59c7aa12ad59983da2356bde533ff71c941df378e8b3efae358fddae3b65c7eef14c93c73379268a1e9b68463d3bf609c39e9da2280f869da2302b64bad356847a56298fd6accf7a5996d3a622b79242ad49b435c9b2a6e9d534594a4eb5255fef3c71215d0ba468a0d1808628d536e802d323be0f77b3ee5ec2dde853dde4caa1ae0962e8b8f4c8513a26d0230a9ea2aee3c540c0dda04eb1a195702fd4a512fa4e511975ea99dbc16c64c2827440d02cde0dad3e5dc8e73efa7e30e99f4f7d24a0d2a587bed55c32202cbb04d5506bf49f2a6a4dba1f7bb516aa992ee81f0c4a982449760b72c18442582814daa0b892bdfef9e7979407fd7349929fcf41f22e523da0d0f1a7ca83eaf50594efcd9949ca4b55c8149240dcee614fb26a0d5f19f959b7d0a5f754167977a9d6de09a874291989d4f026a048428fa7a1b55c18f6aca74c76e9a920d07db80bb22ca1d3802e1f025d1e7459e452ea36ea7eee398f875daa1bbc2d173b8f974de75a93b72e494f3aa74945ee24446b3021a0bec1ccb6712f2d930da824d92744a86b82185274b579545abe1818188ac22705d5fe24b4ef80a07c294d199e2a75394dd694996e4dd3344d5385f4d1075f18181976f7333f9fcf47baf749495d59120d5022024b4ca047d8e3a5946152a50e9a4638aba2aa4a9d528c7329ca6e35b7ced6944dd3adba1511325d6b83e25613e8924f7daa7c6a9a1ed7693ae87350c50e9ae0949940557eaa1da70c8fe75a0756b3da83ef1445e820781121cb83c99a6a75991f4424c3a798628a2917facae7cc974c553187a80859bee91b9ff394c1a60a52e74a514e4762d5faacd59b60b72a77c15ef0175c39a15ebd7f058d5df015f1d26e947d52499c9f4b29b159558e82416cf1a7626fd08388ae753865408753c6ba04558a416cf1c7b258a7a12e6f5197a7301013150d79feaa2b6495599955896888d835569d6d2a577c8f682d72147c330fad43b8a70c16e3379e77ee881eb9a9b5165da66f1a4f936b2d1e545b5a8b0e0cbec2d50d2682ac0a646178bccd81e19a0c81473011050c3b1171c0fa105839f9f494f17c62f7c575a783aa65f1e16e655940a7a94e1d549d7a65dd8bfcf34fadb0c03968cba5485a632984682d4a98e93039a0123bb94288c9c98b0980bb11efc4493ce564b230ee255eb210a68d64cd431db0d0a2064ab20e72ddc852ed4b1bcef166aec83ee0dfbb800f77a1f5e1eeb3fd94649211ca2ead494f82104218a4359e3efab665c206545252c7d81dbb3b486b4cb817e956147a98f7f876402598b8c168ad49efead29a748e428b5ca7c1682ed7db6e2dc46597cb2dd7d2de0d8bf93d7e4fa3e865374a740d469bb42bb99d4dc7dd34265a931ea435497425118d1ebd3b0f6ded9d0969734f2a75f5c849bca4e280742d6f56283c30abbfaaa262be6bd628e641f022a6e541f595294a9574ef4144b7fbbdf76065296a560f22aa2acbe3dd80bfbaa7da46a493557d55e03827970cf5578f48a236a0b51cb838af4b6caabaeab8ae5a3171b77e1011c5d659163ecd9b2e5f5d5ac70301ad41c8b7a7aba21ebca3d11a8422a903ba9d03343135fea6a851e192ebef3a5c72ad6cd93fdfaacb29aea787c7d264f79cb234afce53e73953fd320ea340a70d55dcf90c5eb37e5ea35253e6f327b39e3eb267f75cc677df610edc48fec10b93f09b144e8f86f424717888217ca91f6e8c312ac681497a342f2a9b326f8ad6266537cf69b2579770f6c858f6953cbbba64dd6012be3089dbf1ded307dfec55e53be374aebccc2acb0c3462245e7879ceb01123334e67f295fc39bb1c9f37d1c1719d1639615c98a44754d4f83b54d284284d82f06406e85ad001ca75553c9f972ad78c09e45d79592f4fdde63d5fc9bed521507a5ecebce740268de733498fb2ec32ab2f49ceb46f8ad656e65984bc21f37316966b56227de7658d8bc6b4ecb48f7c8df9e3dd79c9b0f961d933fbd98adcf678b2eaae6b2410e298320e7e644c198fc7e324ac904b40dd413dac7fec753df032a68cbb840ebac7c02240aecef94b0680e5b254d478757978014c1918041535be32e114cd7310174f190b85a8081eb8f7ece10edd67cc1f4e8264bc3073067407720ec66e3cef2aec11a90ba168cab88ba60ce8ae52f082f5cd1ef0cef69c91aae710f4cfe5003cff611ae1aec7e37ab238fb23822c4fd061752cee7cdd3d359e552a6a581667a11208933890cb6e4d195026c473aab5f94fbd5a9b87cfea46dd393d95a23cd281ceb2f2fc7309b2350da1c4c1a97e7d3cb5560c93789678388543d3878ca7dca5d0333dbc81993210269951313373559d2bae2a11572a22d02d0e4e56fdaa2ecb10f47244c798597e6319329e327dcc08cdf88844a00f4c22c2ec0cc6e2ca0adeecb2f095e4f1de25b1eb7aac0c58a3867d39ec9cdcb01f99e511700e064998e4b22cb1cff4013acd6565dc33815c177498e4ba360a24c306c192afebaa30bb411e01e790574db1aed2cb773948559c63cadcc09abb791ee482d4e6b8901fd03f20e891e149f1bc1c38caec16e402d98dadab9a3ee888f2b8eb3902ae115c372f5306822a8f29e37939ef5d15eb07a5ccb22cbb74a12c9312e76ea02ce4c90e121d6e7d2f509681322923a8c8131fcfe7e301559aeb505ce8c930cf41d63d58b1bfbbf1cd2c8dfc0402ba47fef2bca69190a0eb109b71d1a1fd6c35d3062d46237f1d7efb5c32f643fefae7bdc3cb6361cdb087a36237ea793c9e43d02f1b1e021e643fe7f11cf6edbab99fd36bfa50b92e55eccb69242b67b1f098878687c59a3e3ca701a9bcf2d0c0de481ecb8af5c0ab6002c0e24a59dd85504a7978590baff378a29af21955c643f5735add0591a4bc1c240f844d108665735ab9723d81f77ceeb1d373bb315f33d921851ecf792291813ead07b31bbc20cb92fdf30bcaa59ee757cd74e7439faf5c70f816e492a68f19a70c58335dcf4376639b7b9d71de1dfd46bd5f23e021a6e798fd7c0e33653e12c69b5527417821bcd98cbc1995d725f47c2e3f9fcfe7ee73f78f75075dbec8f5d48dafc7c89d871594dd4d1f9e67f764f51a01e7b82eacf2688d823cd8a6635c11f0d4e1af11bc5c37d7cd8b7a5787a753064ab6a94ea74cd556911be192ab24496b0f26817c1b421857da882cbce0853080a1657b4f280d1550b82645f0a0ba93937395ddaa739932eefd78972f42153c814cb744500105df14c10309236fe06db9cf8813ad71122531d7e6cc20c35d09a785f7c4133622114f1b9ed317add1d034d99af86739c90f697f6ce00ea92e3f6b0ddf29cf495ae3255236907afb8fc95bd223e7629ac9bbd1dd8c9d474bcc0a7957fe81f1983071cdc463379a629974ce6382b97e9265ef063f7ba79ceff670fa9e8fd85379c763b90bf8ca0ae131aa27a57e3ae5fde4224a3d61e7deef7aead672dfbbeffddd19aa1b83617a4c36a8b3e46defec832577baf481ce959777973a7ae41e8cac3aa417541e0aa1e30ae262dac6268c2811704edc3b0f20dc109ebfc308e146a0bfeb70a3d028e5cfd5e1f2ab8b71e265e1de77ccc53c264fb88f09e7a0dc68f60eec5fa01bcbbb36eec66f22a247428a5cd7dad3808bd9816ff039c7b6c3dd280fb894fb68dce776f4df2ff7a68bb99e6d406beec6f4ea34bb9b83c2449eed96dd8949651f1369370ee26e3c5194fb1ec67d337d9a67fba2dea9d9a3af3c279978c9272fe11dd0c84a2c2fb9a1b0e56f2833715b70f19adc7705799af91ace5e3da5d2647f975356b1f7b2771e8d557767fd95b4f64d6bdc744a99e8b34f925ea124a5ef153daab0d0e9d164279596f2292e4bd15714ecc4867798b44ddf486ef2b4fcf38dfffae1f488b78773f9fcc7648be7a447477a24f1df14fc729e18985c76127a3befc9fb498f641850643db2350afac6a64dc0314abc1bdc25703bb0c6c1a52d83cb82eec192aee2554ec25db49267fbc6be5e72b96ddc0b7f04747b4cde163d4a999f1e0ddc0e799e7f07f2de9c27f22b536adb74965287f4ddda46043d028e7929e81770d740c813c3c8cb7931cf09ee069f0a2f4966b7b7e481c18242fb6ef2b4b49672f9ecdbcb19c25da0b20bfaeeeed64c94b4d6555c96d20a7937c4a4b798ffc20983e13277d11a6f6da3b524a1cca173caf9ec058e51829d9ccf5d703bb08be040d5e0840c9e6f2cc66517392f56c2495ee5db386d133d2e2f079be7bf295e121ea2abe01c9cd53ed21acf5a3da526d19a3b568f68cdfdb0fd70ab7f2a76f2e6f78ddb819d99a480ec4685ec4645ffd84d349d7cbe693c854f8dc29d57a94db8f3a202dcf919037899d7d963e753665419f5aa4596dcf9ac5e76c4b23bf184dbe1b417e39c0e251ceb704ea689399debbab89a4ca94438ed3d547538ed1d548570dafba7c238eddd53817039de6975eee57d56ca69ef5d2ff7f28ed5e95e3077e3dd07d10ef77da332eeb35b10beb9ef307722f12e6d4d4fdff8caa94a2ed08c46088d6b2db31b11d75d4ed23395702f517a8bcb7571a0635ca8c49d5b12f2d5e9e6025e9d7602991a70a7dd82b8269786c8bb546480aa1eb8fe449122ae0f4c1a30c280cbf278d3dfa9ea8a78072ebfb2f1c0078a14e1de0d6a9362bdaee5baf7a4828227e9005ee06e89ade428f7224520469224e92e02ad491f03dda88be3244e11cf31e220a1c142900ab8211ac084db415d621b2ad2a1a3f29d744892c3c295a82aa46bd958e762126a42a3454790d6d80b1909899871f67897ad0ef7021fa4358a456c1bd0da9f634374e2dd8057c209c9369437d96737eac27f41371d179ee19fd0400b06dc102d4eb81dd22185e45d18a932e5c585722e5cfee6c38557c2bdf03907053c9c78e2563ab640a9533a8868ad8a314a31c618695c23fa1445699f881e8df836459d9aa8e9af3a2bc48d31c33012c3574a0b74a3b7bb9b5e2e480743b9c94960706e0bc74517d7394d740aff6e4077978583f0c143a6bf6f0d1e6a35608b926ed398a620a1aa9ada89d6d8480f80ef0eeb134ee874275e8c91d7b428b6c6d39b6c53572502ef645f57ea68d5045ff16ef02bbbf5a720adf19960c1f4c932129699e9d564798af7aad2c122c815ad6d7c450d5d271e532d12fdcc301a13419ab03dbd217548bd678d609979a779b6013689225742b6798f8d3c9105379d680d0b74029a0e238e8840c7389dc8456c8e0b51d31039eaa2af86f9d6ad2faf4079bcb641729b4c6f4241ba962bda80eef4cebbf14440b76713ff6cde4d8ffae15c70a0dc4f7aa7354851321d04bac1b67931222a96810057a60f3778820b2fa2a865379a236b00fb10dabc88939304d868701a9447c0b22c3e2c8cd06cf3627a0dee060e0fd13b2f043963741c2efc19dc0bfc165370e1b12cc3b22cd24b7959b49754d11aa4b781375750eb4d2df659372c1ec1e6b3ba3571b33ea424bdb4893b8f00656d59963c4d3c7da4762b3231d03f13044a09c19b785dce5141a036d4b3793637ad3d1bcbfa0e528bdef41a3b9ca53a8df3609dde7acb37bd256f3dc62b5ed2b2ccd35c979fd7e52fd951fef30454bfcea31560d90b0e291ecfe98ca795655e9e5ed366a7c13e9f35717b93976155a7f7d80b0e94da1a9872378154b72c4df5cbd2ec70eb35b0b2b0b51a8f3bfc731eea062fcba5f90334b38375add5b05bcdb35858ac848454634f4d27ebf12d4da744a776a3a67e937da7deb35024df76ab7910e746945db248e4b915a3d2f45d2386fdb29ed8b2faac2a959aa7b17e7ddaeb96c78afeb9b434a26722bb15e1f12a274595decd3737f06f3a02611c42b646845e66a626123a5ac38938388fa21ea52937269150684c81db41240e747a754b7a54818ba1dc0de930b081ab712598842524121209c995be728525f3b697138fcc8883021aff601249ba249de744a92b51546555525a9514b391b426e55c4942722569caa9a81c09478a48ae24c524579a138e7483742ddb64e4c6e9fde98a37d44555a9c3c1f0e33f1d6cc37c3716776d5cb61373d72135b037495daaba2d4289505e849272b708254742a1710e5078883850ea15921b1fe9e0629ce4811b2512dc78e7e28acd7b4b20f5b81f0671726ee08c362ca0efd3a3cd8d8f50a42f7af41e87c0ebe26594fa88341be7c2a1db4302e5469c9c48833bd938814cef87448a1e359c3f260b1fa1bcca886423bd5a6976397a9aa86f2c274ab2ac4967922623330ae49be61b99b95007e3e84c0fcd4440d88510efd92ea8b351076d86d021815d7e816e2e2c3dc9f67270a939d37feff71e4fcea5b57a446d02635e8ebb019fa4f26c2a2d71a034d6bfbdca485ab3b068ad0a5a9dbfe8c6ce487e58ef4bf3c7062e76ecb20e79a71e6b0ddff86f7c8aa2aa09a45239db2f051251d49f13f2ee8c97456bf0336ce7c08f15cdb8f302150de1d75037e5321e027de0e54533aaec824a676dcee0257246652c5a831755d6690d8a2c5731a3522de535130782d4e55fbea7ab3f598730e748b70eef2e13d03e5f104207af59398945499fdfac5b16c99455f8593768b1859691b4c6392cc50e28c6526076ea6f2f272a713ba8c3c7830b3fd1bcd7300ddfbab4ecc68d436dfcc63937923ef2c95e3018380c1cf3725e9233b481e7c060702ff072e0c085ef27820bffecf6963c145cd150dc0b0e0ee44f6cd90bf7028fd3233e8284b1204215ec85172f660977b1648b2c3aa747fc640a5ec255c0ab0494a5c7a3e2facb793197a5284a45a26f2fa7a1fcc08bb704bea1c00b09dd9a09930ba7785bd04745ef9180bebbf79b896bd2ae9da5e2fa171d73d9be69f602761856fd42f29ba2ed6372e1cb712f90975ce9301e3af88ed2a3ed1d8adb2107b7830fa14ccc4c84efbb8cf5e5bc295a8394920b3fa4e5a381db51038e6928ac830beff801e1c257840b1bca8be11f3c9b0b9d70e119de824229fe10869760433942b24e7641e11de497c585cc554e4fd1a34e02c6856f335cd896bf98a2635ce5f2969743c1f317f01dbabc4544a3b18b737a248524badaa3e2ce2e86dd8d7ec4a677dd2e08e13529f702bbdbf661a68944ff713f96bef193224584641f7c37ce00ff32c7e739f32e330729e6f3e8b77579cc3b19ff41283d6992a214a9ae34f1961814dec1b3db511d5aafaccaba4dba9b913e397e6f900e086a831d1b14e16e7db8bd3765dc7b5b9ad8130968a18f1abefd7709a9be3dde4cbf4f9b8ad7fddebb337d3e23a1bbbefaba2173c36ef81ef39d422241f9110b2637c3e28a4b2f16bfd1699299cec730abad87859ccebd2cad98a4dfaabbeaa7a9e6a77373da6dce4b3967143aa735e97c65a74da23568c4114ee8e698cc6f4142972681bde7cc3c6637fa795d806fcae3755197ddb06318365d5722856276ce21351902301e93884b8714c282a95c286d6a911e6940d10bd5f4f5e1ee101feed6f0f5e16e768e428b5cca32837dc667d84d32333376961e7d67dc877377c67bf6e83bc362d9bcae6b66f741ed463fe37c0dbc57a5a1bfeee4baeb2ebddef792f1ac6242f853dd8d7de3e7f3398fbecfb2cbacf6953e9e4bd55d2a49b012a1ae641de78897518950b7b28e736467a247d36ef3d53f879780db811d9e026e073dbc1028ae07bacc6eee8bebdc4b25846f4aa50e0a6d3cfaa65436c0bd3ea488110318e07a5e240957f615fafd54167a7769e6af8358a8fd814dcb3283ddcb7a3cc7aee73c5c8aa25cd3db4abc1bb095c02cb5d4547d5897978d529dc92e36a9dd825c7aa70f213cc6c5eedccb965d5eb4d25cf1f7cd1ffc280509b144dbc3baa41042a843d35bffb02eaff7dd8eec3c794efdfa35ada4ee7abe3b1f4db273f932f5dc9a32944844e99dbbacbbfe261cc1d7b7a62f35c6183d44d30c80be9a3e40758e4237bed8af6fecc36175f3e1e27db82b84eb506d4418abe8b1fa6e5687b07ba1af8177569aebf3b22c337de7fb4e6af118d7aa1b141c98c9aaf4aa6655573cb3ea58085f7edcd806c5c58e6d941028eef57929d53ebddce1ce6fdfe1ceef70af1fe0baca22ed0f03dc8959961903dc7903dceb6e8cfb59afcbd2f4af5fbf14453d77ee3a75d1ebf3b1d475d7dabbbc7c5c97a7dff3475f1e63f9218f1dbbbcc4e4bc68ddae57bf8e9dc7bb8e55961ff3d62f1b2d0ba9d0652321b630681c2c9c5cbe7c29eaefd1e27747f37e549608eab5f4a8e59af56265293b49372f0b94dfdd850dde4b9224e94931fec53e7cdf700e13700e3e3cc3ea58c8f4dc3377dd646864890b68d3e8de5ae0833647bbcdda83cf6e35939b8205947396c0ba51498ad544ddba0e0f1e52131627516b5a43c0651527cb4251353dda9ca849a2a2a669aaa6c9ba2468dc245e0c45512a1235710830c2b22c0b72915b2bcb0cdf02a24b035fe47265da14cb7477b7ebf2c4d0f229a6b2274992a418a518a1d402a5e2fd596a31c13a3fe1303ac6fa3b47e951f677d679ee4dd9e5a7795d4a37656a9a5080bbd23e712fcbbcc4f526ab736f6475bacc5c4bb401bd9ab8d364ad3b0f587fa2489d6e51d603d4b94ed68a987d6bd3a9ea01ea4f1429825ae2bdeb4d4160a8bfcb0f1c08b56dc0c86d8ba9c3bac18daa345dbd1bd3f9895e84d61aa8bde0408db01429218844adf55d74503a4d816eda6dcd458711f1ee3611b775e49b2d7d37fa92a22a2b45b6e98b845e2e2ba0fc4d7b614807437530f16ef4a1ddde6160605a6bb8043711c4e93021ba3c5e0cc5940e8c103aec4649ccac19c116012ca05cd08da2288abad20a5aba8509393446aa2cf56eb43b455193952cebbc1b2ea011b2ce8b716deb75e6268e091fa937173e0bdf43175acb4ef808e51644d9e241518c45205b40ba8e814550309a3046179e2140317273b3eb9a200617976a8d3f841d4e7293c9eade11eaae2fa4e024f19a668fe7e09cc7b0f3780fab959329e7b41910ec1705a70c465172564ea4b48ea4569585b2eef28c6729964435c083f1240c282ecadb7151dc1c712c85eb254dce84eab081a1284a35a723626eeb554585f919ed63cbb22c2bde9a735ac6b961b661d1ed9d17f376627765c58aabea55e56458d62d86d7aaee3233b3757e647e2ba0dbdb694239638a52d914a817d347d8a74396cf3d77d84e1d8eecf4c835a10e3717bec1806f282dd73a65deac77bd5a83941428cb0cb4b1e68cb69fc8586fe77a3bafe5be9d17c3bcc33bbc436dbf27d832de138a962278f018bec87df05a8f91d9b2601ca11bdbf44e6b51a01b3feb45b67afe45418d5cf88651d0f9ada34cdb61f4936a1b8cd66018fc3a6bfaacf3fb546bf87eac8cfc7b0175d77acf781cc62a0fab36181de38ae83078e878a8b6590226d3b0cbabb2e26cb659e2c5b017ef067c8add1eb220fbb14e5ac7b2179f2c8539afe5d0e47d734c0e3387237788eb9a20872cdcded17937a0dd609c684dce44e474b69753d9c0d8ecbc1bfb2ccbb22ccbb22ccbb2a265cdc0861d3970ef549675c86251f03bd79c879ca4472cf3a13bd9460a24394bb897d7362fc609cc122617c1ebe8409d4fdbc082154faed322e78bbbb509aed3a20a2f9e5ca7d306255ca70307254eaed322878bbb7513aed3620838433092448f44ad5d0d703bb801ee250e46aed3690317776b27edc5e530180bb78379092f619d1e3d6ef2f8f5a5ee1fd1da11b7839d7ba16e0b47d14243445bd8c804e549d27b316e41a24430de73cf3de75e7cb2c24da090e75301edc755159021843008ce4589a23b8a1bd0fec6516e33f311645f8a30a25c38dc5ca7d3862ceea6e30d595ce9a6cc3b42ddbd5a40dddd780aaa47f11c82e9d18b489c6531e453015d82b908b300a81e51c1a1bed265f98ae9537cbc7457514149d39d976c7c85cc55040fa6f7ec31ddcd1fd37bea6992a64b557a8dc57d9697dc9702e6e9dc67c7524c4fbaa47ca17bfcbbabf1d2735bc40b33bde90a0f5a075af2f9fb1c2e6998842fbd93f97a6811cf73966e867a9e51af7e05abe1a8640d35c5512d999a1900008020008313000030140e888462d1803424da164b3e14800d9eb2507a5658b32086904184000000000200000000000041000056a0af94cfb75891281301c23968a8a649c4c9b7a5d087f346e23be843cd3fb16b24be160c10b9613abae2130e4a2c12cf6e616f9e1ec674553aab398c19bf71a3fa7de78ade632a0caded87558d5b9d2e0a8e02e837481498cc5eec962d4a216cccf0d2e534484aad9b10483171bc1eb398973adba695afcca54518c65ad6a2c83ee6549ba7320e56f47b6f70283cd4260e8d158020ea0957e545a3253b164d3dfc298656e7c088c42d1e569623d9db0c2e9f51393e8ad61d19a6d1ee67ad28244eaaebee562cf8d967b2b7525fa870a70666744cc22c1b5f25bdcddff003e9fe299e1b5b5ec82f4f273b6bbedd5497876ff325cecd52a06626199701277f05e2023b29d459e0b3fe0dfd4ab27fd13fdfd50be092339b4e52d02645d0d026c8bf4bb97d45a208dc2f2f706d299f0d558b39914ae184b4885452fc7b9abf93e9a043283890483464dd1d316e11e2de2a43a23a279dc33df1672811996849e0db11bf0dfb76a8b4a901ebfc43c46cff11851348f6f492c63dbbd9b0e6efb9254c83b81cdfe48f152e0603e917b51257e9eac1f7dcfe4f604e695615056b6834b001c0816495b026f46e4992b4846f8a58de5eca1c5c53c35947551dcb677cb2d32e48907e251a8c67a8c5996e7da7e3c6b50b5fee4cd0c833b63b0e82944b2dd5b9d463862aff772906236d93a7e4380bd16cf4fd049f42d020f799cf4b36e088576937bce8f3fcaa601c95f7647c4dbb245576ca8ef123a6db6f4026d75dd4e0bcd6c3cf4e9d819350c1028022641f8128237dbd091012416b8d30a6b35026cf5788caa098ed177da567682863c68b81619b15343504e0d73ecdcc3c0b3baf05ddc3bbffb05757152a6f2697921a0beb0390487550b13931fcb0f9034f187e2841625a714ce067e0bc76d42956aa6f1fd698214a44e4ae34bda9d9bb0c5b91aca093def579ba85dd6b0e791b611de21409cd3d599b534fd442ae6fbbd445afb32cba2026355f8fec35eeb0d3caab2a16726580f573611d1d3180caa0e3d4a69e9f1c8736200c7c645ffb9ce86e6d7ccc99cc0723d8572a086964d08d2a6cbfd2d048b0e3fcdf4aa6ec683772f775a1a5bda31396dde2bbd434404f84292e8351d94d3fae823e1e077f6d733dea9f1936becdcb19d28a394633ac8bbdb54ab8a22cb018555f8e1eb0f2d3faafc22abd1671051f166c29737a43871cacbccc4b1dafcf03abe47b46ed3e34ead3bed21ac8232bf2469de9532de2e702298d21cdf445491bba0f7508f671d621af68eaacd5471a88d0ac0ea74f54ce7a790e6a15b1ce42a6d15f9a6e2ef99aa23010523ecb33314a4f893eb3a52b52a98fd4bd3a5227c0b95ece4c8a3227343caf3f92b1b017483c823993416fc2b6ed2b2578728d6e1cc1c70e7c895bfb546d5512e1358d68aa7ba5fd823cbda5647009b7548f83c5e7f4893b4e479c947c9daae77773b8b7315a8039d35122c8a632d3b001ea2a1e59abc1f2a8d183b874c2007e6f733a0c7603f4d6522de4d5967dabcfd7a89083af0859efbe8435c3178c7cc18323902f2573f93f1602851aabaefad27f461bfef6870c939c02b79f03b224dfccb7e2b67a0bc45ee90d32068c013cdf0f0d76945e7e26c3a681e29f51026ba3abfe36293dea9984b18ac62c49fcd559511b04afceac047b4424a968616ce5f765d60185c64110b2a6c0732e187c54dacca602aed198a2bce9b65e999d41b7f112ee681acf33b4eb0de37bee4fe4d3d711c8d9a294315290d742892a7cf17ea6c3b464bb787d813cfb5075ee4ea6855645509d01f4fba52b062bcbf6ac69ef0be08f3dc6c86f21b577d7a78eb61681660b85068177a33365b40678b73398db25313d4f678838c4579ecea6956b36578f09b9d8a274ea9c5aac02e9b1ccf05f84fde76dd7fd81f097ace2188128705cf1c4552504d6ab030c7ea938aef75679fd25ae55fd58c465318c8d68a017d0118d864e8ac80619aced830f0d641d2397a0930d9967583495d4e3bfb238062d61b0911f1b2c9a79d0cf4685e873144de05ee9f50c11a65ab3d2a2635156f756a9ffe152aef27b046c39ca6ce8866602d7dc29a629d562ca253546e43f95626354ca9b5f86192f8f121988e1cee79959adc80ae2e791d55fe4c7710404e83eaeefc768b45d7b09ba64cdec304ab87309b2c74cda7e1227ff37dd6826575b7c5e4a5d8ca5768512db502ebb1989696a3de8688873f93cc95a6ce43f48b474eec745e5f8ce1908f43eb19db83cd1ce2fd7eb8d60c46c856880afee9b2cf4f6797241909a0ee4ca76942b9241faef16701636db59db52d6afc75543c4ee7fed08e9b60338a3448c1c33b3d1d2089891ccaa108c6f0724f2d1d672e2edbc9e06534635dc856beca84dbd7bdbc099024a37870a7ba410a3ac45a931ec536ab4bae33e4d365392419338ab92059fa80eee7ca7b7605c55622a3d9484fbc9dfbeb43e8cf270e5f40013d702fa8c091f4cb389fcfa135e2ed74ab30069f1c2aeef3fb6763df93904c05cfa4f063722653670de056383e9909dc7436c9fb012b11f2bec9ebbb723da0cb938a4114e4358b27823b1a11e4b66e0354a1bb2b5c90ef619b8591cfb721080739a942b8d58c0546ab8c73caeba851fc2e155c5e4389a53ae2b112156a764825f374d2fb8610c07b3bcd0c086820a5b71b15325e24cf2795281133d163c6e3128591bac2d03febc8da5a538e1154e2b25138d35831737817da8b3cb0b475cb40a49ea16f7328348d609932e6491491d64f5d0138a4e045fa118ddc5b8b666994ca2dbfb4e5155d8531819beb20a764666c32b513c219641c02217607df05b7c85ab743405a031f98cb8831ec0cf1d9c287912f12c2f4fcb0d584decbda9a251fd6bd4c38828547c2727b124405c3b2ec1fea8155dd8aa98451c3441b849972425f6003757b3eeb867627f32a64cd13e5c6a056c54640c32d082fe87c6b5745c153295a27c950310871e9a7d4881ea1abba1b1aee397a3cc4924be5e11ccb7268b9099f04270610c7b41ec8a11da2eb3826f0cb4ad3e0bd02e73400efd1bfc481714192a1b40c13735a35c0338ad8e5cea060c4907a672a2032dcf4edae6e1c874687a09514fcaaa13369fd19eba74b28beab1fd048fecd3ce1c82b891337fc381dca593810fd32c8047a54897c1375c4fafd6a6b8d0f8d0a44fd38b4a1261ec675a1531f83c9f9f23cc0681c2a9333fccec730c88d2ad2d4a77b6ae372160948bc1571c089583952f2ac4ed8f08912085e12dcc6dbc708bae8f02ae30c206581e1be1fb1c62a50d9256e647d238c2ed0ed6d622eb6b07a13850f6e17044aac2a55dd2eda95ea841d324479224153dd87c409d41d20137ba7733c7e82211a8f5dfddc0bef0580308a22afdb579086f3771de0e163471a137d6a0c7793bc28574191c3d2f68b10e0866fc182a3fa63483c5ff886688226663ff162d080c8ee72b1e5d0db1a023d06f96a90ca3954f255b6f71b7dd5021803473970b5afc39383f0c7aab0c581bf05bdfc19efb99a2868d49580b268b82789c5910e4e141cd8376cf92b3d86eb873edcd71bee2904ade70b35b4a1c0e29f21b9569019aa71ce347ef61c060e8375ba1ab0dcb0ceedeb3f36a385a66912f9341e1290c5941e23895471db53526ad3f42ab0179ed9c653fd7e75e06fb06cdb0be60a82d3dab3336055f040eb4f4974cb4a352cc1cdc24943d0acb41e68ec099e138ab22aa840df4d16179519a10a5e801933be4b1f4a3b6dc7cccdea37076402c1bb35f6ffdd52ef6c4346faab723c8953a5215ccc42e9a54e512882a950b0d7d5386ffd480a615909f4a3ef2eeab4ca3744e50240c0e90ee25eeb431d37b72bf4337ba8f3dc76f14a6b68be0689dd45cc76a4b98a4b43fd2b00ebf8b9ae25a37ea7182efb1101d4e56eb38250c27ad997066609e767e2af7272c53ef69d611c40e987de00d0dc25db8c82303a9facbf32d00fc433e9c80cda501852f63c0596cdbad83b9c4443fe3a59c73a9b179d5dade73bd154b087e8eb6701dfd590f134f8dcd0f63032b8b6a6261af9e283d1350419f89a3566b802c69df28e86a3a5d59d94c8b279b2eaa1ade8e4dda0e12ab3de1ea199ae90d4357aade6f17c9fb901e06ddd7ae7406440151c5309ceab18aed0d94b9a4bce25638e8f54b43c8b17dbc626fcde7fff21d7ae056edf1b04b5d148ae5f151568db80c326b161045c4ccf21bf508482829726715dde036b38c6db144d99efb129106db1d5c3d76efe30699b01206426a983935b684746d9e80b81b061dbfc3b661d8a1a25639828994fe73d80e639a52ca1f5f8a1c5e4e4a979a1504bd15190d8952c2d8d73ad95cda1f139085c301d8cb2f277de812c4876eed12d906970012f6e252c10d403f4f531b750e15f8a72f33255435f13c2a20afe71a195dd44be76df0ccc6f4200540033e104a3e9cbe3eff0dde39651c7388ffef3c14915fb6ae3178cdc57c1858d1c28a9bc7366bc686cc2201193b025bcf162ce538adbaed1ac9122ca5388dbad515c9922d9bcaee1cbef846f6e29d3164d56a402fcb1086c1780ea1362422aa6f2c4ada80872bae2d88f1cb0f6af4e940cd1925b0e9dff11e2189ffcbf38b65322b10c9d766919c0383381e17e6cd42ef0f78d9a3a0f4cafe61de2dd9ed54ff1f7ba3f1bf328b48053c31bdf53d3f0620a42cacbdcc484b7aa9f055fadaf7446f3472a06e75151d981cc6e542cab9a63abb6f27f02d16e1120555125748a1db279cf90edb6783ad8da4787b65a4d7fd4d60679a2ddb267404fbe2e1c4a406eff4843e481e04b542d7e35fc7c8d28c2b25b79b4d787198da4532fea8b7ac78dce8f1be8f7e93b8c478313248dacb1906f1d245cda29d8fa41d2e124487f0eb52949dc76c6edf9bbac13639ae156d514846635840ed6e11bce08776e62d92b15b9c6efa70d265e14fb1d57ecccdc59a0c27c7753a222764d59a8f6ea9795fdb07022e69352b47f1200e1e7ee20a7b4268ad3d97b4ed7b5c00511e6a3026f57f0eba421b4e92141f9c9566d5cdd4d6f19cace9908a30403c8377477153aa552c8b268405dd35ccb549d9410b103d45de5090df11793351ab43a47a106c45f0cc5ea0d2ae49d961340c686c20d398c409d1387ae2747088d5a04077a18e5df45c57c8a793b1b241f50b8b3db64294453bc5c85ca1fe4305704c09894319954739647c5fbc862a523f7c3b79941e1a5db7f08f6bea9a9a0d71b8b76038a21aee75c06c7604948a90265da42fc2f8351e0b6041734f4226577c39b114cdedade711c3290bead861b841adcfc37c2ced87f9c657b8c10880e7cf1481fcd51ca7272755fc4ef06b48f2c1c18ce2243c0812a9facd61c11294205a93f1773275b432f8b939e5b9ad51927656dcba8e526555d738967eb2d438082f1e5dea312f5f1c28e71674c7865868f9d3566ebe77bf1643d79a011598e98852ef4d15dd007eaaecc076c83c727f2c3d15d40a51ccb941396a0475b17879f176efe593719c4ec4e4285d23dc7c63039b53f0b737882e330e83d0a756345163581dbcde13506084d95659e2dd9af5ecc2d7503ce576bdef8ee8417082ec4fc49c7f6c8fd910875c1cffc76e705eb3d98b0b4de7b4dcc390680660a018cbf20beec1aec893aac3f9a6d2b50b7785a28e6550606526b746d47688d97bc9c9fbce77f4b4bed08c8f4ea3a8aff51859da70d8fcef9ebda8f4ab5a6a30e4d1088d20f6be67f5345b7661e56f501e29f12aac01c8a566c88d45974831e286c740a50b2fc49f4baa8db5567da3185aa608b92756d37ade747e4e4654caeceb3e3c63070e8e56c5d607888cfada671ccaaff8a3e960f19a14f8eec7997f56cb052f3981cc9c7fe42b57f629f2517255d577731fb277283808a0577a853e1c6310595f7655fb0f8bd2120cfdc75873fe2092f4c97d5c912eac6190c9573c101dc759b74184fe0873f886ee484cdd8452287322f20ea793215b78b52d94571286f897fe5acba68828f6a3fe4b9a370d5270a1985b500638346e169b81219b3a63450899dc3f53ac6700e50867d0d1c08c9e0be6789504c644acdc740896a7bd869c86141206c5e7b485fb793c28e5967c3012ef38a5c09c2b9fdac9c050d2d92a89d61a5a5553f8acc3d9fcd47e11e4fcf328b3d681925fac7e91099bd7d80eb708a91128530c354057b0d844991f0150f547739f0b4c6048808484492976a7d0a2c15a836a8f5a2002e8ec7a50fa50b20de26c6e1d41b98036aa88b5e476a100572daaee1c1439bc3af482b1b0d7d7d5c5a3e0b9abc7f39d96b95d1936e189a675765eb50ca829f88b10b8438c52cfe52a531bc23342a3801e6108de6c02c13f4d527786e515d01b43fe94a2891a41f7f43ef8b982266f97f880d5228ccd6b3388b71a32ff4f088fcafcd0ec077de53e54458b88406f75ea3c82df25ed4ee934752881b23832daa0d5b3bda2605c1c5598cc2d14c299fdb88afd6e2b728fa6189f5fee1547edeb924062c1846a7c31018f68657043a9c6fd04904aa6957283d464edf43588186c768a2967f4ef9dc4f24857fa0d949f4b306d3d658a0adba303c427e08d96b5e9f1866bbaafcb6137b41991f61d5c46e2931a662e55b135cb4cb2a8dc57f3b1a73b390dd1b34bc40d5767283871491f3d3ac51b1ea39d3fa2ed74a2fa7245735154f6d1454dccd728914810cd5e54a4a629a0d010b90af256b78fa6482c45b08ab04500d061b43f4fba66627def7a9494d2e61c470589b0974da362e5df87ca88dc3947a57bc6576381197fc0cd14d8f608858dbcd4d02dace8cd6cc4aa5ecd297a212413f32c505e2382c7c63c8b0c92cc84aee834b628cd6b36e77faea1c41bb4c5d964d1888bfaa183638d512bd760b395439e077283e9fea4f3434e7f5912e32a87e0593a44a1ba63df8f34b606576f1fba21ba4ed6044e0639a08e22c8dbed1b868bd480e2e1fa726cea358efafd12c09aa2769b44463d2c10e0660d278609b52228b29aa10cc1a01c1749186c5b08e772a812c13b55fe6c615e73d405c9e7641e8746619c55a520268e6cdd7c72ea1be716f1b2135b58fa80f1cbba5c7da652c0429ae2961914da860eb95ce8dabeb430128e416c1051e8480043ea9be31aa2ef404e430801042d986507327bbd485ab61360e20eee7dd160558a02c7078ac62cd640ffd05855de161bd4c3f650e43d97b5299ecf45478ad2e2d9e6c060ca2f7c8c41caf804a205209e27dd42fe2de0dd4f4019d47e4acd344723fbe477b62eb5084cbb4d150ef42a0cc2a281b59a4d23a7084ae609caf7142bca782526df078a8075547ce1e547d43b01f6f934dd58fdbd0110f266e2dad79927be8edaacf7183c444ceb908c7c753c9f55adb591a389723f63e27f01848e7d402dcd0ea4f6ffe0d0d611a3800ef7bb712e340680a988dbae1e887faa63d5309b106041db18bedc27800c4b6eec7b653810a3d95f77ba28b6ff170ef472d8260c7cf865a8f524ce1e96d0a6371989b2ec3c1c70bbc3ef385421340d4fe163b62d19658e93709b5176d7e3fa2bbc89e771131b9afd6c124ac7b8364788230e98a5498d666e425cc72b046b881bcc94f1c9265254a60da15554c992095c42233d40d985981c00ec306fe8305ca5cf46949659eb6ad591a0a93392d341cf261783fe434df2d5abb485e2a55c798e94779f45ceab448331dd4eff99e52e80d6462ab8ec579e029350fa0d31c6ad39027c1b32d93e28cb33946669522a83f3ac93c4c837ef00716636c05cbc34f9859ee4f765f284d9c25524f328e2e93a03c8ae882a31566f2f7004e460185f50fba1284281d4f1d2849075a1b2a9564779d83bc70ba84f6b58cde8575ff3fc533649e4c05bac946248c81697625992d06a0f75d2aa07bc94c946a28fb8504c2155efae6b58ffbfd957bd8a92f6ca065763810320af759db16b7a1e41e52ac25fbaddf3e25364103b351087f36822ae0089af80fd9230c680c63a92b78849351afbda33ad7c34cd04b1a89db6c532e1cb9daa6849f482fc715f59cc9233f2282743fb832cd1a9aa3973ecc5d82835a176a136bc02afc9b856edbd8d140bc0e756a0babb24fea0409103a1e13a0f443f9cf1a4c40d5967a900e8879aea84832446a350e1c92546b02dcaf044044514f5505b673c65ccc09c1b1a7fe418f84fd0b4f93f40429fe030e4b4e0bed8458d2ff0e5393e915107c7d4a02066ddbe1c08d92a2f923d360242d471517cb22938f51e22f1004928dd965ab6c2d2aeb84c7dda59002db38d13045763ff6135481516b5257e9a131c9eb36e1955a1d89393b44f3799954996c2d86d2f79aa4fe4cff7217a5b3515328e7f44c7ad590e2b2411c92c60b7da191a88de441feef6145811820ce3c9ecde8afb94fc57f2a48b5bc76f4ad127c5411a25e885370e40e9c5c11a6d99335b12c75ce530e69fd834f58e8a46a9b118478c79de8846c07858191254bd1c71f0037d29ffc90484b5b26e71a3617a84ad27c01e3c09f8a243ce96d5757164dc52f2d9b780ef24971e9e0d08cc36f8833e42f11e7906bd0680eba730429b9bb8f935f4d62d273727013056a99f37485fdc81ab1609155f1d536d92ba158129e06f3502508b40d8d8decc98487b5c90c7f8cc7d5b5cd76963aebe5b1c566ffca0e351e5b974c686b135d27b6f1fd55d8188b3a6f57e40aadf58b61946e1882861a28b76c5e01f9147c9593b2c093ac21ec4f5663607f72d9191dd644bdd4979323e14a810c083f9f41966f33113c5c2a0c8d2ec10eb46ccd9793314ffd0f49fb8c99afed859621a80e43ece33dba4fc34dce84110807eeb781bdd047f221f3b94168a910bf81a0387a8fa05f6cfdfb1ba57816dae4cf47c163cbf75354eaca8d49fc72f0132c08e60063043ca8834af2dc3819b095233f758e7ad753f2c9495e00eefe02f756edc35010b3b30481d6158cb1c3838108ae4d0c5cded8dde042b29094fb091680683209d6e7f841ba5073c4088abc07f37e1ac9c34e4eb6ac459a5a39e839366814358a8ee92543955e4fec529161dfb6f7ea209b74241fda4276ea77b857d1199b6ff11fb1519ccee76c0070246a0350b39dbdf63bf068389e876ae12f114dc517cd22cecff683490199e032da0277eb5e1215d1a4d4970146d1265fc0ce11f2835cd6857cc6a890fd3fce38b1526520982e54b0973de99cc09ceb99f1555b8b99b9d4c7252015820cfabee31baccd58a56b32472a29c56fb4ae0384048bef62f9b4b36aeb9dbb2b52281ccd67ca91155884e955825ccd41a106d24b44935249a192b5eca8a10d3818874fff05f715b608f8d90ac97da496b7a57030c65612b17a5fde936917847600609209ad167c3ba62124e3b8f48f7f82cd8518e6206900bcf8a69a70462622aea99b83791a2605b0d3e93ecafdcbd0f28b76f6cf386e893ca27757aec6599c90ec61147a6049d78e519affb5b83beaf0facf7bfa7b0d820434d3c176f97497f093f8a3c71d6e403778fbea3cb6f4b5ef2f160cc3c904956cf4eb71ef56f6d0ad10148553164e051cd36a3dc22e7ecebeea6441ed61054f9f136dfacb3c6f4fa727b7bc03462b8a4422fb8f4e372a8ad1836d9d5415f004bb48378b075ce3c3e43abd9ffa13b058a81061eff5a699270805810c034aa80af3e1cc783c26d25718f3476954cb071311005b3cad930ee047d06abc80eee8585917a588cb1ec9a526ae8b6b90c9334ee929a62201db225ff4205cebc22e4041f86f21d79f193dc6124d844b6ce69bd0638abc234228277bb1cbb9962551c5fbf62309616fdafb2c339da5542c74758ddca22cc92bd8aa26fc45e6be4dbae1838eb63e55b42d18cc30ca20fe505f284eeadf47724fbdd4529f8a28395a482ce7dc7ec8927d524be4aa798e14399f8bb55caa19d71a6f465e9ef149d0e295f96f22f948b7eb3145c964e1f5f7235ba1de964707e30fc3667e33e4dcf0d46892279eae0023f93be278d3355d17277281a0ef0e4ffc451a4981ef3e8733ac73a9f1e1f849ec76eec8d3db12db6269cf944eeb9d44986e99fc037cbae134960c5a24bd3e33f9ebd2356fb40b43886200e93b928c6c4961e2217f5eb15d69d94230ba56878222e026699e52be2aec156e23b580ad48232763f459ef02e1f65585efc8a15db36c9f6878f1ad93135cee8b65eed370ee46affb943895ff78e9f0c7df3aef1092e11e909e9f3b0d551f27866ffdb191ed5fda9123d904c961fca0609cca6dba23f29aa8b88a665a52a50838db8f5637e6d79011a0e2a268d8f62f009c9e4c1b1ef59992fb5967b0251bef2a57b5486e41019e9229d80083ab546a950801f0827417c9ef7de5a21dc4dfe3f761baeee393656e324e20faef6ab9a062c0d29d4bf6ede1e285e2ee975c2b99ae41c68b42a4fa832c3a40cd0df222c782324b6608e36a047c7dfef12f08c003eda8c0c423a0541a9d3b2024690761a09b7f6a082042958738e9b1502901364ae6032692548fe64538621bb0be88eb8a9c6eb6ded998003a1c3455511668b0a36f9029f70903b4b04c1a54621acdae5e496d3482099c5b2f7d11da42a676ea230cc7f33d3290d082a858cbd227ac83469ea7cb6c601c06b010b476ab510efec03e89b50644cc69379832fd0a1fc0a05372e8c79ddc86a685b759e497d09eef6a3163f7ef5b3f6f12360bf1e305f4189774c868f8212a370d57c30859fee54b0419de9770fb133f278566ee4ab580c48e3fbd803abcf01910141ee1cc471a42db2854fc1751195e2228c5c0b202dac370323b0423b89c84109bbceb89a6becf2200d875e586dab2a142ef3ae04c54a048fb6627db94e1960f93c77acdd425cdecbf7474435f9e77f482c1083ac333d8066bf791e287d7aea00fe8a3bc25f404a5c6d63429e9f2837d9c4ed630af057b921559804fda5249dc0aec217c211d4a51f68eaa7ec3e26332c1f5584d6979396efa0c0779534d6e775718d787851e7c7206f9a1fe63dbeff9e3fbcac4952b2a20f745778ba3e8ec00ca6ebfb08d07e1b059226fdb8e3ab83d577be998fa73b587d4ecb416d48024c015e5214d0348deea6c47cf9a6ea5a48a573d8d1a5115e0b2e4bdb91d10a4aafb82858121d3209e9962ea2d6dbdafe365e62a1dc7b60d6621cd8fa59526079e3c818c9b7d0e1461c1362b2895f0c6b98cf07223d8cef40e369a5a0b721928852d95027a8331d337061117f8408916b3f7d63c8a9ef0a04e1ead5c8976776d1fb0d672e81805cf2fc13df8805aa11f8a6882cdd3b8c2ee39d382809061598549ccc6ae493e7bc0b4cb347918a2d806045f4808f729bd0f05539f1af54ab66d6c887581667fc596ce00ff110bcb4fe6b53a3f8b4b3038f7163d34f5d745278d3213b5484be26a9692438cab11f6ff556c1a0bd4cf7607f7148ff5f88cc1e488b2d4ee2cc844601603c1f3b6754b41e570235ac39c67a53b722f6e94ce57ca75a6473b25852bfa5f7c17207b2933dea06d0bafe19c57fe6ce64a0002005cac1c8a53c5a447b2a68e152bd6b21558535a0d619ab843fe77b8b891cace872cc16ea4576352b744d1555a78fb19a0e1f2e1daa5df396b084df0b1464875a309ad417f5a9ad14f36cbd4e634a9c4ffe38d9f0b104a29c1091a1fc572f08e3487074e7a26f5f0ac21e56ac73343b46cd5bff54cb9646f112637045db40e27d7d83a2bb0b3162a7a66f8c88536e9c5a7b7a33afc3fd6c6673e793a6c9bf3606dbcfc2a97831d102aa0f5349ed35983e6010aee96504026b39acdc9cb183f1075ffb7c6caa1d30552d84124e23aa15fbd5e4a1164c94d346cf9baf4838aac8a2948a6204eb1e4326f8ff5b17913c1a9ec4ba8034f990541541ceb74fc752efbdc8c6de343b04f6dd7e2cf6c3ee43843aff51494cfa21a6ecfe9b8f24a4705d91e25c14bf16ead5c6b087f155e2faceb0bd464d9a00459f80d260a315795f00ede4dddeaa48c5b13af85d57df9a6dd0f4bf3f8e6bf657fbdb197f18a1bf4c1a9a9bc20c594a147adbf6afbdb07827febd7af34f71a4468fb80b1ad1066c5088061b510fbb722d7015c4e34f324d46e2041cfd19566c00f0f513f98d42f8a7a777410433b49cc745b0c5ea6e6b56818afcb63029e8ea635a68c841ab6e77e740f48fa65b014df04089d6632f89f8999b4185729ff7a47c4f74a62523701607abf8f4d3bc16ccd1d5f71177ba21b10fd116be74445c852251ff4a2639b9030d0ecd7d93b13a50421c346d52ac4f3853d50fcf204053ba3f81c300d30452612705133fdc85504182d91a7c1308ca1b7f0f17308676615a9eab29b0d09e8ddb84275c7baf7df1260a6b750a68d59a99731a5951f5855e8b2c36b3b0f425e5f18ac813976bcc75969a5d1789723bf5bb42825868ce06070685ba18a304da142ba3819b166de8d2099f64dfd254f5fed5c939d892355a3cb3d6ac94380c9e3c3426044bd780aa27111900bb4903c8c81eb6e6e597059cad5417a8592f9e4604bcf499156d49e39edc17cc86ea22ff5e23714c8605a37115ba9d2300056a5074ca052eb8e428c8c7f6c0fce70b59e56f8e0e4c3f041065917efc23310070a4ebf5ceb9338a250e33109105d808de289f892df552673ef3c150ebf838dcbef8c7ed53783a4686e569ee9b5e6c4be1894e788c0f3fd82a53f707f738ea38057f5c2d89584681c36c18dc93320eef347beab80af5f4e53591a70bc02bfaaa4af6c6db26874a274429dbdcabb829bd76a12a404dc19346b90d3d6ed9c6d8b1300bee8afa3554d194f164bdcaa3c8e118981a411fe4cab65624f476a0525ca40ac9e29a4b26a01de69f0839d28ea154f1d1e6e2f12ff84ba0e02f8dd8467fa4bf6356b09719f04f31c80b8cb53ed5273a14f2b9b3b68c0bf01fd03374c14486d2cb74a388fdfbb97ffbe88257c70c314404b7213e363910a9910d6f6153db494bce0dc4de9a7f5bcfdeac77fdc64bb1588f5a2933823397c3d046cab9107f83b35fe3883eea71a89fcfdf7252cd4dd95a399a108bd967d280aeaf1b701a7fa4e007fe1d41e4861f170caf3d5db03df8de618d281e0d84b77798cd0c9312bb77c5befd00b813cf482e5401d5a96317a0126349b747dc092a22fd8b9f06790a5c17a4c2442a81e2c817982b142cc0fe5800ea7abd5e5beada8fa542d12622fc3e4985060e520451f5107393a9a87189035ad6183e054d7298540236222e7ae313df714dc5aee752bf81179f828c4b4e51138da7d79194beee97fcca890882ac59c3b9b40118db6fd0d0cde8d108ee1094d88c821a33452bee1af6c3c161fab626024ff82055472f92bba49b528fe22f4b432c50012012759a1994e4658b8b17f5018794aa7d0ad8cb96fa3d45bc21b9d9a40874bc84e9e4c67e3f58b734d09e50a8d8b9f93e7f0b1cd47a3b81d20e20fcd523a88188e7840a0d8d2c1136ed50c333e327ed59ba02342bd9f0d5028d33db54c2cb60b1061350d42c692553414a0f55e505461a07d727c6981c6190eef21ea313a61756005123dccb0aae9b18b504007b808b795c34d3f3a54045ba32a7e66f22a6b8c007044cae3c9982331cf2181cd5cc4ce1ae417e17755390813700fa66182d9207c03e2676ff2673003a92d0c0f3ef52dc49baa1b7d177bf576ebdb0e02892c52e11422d8ee7a8c11e3376fc428513c58f7b645f7623b118c34f107ff677ec16d353b3a051682f95f50eef10e3ffd8b2c309fc8eb478d54eb0c00c569e6203579c1227939d1b291984d50b46726c0829a3eb8528a644dbd16d25fc5635338909770660dfac51a3ed0b196102aa3ea5ba2fb1eec0cea6a671c37fa6ea837e0517e4aa23817576d8b7c66a37981e89cdb0612a463533bb4244fad0f62e770e2b33414d8f5744241d12b953c18b8341db757d27faedaa67a5efd0d2de650de692f655bc0072bf577664324d03e0c039c736019be241c04706a464801231497c943b4ac1e1f840ae8b2b65b6e212f941b6681c41a78304e55a1c35e5d5dbbb69577f491d4ca12bc9a870ff5e3152f47a5bc52e0807ecdeb4e36f6c060a715c0e421f0558ff97cb99ed85b0c37d2d7b9a0a8c0ab8cf8ccbebe2a6cc6f76b89febd84d4c3297f7b8572c337841e07ca56f4cd6f4190b9cf68229610997b63f775abb7ca10402a5b01bd6fbfd86014795b172b2f3c92fbc86c46c76ceece3de0e5089f1c09710ffe0628e0b968cdab1c27d0113b848b2a316c7490288e4ed665c4cf41b003b205eb9d1f968fe99e39d480ed58af36a4d7268b2410300d0816f72271954c4d0e729442229abc68c50b883edd56b3eedf9fd186a83b13fc2906f247f67fbb77d4b98b15dea4f9d08401ee67120e833df0d65de07a0c24eb1eeeba3187fa62372aa556263e9bd979e9c2f4cda01828c37ef02dd6932cca89be9e68d5851b775613d892326703c7632afcb36cd05ce26b9b62ff3c40ee38b22afc54967b4af69b247d43188f04f00c09ed89d93a8b0dbfb95a30368c04ac56120ae648c88383bd8019ee3c500a6cd9947e3b88f70f1a3ec752154566481e64b2ab7acbb3a9b956ee9fe5e59c5627aa05d7e24a9dc7a5034396c4196fe3610d33937276ecbdcba5ee66a1590f35adfa68e76432ccd62b3f80d57ebc2c33786441c1b083bb87c68ad3cc2331c7bafed8d5fd5d473ff9ddf68b2426d46eeadb5b2dcb5f759b7832da82339450d806f2fc0451089bdc47a77cf61d8ac1a586ecebca121201f5761146a6b75e4dfc2f6f8550671b8bb53a6f59872b65bc595cf4c287fc75a8126923a33b4b03cf36202a5663f10d972a11aed3a263ebdccfbade523aae57f37e749138b2142b2458398fc80b20ae567cb450172e6f5c75e25fb3c5de241a4e8b2e0d61487819bcfcc20983621752bbbe454e0d3b38ce8764d3e1003656b0555d956d5fbd5896269010e98e7fa8e1f918e550f487964edf63c4b5ca14395000ab5340d58ad6af503559f81972501d7f1afcf09c6fe470c51bd41e9e157a4aa0cf620b3e8956e3119e6e4433823cea2addd8f9bf9c8b9e0a79f4491690fc9e5197f29f4ff5533a744b04bbe765d75d7555c4ce4de9b2bf0339f0a6d86c0298c0dde3d9507ba22958f8a8347aae8c544726fde61751668dabcdeba9d8e2392f65e3f0162cf51fea1d5c262be4e47e68f483254f0fc00abc3bd04eb41a7cc49aa28391f114f156a8e9c96e607ba1c5bdb88c7edc4a5573c7b035728bb81e65066f39721057d05109f3d02d43ed89993a0d072e889945a51befb65fd26ad54c1ec0bdc5981ca607005aae981ea9dc9b18b3c80ba0466f2558aedf7de4b0fad0260985907e2fa9e5125ed9c71693f9126aed1ca79aea02856123f10be12b9ae9ebf01c8d0c5b199bd97898b8764d8cacb7cc48030a85f36e242dadde52bc3cc8d84f1b0ad5e1b061faf910b9cfb18928ce48b1cb95290288bccaa04d1274a767aee4f8c1ba8ab43fb02ec3320811f8719869fbaa6c9ea5bda5d9eef4dcdf05a46a28067f814acc2a41bc432fd9dcf01064700033335d337c2e23aa6436de5dfcaa7709bc9b4a490928ebb13524269654a790a6b32d4ba3c5f4bc98bfc4c9e38e40e556a80e4aee7abf23d1210d69510b21a39e2ea1922bd9b8f23002c2ea1f111d676a64df7885c9dc8d549d2d8cfa78b19a5ef820b38c304676245e09979a4f743204f742e39c783351644005855e21e7160c730de9ba562b2e8715f5b40184747e000b1490827dd990d3e8da066d6b9f71036a2e59b9f29f41610c79550f95d73335dcbe906d0195f9d9305b05c85d926a1f9d6cbb2cc5ca9d9f0ace2dee0db2f36901cc8461ba1b4369657c081a71421e8379813298feec6db65b6c19ce4174c544cf9b9ff8df6038172d76e3e0ddb3c516008bd65d861fe00b8d4166b7c0f590195c95095d631452e768636adaef73e2435ab1a4698737acd8309fb463801c3947f6950db0957b0c6ecd3e36ec11e12a998cf5b1a255c50e58c5d5ce6fa17e71d260693b5da18f004f68b9a769a0f0f2d1a747dd50f1715172cdd4e01cdcf8871a3f2f69601ce9d32b842bb1a0c2ce46c1e2e8a991309b72cc07283bfe12d659ef8e50f41e157fc4610754651edeb35817da270d22c29eea9548066d4adeadd6a26c761ba0ce07876f6d5d498b7bd955b565f436b44f54c405aef2e5dbd9c1037f30f3040201ab53df9aea1126b78c8b33569a8d478067b2935160fba50b1c1ce4eee39a6ab053d43de5eedebfa163dd4dc9518f4061f42966037d9a8a08dfdbfed9585525669f1c0214475ffb2a39328b78c4be2bc9433307c74ea87bf93917a6d38ceae4f4918a0ac6408842f1dce4b96a07ce21000e1107df9ec1c82cd4c37d77e34e32ae60cc609c79643499769a66c7007d486c53e23c09ca8c757cb525e8117c7a0a16e5456d0bee379837ae7ed02b4b53bb49dcdcad4ae4b2c506f09ffb9b554cbed158833d85e36311e747dae022398203237b53390898897556b9d5bf51bbf65200284de89beedce316a4fda77babe3434bf97e4d07d479302edb9daf09c7fca69b5a583ee3ec9bb75b42ce07e0b5ecf24d9d00430692004f67294d10eb57558f2aa1f6572f5179fa996b2575ad7fe3150eed8ea4621fe869437bc6b6a619c830035a849289ad115218884b9e04615f34fe6aac90e499cea980ef5644364dc1ec4f50d49b6bc0d89c1128c1a928688294802796af667e1ba9df1cfd3bfae0160c925f85f1371919eb3cfef9842b4231fcb788a08074b999f79de0a8ef68412dbd7bfa5afa068df7aaa22354f2820fd5d5c10e58bcf89b9a20604faeb95ad91a8ce9e36a000980f603a5b98f74f5ecbfcfa3f15842c873be8985f1f44d160581662778df4a760171f3dacc287ce91f7d701f429887ad104a8b12a3b8fc3015161e5771d76ba662a98bb27c0b6d5609ba6697bd8cf6400e4906b996d4f18b8a2a35a8100f7df790225157a1cebdd7fc40ac463d621f0c067a079a4339b4bc5e3273c6bb3885148006e2470827a17032b6f13f8c2ae728cbcc862397ff76557416be4ee1c4ea90c5b63e9cd8d00f12ae89b52d7c74bbb49d27937cb96df69e17debbc22bae2fb85ffb913bc4f88e623c98ff7cd6c599da70867e46297ee55d006d8e1e37d019aebf85a801d69693dbfb180ad5f8ca550e17914d38111e3446cd728392f4fd7d5ced9de2eacd6a52d467d747d8ecb8db96aa255133f013aea792659144fc0495ce8971a1735ae1d2837a7c5c138690d36672a38267ff50fe34cd337a5c9b04762ab3decadb652a89da178ac9ceb9151c325c25ad189c6baa43f160f610f7648e16d04baf649a36177893c4f452ee706f72d53ba426ebecfb950db3da24b925ce7e4e234f711afa8d55db7b9968074c407073aee39c38141ef029fac84f0016c5014935011d7facacbbb5d921839794f2365681601d54a1864b7549533eec3f95b5c66350484a7f89c8cc935b895ba0e08468d579c40c00fdeafd786d6e7639713cbfa89c951b02c93cc9c55f3a58a0c770032b419abd13e7d978c695d22357038f63371dc9af39d740bf4cb679754ae6099809e7a54b0b179f35b7890295ba245cdc9934338c857947691ec51793dabef2e9376b6b27d7e502fdd3029f40c2648a24b88090ea2bcfd359b70496036545834ea27bdb81c52c053957f3c1e94c2ad47615acb1cd424e60ee9fb11ade0692e22efa0664dc4df2363c02382edda1955aeead094d7b5eaed54d6625dc846b963b070bf322a703574f75f716f49b15aae1f880ede0d8bf0f1ac17d682ce45e9758500d6947227180a747192042d7f783bfc754ceb44bb073682e8d2dec3db6aa42d7a893de49e6fd2ed0c0200e3ed1f159486529ba32c48c492cd4031e8592732e2506ae679b23ecb0234fca0972b14ddc1d7e434b3af28e93129840abbba14e15319301a70b721db712900c225e57cd91c6eb5d5bc4253501a5956e441fb73237481360459baf5cd823326792d6272539c11e9104f8a3f038a83fe733c1ee832b076739bf5b7e01a2ae26bcce5f4b23fe1a344b6beda3de00f0678a08f925fc0469e9688f89f5cd34986e68c8fc85b4ec25c0721c8ff3d760c7717f700ce2b5f1041bd2200e3a1a5e38fcd8e804ae263cb7ea8bbb620b2234605f01ea89d9da820165b7c4cddb81f2f73b4918dd9363c3e70d6d62a4eed685c04beaf79798811754a4e771eb82fad3c3548097a647f491e8538645b96f675c0798e58e873ab3b78c36f3030e2f9bcefbd35d471b6e7b7d588d6d1735cf779ac57e1cae4013ec3f9d4e4dcf157a3dc16a57daeb8cfc0a6787e40c87b7596a43604c137cef586ebfcdb7cb9069570f620992cfee716b5ce8ef62cbc77faa669882257288a32d6b036cd20d62a43ba00f2dae7542e34f6c552a16e9d36882e1a49460e48f6596d1d090cbd24cf13893feafd4e42cfcd8b7d133f462b1711b28eef5d65f34b4eaa8834249d173482a35ec46d448875046a665becdcc2d207d5864cfbb811643d8d0c09e23d09ca681f48a35f566a678f0435f387bce473e122ffcfed738e5488fcd204a5f08f9c14f348d5e2e9ba784cc035068126e5a10faf704de30d6ccc22210d0240c5e3e8c3cef3932c6471165e731b8f848b0ee4cb1c9d8c5ae770e08d82ea94f1421b89bc1615cf51c39a7a8483e44a1394211c90293e234af6ee0184a73ba0a62a25554fde0e667a0beb33c0902eb9d3a75a7fbc89c053f89839dad08769388ee0188dc854bc74d493356154d823765d2375473f4a5a764b795780ffe87c06e2f59c0ba54e911e4f9bc0776d70b98336cd9e18f1d1d7871cc8f34c55e6e7fe6f2629254f50f0044fd046647ded32d27c82803df3d9961e1e8400c9c511710acbf1518b235b58c74d7eef7a8506afde067284b6aeda4d1dbb5dc4d5231425bce3f51ccb78fa439d0e5d566e8834116930bcac8ac801b8f2344f9f71a38a70917792f26ca984b6ccf3442a4da838488187250d557d4920f1149bd1b3e502fc55f607f173e16515e60908bb560afafdb71a15476159f0e86bfc55702f24e0b35f45a85313cb9df1d7b0cad2a7af531d087927bacfd220e00938a60e20eb9c66942f5a16da2566031115e0fc54d0012221cf4e23f1915411993fd6bb5830d1dd16fe9d6847da1213ec1f11411628cbaf7c35aeceebc1c09264abe427861f666b10d4d14c741a39813fef5da43c38e68b7df6b2e94cf411710c89028503f6b7b2c596d61042a00eb8f16dc9a05814847061488af822eb583d57671d58fd3f26cc9032391def119afe26aee4b7b1c5e62af9b305cee07cb96721c5239a493ca3502682fc1e300eb5c9a3fccfaf421f9b578a7022cfc0be01563663f24a3b70cb82bc786bbf26372044454a75edd6a7ea4d821660ecafcc051f4f5c726ffca5e3c795881ebcf268b17ba709c03b516284690adde47518046c86c49472f04ae599be144e4c696ffb96be633c49942d4a5cc23330ca5ccf220b74aa3982911d7dcbd920df95a80736489d77836bde5a86a4862ef1922d4c4edb5e134378866111e238b66282db3e8141e9f0871aed63f9e60ef5ae2d1204622def9c10a562492c9059a9dd5de9f77fbe9fb8fefbc7f68459b07f578f9a13c96f9d107cd33e5d1e03d89c359191a3cfe05603a399421a83529284129eaeec3411c33c3045153ef1ed6c4d6c2cbbe59d6da882adb635e531a179633987fe6a978a09dd2ae34427b3e69fc7e05df0a40a70e10ca207d3d04fd28012854858c82f4481fbdbef4813205010acc4568e4c0977ad09806deea899888a7a5cacf90ffdc2309b1e07e93c24e5aa515086adbe31ca18aa3411494b61a8c3d198713db1e7cd23d6b3c055b94aeeeb6600308e7a2c63f2a5192934d0c0d41d4785c0029b1f22095a39f77b9c5b960f0db847e05bd0ed8736dde05fe0800ed4d251e23bd74a5d02eb117d5b31547371e88f482852d1a84556c356f2bf51d73b6e888428c0c97a4c84189909e684722f39976e255f82c7bd4d02197555836741460429acbc17ca4a955f40ea13b28569bd1c9558f0eca3f390e5706f2a66af8338af9008cf1221cd260acea9c094a8653df2a9e617cdd13f81b72e9b8caa542e020ce54e41fbaad21aa583169dc0f9b33621e89567c06b44135f01107432c7b34ab78f23401530cf71ed8a63a997ca4562a5e6d49fd23ba14b6712495361b7c7438b180031eefc0e93f9164490fda703f5aaa7cbf877bc9a20b1568de266c2cb0be7cab659cc845289a7ea87c7b4c164578103305d4e93ba016b03fe3b421b6017d1f045440a274d8ed667e1ec24b437eb59cc1782a4774536292f6cf040a3b332567ff422ffcb9b8078e5da81de8fcaa4b666ab9c3c63bd7f022c75568ddf80d3dfed8bfbcf2ef275352319a8b3c94958eaf4cbd08962368ff97b3aec6d6ded9c2e03ba2b6d508fb9777a8e4f23d281ddd648fc8959a2d6cb1677ab88e572ccb55db463cf9326311f61c089baeac7d6803a74d2a57bef055f335af728f954f3445d6c8d00608a8e6a2212f5a9a003175005067b462fbe46082ba01f36b5752928888c0eef237d7058157a7d3b848938029b5af0954443a23e5e5ceb274bde4b0000ae5f654ef62b61e580c4c180ec9df9a110d083d16aefd58ebefcd8defc861e8d9850ed5fff0d78b71ee94059477c87999edee07396698b982e9d60853fa92050e50ea238b48c2534be405edd47793c6560895b8dbedc7d7266f9e2f7b818f72b7dde937b09f0250d04d49190a5976e1777fc18da0bb70ba61830d756250a98125ab919b909d7626b696a025f489c2687fe246775499153525b74827bb51de2cd89e3a01c3fcf6ad552794cc3e5ad402fbfa47b828bf1e6b1390830f7dcd01b6b3aa37a1930d38097a34314f458432e6f192663ccf5f2d4a715461ff78e058b6afd8bf2bb8c9f383adc2a3614a49fed666cc718ffb60c321c22dfcdd33795515c639fc417b6544b4b4a66b97ba93ea2e1e2563fb81c5aeb2c835adbee1bc7ce8539506d78f9c490cbadbd2dfb4e46faf47a113eb4b6f4ccd85d92de965f58f48f08bff9afaeac7094a130228a206a123b0f011fb2dcbe595fcf704b31b6dfad69fb7a0216b5ad97552df1815e7f1740f47282e5db3215a7e05919cdf3557bfa709b9176e7740f4a3ad7a58ab357ff13c9551d35d2183deb960872fcebe50fbe9c99df94208c09d68bf27a99e021f0b7bc2519e94b4d3d33cd928035af5e1690f659fac93d94b7da8d42e5ea7f207541934268ffaa977964108fb65cec7c4d9a49f7c9a2c0ab8bd0a46a157fedd101491c1da5848c41e7088ee350ae9719c7b17f5624242c09cf78258353f4b23c07d7d68b29837f10d2156d4f319dfde1069a770526aa9e1ce84eeeec4902efd38c780e8b1464ba94d207a96e57dedf67452f17330c7170e9ce00bdbda1a908bc7666b89b75db65a8419296aa4e2faffc243977bd4677fa1ae9590410ff1181a37a39416b3b1aca0babe9e5ced897849a1276e824655ba17ec33c93a197b983afc5c57beac33bcfbc6562fbb24609565ddd4cb8852241b92ebdcace5ea1cb5494181acc19a1d722cebbd1795fadf832aff0e4e7cbae0742dff825cf75b61b75a349904bfcbc31b4db1976aad811cfaf92bcfab2571f1abf1b0971199354a3bdf03a11d09cfc77c6564d0dc1a9d8c31d83d436db9491216b9d89515f3ed5128107250ab7933a62fa533480a821fbc9628c6f6165c0b2e589195e0a2e4e9759cf7bbc294ae810af40509677b8ecefb38cca1424050231ee8cf65d7b5a35aa586fe99bb634d7b5632b8f06b5f8a4711bb2c33955d1e4863390fe1e0c59578e59f25e7132d5ca5f0ebadbe1b70284fa601a6fe124e0bf85a2c8d1e445b0d589eb8cac257f8f96fb7525a49073308ce98f59d7c8459cada895b4206a767a7a69f9b3f24ac19f2c8317e6f7b1cd18a1d6301325cc13e016c3bc8755b9405bc6886c317238451bb360c762f93b5bf6d9614c02bd9f1ac66d3d2b3c5b8e713e3d294ec90b4c6361690a92b3009291e9460efabb5dbd9a28ff6dd69e1178b44268493cb2cc9da083dfdf208ac37ad52119183afa5312351df1feb16f510be98eec4c5ccb3b31becaebcded75ff6d3fe38c99a1f7c3c6060bf02eb47047dcf0189a4dcb42855ffe4af2c7bacd43f689e17339086becc8cec510108b8716bcf02604bc37bc510545177ce34354178e0175ac7ac333408759e29732f394ebbd7f2fd866566571a9a4e7ad41f0639d54f0d1703ce86772bca180a7ac033b8cca15e61cbb69d12b1533e9bfd0aea416faf328c7d0d7e8506053cdc8e5347525da1b197c55021df4150a3788cc1a23b0023a3b9d7da7f5c420a95645bc4f0150afde3cfe9183324fce563134473f4f1359c2f874c7b6fe1183430c40ea00152adefd8c81040551a939f02f9cf81c2d1186e587f463b6491401e326403d4f7fd08bc31e9c345bc5e6a6b8e899a84118f754fa7ceb5e0f9aef31c852aacfa5d72351bb911ca615f8d2f25f678fdf985e6c8f26e94dbec49ab04ac2d6532454f896bb94ec99a41484c79233258f9a75ebb326fed21028d26e39f5573e444e7acaa93d6b4863da48331c2ffd8f75bb5df682b6bed79a7819b88bb6d133e11f176c6f15f8aa6d63106b67245fc207890b24d85f2d32d87e7a46ca1fcf40fd44325cb562382714a7852813357a013af3ad9573e65a7b38277f3080441e133c14b3456e06e943591178cd5ade112db1b40edacad8fd0068c8dbbe8bea894e195cfe1770b372a6fd711b44bad0681e458c7cbe947300cbacb7b1a6b72c471178aa2aea1a2c714c42a595832576eca52af7ae8cf92fa3b129c1423601234d3ac9f6b10e49fa62c1dc2059267d5f5efb9cc9554a8fce5d1b937ec23edb51d7bfb851a49f09ecc8fda49f832d9d82d7d865fb379ca9b0ec0a36e0c35c1ed808e87ffaf282c2c91f7f0d7ab88ea92dd6f4c5d56422610356fc6c4e1c9f48fca5ab94b2843b87ebe8aa6451f781855d03d6b1fd734e72573becb870048b6937ee4708da8288ef58bc4ff6180ccb2e6d28e778caa1acd2241b7142520a6bafd698008d4df17e8bbcd3605e99ef0e020d59975b66f60c4842d63708ff29696050f95db5690d513a48c0039101b1da5c8792f75ef15b30d89e20888284a08943f853319320df5d936197c429f124011baed1e9a5f3bf7a5501d08634f8074e4fb6a7eefd5bc5a24bb38b073a4109251f344f51cbefc638fea9796c0def062c787eca06ddbce292e1b69c952222e3b4390ef42d396fbbba6c68ab0be90ea03939b5d9022315aa493e850db85603bfb66a7baec3f7c7c2177f9e32e7f69038868d4b58d0ef14ed7622619d03a7aa1357419823a2951a36de2a3395d726e172bca386dff70760acc37148be8a41f13e6c35a8a29f428c3055a5400c25b64736a613a8e419e4ed5f6e0f4bc39fde90209a07107f83b0686830b57542a879da0b81f637dcdb8a6ce0f45f6b1661140b82cea4bc8a65a5f16c6a5e552132662437fe820744ac00dc2e8a577d70c3f00504832e94508ab3dc45cc1d802fe0b8bfd2e73db987401b62a4496728d05a03f6d8809f4bd5c367c026fa5153231fa19f5e62ad7577c8b7837dcaee23b6c2c5e8ffe5d381a50a5d763d27e84cd199f16c63356e02a27047121c0426e6b8d2120de7ebc30f2e8f9563c97d4ada176e62b60275df25665ea8c7e4d7f81df730e100755b1ef050d272f9c4f2bdf1faff9560c56f23caa0028a3aa86ab1c667daed3a6907fcfa34de267a8bb28f5a145dfbaf13361da1a747efd1b75fbca982481eabbf61d00d61fb4fcf84bb463a508a04d5093c43190e038b381c020c24bdab749d2dea83434ae8804ac92de3ebd5cc2aa1e31b543c87fa882de70470e4e918758234c2a1a183b0c04933a3421a4040c41df4fb51c4039ef202b8e28643d8a10eae4b2758333a9c0481dbe277b00d29db92a707d78fd2b28ca7793385b0a702737c3b59c9801c2e42488ab9772285d947ac849d345295cf7f79dee1928eac4109d48d880dc71ee898439de2ec5b528b85b1c5b5e9216c57000b11d1b7158588a642b823d7ada0d6e2da614cf619e5061fac49f6915d7f0244a7ed0d6ad688c6eff280bde82b8efc1db10a7fa416cf3dd70410737edc39843cb2fffd6be52df28ed8d69fe83903b3eb41f3deb4350500857a3882449555f7760e30dbde964cbd2336e09b6784dc6ab84ade40e0c905978c609218368f91f2990c8164324c496cd605b3a469ea419c5de8a549909235b928b95ad47f0c3ce7c89fa3d0bca8836d22c7161139a86927e1d8c99d1bfa4dc07fc4a9816b48916403750a42af8111217d26df27f2b800d416a8258e9a98b359c86391a57f9c3637aba4fdf851a2dae9bedc8c78a5c91dd64a40a27345bcdc1c5910bcc2be74cb07f08f0ed65a48038594f623a60f48bb1a7e98f0409b2af98e9c327bb03e5d0e3172d31e17b39d51b265d70aa3a54cdc9cd74f999cd187f3e847e8347c2dead73480ad43e4652862e56673753367a294f28930bcff790aae6f75ae94eb2a768bfef70ea6620cf4fbd252676873259ae091a6a85ebab05635329b0cf9f22f8a779a4475d45c0a0013ff015541cd663c848060c163ac432c1e609e8613a17f530bdd666b1f999ac1bec27d0075b034b6c083c42952247c45ef5b1ccdff2cca4740f4ecf17fda60524152f4ba5b7707004360647edd4811afe44c958ef66f02632e05a8c29968cb2bb15fd92adcce8765019f5b07bc07444e0dde208be5824d6c3917af7f9b6d5c04d12c829ed3806321985895ee3531128dc381b1db117c671533bcada25fe064e66e06c600bd8526768e72f5cd659fcf28e16017971e035e3775bf6e10fab8b4a559e4c4841e5810a250189183d0cf183d9a3000ce4c12aaa570e08129c77ef51b6b845c83d20c7cddc18b045268152ed2267250f81fa128fbe51c7c7b070a99a17c27e688a42e43a0715ae952dd0931363cc52835168e1b506d626960d16e283902459598fd25b4520749486938d21818e280420d641e42d24a4382566bab255319f779ba465a46d6e5c8cf6cbe7e1bd883929712f0fac23e4201bb2e9235f663c2c45eab0cd517c3d06349a8c3e991e441e59f5ad2987bc6c5798974a3171c887e84d5ce755cccbac6463f5b5ed11181876726d2eacf0fd3657bdf2342f270a91a17da2327dfc89d04e6be254f1082685316cbeac1674161eb362d7423892a99b7ba075d986c618b1e40febfa2cfc1f1c06c99b3a7d26fa508e823d379fddecab31c19df74e4cf35eb93f8273ca41118ef0b92d5a32d6ad513261bdb9ef2a8fb97c14439123ea3c201a0cb69a07f105c77bcc7db4557f0cca926ea74c475905ef056bbbd68c485d8df780b07f9d6e098c37d9bbb6d1a7b123b6fc20445a7855602c494f2b648741936e89e3fb48d1494449a5a563e3d767e88299b0930c4bfca0d8aa21c280a26d326758039ac820f983c0add8d2cb7c7445dcfeb4b8ab1a69aa4e02e136d4347622ea1d82f7f5d3ff0c58c599fe8196ef2944af5b71e20cc7cf3c1836aca2b55baddc39f934f9c31d1734822c4237e63e48757af5b751345fc8c4c0a4a725c17ab65a4bca602570f1fb05e56a2744cf472cf59c4689310a17c68c0bd073d7e1b06a1a6397fd1ad5c2d7282ed57b4211cdab0cd7343109a1cef3ba61555cca9bcf365daaa8f6892e6db3776a8e187cb120bf2d79fdf9efe74d7ec592371a4da0bf37097fd9d51cec33da38d545edf892846aae68ae8e1b8f5b56b453d4cfe2ca8f1da872f70c5e2ee077c9f37ccb3daebc70c610797b211cbdfeee4e68edfa4fed791963bcaf74d074f178446daa7d59bb64188cfe09b89b9a1af3426e8fc233d0f0d6d2b6a468c7986745a2d33ffe53c6e1d98481b7ad482fa16632fca470db12dfd29a6afeceacb7892adf5c386f7c41797103e576cf82a6a5226d3016e07e7dd449947642a34f4f1f6970087689f2fab3441556f2ff2974dbe0cafd978c7e1263121f872eb829be740cf1fe75d44d663923cd2bece850bd343cf4a70bd81566243a07407c9707f304046baf607c752f577c3ab9a55f16bff8d586b705b9329956d56c3495f5fc2e75574ee5f44bbdb5e2143a77640c972d02db38d872adad16aca8745ba713895585fa3fe40228d5d6fdd040db2e7a900fa91faefbea85236117c4f6ed55f9abe030445a7da58fc727c0c81c0ee5f8eab19a0cae434a7d53178b6d904298989ecb8103d944df5776f97e1b4165795366e46a9234b956ab86069c6420e1ecc78e74e49e8dcfa46de72e38d16940a9f6c1f8e1f6446413563bd7d479b14a55fb057540e875308c4015bb797e7fcb8513a5db4581a7e7bab7a8935617324e155c7b67139daa0f30c29814ff1a23c6ba601c0c1e08dc9d594a4ca1f1782befa51577d51babfb4f8ff45c146209366034f2f5092a8bccc854d5136d35b81232bcea3408c63248b239bb90be310c7596271378285c4840a437a459e2505cc870e86e196b393f7a27f65016850bdc2f882f7d0c44c30458063780faa332b7cf735d6a764c256ea3d6bf82a29833dfc5dc4c309412f69acba53ca5f4cd38d5aaad7eeb16ea96e968d1e8eb461a7db530c945f5e61a8d284efe75924a19b88380c6843222a0601cc4fbd608e6e2595312b7c9bfc1e89f833ac74e2e5d820800ae0dbf2276aac8587bf130e3573889bce254139f465134a2ee94937cb2198135882b6a333e7d46b53296da5f27c5c2a1c4e3e0b7d18f82b70a6da659af512b9ad75083573699664319e3c0fb0d56f86ddc6ff6fad6970dd0401286da083532dfe16928c3dffe832c94ed2987d5d2a5374e6bf39b934f2f8c56f34463aecf74bb9af5dbbc086d961704e3ab2f37568bf818dfc0d80e0c9d5414c851660c6041e443b9480bbd88c5f4beafb09846dc1018bc14027e4be8e328837b51310a6749104f1f7bb5a8705ce5aa7849271f33d44fdfb5cb0701c685742f01ae2d0b3c8de50c040b9f4c6c8130d6f7728ebfc018571f46e8dace268cc4b22286d13d28e655b361b0766116b6af3d62a0ce3fd813e2dc1aa41fb18ae5a73ca7de1c2062ecb3c473c93089d9f74b158e56f5617f625989837fa05dcc11635167375cb0c0ea1ec2269a55ef87fdedcea611c4e10ba1438831033148e3efd41b19914e2c601db6207223633f335b21533102c886481fdec0724b4da0d35c2429bf503f7e975b9bd50f4a2f7a0519f828b8e7dc72edc15643432cd205a4416d8557c435260f3832a2fd6dbedce355674360d403e104f7b811e05f5a518cf1b8fa53a8d5185b7db6660058e17a5aa8c74bbfc454253b4d46fe5af833071d60f34a4ed993edd50c060e1669db6fa6e65a392aacfe2e4baedb702b5506facd7e238a9ad55e0775d0efd8bd17a3d99b1c8bfa6aa04ecc8982a355cdd823244005c2ccd358c82230c50a073fe3b67ba24e6f41706d27608eb47da8cbb3c4a6fca74d87e6e18ad7018aa96fdda5cbbffab77a296a829ca2593843e31cdc51ccd8b0730156aa50f2e168044f6009c62b43d685492c7e583c07787672351c3475e10b08aa32dd7085fb2d1234cb041625eef14d492c615abfa6dacc82437a9a0584ce4e8805622957bdcf39124be2ddf27b73020f48e45e91d924fd56f2eb33e67d6cf57c2eb12b2a185c59432552e6054467ba930154a9f3f88ac90c64c839310c28ef9a1cc70c533b6384225109348498841cd99c0274b74c4c0f02f3a14071ea24f68171485bf3969647e873853ad843374e37f99087fb9c2af26cfbdfb1a3c7613573f88b710a01d98a62d87fa9caf35bf7a01636c82e36af5fdbe981ae43f55c0e48249d588469917b9bd5520468798d44d400de21ae6388fa398428378fc85ef83c03234f5fe1c48afbb753f6c7588407719e556dbfbd6e37e3584f3ca056e3ac7a1de7a0fdd8f48f93d0a50182468ccd239f2c4f416b99bb3eca9111f5795a4e71bd70af9be0ff0330b262c3411f3017ff5fe858b44e05f42b289014f4b0a9bb8251b81321d75a86cd65c0c05b7e2cca1debad4c8a62edc1eab6003922803ee427f55034b78b31a558feccc4b11d1222163c69c703a77f1ce3d3d6655d5132f60dc7494cd34396a987821ed500da06f10cc654df571925dcda7e08a29aa50b594af2316de7c93c5d3a91153c1be3a126322deae592d734004713d7e94cab88626d995bee3634b1b99a3d75184c96b844e9ce65f0fc9dd6c6367408b60544bdf1caffa4ddd0a763b26c82f463a52d5d7e72e81f84d167fd9fa8050aea168acf9d58aef26eea9a92b1285c4ca632574044e5f8d2ca60ab680bf8bf3b66065cc4ca9a421828c6c1e464881a1fc30017e5feeddac4e3aec14238b572c55ee10e08830410a53efde90f3d228e466721ab9a346aceb63a74c8f1b78ce27cce27d706c34867a9c096659d0e9c8821abe2c80ec09ea3e6f3029a02f65392ed9a81b5701c377dc0de32504a082512d707e7b9d58186dbf952d5ad49c2e3fd83f6fe46d6df9db4a5f632b640fa467242a4044d4b0af9f96ba52df2dc8e272ef938a9be14dcd52998b4acdedcecc678c3c96a1a98f10513381ac0dce7ff9b88bc095b6c771371ad70e5f371a4d1c314cd67a3a0ca531a80603067d9ac14f8d0ef80c80631a9f9a06d0b20856fe7ca68bac442baeb3cb51e79ede3cba8dc0326bca50ceac84fe636386d510c35d9f291a82b4480bd449c408d410b4c8298859fb0cff6aa0407dd6e64aaaa6d06231ebdb175432bdabf2b47c662e90fe1da88ad1a0be172debfc8501e6cc91d6815c40c25f4b9465cf04da84494746a39d8b404baed726d51389c6a88868c85714a9e5d93b0ba0ebec380394ca38844dae47ccf65b835062ee0d76993946b90f23597bdbbfd36354c796200169c538c3ddcaaf2403c2b29d1bbe4beaee090c675af8c9985d6762914ae7ad11d0cc2ef94f51c0d7b7b3fd0828681fd65ff51e31acb12ea4ade6014969fdef286d494b79511469d59deff72285009723491e1d9d1b8fbd9c8e81f1dc13dc008ca1e31a913983456dba3020eab5a40f0f31981b44e6e5e7443f5b604c1fdb31d7893e49b3612ad02d78705c577e5b3490aeb379ee0d2a05285b12004243e7fa7512de186c1c7780f616fb14ead71b68aeacc6e23f0cd6349757264e7bdb0ed27efd59ed77bf1a782b5d5fc3ec052edaef88d92e8ae59f8948ff1addd400bbb1c43d71635b053814439fbb41a97244b5a63d31a4f02cd7a0befd52b4d15ab45405cf65ceae2d7a9b4ad93c5b1f432e6e1981de37f70c37a84bb7c85bf2e3a34b7fe2e6764b6b7921254d3b04dc6b6a4e5e9ec074c4633be261db9b72a1c5ad81e89a7b915fe48085d35ce284280f9562fb9fe95b5118645a988ef27d66f43616a7b7aaa992ed49c4fec27b020374d154732f00fc5a5e9a142df2de4c2c8895bec1e81e37d1da04a4ee6b6a7484b336b24971e1eca7e6c9b8ae711a48fe6c87e9034263203d8cc5854bf7d0a4e3db5a87ebcb0f3e1025a520c9fd075d9922105192f54750f9d0dd2ef6d8679bfcd3569249f07dcba3c6f9399896b59e779b35782091887e3f5ec0be9b96e6bc0a363732dc1bd361c944f6ec7e39eca37410b156d6bbbd6e6ed0817bc3e0c1a753d93ff14017e9e473f43ab8e831cb8ea6eb13844fc48d9d37e1a45f28a9c49031dc752e1ed9fc46856ac17c51a1b4972af2b295ffd92dd401428a7fdb232b54a9fd90f405d406c7d13ad3d37705e1f402c9af54d4391144e5b4b2db6de593d39d1db3f7564f29a47a32bb7c910c30ee0cfe90b0a7ba13cf046cef8a29318fb8e7dfc443f5400807ede71af3c132e857f3328ae8889da40e865fe0304a370517978b9e74e6726d00ab54af0fde8271c13e736e27a6cb1ae84445e693ab528828bc270941d6d4f6c3a4040ab394850a4eeae34d9eca379c37550f4920aec52ed0cfdf6aeba16b3c6a8b7efa42a3300d13594d7e3d485f95fc73f0cb325c757a22d4edeec270abde7958ce3d65ab9993677a347b8b3d916dc4ac00aadc4375e2620a965900360007db432c68b4fe1390524ffcc4b802efe31f06152252f512e92751142a2e4e551f0266f52c4bd614cae21e4f82dd831568e97fc441a0f0184cd8a45e81d18157b4523efa522091388c11fe5fc5c32bd1eb3efc611b8751b44f012487d37748a9baef918d4b3df5454b38397e4f2bae863467e9aec6f84e3972dbd06f0551a701b1f1976789747db976359baf872d8b9ae50bc79dcd2c585222574c08d9833a48cc7cdbcebb1a7fd119aca6c720b4dc7adeae523031590abe6bc02c733781b1c44a7860305cf9c012e9286fae9c2b63380b9ea95c3cc316a0086048c153afca80e2e8027eb1604d0b6a8116834348101abfcd22c4c296c4d2bace83a43cc46d51e29b4556c851634e405c299f38ca526ed43efd5a3715c07f38d577032933dc37ff0e4e13ba5006e957d884bc7ff839b05ae0547540d234884b10c761170b7d9e45ac591c11662e28a119294132f04e275712a3a3814c7c2513de855d920d903daa0512869b592641bbd1a61b479734647b61b778811c119a0597dd018d9268bade5512e66568b2a9752d102ee7f91a5d350c3fe4afb54f2ccc6193cc4ef434ab892aa1b571850d854e9430bb40da21c82e6469ccc450cec4bc81965320b8d0eb66e8a98ef1149b50ff61ab670abfbfd3b0dd2a6abbf50108466e97b5343733bb64d2ce740d1d15b163f064455dbdde0c2a13a43916a2aa75afef38b29d25f62bd01573f676d8fc158df0a8ee7a910a307a421284d1d0729d90e7977f40d78433fa900c7c158ed4cefbd682898b3a8daa0929a164d902eca6baef63c2fff01a31fb4f7b5d13d2cd1ba95f087f105da79590c1fdf849f4eaefb96e837d83da27f393ea9513a665e4d20377d6fd787904dbea435bf854486fa041ce3aa5c63b8f7c208a465a114ebe2eb69f74a34a3004f6cfd197b009a76cd89d2f4e2b5104f28c09a47295586c63cb6d7c70f546cfed3cea19368e88b7bf937a9353c8389618e4b0c393e5f46afb1b52e1de6d08a3885410c65b26a56cbd471ffc936a7a6b6546a160200f2382acf6f687eac205e1394059269e760924da7782402e8d0daa8d0b114a9d4070c11bf06e5f66838e620b963d5c11e73d1bd45c2a41116e982b7cee30e05db45d5f257ad8a50757209afe5d99b7934864fb4e15af9bfeefb2dd50769589f98c8e857031ab77b9aa50c9d9822cb06edd4e6b5354b8a0610660039bccb2f6e4593bea7862623b8ea6032bd18d6e8c7f2cc8cc0abb181a22138a92562f817c91952e89bff8de6634d98023265c181e4f2e6b25698d70b3531656e39edb43d77d56253bf41ff6019747c9346b72abe56527e88784c350c06c4745ef73241477087ff62f1987c8239953e0a0291df469eb60c5d830ac53eb33a458d2effdce6f918e069a17acc3ecac9c5a26e27ae3635b430884ef4d6cee7f0201d05dac3c73632ff4e5f23ae6327b9fec3b4b1aa404c7b4f72bb26aeb6970d57fe977ecbde2881fffc6acfcd48a43af89c4e89ecabc6a3403b17c88401054d003eb1e88a16783b614dd31ca9945128873af26ab207ce7bca8c0b8833dd3d300ee68eb0ee5ac489e65821ea566989ecc81b8f98f9febeaf673a7367f361f2bec85c44827dfff9fdb2c443161533f4ac4028314b716e6adab5a3961858d9bd67e004f2fa68627e5666d8c6095f6f754ad594bf629e9d238182c2b8b6d64af97f4819810b333f619ece79634e27f42a2f5c303cf88a5f31750482c1ad240e2ae3f4fff683739b53d19d79193538bf6cbffae8e052952e0844a8d46a1b073a9018a4ae0fd79471ab04d91cd3655608d890a9c657455bc0daf9609517c9c309c8cd039a81f42110940927b6b4401a596a0ce93ecde7043fcc976b3c381b35ea95a0b6b1a410f2198049caff3b844300088071ab41e849299878e94a18213b4aef24c1d436ecba65114be8bc0729bdb6e67190459adfa3f2d19865f30e58e16535d3fe97a48caa82e66238d370834eaa86fc704da1cae04c78f65fc6f7127d76183f149a39a8f9e4cb3335f3c57109d27ad38c752566d3b696db6ceb529eec17856e685d2bcf069a0a9437a637713287f23133f2f4dd833c1100c7795bfd5e683dcc49f9b753d71c37332f1c9d40e924c1a6fa5219959c8adac5c971993c35d4ddcb9dbd4cb8b08b4d9812061da6a43ac44560deef852e1609d3b4bf2bce97b787d7839021ef83515c8ac59979b5598d8cffb3beb666b677c40f80d7b49aeff1df3fe6a29ace8e2aede03079d7eac73670d1233d5f3f8db40072932945561155621bb41f647d3546a695bb9a2488e55b5145b83cb1d026682a1b966145b3430a33e41a359cd677154cfdcb96f58b6d69354177b7304ca70d8a81bf0e309f193dc5c37f235232f4ef5a08be1a9cd2ea85f8713d041ebda4b0fc7ca6ed8f0085b9f574139888de6ca11f131a80aad445bdd5aac0e22bf41389cb26d9714a326743bb399c9020ba2acfc27ff2ef68c1cb6e92e1c13afb9457e68ecb48eb371541749761d884476afda68abd1303660cfa27b2b355a0da68c6a04c2540cf9609b6de8c693b523aa15278d729cdc4d03a5a04a2d92fe3191770f7a38d44664156de0f81bec4dadf7df78ac5e75fc8bed327bcac2d59c7c771da838c09994e69e1ec4c8030bad5e8a10300290f5e5886116014b5fe388d2ac7a58275add4fa6bf7a744a9ef769a3b9e304a0706161221aaabde8b3293440f1fccf85e1a8f99a058304482bccc5c6db9d4cfccb304b11b5f0a4e76668563ade7125f7177405bab18d6d423ee2a6f9c733303728ffe94eca5673a24d42b2f07b83c10f7c01533afa160eb4cf163f62b54e5ea7e3d7faeacb467444fda3ca7faa4e002e0e15cf03760e78ed7d20ca8460cb91d2044b856edb1d12a2ead6fd83c11fe00a5f242675df0d2e1e5980fd66dfef528a12bd537780575e2778af0ae018a37dd610eee958025bf1cd0183712cded5ce9cf6abfd99ab484c021b51ca7f4645922221148cc1bd018d0798106c66cd0cc24d886e0686e2bb64d2d38c48d97099e8d71ca5f1b9025cfb3e83c7addb2645760f7a8e8b28b06b869dcc50ffd01b86b8687efe0dbfa8d6928a635c8f4f63a9db50ab0aaeba36de4263c149c9e860ec22c5a9f94448c5f553c31a08bc8b1e7613450a91f75ddeb0d94829743efc5cfc06d0b1ddc3b3a868f14abe96904dfdb6b470dcacec669bb518ebf4e51dca5d0b067b667f5112b34782207636911ba89bac8d8109af3e38b8146c26dc96f7b3c83bf6decb9f72835fc929ce70e5eb52a7943d671d207a419539b576ece63b8da85678f8a39c2a655628ac41caf1be3a83c1bee33851014feb85286495595300c93ea195f630907b1dfc546fd8beee11a887f83f51a039078d87083d66511f87903a7fefd52d0adf57941787adbd5de0791159146a12789daf04119cf1424c91e5842d32bad0c4c00631eb3e9f99d3a11d148aa5399c8da6b37b83193028037aed56672c245893395ab521d2e3d78c893d22424d7280490e34cb2742c3b653e833ab7f94e1de82d8922bf858ac2581e2da27da61b922145fbe4179d586c5d12a986039e2273693502d2344730160f1f9cc60ba7cb7ccbacebbc7ec710ffe0f86342cfa50ea126a6d3d3e50e03965424be44127a6c4caee84e905156e9516165b98a6bd9f1828c27cc95c8195022270cf490c511eb29b9b51b6ae4e9d92010a3678bda8301375fb1363531ade050757594c4a61bae43083b049702c428afa64e91dc880ef741f1f8d26e61f42de72bceb774ca7daf6aca7375f5ea95c39d4a38d5e4d539e4fce39aae3a66f09cbd9525555910ad400eea25d73fd632676d1a080dd0b1cdb9e3077e4e4738aedf0163b089f35c77de76a0c8bdf0ffa1f1742dae0bc7253b416c43dee2f43a2d2fd0d0c63026cb918d17eb87becfae4c9f1ec80dc5c84eaaa1e11013bc9e8c471a1977a81c83839b4239b9db0223641fb8beb800e6b3114ce2a62f57d9d4b147876a4288af9cf6181c66b62334c6ccd26696571221c01cd24d40064da7cc56d5b8027b3fb8e3ca9b3606462f7fedd2ffb6f7f634f1726213fbf34482c0d08a5cb70082c7989f2d984246a7c46677d43395689291df089d6b3ec737bce8d84bb8bcd0ce4019e4e918c46aaa3f2e1089a20ab5d56c0b12ae60ddd9fa72abc24258e72bad070d939d9003033e3009eae1e2fe4b17993180bef50b2274c12b48281cf33d896988103a486468675d7d473981ccf3ac539fca7356454dabdc30ac14a2fb87865e5a91976d6d50d15d6157c5ac0900ce639b9b2948d32688b78b58156f5738e07aec36143e90550469c284ed1ac0796f1b1abb3890fd359774004424ed4a47a9303d2970f8855a6e3898bf76c7a99baa5d8eae31a27b1ed010eabcee1ab45c9492cbf5f42a3b569a34029acc7561ab091c681a19b150fcfd229811ce809eb541db2ee22a67762f79d7b5857ce051d7c47742b91ce7e65697a64a1e7c2d69f541896b7f37f064967b1b0ec343a6b1fa1b526353dac4eb7b25601075062165b39c6f7b7dc6e24be85743a295ba03d8435ac39ff63d7a793932e135ee8fad9bed919356c5398b6e559818811cefea6368cb06ba728c054fa13adb42da7e745bd8358ff3cb6405db2d76d0ff1e13eaff998db06ed0102a6dfa62272fe2810fa99326f35cdb46655131adb04bb8ee84d61cc688d5d2a646ac83e49b50031e17cfaef4f73ee051a048d02465de0c05e2cc7d5a764016287b0a55515dfbed699e32eedcbebf5a221f9c04ed7661f1a0702d0d23c80c3a399e130d77f1f0d25050d2aef83fff01760606c6da8fbf51a9001df3f97fc71e909da9ce4490de79a75c1b2ec1cfc78e0a02b9dfaa056cef492b4644906cdeda84404d2053df45431d21d5ae12c648f4bfef28f1a76cbb27eafdc13f5137dcb0a17ec48c955c1678dd15284cbef6b18df6966c524ed2011b9cdc92133dcc151a2056ab3a4381915f79be5bde68bf57a005d65a5644d0a6cc2f054ddba783323a69e9d388ba02bc472c80901f98eddd52bf6f34c0c49253c427067dee2dbbed1f60be61aa8b2ca31cbb6260c4985a10c3ca33b917d2ee321118a1570b8246cc10a12ef030120fe14b1470f7733aab80df6cdede15825f5dc362430a9c7f695e57f38f007144f96b3be36dabf48979e198fdd88c8fe851bcdd0147d910df27f645593e78fa1ee9202bbb63ff93214456bfddf036f84cfc3bff30c7893662367ac27f2ba03bafa2205693d8c6ee40286e4cb76a1463e1cd28b98e05a8e32f2c40e5aac316b0238c9ad70ff3dffe7f504d78ec07478b13403d68b134c6eda2a6e75055d1156c157c61c0a1d9d30c57e9ff0a2db6d5bc162d0cd80e73c8ecc5bebb838fa43df921614b1c0e9e1019e4850c78d8d541c376d434856404013939eb0a0c67b0d1ac673f13f9380635a1a897b528c75e0113262a314b9b7496bb54310ce33bd123b20f46806b3acb1c9fcda8bc4a9586c5ee47e7e7e86729a45db59e98e772af49bd9240a94a94a372c1f590c09c00ecaace39d1af3f3e4616fd03ef9ea94693a40307a8cf5462f630311ae9537bae816b8a33ca4e01049a53c05294f3c965d2017dce2a96c8474beddef1946dba389eccd00e2359cb061633ec499d0a78c1094a8e590bdacbf8a98702c36e8144ba314778d30f8dfceda0aa1de1444e8bba6b982cd323f5e1c43acaa4ddd158c8f5d279354e58db540ce58fbb1ff2266c0fd2f25470018fd08189f846af23c3c40d18738c4def160d0a34da706ec11246332032896d6d396ffae1052b2ef9adcfeabf7f7f00b46992a31603ae82d681eb712e55d7e3ed5c7186060e24374f869e5d7563c7380c548dfca8dc174bb254ad62814d843f8f2ec4cf0cb075c06a19600c93ddbc87a78c8cb17131fa1dcb2ff615e001398a0776795922531a2a79ce7fe84a1dc1db0aa8ea6866aa40c9eeb8558060d01d3cfa22c77ef6a4bad18d2c6f4a8b3f6e7aa4f890534492850421eb50d2afa7925d06e23947f2b85730b30d1731a42ca9083b7c5905597c58ab3785fd2ef35a7f3692d9bc2c3a0a5690680e3fc1bb4b6f985b078cefe3be7c237f7ca607e210cc52cd0e751bad5068a881a79894cd0dcb620544c0903fb22c4ab14e64e070bbf9e4d5e3d3a510e49a30f047563c074c6a2e64d4c65f6ef749e477313e2228e143f914aebaff12da2b2c8f60338d0e588542865fec3d0e22b1d73208870a0340c6911f7e1c92ca30d888c0bfcd4217179c98f749446c91712c8dacd289d59c37972db995a322b22f5187944e139d443d0d30ac47c2d4a1f036427e4c3c0c440647cf866462daeb4eeeb55a1c3f8b282e85b0c543f2a0ec50f44c50c8339cfd014ea5b232dcc31556946f66dff94a197dcfe50510cd5f9010a2087ca24d4a5ae8347424ebf3fc5066151817e594902d3d5685658f45d2017104fccd85e32775692220b627fb7472694a4161165894521eb43bdd0cca8a00fbadee72825d1aeaa01c7f5e47e5df61296669e667e3d0e8b45726883ca3b96483111a905391e1ee3d0010092dcc867eb55fcfbbfa9b2baf6889ee62b43bce98f00846bdc8eff428312e24eba033488fb8c9d1fc2712e96af5ad880c24433bad80d40acc9e90b420ced9ce500c4b9acfe91a3475e2d879ed71f5fe7b49cf0ffebbbd49c8658e128de16424c07edf684b2b12cc3c35ea02737a6df753494efb6760dffd55635d6fdc926afa1f6c54138d6029b9d7c168f3c10e233332505b0ed33a314e25924ff1fa528b720b5f738438e263fcccca0218e082ebff147f4fe7d5398782ca0829c7420c8bba85f71447dacd3771a09bf9a683d2767989a0946f9e879490bf84ee8d64d2c0901eb3d0b8211d31e299861b963abf7ceabeb7fd9732512e0fa7f5c46956e7036045ce45d7bd8bb23666b623738c451bba4ccdbb73b932c2a9d5965e83e8c26acbf13c8d7797269906d3c4f0805aa095fdc284db2599f3c3b5f17ac9c0054f06f06600b31c20d670d6430fff525fc5b00e9ef98cfe42581f5ef6d5afc5501d155624ed00a957eee5c7407c1fbf599d0dd3c5ca39da97aa237220d8bce23a0b2bd2ec93763f0e5bc8f8847f20850152cf10afc8abe4f0e01daebb0d92dbf07b91e9ae7bf496d229c69cf247a7baa8cf572e07ca256821ef97a5e628749478b392786a0de0eb884b03e1842e1ce1728a0d2046e409b3805e99bc607553fafc7bd66ee7c1b5680efe754d126eef5c2bbe0a8dcead1c1c9db5dc2b6a1e70429e261828fbd54b28fdcdb42e3709b5bb5fdf54121506347d3a06dfd11a0e674c6cd16227aa29d7b15200c6048d96e843a15817c217d4911e45ccc8da5605a1871584596fdaf1f613c2610caf695805bd54e3eea0156698152db16629321990f6fc9d62830624f1c08f4f9e9a10fdc8d5eb3e284a3e2c4dd547eb7d2149e06a7cf2745a96f3f0aefadc0a11cf7756c8f80a902a11e27b8c48786f3964c76e910c08194bc7c2a38b6b1693eb7f183e66c96d4b6d4eaf68b68f5a6dafd8554b14d241b1bb19b08d815eae9ff1e3cd61b534576be0ddc599ad846ac762741008a42501a20dcb8f3c60cf5ee6adf5da72f63af6c3fe049f8d89c7a41d7d55b15dc1f3f20e338c9f1ea5e37dfd2d7000939ee5b08e875ba2a82154800d015e7a574489a6f583b59dd2ddd96b0a6e387862802e112c30c93c67fac8e8b07f75286348ed63304969822457796851f1a8309e52fd2e3866c7c0e567ef1135223266261bd59c070191d7abb9cc229388d17374873f06702fc5cdd71627624afc294378d00c91707c4770a489313f74e2d534fcc4ee0d4016d037c101bb82ee19441c2805b651bdb801ae17b2aa26a9c8d54d962fee4d00d5df993884ee40f6c4139ab3416053b308e10bb1aa802e88c1f8ba04e1e3d6deaa7704186b79ba20c7e80ab7788011a75b01c7b9bba80d366bf2486f8ab9be28005f00a7e2d6c576b5fe35e68d3acb4fa7dd4e14999ea5d8b009e40780e7854a2ca6217da56407445045d23f152af4adf317df15d08499aa241df72ea2c0cbdb742ae4120bcfb1a30c018e5428f22388f9dc66db3fc9102b60688712c4a5d48c2d9fcfdcd3cfacc90398d600f017b2d2640613438e036323b2309731aa2acf4c3a15b5c5dfaeb02b0d12cd7aa6894e20efa2eab177074cfeee8a872b8c5ad488067cbb055fc31400378968b457688304a058fa6796d24f97aa29d52379f1354297867f07fd71019172715c3d0168abe684dc9f9c9328918030a6ccafe5eb1765264e3e4389a8a1c9dbdaa5a66ce3097ab42e28bdc71c936c2bb17961e1932e274ae039161d37842b4fafadeeb89fbd72f906834badbe0725bb44f8bc01155f21df6c49bfe608a461251f79b37e5e390a0a5899b90d11dd5501fba17e88b857642d7f1d7ba8964559614027227d0de53828d44dbf7fc228be95bfb578dba19e9358b2ae8120d0655fd34e139a2be45b8a0e903d2301f57dc20d97db9f99c313d1c9c593f8f7ee879e75730a36f4a61cba81ba635049c7c4acb4733fd45102068c67a3e028333ed6be287d1b9bf897c115b666320e7e8e8914bfe0f3d35f8493f15b03f45280c4612dbc623950619957efe522496fd831ead0ddc792edb6d00a9fcc50f6a1c7f9cfa4b16bb0d315998d1d464d1ae969385a5ad270b2fa150169656ef24ec34b0caa0db88114c8ce0caaae142fc2964a858226c1452ecc1e5f4bda38058c6d4c9f801ec9bc4362212381b5aad8e228f8ad7073ecdaa9d331c55f433307fadc1fdb92bc42c1e34323b8147294a6b2927578a3effae53ac8da3968810d87016854377780130e1541c15c1d1eee335abac90423c38de2610982641e6d7e688d316fab6bad83088defc2a416e143cf3f6a088349a1546683c86e6854b6897d118c8238336384ea197311d45d6784b071c9387667758e26e78cedc6653a34bb2af97c3efd86e43ecb389dde64352638c1f740ffbcb1e3493fe736b944be0c97c9289b523fb0a09178bdce39265b1ccf12f31a875d5d079ea9ca31cb13158efc4ee38ece752b220a98559c7403838b1f89a067aafe34e6f4f54c4e8a5499f440c4aca56142f5ddb2db9ec00dae8d1ddc7e5674ae1e9b85fb33d8a228051079a6e2eaea80a88028e017472c0d8600958c0f4d044f2a929bf80069a5e58358ef06ce04749e1b3440ce0b37800bc277010992fd869ae1c0174da01ee9bc96039616d8baae70fcd1148b9cd932022604ed0859323ecf5693e696411ba34b007426768e4bc979bba3ba9c3eb87cb215fa4a2a1a10115258f3d095f79e8804713b9047a76369dbc7b6d7f17e92fc795515185f1c8b92434f5b44742180326f8f4311166f4bf30442507344394cbe5edabf65217f1f6bfeaf8da4c6c9e103b8af30ca73e9c6ab8d66e794a9c404f62e89c2dc40452c7878b97e5c1ad5c60bcb0d38e45374ef5259cb7ebd5bfbcd696846d2251d310bbd08146b686dacfa953f4ec7c5c6a8008b88f4e879d574f09e48cf8ad8c9afe0f5d223b672c311bf84706abe2165c2ea01ac114def0f3050b664733e38fdda26ad71bb3d6ec886451fb6ea694c9e895eb648a9d1281a2a61149312d7f82bac4be4aa7bb9185b6aa496ddf79492564c73fa239047cf3807ee008c9177e4f3673a8f07426b1ccb9ba0c6aa533cfd6da2acf56b5311086ca30d973de86852cb1d9e02532c2c721a097bc253c84b794ae29391b5291233aeecbd86b11f3667306402df3f7811b2603621f315f925eba864a5a0d14fa31de9ebca46a5013a51510232816df194b2ae08db569756b21f05b0c93087178056879bca9d973e53f1c29036a6772765c601619271db53d7b578ccc69441dd23e1fa1c87688f323ba7f099c44eb6ffe00f44e0f78fd415a4d3f41a8a92fff668e30f13665f8076ad027afa60301cc0aa0ad90162bf5a59c9b261bfc2c10f8618d6c23d208d984ec4df6de72ef51073b074007dddddddd2f6de1ec5d1683f3f668882e86f9924118a92912c486668814129f61adf5b64ec12a61eb7892c1a86d755b249cc0ee0462b66a8b9178d348a85a0892cea5dc46580fe951d7c408e8d872e46adef8240d49754904f6ea3288264554af549f2c225797953c42c4484c15e96cb621b96a29245787db1b0018dc2e2343748e36dd0059e174e4aaa55b5aac6a596badb5d65a6badb5966559d65a6badb5d65a6badb5562883615990b51600308b656e9116ca8995bdb0dddddd171bb9014990f4e28dedb677a3b7408bc177662b10eed72d2aa250d5d65aabe5ec61b4cc711e8dd822de48efe6e6c64a1a19046491419040903450b6589aae815b75968c861259023daa22845e056134c2827118661c387618018e1c3870e0c041c466adad52d2481a49432369baa66bbaa66b502e2236d8239b02bb58be62996b74e52eadb576947a4d1764a351d1a3968fbab7a4e9955aab0d65306cb5aa0cd63f4963720359aa5b1845bc8215608aea2d379bacde355db37d5dd37d5df3d1b6dddc2e6c9d77b85fde6783c8731a33830ea365d0e5af8ac871dc3fdc755dd765e851cb479d6d5244a96897fbebbab89b6430b80bbbae962c822b160057e0e851138fc8006922374e42e4105307c9446510ce0e929e4bc4f651af0583dfb778b37934d5e8efba1bd43fbf91a6026531ecfb1f54bb4820edd234a0ec857d7f1d59757777d7403cb1fc0164a9fec1b2073045f50b774d8faa21bd52d58c8edc4857a4fae5eacf4dc085ccd5933490a57ac40159aab3680ec33c22f25457b3bda657aa7f98fd6ca14ef4a12062d3ce79f6af6beaab7f33df78739d2069ba26d2d0080149b106aea8bf8949a75345d9ea26c962d857ef6b1ab077e7585fe36032342f023075c1284800c7e6a12ccd16a4ab89402a55fd7024bf9021103f04c93373a1651aa7df255ee72418fe0a7023c6f1628e1e551d654233a253f55bb1ab3a87674cedd56dd6bf47b62fded4440ba65a6bb7adebfe6f54bdf1e5c276b7b0d91ecdea56e6a2f3ed56e6a2b1c7f3b92ed0332ecb62700ef268c4fcf1bebe762c8b617fa1bcd8ea7188d97a1187d898833dc398177344140cb92f8305b205d109391c82ea5797f76da14e7414f39421890cd01c3c8d8192753ba90a6bed2ffbd9514cc75284a41b44d0a5eab69f190cdb56f70d17defcc6265f8fde8071f0a1fe6a61bbbcaf25471f623e434dddc0deeccafc9d31c6185becec847a44e70db201b127112e6cc166777f5ae0d2156cf0b05ec2f919334b09718ca7c085a2cfc2912b935f2aa44755909b7843836ce1c6c81029275d3da9fcab3f5e4ff85f0592abc72162f7d022680fc4222217fe98bda43c662db64b7a494b1eb31793939357272727b74e6e4f3e5d876541fe4a2c665d7798bd74cfdd53fec19fe89f93e08fe421a9a2422f7ae8267e3b9dec85c43bd98be8d7838570cca24d444264e20332412a711109cfc4af044990e498889fdbe2f37b0e4a6844ca49c7dcc0f1c23dd9cbca3dd9cb0bbf1c76b190087f319ff885db0b2b2f883e7b246fe407b64fa67275298518430064aa5da64dbb5c4444af4e85b40b897bffec0bffe890957f1bb5c9d5ab8f7aaa3d8cb00501885c7d3507d8bf6a835c1d7eb506b9caa25f4922492447f4ce291e0a4ccca1d398591e46cbd2c33c1a3187bceff3138f598b13efe4c989ad271eca8b13efde9d903bdac5c4ab12d79e72d22eddabc7eaaff0abbf8065901e555fc152c808cb1aeeca5a882e1fc2a25f29253e8d995554ae72182dab789fafb8ca62d0ab88ae721591c7a2e507dbee21316142f479c2c461b46cc2c4514eb318f422ef93ff7c66314237e1d188f984f7c98f380bd9c95e364fe662f3647c7e2f63c4718839f40bc2e02f09263f97879e0fae318893ca9bc0d287fcd12bd545d5496049d3a3ea1e9641f4a8ba8ebc55c7f8b85570e3a87e523d05778d1e551f81bbd4a3ea211c8ff4a83a0a8e43f4281ad161eb7ed2e1eef9276fea09b254bf6eb6ee272ce4092eb909ae3d7a54bdc3d5478faa83f0b53e1359dd05cca0c3acc4aba71e55376a2106bd9437ed328d0c01574012921300b6c4184603802b5e802cd5b7ec2c243ce5ea1e1a64c6dcaa6bf8ebaa1cb97ad622210e11a61661abbf00578ce42b59b2556be15091273dbadf937fa36c15914d7e238659f8b3a1254f20874cafc1549f800cecdd65601c9c3d8712485b0149ba81ce9ac305b29d55463b650f1db6eff99f10c38ace0681fd859b755d619b8796c698820b616c5a7dc52e6086de67c6ac53d86a3df568a86f1b6df544d203b37bb6c45c62945145c6009831efdac226a50c59760eece1fcfc14363885cd9bf69657d94b193febcdd78087dc85a25bbb6d5d07e161a628f2fca85d64c48f0e53ff55c07a344caaaaaaaaca83b1afde7b746fb6f9183d8ae2831e4cfd172f5fc321b6597a1cf060ace783a4deb15e811f7dec8454870b2529a210853e5b27800c5732b438c3cf64fb54873564ac368cfc7779f5f2fece393d1bf6b7deba321067e0002c6286189319aa570ce343e5e9306f83521b36a677812b052a90410978c8c10f6466a0b76103c24daec4dbe8bc1c62acd405370b170b1de8c0c5421370d663215934c5d5315cab4b6fddc8234ffa0b5b32d48b32d58b71470d73521c9b7a416270337cc951244201596067ed257321b12b210b7cc73884fba1580145a3d8724a39e573e818774063833ae8004dfefc19956b6ba17f2a504640225d6aabe95ab6511566e44a3d7907c6208bc414339c54167d745d27e188fb085ce188fb075f38e21ec23362ee149c0657b8d7c7209a1467e48c905cb9731f813f0f61983fe78e82423f9d6cc810426ebe6c03b9fedec6959411e513080e5de2ea91562194932bb1108e3f467cf02dc514f528ef8ae4992cfaf838a9e8a3c3bd72529c54f4117f4096fa2a02b9a51843bc014c516f7923bcaf4bf1be2844522f0790a5a27c76354f42a738a2525ee1799912c25f0482e27d94662f24a715ac24c7a45d3c1b668d48e13ea1d8587639acb1cc2798630359ea25ae384e8029ea3950802c5929abd1a4eef593354dd33e354dd3b44b4dd3346dbba6695a27354dd3b44b4dd3346dc4354dd3b4946b9aa669dc354dd3b4cf354dd3b4d0354dd3344dd3344dd3344dd3344deb5c9bd7344dd3344d7472946bda61bb94642fda9569579913dab8ca65338e86796c70ae47bb9b0dcef5681766c3b3619a65d9f06c986647d8c0ac115a4db1815923b48ab3312245e3e8c7c688148d9b211b1af709491b1af709b50dee13eae0e63ea149a3c7334334e5155a6825a724aa742639f3524f6552378b5927577523d619474339d980f44aadd783dd93941bb95ece601fcb496d5a8d198e0d9638d370563ab192a65444875c3f936b26936b2d6520a842aec76a6cdf95699792d7df1df6837160d34e3f49d3ce843e75b48bca4397479a346d8d2d943d7459d3a469531b911cba14d22e9c872e7b3469da1f1b901cba0f5de26812b5a6d0e58d76f13c44ad9190c9436f9a26511b64abc9a1ed216a79e4548f1f39843df42e75bd8d093d1e699793871e8734a9b2365b911c7aac6997eaa1471f4daa2c2af450158a3b78e4d063e83734a95a38c456caa137a049d50ad942b7a15d501efa02da6586f54e05aaa50b6d9f1c0a7dd4a48a12b5cb8c0ff7d067936ae87ae829d94b68ca485256922b95c4c45306254957460625839241e5fa9992a45b9aa999baa5992a49d2954a9552a5544946922e144a062583924149d22523839241c9a0723d4d49d2552ad1144dd1544992ac54aa942aa54a329264a150322819940c4a922c1919144a0695ebab94ad5256a94a9524c9a652a554a95a144a0625932b4a92acb5db26535392644bb3d475db96caffecb7bdbea3a265254424bcccc35e567ac8db32cebdcacd6ee86a9cec5ec52b712e96ca38a99b4ae5facc735119077551a85c8f995c97ccf55c322697cc665da5ebb94a2657e92ae5fa0bb329932d85a542271565b2a130540895eb6d55c9c8c8d4d748ad92dcaca79572adaf1a736c36b0cdfcc91b9bb25b0a57437a488f6a678b3a4155a846591dda1d44464646e6c3cd9a75fe6098adce2827d565a324c58ec96bdf644f87dbb04b53ae4fc1f523eaef078b998b92245d19b9521ff23e6b4b797a40a4c7b1e951fd95b15aa9e3a47a548f6960b33daab7d42e356e29d7672569edb6c90e05cb7a79a45d3e7b823b4b238db15c6b901fed02a45d3ac738db6f87857e3bacaae451aaaa3b4191a110ca090aca2f4a25e589a4bf2858e3f9d8a3886104922b0a3ec13368f6d1a35af9f87153b0d92e6dd299b2630ae5f44d707d876be4fa921bb99e04d78386449b5cdff51fdc75f0c7c7c436ced4471f3e6c7dd461936f4e2ad7eccae47a1258cc1a739600596a0ab2d47352138aaa2763cb40cca1237198c195da97c3295b87d9fe307d98791f8a2c23fb88bbfe59e7388ee3380fa67a7bc74a1984c92c9b595eb51e4c3fbbbd8533fc59af67212dead54849aaec6573009c81e4db3924bfdb065934098761fa9fc7e33effbcd4403d0ed05f208719e86f858945e4ec9d6b27f976ed97243b8824037987e97fdce9610dd4a3d4b371ffe15e3ad937fc95c832c38090e5efe5c598cc404fd9560c53793e504f077a1b10902b927aed15b17d100292642320495b0789d80c74cd5c70a1e86b61c9f028e08aeaf6defa9dbf167ff13af68bed1bcf53eb4189e119f4c3bcef97b5f7ca5f4cdf12cbf39a41a5a5bf3037507ada8283132402c44221db10152db0a505ee20c318a094945e0ec3c8711cc771d77a638bbbaecf256e9bcafa657dbd84af8980bc0fc330b8653494c8d9411c77db15748bbb6e8f9d93d5be3907752a355d03fad0c8cb98248e4fd2a868acc6e3ee6dde7589d84c6e6bba663bcd54f193d790d7437aa546aede1e4adbd813cffb7cb4c36859fb154120d039208ee3b8abe0388ee3388ee3380ef4930c0688cb388ef3d1b29770d7755dd7755dd7755dd7755d308bb11d0505e5a6807e53b08aaddb2b056b6c03f2be26922bee15f712726561e760ae7eafaac41561160632c3aa5e491db93a6a078f1eb20430457502538e5cddb6481cb98af9a8eb9a2c6c34dedcc85cb5e7032957aa3fc2ea557b5f35f52c64681792d71872bd0160adb556157045e7b5567bd9cad57a7d3193489ad86d9d3f49d3dddddd01f1e6a50b5b8c4147bb602d03c3e5e295bdf0603183c19df3600cb2d00cae50144094c8f43ea4e7f697bb6706e7f576d64f6b45b9c230374c6ccfbdfa7551cfddde7ad16f9eed6355cfaf4c8639870c8352166508c40b6ee43babadb073f8de7eb857b556f67adf3df6ce62787e6fafe5601c66e63c520192e44c11206ea0da860f22323d6121d35bd90bcf84d172865fa6071369c43cbdcfd4237a1ca27df976e4ec65522feaa0d93c87edec91d4228d0c365448b7451ad213e866a110600f0c00493d6af9a87bd72b14766f95f478d3fb4e5c75b334250fd0434c8a008100790083a845f4e3f92743a61e222c96b99039c3e48c9c913396853916ce2c8c59f85af8b2b065616be16ae1cab22c1b2c7b0340ab83ad079d102e44865c86b5731d6e5ad6e27a300fae3c5ee5792539873f98c4037303f7c954e26ab9cf31b802621d8e25b4075cd199ce7ffe79287b31fff91d81c50cc6fce73023c120fcc132b4e31033ca0b51b66e1dbb2dd14f1cf3b46b3abdcf06114ae642e6aefbe18913d154994ee4eadf89f9cd5b9becf13e51b64194b7dcc15a8e530764b1d772077386e0e40ece8464b983b113963bf8ca1b3777f045e4ca1d6c01b17207db96b1b983eb919a3bb8aae960daa383a7ed60690364b167d10b909b27822cb683638ed3829025c310b25cf8cb0c90fb91084d8c218329fab41b6d926a34995a2a58579f9ec01350994292a3641b27db669cfc368c23a8f70f1629f10f1251f9076d3e140818a9906185e81f44fd1f0482ff411aea62e2dfe7843549d9810c31057de88af076159c1d6b278163be30843bc79938d32e5d3cc115b04b35f043f5623a6cb06227385e159cbd04c6e48bbc55d9aae456c9af46025f14f2ac8be62fc92dc1527e4bb0100d9b45f70415673ace7c30e4afe1f6394a4643899c729961640f5142123a43868836255e7269026f0a267908bf9498747033f9851be7017d380fc9597487b010c9630a4adf88363527f2c37d8420a995f374ea27052381650ee1988265be136b1cb10645ba41ca928e33a25049e7dd705d48787146863ce943def3be880222d39212cf2b31b9278b619590c0138544280ee1b058136bbe58136b6a6a9aa669e89b66947a4d1764a381288b7d2a3a998b92ac6b6c84a027f1aff359d64537c95f34e1c376c11e5c29392df9bd9293f0be582a79c813795f1441a625259d5772182d9778efded14a4497042bb9756995dcd451214240a69759ace95108c37cc3cd9026b1902b74246bfc48d746302c66fb565e72ab46d25b13efb39bc8fbb6ee7a5ff758d342e6ed222cf335c14e70cc5e09151f99febee4762653da3cc014f424701cd23d64fad117bf58438f216439f131314a398d4e8029e8298d50c834d678606686f612e0cc264768136ab4c0806d47b6145cd1fdeb25e44dcb5e589735edd29da6b6ec855552f28804216a861829128f74a96b449b7b2c0593dc0406fd04feaccc1cc2314b114602cfce62ac5cfe76d662f495c3ccc5ca4b94b84844e25d482452f946e25a16035f142ae1a1bc187de52bf8238c6bc0b0070a70015c4163cb2c8031ccc015dba9765ad1ff108d50705cbcb050000aa25010d5a2e4d735c18eb563ccf90af67c84b99fc09f9bc0a08bf066abd3d3cb10b7cd6e1b9521d393685142e557e5d1f34222cff38e6f43358bf17bde276ff2a2e2a1bcf05ee2253c0f471f187f310691479c8930883f441e31489c9989d704bf84c49c9d37e7bccaab2c8645c2fb648c7f7a3462f63c92ec0597642eb027a3e4d765988470cc57057ffee394abd014af87744dbb989cbe95900448df43e00a92537a234b99a2909462f437d432c210e58cf0ba338a4909c907733064790da762c8f2068029e4fcac4f89b88016f03032fffc00a088135738a297f8c2117d48832828d64d298adc734e095be48ca4d7ebeb75ddc2b647f3c26f7a2dbda0f51a7f61eb73be5614093fd4c89bc462470ceb515b59c3842b3adb203b36132e147dfd42fd741fcdd23e368e3962094715ae58fbaab2d68eacb5a9cd4341a7cc2460449b69f4587434e1c05a90a52e555deafa6e8ab12cf4efacb56bb5554584cbf99ddb27fbe773da3d23c9483e399c32077f304856d2e1129c1d66502943c842e27d9947af51ed5f0ea716277dce077f945e9607f3f17cd0e1ba0d2b57e4e5dd2236f93ecc9ae7f29b24752e2f0f218aafcfb1723b5d7adff53c1faecbcbcb000c6283b97d26c7c69d8fbf1a94a40b607afdf9f6201440add77708572a842b5f0536eb36e4e76df4ed6f010af05d207f9000f516432880ea1e8402a89fc162384365f105ecadf743f5394251e23d92b7b1f50a3c6c782957e6b43db850d45563f6b4851e764b0f066c66838979bea55d602cfa0f0a01d27c4231e8124fbf5515d699c5681a2a1684d1d769812bf49f652786b905bb446cf204802ef3f424e8d2a79f55f612adea4557301f4cd12ca0b828345dc45a5d6cab0a570b5bec7a35dff5b2dd17d75a5531aabdb6ca1649858e1d3b768c74f41247f42c3a0eb1cdc3206e18e5d992a78a3c218d8d296ab8419262d705f9bbcea317b3bf7126f2c88eab2893f1a8de57613df4b0841e7a58420f4be8a1871d76c048b0030f3cf0c0030f3cf0c0030f3cf0c0c30e3bec9023478e1c3972e4c89123478e1c3becb0c30e3b943afbeeec72fe41203457d5a094526a14c30ccb98bfc230acbf617943e290397a5445100298a23ae7ee98c1ee8e194c870ae2fb2c1aeb1cbb7de775e5263dc74cde2693c9c4f91ca55e233f1993c5a868d983c70e1d316dba27ce74f2984e98e9c4319de009be2926e6c68f989898989818d3e9b4e3c4e3d4e3542f87e3228661f760a3d46bba209006a2f2bd8abe3137e6c6dc981b73efbdf7621eec76eef57038dc7997c5f0fc72b8f8792814e260f9f9ab82597cddbb2ccb9e636dbf2a58e3eb17ee736ccfe4aa55a0e3da8ebd75c8e0ad8a3326f7ea643af5f091655996657dd57abb6c01b0448d9b520b0153341272c51992abdfac85e4ea8dfd4d73d34dbf091bc129c6743ac5dc8831993e608a0171a02ccbb2cd6432994c1bc8946559b66d2693c964328150ae298bd9325366ca4c5bcc47765e92c5f0bc3d1a22ac71cb982b6fc01cbfa67befebadb06630aead7d8209c46caf8da7d309aa2e0109283365a6cc94993e3a4c3137374384c820b21889bac176a349b1b4fd933988913f667ac8f028ed28e928e5287db01a213d7c08a9393596d9ffffd5b2d65a6b2fcb5a6badb5f7d6a264302c3badbd3cf7ca5e6ecac55d92644ccc631ef398c7bc648ad1a146e9c4a45423e6c4643a9d648e5c5d56f6727971939783d5e01c2b959810632ac5c494e032994ca6ebe278ea759d4ea7d369a2c0e0561dc503b2991d356276cc947aa0c0340c2f2e95b0ca01c8523d6a00a6a8feee5bc932995aa64d9cd71a4d3218b6de5aaddb1c0e873359b00cd34b7c5dc392c6744f6fadb53131313112878c91a15d14d02ed7897669bd44de0b3a48ca8be5bd87d1f23dbd1e3feabe7576bbaeebd8258390a1472d1f75dfbaecf27a4906e3929b9418a594524a29a594524a29c59d7f2411dba7c593c4d725299e467f579d7e79639243d87f520b466e3e5cf6a2dafe642feafb1f485abb6d5d37b2f1743ac5d306b598522cc918ad5dacc5581638bf58f6c2f138b6479d7d3e9fcfe76332994c2653e75f9b7a5ccf4e2726c4984e31312530994c26d3e565a00df46dbbdb41076d9ed227ab214890204182c8cc05f7925f9971b20bc210b2dc02dc883de0625e455d80fe79cd5c7c348d83bd73b12c8687e37d57f3505e7c0e3ae8e3c9e0bc1a6e076f426cde034a9905b205d10979f51a8204091224009826db44c366ec97a4d6d1407ea07aa8e0b1e3d8bd8f727684250a600123c104e41190fb52a6a4a424204fcec6e1a85004e46e04e42ea2001ba455b476fc80caf0db0f3e327c08c24f08a3fb9be1caf19e1c4f72ec15314216495a910690f2f375040199c1b06a780004a66559f39ad6e5a1e891e5c11e35a0a228e66c989aa9be94d6abea4dd86ea5dcaafa6feb645b355675f7dbf25034a047b2cab0c7215a0b575c9fb730191b76893fccb35e59b7d6ab340737c608e7fb744e5ae78cc1116e32ccb094b51b4f7f2f8b626ceb11ac6f6c1fa78cbe842b66cc1ed17f62d9d3b63725fea0978315650d186184304219b33fe79cf331460e1c0092a2e501843e929061cc810a1960637026f2e811b5f910156da2a9692367382b7f7246f298a92fda64da39fd4cd9066222d23de8db3ae68315c41069620a6a92332f38c186304e4e9b7cc8d3a86968aafbd736b99d704172469e648f1e51ee933372067fb2c775394e662dae6ba6c7c57246ce707206669349a248d98ce28d58e3889122cf6890f9cb8075b8597aa23d3e24a922239bce8e467fb7590c041bb56931d5aea44d9002d827802ea04f1cd434031c30f0217b3c37b20704e264c54992cf7feef9ed30ccd407fd31ffd1538bcef399ca009250e6e945234efe81be0c63d6244928de0928fb6c9f6ccfc033a3f32a5fc94a96549fb8bab2aaeec1f7b53b872b5975f7922fb8c1b020c05022c311209bc11618e0c8293204e205a87c218c4dc334ed5e256cf3d4e344b1219d105a0242b750d3a3a862b00f6c16b3279a4a9d52a7d429754a9d46a9d77441522aeca9c53eb07df4447bb40b47ff4d1acc1e3da2d464ed101b5c918d24bd8534923453f42457e8bb2e95b276db3a8f37e9b4f778a4e5e3c7c9f2f1e33a9d7a447fd0ac8594f2f4439e4e99d2d3e9d483a66a658fd4b816465394082d72698a16c9f4d683adb5b216d6a7853feed62b9ca2453e9a12659ab23c9aea11e5fed1944d8ad25bb4446f638b6c921e992749923c7a85be87fdb101e9664e49b7dbd675ff6882207373ce7320e0386e72af321873da39b96892326edd479f25913d1387bc30b69ce911c521493465edb6753425496d822bb44d6db2c147478fe84d2c0259e83cb5e9519f20f3786e3dd656ebba6cb516b589194dcdf09094fed2a08b766a1353d09ff854320d4241903d56d3eed13c1e5b2dcb633d757218655e0fa579a278fec5dca23d8f45e68954173067bf70b33da26d6a1d8d821f40c800f503a5a696e91db54d3bbcaf56cfa9750ed75bd3d33b2a539b7a440f57702a0c4b43fdf4b0f96b4d2bf36062f6d48fbb35c11525802b3ca7dce7af87c3f39e798fe7d1643156010cf4777aeee1eeb9cc5e380ff7fa8af3541606c802139ef1a8846c99c97a16aa990100000000531500003814080604a3d1781447c2a8dd0114800c7a924a785ca149a42807421074c610628001000010000000080c6d020033f0be6cec7e8d5e593e3e6de333a017d089ff4eaf7c8abfbdf11328de37f5d5e801a197e93abe34816e7ac547f8aafc5d017ab71b1edd8d8e1b6b7593a75bd1f1b12e6e38f4686eb8552fcdc667c9de15d4b3bae1d2dde8b8b1b69b1cba051d17ebe686a747eb86617b01b297357b7920f1096348001ae61ad016230e08760965687a4aa6bb3ac42bfc7ba9a10670d993891b0e715f216fbcb74d1d3227eca63e5dc14779addc8e79a310d40d0e7c420844e97068272340b2830657c8d6ed3b5082e08b600022d093e0fb430e6164e590dfa5c4dfebd74693afcdea981009cbe083e2e6d7401e42398b65696328767478acfa7adcb63e6ea41722a5937bad2f9084e3003a66256c08efd591f1e0eccc80729d3f4bf1b7f9bd8c47851d404cc96b80ba26e56295bc4e2a3f28f5ad091bed06223607294b8a5098d9ab0c9fc051b7051318cc9a0c2cd9660ea2b98568839b08a0429e2b224a91654db3e8fdca3f961e204f668360514da3fad6e0f3d2fd88acffc679a87b5d6d369638cb06c4368338f4ca3f0ad39c671c565fc7fc527adfb310386368d0179710f62f1377ed07749767dd41f73f80084249816749dc5b43ac915796749f08f9558e46365854c639930b9a2c3ddc37e76420239447531685ca00e2767c25797d5e855bad4dfc471d2a8ba68a3d0097194b225f3738f52abac7ed47d800cfcd89e562d57c66d53b2958d6692a43d88005d71d4c1e6da775c7163807fd174e7b0b92f5fc2f5ecd3d266cc8aa5124b040e7f108563f668e91df3575e1ff2461d8050a4780c2a088a8bd8d89982e7488fe077c130cf50f12e3521df8ca674214b94ea1cc4d5cb245cb33ac2d1209e73270d241b161d444cfe3586c8c1ba07f5059015ecbe95da2d54f73a6d85027f00d6fe2952c186c2b0144884483d3e0794527827f809287d0855e25b15b0cd4bc5ba930706d7ccd11d20a67d54e6bf61550fa92f954203c123bd2ab51570cd1125713f8c0ea3926d272eb42e06ea53db262436ac0b751c62c1f050065c180310e606758f967a75be41a655f3ae128808aefbdd1d102bf95d9419d42b89efcadd3f392b554eaa1f4146cf81f3e32a82078e3537190e451c7f4a72127b8808496000285fcb260fbc97eb20d06b5f55e845cbb8da7b8fbf235b59f16b7c93d4ae8421bf9e9e71f8b6ac0f72e0bd2dcd8aa2afaa1180043340309be26d0d4850f3b21cff8b92e209f00567dc4d94a3f349b966ed60539c23e3997ee18a8273264b25c0a241732d5dcb5a20a04e66a2c5331723497aedcac7a70e1d8de1f51c9fa7ce2c931830cd52c33343109e642b0b20031087eb5f2a2e57061da2b4dbb08c24d9fe84fad651af23e68dac588c4d7159d9752b4622dbeab96d762a9104d270d060ccf58a82506a8dfd976eeae25647eb44179e1aa414067b0824203df9290a8cae0f7617b10c5ecc985dc50583631084557fab6a599a1bb4f7383841526ae3735befe2606c7341a6f8b704eb13407243b52a38fc4e1e62cc47246d0307863fe5f86ae4bb5df2f76f89a339bc6c929695ab3f0d524b299e7ff2a16ff8f4f7efc162e157caa6cc4156ab41422661aea118f4cb7590f98d0ca7605acd26632e63531c846f68ecac60ca526a208a5efab4f6ba060f9516521ca2afe1bbfd65d94cf740e65286046d3f5919a6a97cbed9499b7fe055a08799918e05053acb1872a55e36ef785f690b63e30291e24022ee1ec025a87501085968901183b30dbeb039bd1654c7264212219cd9e32a06f0e7dcc741895971e6a47344c2881064b931742d5ba2c2c317ce2404846830c2f341540d16c833960be7836d4008287834c79c54c84f4290dc860797c9243bb0d80ed143c2009aa57d08453e186e466b0a3ec13718b757a7922f762cdb580794c3599f1c5101878069b474689f953ec9efdd3cb6ebe1eb470a53a913a5cfc2b29ae9919756e28858bae29f1c89c04339042fb54717ccab52d43015f19b62092b450289b824cc28f718fad0c79de08da0f713c50563ecd76684c65c0204e39e41b35fb3b0f1ddb17207d920481adb9bd10c1ed7c83e897755bcec04aace44bea07921cbb2040f8075fd45417477474a4624a5c552cbd46045be0a5a1fe469ed6c45fa897ec82363b4621129d760367afdd6312b5888dd5db7cc2eb36c49485e2cdbb5c7f8365545a66f0d7eebef34b73a6bf8986904dae8c893dba59eee019657640032c2af6e470b5cd29f47db08fe1f9a368db2b0d86bd292609df0af6e7aaf2b799444e6b0d0c0823f9ba46d7795a18110a507c0e081a9aa4e0b5ceb3a272f9dd2f52cee2153f7836133a7ccc5d65618991a143217ea16b2df1dd4112746a66f6a5e6809d8a48f3152edce755c0fea4fb6ad5c3387c3d9abb1f4bd253f0e36b70e511c64ddeacc4a1504393861c3ccf031189afff7a6d88505100f03c54dee6be8d7496f8525567dbacf076e31fe275b446d45f8ae097aca2247c8625ce3fb41ed5b33c0250279d7a3e9ca6eb8ed3b74330082b10ba3b5c3810bb61fe638a52d980bb49a4740d503bd082f62f982691511c69b703faa3b3db8b3bf517f0b569cb6de9153904b15720305c32bbf20b5f46c18b08cdb4d2cf87104e75a964834aea32087414a306cf7099bae65466b173ab9932049dc04866a3fd78b296dbe6773a07a7ec948e57d021c38e016901a6155d091fafd0a3fc0d541025188eff750931d82dbc4721a1dc98355ad14354bcfec2357d44899658b1939c99684f9f76a1a0d9917e00b8dd22a1b74bf995015d4497c08c7e97c0ee6ba4683b8a6a4cf047e48a65056237aa2bb173f41fc521a48252a4d583a6e0f388ca7b1487fca2a54ff04b58e65840ae2bccf0502ad5795b9d4910d5a54144bb2cba500096bfa3b9fce905e5ed4214675e9f1c89ae2e289d16373f5a344873a564dbdf04f6c7b650b0bfb62c165a77449a6b4ce36bcc19c4a923bc92d5da8fc9cf004874ace3b8b4e7c700c2b575d70db2aa3fe7f309207522e116bf08b55b816cde23e0a23041d64ef4f7d68f3a2bf0945acd868a1c1b637e2b12a7785d731d01a2ae884a1393011120b2701029ebdb20780284d51328393d71364c43836a6c732be7b42d3a2dcbd616befd06a92840a8daafddff0508612d38faf1c09ed30f2e38b54230f360236e2ba9c019f599525cd53b82c50d1e1bb045d0181c02287104c431cef315d9bb3656f3e855863d1ce2db9ed1f1ef306b1881314afe83621ef532da884e5e1330e210e530a926df6e4928c27f377ce2ac71140be6b10ac1545cc932884aa581c665780df3a150df314ca07cf5d2ddaf9d6649d56a0330449222b2827ea85610beb2878da6dd7fe747d8a5164bebb8b8261db75522c61ee52f5d07fc08e36f73c2867976eee54a0ce306c4e6f04819a4f0f873fc1fee9d35df94decfebedf164f5827ddafe66af5e6cf2bbdda946a6ab32e01654e98bf55b99f2422ba067c998572d257e6522fc98c2e16b8cd17bd1584aa619fef82dc62d0ef8cdd9e4c84f090cd4e9bca6c891d2ae606e0d18d739b0863480ec22edbc7b3399fc544a4723326db855b261f2638ad5b7edf62290367768155f1b684b4c5a472b0019ef8e7ab783d9792c4341fc7604d1117d82124f77b2447ab4cb16688685c045a3118c523f995e0a1eb934600b9f6683a7bf1677e473d9e56e97b2c3682262cd3f8c915a47505c4f080c6c33ac8d12ce5393f6750a4576beab25ade2b1335481f58c06d2806eda4cac078dd054fd6595178ca4b3e9ecffd185fd6b9cc573b9dd2f5fbae34ce5a9af44fcbebd55fcdbfdad680c78caeac8a4604a213d14dc57e97a30c1b233397bc465099152bab8f26b12a62efdc4e911e4e3256c6a1f4e4bc6a98eb3993c85e2778febc5aec3d3da04452bafc81633850c99d8e0b819ec140cf90f51b8160869007a5a0791885e8694c455c4c98ee57614cb12a1aa04a2dbdc23182ab29eb139a33fabd60bdcac068785a9c9078d42ce495d06b4332e98982af9179300691cdc4413d311f240a4849a6fd52b16e486ac402a48305711c0d3d3ba8a8ec6095ab3b8c1084ae3eae948b2512988035d1a26d9e04b9c2c96267257e891abf5b9e54035acaca7b91250df5a0447ada4c57826f808b7ed8fa0cb1886da952cd1e4420ce279355db0560f712b29bc9378c82f4de1e4370d1b82f5aa5b6c3f3879ab36fe33554bc38ab22bc32a129e8720ead7f107a08a072a4d676635d862a014a5fcd1f2008828b34de8814b910050df757803f6247f010281e798328d8d30c00f5ed634abe3f24e82fe153eb6fa16bd9e2cf842d58704780bfed16018a883f10af589dcb290eb8e84f90af608c9e04a278ca43440efa0c7c73c33c6de6e2f30826e6d3adab4e49ac14fe988202fd410c6c0bceba0bf0da97a68468ac773da1af195c56aebde6ee4782cb6667dd297bb4fef19f138fc9c21dc8f826bd02133d70f908e3f98c7c3d48e2ea5a7fb7d50be27bee36549b3c33bca52a1ffa272949f95ae3cf6f5e9d5048c070a086c60690f086df5ab35211d81372676d306ad0ed4b1790bf04ae06f797207bb372bf8365775e244e67d142846f72db85bc1736584cd37747887ae7ac4864af60101dd81e3f211d56b101db365aecb9b16eaeba6eec906068dc732f2d6b979e9efe9a94a6bab9fe4b2d0b5d882c8cb882b276d226cc5a8cbd0c97d7d3d3abe70acf2b26e038db66f17643b0bd78e287b8df40521bdffbf1cf5e41067a858a39b6c3c5168da91168714c2bc94f62bd469699703711d968340ac4089807223299127115e74b8adb9e201a649469edb60fb9ee59201d2f509f84b2c04c0118083b6c577788e22229f748dec885bbf87584f78bc040561e00299f48a8c6b5e45976a9bb46bb3f6a2cdb94d329c2b5691c80455509e5814e8c13ff98ec36207f7d174271a2afec2e17675a1fc9dda0a56411cc8bc0929576e33e948b123bf9ea48afbf1eb33b595ed2fe959414a8bc1b26bb6a7b9810ddf60d97a034a95d13bdfbe0f864af5d0f04778cbbd1654ee34e4042684c562d925e56071608e33a77b7e203eb6900ea59c48b4ed88abd8e7c8b9a5afaf0dfc3ef6b1bf2a0ad7f76fe7a9418bb0b8e7d1286bc034328a245f47d0938d0f4aa025e9c9cc8406eb4e343b216d7ed7575a4271b123800ed2e67a1c08f74bac87736c0f2fe849a5c995a7fc6cc9d5220ec1a45504d80d81795a3870f083ea0daf51622b0293547265430665fd9e42c7a2ba115a7a858ffda26851f6f0050da7c8708f881575f1adaf7d08c835ef6a5b3562cb36d2680ae6a1721bd276548fe662d065858661786571801d1845b7882758cee4c6836d05eab3531891d00c9ecaf29aad0e543ee7ad34f80b0fc5e47029cd79e9788622fd9e1423735be1f011b49ff25fda355b314b455249259d3a12607db5b884ad79c15f91f5abfca66710f7556ecffa2cbcb7f70a9f792d5f9900cd66c7faf8776de8a017a275951a6bd05ae997b9605869c01afcd56d6e4e096e735ab5004b1225a1a739e610b2b3b2ca438e83fc1863e33fcca2c5e59398d17acf7d6a6f7ad8da0a0dc66f9b619c038616c28bf80b8603dfe05feff90e30293f96f3f6f6b40fef5df1dd93e25483ceb44fddddd553cd74d5f2604f0063fffdf992ad1a408c7d6febaad60f82ca650d6ff880506d0b0f178cb615fe25d6b168a39007b6953a68b52cdf45acdfb6ba0ef93e95897c643fbb3306fbdf56aa9f0a53e23123b8af56324ba2cd4407d6059ebd579ebf17c151183d57b7de57898ab81fd448776168b9e485528fa7319659a2e3e2f57ec507ae8605a1c85ac0d994f54d6e820856f5ded0c56fcf04b922ee4fdcb88aaaf364e574a278460b225327805f94ba17903698938846a5315be3b49359a004c0b151592d1cae564cc597e2e82e21a12a05da0def32cfaa624fe104759eae514f9e75a00ff5aad4ed1128eff6401013b119d72bfa700690575e5a327ad149b3b442ace4d30680e7b1fc2b29d3228a0146866bfe46d77677d2bbfca65748ae07b0e87fc382ef7f5b82130d1177e3a1cde1448a92d4103c3508347779fb2db36b9a4a16567327b6d8ac3fbafb166803b5926b0f040b71d2054965782254453c078480c0ad050f8e84e131b361c88ae5684b0c3a508cf097b05285641e57240b2ed0527be5eaf501935602e14aa60724d840e45b974549b7945ad8c1f017a8a2e160aa4651c41dc98ae13f1255cc52397ed4f606ac5fb5f4fdd8cec8b4900cbc092973a8e789154cdbbd9a01239ac8791ef6fcf8ed4ec44a94c686e6347911389db3417610bc1a00390ca30595b5adcce1a7d429a4a7a4164b1094d29c5a194266e3ef577887ea4a4193b100238128abd3e5d85276c24af466b52d954346d7e130013f4786bfe652d00bc0f75b53017892dd7f64a160d03ef28d8d58fe10f76f83b70fc4018e1fc5e84f3bbfd57fa803c04b334582f9ffcdd424a63885acb839086f64267d793e5746b0ea4fc538d11eff0daf8eb67db716c9c243d31b805555ee3ae3701b7e562726dc2b8f53bd8ae71d727e4e3a12f4b1ae0e85d66c172ec7d288ddc6444a02a1912c7f8f48f55958977f77fd2705edbf8a11c68f19d7f2a44bb94041a837092c30c9271b3f84f38dea81b5af45a32f0899bf1e0bd8b57121aad3cb656cd6f4ff8b65c82a35333e03fe77b1ca722d84db082eb845c327094700b2c4b4ddc6d7bc3d8eabc0918ba4c2762b9e108ae24363b76b55d02526472e683e5993a895ee637479df601ebb4c5f0bcf6ce2bbeedb81803123f9005958ab67f3b3ecb5d38202dbc4851eb92a5cdff4b4f1ed314962d4fd74d953b14ab0d3b22d7a153a005d1e9bc7729c90e251012020bdfc33536230c18e7a3eaeb727b61c562a466180551b2bad6be3eb5e29e06f3d66b9eacc2e28ab8d535319456d0ffe4ce5e82e8718d7496900d88826ad4f4c7b879ac5a0445f4917cb97fc396ca6aef355bf834945945af9d9b83cee0182672b467678213537d820fae768f0f24976f2235b100f1b52dc6ab73d60f665aac7c924395f4b177066ad4dc907a92a327ca1ee3a77bef86e68b88eb662b4617e0cc024a5435cbe689dec5204d1bfd030566f7ff903aa50cd4c649004c0b4820d964d594994d79f693f297362be7ab712c1e72576d2103d0440e808eb3e1fec8e62a427d5fb91216992447df6b6e29d230b57f897b5e86c24fb7a86f059a1a1a964d043446246f55585788e12b9ce90e94eff00a9333e52f4e83a2e7fc0aafe8dba203125bd456e48b796a4f9ab40f5679ae3884a512d1f94945a2e6a40151230abb2342d62cdc90b019c89b425a5d7c31218498e7cc97c46259e01635e5d04f7bdd248492b59bca7256bc9c0e2118e5f9ab521d636d569042097eef06b001d21117b3615313338f6ece3ec4b98f5f25d77fc9eff9dd12e078dee53d201708d092f1e5fb32e24f45856cc7a93475e3e54ad5c053a01fd326a3c18972dd7133537349105bb24652355b378e851a13a25d98b9a0251e377d6be5622569a3cb0fae855175d28951c72d5928cd1aa56dd80e9e83dc7500b6c424d2674522696881267f7253a3341408acb6515a1146bb30f4c86f16552464af0416b7f029515af4318877a0c081a5db43f5d5b408bae263d36857ca5ef1b6ef8a81847bd52ede651a232c19f630f39074d88897e4146698126e054144507a05286ce569b476dbca8d9fa9b62cb55301acdf46a31422f6fee3f77f0360063e84a8ce1549ae17024f419308977234444404380934d6edd7df6dc7ab25f7988a91d88de4c9d787f0f73a149dcf9422dde6823e2548d9ece5ac591eab29f5876299eb382cb3b0c4fbb3093246ab3bcb78c381a55c09d64fccbd37b7ef157c8a5ed44fc4e1de1c7511e84869ffc92b322838844757c7058bedb401b957bfeac8cc8c3d61e4daaaf8ad5b2f6257bec42bcb17340808600732c2972949642b407a926ece431d3c0ac3a916f534a54e03805d3420eb90e4dd242bec3408a84460215cd27249c76e4214203d1accec66762ba5e01d34f9d18c5fa0c6848b4fcb4112ba1fee436d53777376046fed9696fd8c6a513faecb49f1611dd1810d390e293df6dc7f3c6780818f9b9716e9ed1d9f50dcb5143cf41d327942a549fc4125680ce341062124b643d65fefeaf6b634fa9cc88d650cfac4c51d90e436799a1dbe48e78e3f1a0ce23d5450d2918e86919991649ca198e047347fa7e8aa3e2cfb611731450633fcd50b3acce0c242560c8c3cf16aec704f3f51486e54522a0ea05bc6583c1939f701c4bf7a4682a941210dc45d4efd3ca7c16dcd1fcb813d2f7e6b822a01a32d717b49ddf1f7d48c8bae865b51f7c5182cf907f8a8609edac45160d6f470664aa6729eeba0705ba60c3c41afdae4f43f3724f4370cfa96404830a22510208ce86981b529eb8ea34c4c6cbe37a8037aa3ea41ebebc0d90fcd71a10e08799ac01e2f827a28fddc140b4f19bb89d9c1862f32bd5481966e6c7a1df482b323164a49ad852f4a8a6b75436aba928d9f7542b0e8caa949f4ed5494b551589a6ae4ae4515975d2525b45a2a9ae3ad97ffc2afdd28fc87c765868cc8d858151f76a533b6b262d28b8d344d45b5d548d97f5f4329ac0b26e68def560b471f4b52187e433174a3802866f686cc8bb7ccbdca7ce329905968815c0850f007fc15a1b9fa78a5ee696023f128b637b6a278738cdab79de66fde0c3c0a6259fa5a2ae173c9dc9a4a89b3b656e22e600337d698ee372ed1296495883b3ab0f38d41585aea59301fd5433010346cfdcd69f6cf28d380b6b34db1d3df3e22be303742f100353d56f7cebd4771766e8b30c04f75655f739890310fc116e938b47f5871d326587600762c5f169f7c0c2c82184afd3bf43ed3ba22caca3af654cd31be1f11741a77232ca51e89ecd9fa0708ba084c01d091856977eb8c70104c56ae522fd082420b2ac0d16aa402034a68458b968abf8f60dfe2adfd5da791c1de7bd9f6665b53fbd1f8ce25c8a915b9c1c66bd8fd90ff52ad4402638a73dbd51b72006c295e3ded84d365bf7599be55b382fcb7c6f30fa4547de3bead78dc07020782866e6464e20e9a85b7c2f907cbc642a4ab431f69923bcea1d060eacc8a9c8089df8009186d5de07351c3eebe85813d0e04500ba1cf8b75f50beb858f4be567dce60072247996162fc4febe3083edc226b28c49bbbe53ecaa80260e83d5b3daecaf9679770d12992c0d3965db1aa9b2a5fa100c1d122fbd1be570d51824ae80c9be8ec0e1c967d1b84fdbefe2e2e213bfbc239fdda31c69ca597839c6a749660e584abee80762b91427dfe6d352a17deba37d16c882161b3fff27c6d3ede2cbb8fd7bea77b7d3bd7091988b7d2aa306ea51de0e59707230dfc9014d8df9d801361c0f875d1e82653a3ccb758679a7e4b8459775b100398262a329dadbb2333d89cfdfafd1ce51c7cf82ce2a3e402434fc41cf2430dc74ce4a3aa21c2d570a04283e897325c6aad6d5ce43aa7ea3700139ec22eaaf396eee37d3a0badf1ed18a020a018f9932dc6b787c3c9d247e6f81ee768ff4c98ecc9053e8224b1179f166871c404dc89702756f9836bf35251dbc7480264241517f41b744cef0fc7be9bf7c11ce782579ff344c4b148080118bfab156055d83e427b460d70bd2987c4b8d29e8efd8559494a6e02e0a0f30808fb0d8d9008ee406d656e6e9edcea5e67fb5fca831e0e0ff52cad946e842aa4a8fe7d1df8ab567eb5f73fe04ed7d7064ffa024b356123352ee96f481cf7b1069ff66e3b1c338f1c5c05b713852daeb2188d30e392375bd830321f186fc3b8b3cb28564751cdc3f0f7749cad65fc800faa8bf6198006e931a47c7aa7d007fd79f8ce21271fabb2651c2beea307373194ee25d4a4b21eec5eb993cb38308b667d7c12c4a7f9655ef4f4374bf4dba35f9e983a605e31cb42dc8e954d4e910d37c89337284302655cc2774e3d713f8d1b11cc6ba38498fa7c7865f1a965c35e16a45572876c3fe4936532f805828e3e248703ae10b6fc7986d14e4ad668f642a3d8602ae6e2a800788e3252b71ba38ea4a7f6856e10e956dfa385885c06eb77bfc7e58783bfaf9ea3abb3529189698d905b0e19bff64579943e4a942eff54ffbfb7163910bd90d10fdde124ab5d034a280599d3c9c38f523ede4c59e5da40efdc7c4c8f6e860396fc089435ca8d8d2b9d56e4e30c8173b90fd23f4a6c7a8f1ec3b7564192345c2adacdb4d9cc2f4705dc52cdf76aa073b41c25e876a66a2c2fb7db44cdb7f32ba81ae9056695aad551b07ec6fca3cec074d37f6dd6c67a8a74afb3b31dc8fe373a2f6b4fff97c5e840d73fd1a3c13ad44d28b5242077683c32e532c392851a86cb216f5710ecc3cb6df11731e6cfe1e26e40c33a1f1ed953353ddfc299f760fc8e9dd91e6ca781f382271989c4bf818d610a23b0e6aad42197ec6fea9e0a9dde6044c228cff885d3e25a0d6388ee7a67a3fd361334c240a2817f63ca7a57d039c194b8639ff10b726dee24466100f883b9231434cb63d0e0e5f16bd65fdbe92d7d5a4ba06dae49e84f779096059a8b1dd804dbe66961109a41886d9d0456bcc2cb8ec466b066288e26576ea95751389480d2ff58709dd940e401684d44e00d702c03f07869f47d684727803fb07e007bcd0f1468a3017940f1ca0c15d58fc194a1280c1f635933f67bc12b3156e5a917bcd902804d95f094a4bf2271483f3a3d61861b30f57c8ff8b9016ab9b8955244102e0cfe25d965fb938c15c113fc268a5e03d8f2d5428b2a77b96b3b8507813a25ec06803826f5f57b4b2185bb2a47fbfb418f5565b273ef6bfeb86a91cd98cc908e5d30966fab18a3146c0589477d957f42a80a5aab531ced7807362f53b8ffab79e6e7344b88c3bee6d1355233804fb55fe84ce7a1354b133b079bc44741a23fbe5a0bcc6cf7d2680cf84f7cf298cf1c86b705ffb1c5745374e61cad0c291a0c39956f20d8a06587385c9fcd754e9f6082d290a2f3f917dcb0df53bd79811980f06d729d807217ca7b8c3fc4f4e92ced99568630b8402d1c30fe8b59e0a856d476fd14eb5bcc531f9e5dfa8c1f25840c8ef387e953e096c033705e2bac6dafd17284537bcc67966e1437811d78e3ef4343a11ae576d87d5f104445dee6edeade8ab56b282cf0a1b83bb213ba06c379ebf50b8e6aa7eec556e2744ce680cb9ce705f3b16bb70e23bdca274371bc19fa65097d99dbaccf7467844b26b4291f1c589f330fee388446cd0f90c113873a08b185b4b230da97ab39788a4fa50e1839bfeaaeafd58d1d9732364b170196128dc114111247438450715a7627f27e72fbd3105348a76772ed7e906ce4bd101655eb3f272c83b8395782a88fc582e0a3141b03a78e7bf208beb79e4700f1fe2dfd2b7ac4b0d33b95d25a006ce7981e50a850625b762886cdf68842eceb1338dcfdd617d9706abe7555f3d88cccb46a72bc32a7bd4f3c310a81fa5c2c0a2d47a9ecd78073a46ef4fbca1068e27f08085bb59b427a8ca48c56c1f2f4eaecd2bc9f3a07100404e14e3824cd8292f9c93353d515ed728e3d4eff24bf454bd7a10669d93db1963a4f089c1fb59f3ff890480c6dc9a7b910526d01e410268a7ca8a61822c63a18d5d6bcffdf793b0e2206f26771565a993a3d4242883675e17390de857868e74162db0b7f1543e76f4c60fe061668368ee0d67fb8f0bd091f9bf0e91718cb7d40e3046060f778263cf061d5ba43cfd467d7ba18c0c67805614316b9b1db186712f3c2632fdc480e4d2aabf7a252ca34425c8c0902e2ff6d57abe4193a06493b69a735841b9fe05643c8c0263e3ba4112d11309396434872d289c860a069f9459a5765e193dc130eaf78108ff922cb9d2967720680caa4e5b1d5cf8ceb87d0d34f49460c33a06b80df159049ba903a13ecfe10a785c85cc935fedb5d0beea858a5c458bf7d7007c75a681e746e127dad0b976fcb46c3b2e7864a2a0e2b8d01230231633c3b59a447934cfbf0243b95d216e877ac97bc27bb6db8e3b8f61d1bf962d9c278d20d7e1bebe79a1c142e55f770c1178f3623a7a38bac9a679c62b5d305a04f688e9d87723a555349d98a053b37f7043a553c3eade9f7575d03a3e385f8755de143693f60db6c877d220c8d2205c9720b76ec88ce0459d5afa88be62e6bffaf4a0d1c2f00c197bd3dd2b97b8ab89ac145ec83455f0acf2d39809796e653da72814c51d10bf573a56b926142d5b7adbda9ca8c1345ea298398b9347f98910060450915df74b4349e2c22ecb144b18cf063f3ccff585ecfeebbbc6f60f973d5133458436a68afe2b69fd3e1c1abd71d4d997e9a124dba122be1bbbd38bf8324393d7070cee198f81bdd7653cd739b081ea436c30e92ccdf2b15776290357f1d245ca7c2be1e79b424296fa2661b5f83fc03c41fcad867ec49e10e0804941abc68586db9de05ee2fb4eef34be960548cf156e99a37ac920bbe553bda137d25ca1a9c2826c903851f115fd25c424123f1aff03fa494f949513072516e053a6005d8968aa382252c4667940b040257f3975fe714d3aa48042766f61ec13136a3340cccd68e805ca1beb8e40afd96c392f7e4b6722f6f88f048aaed2ccfca82f6b4fe0635a92c8676a5a15cb84490cbfb3305eab5db4c20d8c18515b08ce3ac34cc44de70a7e7f1a8c16153e6b225b8aeaf162a3bc57875a7e03a030e88bc8f8a24cf0028adb7e23131af694e91767d207ed6fb475e8944c69035955ede094f7eb0e3a387b10026c645b72fbb2da3bcadb9ac95f7a68ffc6b28544186d20dec6764407421fa11d75ed43e1ab1e26adfe47af946c1a1041cb8e67513e56fb01957da65b6cd300bd21a5658f9a4cb68412e48daeca9ba5c0bfcd5015c585526341e3df1701cf2b064267924c9ce624c4d95a89862b650a73c31c5ad6f7c7639bdf94fd459a21e90206f500cfc938d1fec6a25d644973223e2178bf4c9fbc5e91b7910ad659e3648c5fc964f5eaeb3c484a9d91c85b11e285529de0faf222af02ba8975f9f1cac0a6ef76c122b0c2c8cc1149a6e3ba734831eb318d47823c08673bf3b8a0474bcaf2bafcb01f1446d103d0df818665e2bd4f207da68467f011146a4d52f1f2c7df9cf3396b7fc9e1262d4babc07202de5acd297ebfaaef74da97914a3c932e2664494afb4eaac33e577d50adac2866adb0584793203b32c35be1419dfa6080d23e2c8869543b702a23c044ce4c12df156d8d688a1dba2c66b709ca18b54af11418045469d83f42da8b7d4d62a630000755ae695008746d7ffacd5069bd0cf83dc7e641a3f24f786abdcbd99dc70a4fcbf7ab38803290f2e55a241b1613775d92c5923f86e6586a2bf776c5be2321483995c1244191b11cce885b6c0dfca60d26ec1d306b3f07164ebdb11a94b110e3794307a53f9b33db115a5a502ac9dc0092b298487a4338167474f39a16338b92683cd5eafc559260273750a6b21a79f56d57ae109e956c2cf2e3729632ba71bc2cf894c6aabd729f084cd78d566ada79298b31ad23fe440577b59ba6880660574a9d990281de97a11ede0ae09024757529b22eaf873e05c444d68cb45447acbb9467507e6cf70322d7991dbbc84ea9e4b1e43bdb9d3cc4773d409e20c7f15bcbfd9f28087727bce4260f08a022f9684d73a728a5d3e771aa93a402e0fe0f4689d529eb889d1c1b687cdb745576639e5d22f6527c69d2f0549cf137b56306d7c0aa3947ec8a5aa0f332d25761a3d44a56916beeb49c7ad89b0b47e71721aed6ac89ca26bb8dd4b2f43b940e3aa7bb8ef158614216afe855b12bcfadee25146f03ca6785d7071bd191ffef7a7b8ffb41252968f900be3cd78601cf48d4c24a22352f287e733aa82074ed8852cd2e9a83883c4b31577dcbe354fa6321160e12a443aab05730f7d9e7e6820f20985fbea98c05150d61d12a46164ab9a18299db69b84771fbde0aff68bcca7c0234dbb6a4ca4c5134741362eee0115d2883161ed8ff2d9a0a7c1c16c74b3eaf6f027976d742331922f373bc6f81671ca7be58ccc8d311664de0d9b47e511a02af9b1101a0ef7582c0bc8b823f6de626afe63ac94aa49797df92cb921c50b0b9261aa4cc9111e86f1131fe71f53aec84145422298153e8da3bcfab02cb9a2f5980705e2856de0ddf78afa7ed2dc7bef7dbbdcb5bae8b04f15a6d19094d341f20f651041301790f913c30d8a063ab9d30902dc7b9e516c6e40f9123c7e3da4359214f82033b5a337b991ace889a2b1e4ca67899d0f855f878240db93bbf48845b97899185c8ba67ac6dd3edc3d312285e6fa9c349b8733b204ff14558408abe3f23ed0c7791e4521f3ffc0944c048b1216058c183a1d35692769366928540f0cc505ec022e8a7d4cb1dac7aeb95e9fa049d32c6531426b2ae36f42b461f91b55901942177a02b8c3627db32024d4819214feb7b39687354b0e0b6043082ef46655f99fe92e9e4429c2db862748da2b3acdf97f95e024eb921b125054a0290d2a004ed074cb1c70b8f8a87a4fd822586f860edb01021287782a2a8f5b80d43079eac041d55a0cd20a674be0c894558a0ecaee08bc6faa69ee30f1b6a3abbb80760538e5911b77ac808d7e5685de897c07ce9723a44e9be789242d68b7e8d5dff75b57fabf72299a8c3e679dd63ada6afd0e2ef5c7f7d266db488dc7622f0404db50e80360ea13b39f85a266c331b70041773f9d14dd2c58339822e5d00b831f3c8453f5652f92dcd09bede777e643459608ea5accf681b07e21064a92db9c44e37fb1780884b4b772dd01e43900bcb810501c6dd8e07e6cb6f0cf0474795b645a256fdac1e0fad066de1a11f9f0b052a151c0834dbe526692595b2f4c5670ba4e9b5d055a94e0958da7349d063a26c2cc6090571fdeabe754c90fa9eb6376f97bfdcfe3953a2d4cad04d203f09ab5df465c48e7185d5d3734da0a79788b157488904d0382ed8c17b95ec837ee8a335dfe3d5d137185023d9d9c04e6821e726b2abc09307b2ecdd9e03beeece7a1d9fd82aa52d5475b2daa29dd72831ee9a77ab2cdfb19f207fc82b0d52f6fb4058cc7d1c57d95c4f44406123f502ab8f359511d4abdc6ba510e571ddc7caf3dffbd9fc7219223232dcc1eec238db4b0113c76e7c2a2d78186afacec6b50dbcbca60fa3dc894bdd89ba29ec7ab99b681d39502523c11cdd77a73f29a917a10260ec5cf1e02aa12036c9e05e4bb75f16c78bd30bc7fddc370ca684dd9e7d6ccd9cfd39d524311a89cbe500309eff2669b69342087fa142c18f809e232c979ce5f09ca469d6a4c9c5e45882c4e348d65bfba1a3185c42ebdaca9dab7efeeb4001d0aca7d3de20eefe0f2ba660a83ff6d5bfe798505b7d1fa0a0be82207249fa81dfa53e7d46b8b08168b029fd6fa84640059aebb4b561d9e450ec972bad59f0323e6359af5e8283e4be69e4648e7ed2db5c6538a9b451b0498a5b14879b1c4c0ed7f76a05926f34781f2274ed503cdd6e4bb4a27445c6b0ef441122e9a69587ccc3d7584fb513ba3c170d1fad1cc33f5803e225cd6afec23c049cda33e229c6b3eec23c4b9c6831e229c6b3df622c4b9e69e47c01eee4a597c96b2fa63b2cbc60d0a340391a9e7563ee866bb8ca76ab5c0ab1ecd2ca939c5003aa05842a8b5e4c38bf0b80934339bf4787de0001233256d212948d5a9924ed2cc1ce72472d9c2c12c17883f535069075ad1ca2018dd65281fc8f853a8448758c1c22c8ed2679823cc3c53a2040758cd72288ff2c89c13c83952a03407adc87a181cfd649807c0e1774a3a90d5166714789e2dc56b668f525ba9cbc7f216cd768f92565bf71d5637ec94cd93cda65cfa0a8c5d41699e4a505436b201493ef0715f7dffca6d06b9e4dfa93373f2cc503fa36ad0f61bb6fcbaf79194e1d4ee6056b33297145eaade9bd3a1bfa1b3108011baca66e2ffc3963df427278bfb2b8bc7b3d7c1658542ee90ecddbb142b1b12c30ec2b2df3b4d87d074a645269553292c16b22dea391891993908f3b18c05b1d277036e859a6f1ab9799ef02850b92189ec8ee44a4e0976969d22b28af476448a08d369ad211508df59c6a9fd85f4e6c881c16a8b42e8612d586826f0c6e18a084d9d42f452563a751edddeee95004416917db1cf07734f58ef65f89f21e5a4b22db39b0aa173055d6a7f2a06f2ffb840da0fc3e8b0b3c5ea532432e6fec469d0a406cb63ceda7103a05ee13fd11e3af9629998b33b4e9c4666e8e24ffdc9189c8d98d8c144595dca9cde71920f840c4107e54fa6787688d10ee2ccc05716199ee8b334d6b71718819e6abffc1fe00a18e578c65997484ec20dcf94ade2e68c2f6d2fc16f467109e4195341232d22ba572f40945c9658054f2fd66c1916719ea0b5400b70517e517f5a5c8fd1a567552e33ea1d71c1173037e2cb83783ab6257652cf3d93df2e418e796317e58714bf030f9156e0c54ac440026776f62c0d40e7afbe498859d7c06485a51f2ef8f8549c8bffa839804a1ebfea3fe1e62090c352fd033e8eeee901d7ca5f007ea6be821f1320140dee7082655693ce901c9d5550c7c2f83498738d17688acff3d8b81fd13719fa996f729a0fcba9508e20669264305cba0bd2d1c22507497ad525568d3a63bca0b4f474a4a846286321c0450911498663903ab1f8de1a7630ee3ba9416de88267ebdcd64861a902ebf37aa3adcd0b5a274ad36fa8bfc42aff1b75e10a8d981a9624aa647ef3c7a048dfc8d528934edb524cc0da3294b62b4c8a0bcc7349f21d62a52eafb752b08a9fbd6e4b799bab5f92b32f4bc952ccdc6eb6550d97296cb56fd4f992b53e8f733422647c064238fa28d83574d1c818bd659f188a8ca022b086f40ccecb645b5800ac1dbd5c8996f4afd56bfc9312d4ad6334414f84097094a06839156317003df33e4da28f33a938389c12a948969a23aed8572f1efec02805973234c2eaa8c9cea4349eaacf1316caa76a748924a7ad67653aa844564c8a27838f3258b199f7ec66ab0a372d0969af59d35d3895cc3b0e7edcfbffe00dd4b9c6341f871acbd504d705a89bd2a002ca012a3457bd7a7b857745f7078e5b8c8dbc954f0c2304c41c489b1bf657e8bb376d107193c3d493596433b5862230279d06918b1bc0b037f47c0e9ad351702aa08256afaebac18cfbd350e837c466f493437238907cad05aace5d6c4f0b2c2b677c82e9f80e58a11606980ebbdd101d28dce11227b788c709dbb941f09fb8da9484b32d28f55ad738b1b54c07341cc8b8a1000e007d30c93b9c6db0df5ca4bdf4b44897c275d3c96abaebf8ae45c97f01af2914ef441afd2b5a0f80891553ec3ddcd02e72ce6cc78952eb1268713ca6b098749273c44981dae083352e4181170cf08174552b7c433159d5b6a7cebb51cc8523fddd194d5b1e334f8c6c115271a6709f7f6eb523999e6bb853348c22649ebc754c0376399186ccf0dce03e94fb55c929ca73d0f7ba4f1760f18551df08ab28b965f2eb9c0ad7bd292273d328f39c48c50d1f8f8c957817c58d2deb36077fde524b3481b31435f42c55316b89b4e74adcc99cf853eed20d972af35073b7175e5927de06f20595424367e7d1d53c9937dd7bc4e48583cf6fb9be003efe376b7b4465e6b2ef232a1c687eb8b1bc7b92c744ee6198d9477139db5e2dda0db80569bc7b31eb0d0da654f6bee7af34ba88581387fc57f5a541660705ecffa5ba1ec5d444f47ca8ea1cffe769409301491f9a3a025dc688233f28aea45e03e3c6958acef4e5190cc0a335ac4770f359c08d89aa2193bf3c04bae68eb2869a7e20b1b56ca4bb0616cd2c46479a5e2d4738298a325e5181e63f7612148229f4f97ab391ace5f90a5af6eb9bb61c0416b4676740ca119df39896599dd0d1d585f7883e5485f6817b2375773943694dc66a1c4349de93062bc82cabf5f99b9af566caaa8599af0c35fcb5257a94880f37161f8c8c26fda36d62940f01cb12402df59c2501cd26b0c1c8a8b42d96b476d408485475734dc880618a25ad7434c0344bdaf601d7d753a67e9425a50018e590b99e847151a53884040e9420e04c4380b0701cb03783709140e27bd06eb0f4726362e16a15a503ec23d0f007957523c8b8276d208ce684cf8e0c21f9e6de88b2feb346ebadbd637e9c48636fb5c092780cd58da3225ea22b2198061516d39bb5986a8ddf01a5277314f2ea291770d8a0cb9c90c8e24ccdb04794360853e1ba27649a625c73e6eff8b5b7516013390a5ca109237023e748c09b90997edd2d32329ae6d06cd3da161aa999dac4fd2ccf064566cce81b8168a9c17a44b557a8e5dc493f7a0d2721ace46c87060cf02b3169103e16b5d92a61d37e5ddf80982863ade32f475bdac1ebfc0148a814b4b4cba6281bac5a29847d80574469e833b5709761c4e495b4794bb9f7e8437b2549a49c85842e20624e59000b9432f3a75251282ea73596c2df2c08a9198a45153465de1951f4d1683e9bbec5d4995fe752b17422a1faab4919c45ea03c1cca03df09293568fa4d8bde842621d0eaac4c7548e1956afd6371903cc92e91a91569b21eb2ef17c258a32496234f069be447c0c83af662d5dcdbc6fe42e8cd8bfeb9a9460be4a73a50eb772d12b05ffad6c3a2b4218b671e76dc8b3db40bc0bd4b64821fb4a149da9e401253bdd37ea747f4a4d1bc58d8d0caeade44e9a7386b58aaeba58bae28bf57119f7febd5ddb74eee7fc76540c39bcee7aea6d854b0258daf8fb54058c2a04c8f06cb013f42f5b3fcee6ab62c553c72c8118d4bcd3eaf6d2e24091ea4bf16b4c534ff94eff2563250ca4cfa80ab54044b84307e1a8018d3523e4a47a69d1229bae30b572164e473943c10f12097d74f59fd55af6f3af180e9c4761ebde5f0a9e0523a91e3b1af69e207695c5f2ec42793d37cc97a533cc2df64af60593dbf46d24add9c2802c549289f5a97a44f2a5013749ad43f38b32606dc26ef1877e42d92ba972d7e0a11c6e7c4e3f034f4f1313df1c9f70776a30a49f758c9dbcf56ea4afb1fd17de417dab4313d6588c52ea75ab610f16ceb86418d67c81bc97bada18d3f646bd5281cb9b0e465ab84643e69ab095c946ca59b7c674a207faafe47f1e95369be9a61139b292e50931131c5587c3e72b5d32f32f1a13977885a9bbaa6f934c9a3ee35a786ae5e276b8d7bbf64c3263f807b05c6afb77bca8d96a483409d549fe92fbb4326921920fe32ec05ab376985b16019c771703d349862848ca7d2e57eefdde8c26fb21094adbf52ea115ea1abbc77cad08dd7236fdfddb9a57dee314e6acc459ffe56c387ecce4bb18171276a6ff5f1a891b2de7fb00dcb8013bab2dbc7e02bb7ca0c260570629d68e06aad9505a2926da9d882922d3846587d2da52b4392b8acf6f2ef2c64ed8d7d270eb82e8e7c13a3c300d5a2aba8f3b9b99c47861787377d5e3fe5cad3107e92796e1229a71af3f9b3876de9c9c705b13c3abbedfd514d620e4cb0b81c0218043700c2a745296d408510ea5ac0cd9bdf2d5da1f445111d938d6134cb13d11c43f326338cf91ca105eae67ab35d4716656e4f2afbe65608a148c2e650fbd40f9ddccc6926913d27fc1d8fd28a28c90f34608843b87a08468744e781ca3f34076051a3cd9abbb124f676229407e00ff3b373f2af8412757345ea8fe49e0f3d87e7701aee521d14b10048274ca74448b7f8038f2eeee90acfe2d52ba2b651d98ffcec9595a0f87453239b3bd36690885538f1d30e335663cfd79572ee9b9514371dc7cbd0dc1db0d98aec59efe7d3732e22395c143ef60ca74574f3d3bbaceb8914067a396e3323f3996b0ee3d89e5a2b5c05155f01f9ba0450ec83f308eff7647ef06c7382e149a595240d2555508f2da00ef19ea56ca2d332455b66da2c1a11b8b6e0ec15d785b78ebee75faf12f04a537a5e88e3214dc22bbc70ae9abc3854ec3027ad6a9c39c4e030458c5a48cc6ffb9d07ea6219c98ddc85ca57232450cff7c10231416b26a5e8c738195f6df2662256329855632b0a4802b50daf248809ef410332cc8de304ad30a113c6b110e30e34b3c6beaa6533bd5d8823f4ee023dd04d76e5480d9a5a8b421d66c95447dc8018a6bca55fb30e1165166dd12223be2feb263fc707bc3d1ad713a02f2f668bc600574e72b4344bacb323e58390e9a4fe0bac95525f14026be1ee566f9dca9fb28e13b397fac030f716512be2808cc320ab6abb3c849f4cfaca91276faf8c402328ce9d310d50d835ad1a14acbe05f709afa71eae54c289d98b8ef1e39c66181a81b41311464847d795138f959079ff9ef4e8d711b5f34bb16f6a97974f3b7ec62436103db81e721ea9ec775ca6803abecabb27e9d886965d9c7e6cea529038875986fb94bfd8d25395a49d9ec52412eceff955267f2e9ca96976ed05dc2e4b0db29231ea62446c7133c4c22c6ff7b48e54facc11c22530a1d7e933d22532317a3d843b14a8793a031ab8522a5ab61da36bd55aeca3f13fd33c142f641c744e50bacdc230d1a02b423703a62324173f279f76b6bb9183a9ec10407c649204be013986ae3ee69984649c52f11bce683664f7ad10f759db9985100b9d6c7bf9c2dc19c19cb7407b090dff8bc585f0072a3d7ce9342d404e3e7844830619daf3a9d153f50759c8f689552b084dbb0e0dcf81f027c80acd63ed5e1c0b7946a4ba6e529b8a497b4ec24446c1fdcc32141a39c464bec071800094e4063aa1ebec9c718a798628d0eb11abe88f0621fad6ae73a9b5ad8c62aa9273c9c53a750ada403485de5df12443c17037ff4b5dbc59eb3f90339a59a27243603d021d1cbd983bc6437afbaf3b6206d8f15967ed8e533a7bf9ed1fc2a12710327371fdc395e6d0fac7779249a232b9aafc70f4ee74c5eda3e1f5a8977d6f67b221bd3c043d622f4c78d23f4a9009f82b9828499cdadfc0dcef59a4d9390f350f257b3934f2d3a4e8062bfc638acba19ba60304f754c3c714ceee3bd011d1639dc5ab5a08d4527b1744d33b759689cd5d62e93fcb6959ef427234afbc83e3c683348d17d942fd753c117527964d735ffc609b4130b433c45019c5eb8c5e7b4a12056599d200d0863ccd889f0d29848938f584bf6e0c7fd9d04fb49a54e188227023633e8c7af0f0d76837f4d0cc5e42a043428d14dcaaa6df14fbc52736a5bd645f5f197d263df8071d37045e78c79a6c33df17e39848dc17d429812b6b6e8f468a5a4ac8eea1574c587b4eed1e437587cce43b356f670ed917e8172a56c040ded24e89c22402a544bd0e766646e2e4ac52133676b7260d2a08599b76d3016c810eae406235246f9e913363819d15f47193939a3e56efc57747334901c0b7cb24a2f47480e093c8c77520fdbd81613bc04027db8711c0d5c44f23c77919fccd6483a0179804ea36e41b9380440d52181a6e3cff4836d7c763a2226a2562eab41ccf0a7e5faa9047a63ab408269e154c600adda7d16148d03c2d02813ecf59e9b58e50cd9c1f11eae578e3931bf42892ddaa09bacd440571af18d671f6ab3e132f525992fa807651fb65e6bc6f1ff317e8207d31e1895bf5fbd92248b684963c16d3b3c8b471f936a1892ba2c7333b3e4703e572cfa610787f9c470d739aa7ce1d30fbe354f982da0f6477094a1788f9282a2eeb240b0776c9112bea7917cd313a9d64f9403e08ba575420a297aa6677cb22ebf4a0141878b70082a045266d800213d867d0b31d86c10824087607cccbf94ae42d0ba146a9f1f056c710b5f1b67839fe0aecf3f7da2aa1b37904c3300a87133366915bec0f65eff902b62b9d3d5c20542f07e78acc41248b1447dd6bca849b1992d585e7710439167b61883071a9926b6d45cbefc784541afb7383f378b4690a13035ee4286307e9b8d4bf819adf0513439148092ef0141a366107c7bb8c612a0eab184ff84c0f8108d0ca631e74439e314f437067c0d7d13d64772c369cfe028acf00ae1f1ee30993d0be710de9d05ff2b87a439844a357dcf113222fee68f0dc9ecdec4299f91567341d6ed6daab96994c7e64acd5107b018809303bcb120202ad6b400b08f33d712e7b580035041ec5e8979a21109dbb434fd7915842001b7058fa58a4255b6e4b65522cd64f4acc665945c7293c8320629e58a5f06af22a7d244f7cc453fd10c5fe2b35d2c03d0d2a8e5761f76b13b237b9b4c10255010bc577e112ef81a2ed634f234d9d1f5f0a4f8821c5b70016971b11a6c43d7636e8278a62e97b7f66170b2a08fee1ff93bc6a82edcbaca16cc92e5e4b44c67c27db725f71784e467aba283b627ce46798f2cdd4dec7ca458880aae990390454963c5db2cd6b791c8b94c33ebf26019c2e95b390e2c9067c72a1bdcf2463624c54bf3a44b041827aa583a9620248726cbcbe08068f3213bb54a0367088bfaa4ec4e01cac0ed090781fd1878b1281f35b2f3e0dc1409324acad577a6e6b70e08a393a4b07a8d2c3826a8ef17f75f681f799d7bdc8b3c8d19048a2b9f831808f0c6a158495548130221bb064e0355beccaa2f046e6e12a73ba6ad021a9ad0649949e2cdb5691c63d4ede4c44bb46221efa2a2d5aef0828a442ef88cbf8e681f68e6d8bcf1902720129157d78ec25978fc24273fa5cb365b2034cd889adc889b53a1c4e087ea9bbdf2cd864f96cc503aed38122f1b699be1e9b48b5c4c804e3f3428587a004130e820e0042c65dca5447fd2d3a812b9f5acc3a223e58edf0e1b4125abfe26e4ead6756a359622b4fff4a40f47f54b04b5caecf8fedd74fe4b9a1704b1c1c24b20577fa08bd3f9e0981a59b84c8386e4677fdd00675c00c32e007e4b61f747a32773047f59a1d06ca099c234f0c8aa768a5daedaaddcbe64ca0d347549e8d19555ba9b22b7a42d80187f1d75f22670b142c1fbf6f5dc68aa84f8129af58534f6185e7291be9280c8688c1b4ec3a1638211c93c40692059fa797fe1871e48e574033a539190dc400778bd4d85840f39053c2abbdca5edc86f390ad587e9a2e65ed9022832d04821432ac22308359b7ecaae2d4a2fb243b457be5e9eaaa8c5e94fabb9c875ef2580b858d28d00bfb92345e659f257339e5a2ab022a15e9d4ab30dc4045c63ea347814c1d6d81cd3da22ff294b3949f8c01e525bdf702ab67a1206bec293a19cfdf09e6ce2e05cf4060e9f44b5a7fc84b47688f775d61d92e5658f94c00049f50a395198bc8da5753f872fc925ea66b6a9a5cbd4c4ebf8596892121ab09b76f3fbd772a0c78b57d183bb569cb264fc7a1754a68191220d2e219272d37f91c4af2d8a7400023ac6526bb2af5115583ec862c187333083fc208a3ee655ed80379b77adb65dbcf1097569781ac461b383a76b147d289f8eb94060e6afc9698c8212833fa87037d865e1eb7568c3e707d5becfb6876c232bbc8f5571d2179e9950bb1a4ac80b15ac724186cc6ee4fec496dacf3c8a4ec6dd5349fe695463ac0dffc6b19df3c09c46b400981a1b06bc4efb7d1a288887dd001712b746b315169155b788a5970ac919dd6ac439c1110c24e9d3af9a704ad260228a522f9bd7b753f09f4ad506afcf615c5dc6a8f2ccd5ddf47aa92192538702350d93de51b081ad89b951328718b841d65989899d242254bd962ed417fa0e3dbef07e712b3000f8e182e35024c798f0064a8f93a0195182b057f093a3e64594643f53b4036201406f8d3bd8dbcd207b682c809c01b4192c2a268c025fd2f38ce07c0c8ea8f0f742d2f762e59de2a6e5b3e6f2420ebf448960f5028a185b8d823b62acbb03628158d8444f460e64363f226b2480449e1276779fbc657103f38e9e0b7270c986961912f80ad6c6b9ba3d8bf2ed741d850023a4569afde6a8119ded86f0e40745867290992456d200cef1030fe5795df1c9463e4f97b64eea6e83b23abe2eb2bc5974994e2b064864986ffa81712eb5f85223ce3c3cc1385652d36cabd5e4d437773de3a8694dab6cede4af29178291dce9d65832a2a4d3852b797ef273d5c74ddf382c32c884bb021c42cd52978275e6d7b8bf2989f30fa2bce0bd988d368563faacbef18cda9664e9a3276f439f8691a3b22590ba100d77cf7d1bc811231538db97dd0b8b9d72e8af1e75866a1cd64b05f60993d561d24d37b9283832920e921ada60486d5e5dfd85cc0a1e3c0fc4c675f893b8201b22b420263a2bfd106a8237193c44eb6fe1f3670021dc9f805d8c8a2fba8193038db6f0b692c99a986e0cde3b41dc4d4d0b5ad0f29fe0c62a3d9dafabfa751bc25bc4471743f2a5e33f84071690b9d4bb58de1e30af57dfa46189405dd4e67c4c38ee450220972536639146b11222e2ea8370c545b6619b59b0cda6e016375699676685bcb1a11a7181e55f595b2ef6c77e5ede7dc40d0d9a6fb7f3268bb3a465d939d90b9bc41dbcd1c7e80978bcbf0fc533d79ffeb9dc7a467d0f67bb7c5898b6227d72268fba21f49bce87a1b64c8a50aead7a9d537d6a0bead98e9ad7f73f8511dcd8c016d5f9fb598f7d36700a63aad6b41123cd1f2e0f5cd784804f14c5c720894ee1a6f25c70fca2a51cd8e0891795433a3affbcebac8cce06ef47c0d7d0db2c290ff84b70c2f97c8dfd5669172e0ce3d046e7c2239d0982e0d6d12eab0af946f38c682ced598b86930b6286eb2805acf7fc21b209d630eba13946b1729b254b546c9adad49d16bbc17480c80c7d1e18294be331a17811a4da18ca8917b10484fa37ff7935ce95b96392122e48b670262220058080b7f8ad28a70724b79a4a95b407101aa3a0ce22ce855d574d157deb7e0b37e927222a49a9a6155b9016a2b23bc0319903b455aa9e30efb9a12a4af853e02034410369d8f2d1e3c4b7b6099631c8cdc7949a90b56f2188c753757d2a043d1d91fb9af07b92220ba9ffd0d08c21db876fb7d76d17c28bacabc0f801b7b00a2f076205b5f3c3f1cab950028d8d1329502373110f689edf763838ca6f38bd06a8d0edf04599571d6b92138e2be192d94f6ad4adff2dfa1b611d57a10d5ad766b95c773c7cef565952c6b08e6ae936faf07d49323cae8afc7b4209935366e6115d3b606c48e302b7bc7d7ad47b793c39bb463cdb15bf0e487fabe8392ec8f350a3331dc9fd523eb7e385572e8d247df2cb663d0e209dba69f23f698cc30f15bc62631929d15f71f54efa655ba9a3fc828878a02751acc010865cdc66bdc3439b97774c6e9c7f87e85d7cb3655a80705bdd0cdcfd014c5f0798f6fa53fb54c0cbfc987efa36131371cd83a8f8476beb2d9c1e284fa2ed34281122e6e7ce1650cf046e47f984d39dd89753ce6081d5d0760bdc77ed7fbe89589d6384c6510c196148967f87701ca0181afa7f9be5197ef69278851c71687fbb0efc8340f84b77477d3cf062ff9245861be2660b1ea797a0c3f552b599d177bd3b442828adbec39e38e4a23a1098f51993af8f7c22eee7b3cc8a9d4dbcfa522bf37ddbe62825ab64d1b9daaba8172a3a395f6ec4e0364c3dcae51ed5624561fc3f6a5af3213a762e3bcc7c79a532e4f65161a15e63d5ae305a48b7e8f2fcf01a4f56c4247f9c5a00e1f56a8eb22365dbc39c83d347ada579abad3ae50daf3013d084f3871c30e5f6f75caab73dd714b2c23a3e4e205bfd13e7b9524f8f3d890e27a7d160ff62a4df846019f5d45c41f049e27c40e0e581048c98a73a311830064ef84608cc864400e0c94080181181820130a5941656ea8e6c0a4abd5a24b05fd45cb4d32c3b6ed655ba5fe7baf3564c777983abc35c4a3289a06792214e769ebfded6acde336b36e224242b64c01840eb50e4a0d6efd772cf9eddc6bbcd4a8b10309eb5ee3a5468d1d505c14772ced581245b126bef8a02adc777cf03e6a15f31e4b0b898a8959d550e30af5be90918941a554a8d515c1aff952f385663c5db10918ff113c0a8234a96adf17f37d4cb772e291354b8662087a27d32a15131363fa189b521da1de49934cd7a552a6188741824a7d2d057eefc1c4ac6aa8d4c3a852abda3689d7c51a50a4b8aa7d2bd002a38f9f5dcd7ccafeb57f53e15ffbb709d5510d7cf183206d0a7c9ba599b7813213feee48f17eef30462c09534bad64523f93fa9999d4cfd8571dc5bc93a96b63a676c9d4db2cdd97b1332b279e8d3b23634d24f85f387e38b3aac5ac6456b56dba6f13c5268a4d149b287749c6826688ef797ebb54cd92a2f716b4d73af148bbaa3d21c3276bbeaa914f7e084289ec2cd9fd0c5ea7aad934e1aa9ae7398cbddddf95f75f97b176c9dae9fd3d750255a190a36e55b326f14fab6d224dabda13f15130d944b13cc2d5d1db44a15902d1d0427a7f97ac0ded2ad402a54aa1ca186b978a15d1caa5225ab954c610adbc15f10af10a169d0f2866216ad1f9a0b264e1c206cac966c9268acd928800918a5845a4d2f9dcffaa743ee15bd42756d1e25671c5b572e5742263bc54aeb072658cd192b54be522e056b9c2ca159b282295cea776a988583a9f9a48e552b1222240b4225e71a988566ca29c5636504c364b546ca26c93b5abda365d2a3651b4a0b42c91de7b5c3a9feb95415a8bba318ee106621ea60b8c2a6625a64095e883b1e675094571ec92e241f805cc7fb1a5f309a3f301c3323a9f2e9d0f8c172f6a8830b6c64bcd971a2f1deb5b855c74ac2ca196304bc845e7f359982fd4d2f9a4defb7003305fcd178b03b302533d18c3300b0f46ebe3058a27854c91354bd66abe581cbb8242825b7cc1c2eb1266f1ba78687477290cbf0867e0855fd47cb138a06955a386c5f96e8d978f44c1eb52f3c5f2b0ab4f4c9db290dfaaa69f58ebadaee705d13d09bdd401b204a04a960024d10394bff790495521bbb00c32ec42762117bfe950afc668b3e436b5fbf94de7537bb25e5275a728a5de460a0a89d4dd2632f5f76b6295540af52655cd66898a38a563ddee8715110f65130595425d31c69a4c15b2abd2f954d1f9842f13da48219f78b52764ea51aada5d22519f5285558ca8b796349d3efc6b13c506ca13941521c0ca42d6f625bf1aea7db163a9468d1a2f355f762c5181721db5b1a683747ff18a524817eadee3d27d62e895d1b1baefc2254908c5e885617435dd97c1058d2ea11a50d4a0d244ed4ed131a6d4e84871cad75d0e5c6b7f84a2c405c3073434341f8617672421e589226220e451b1336319244d8e94bf2cd9fde82f572d7103355020c505a0c22b686081860478b085026f02433424f07d16042f288249f80b7280c5032dc882012ea27082bcf78e37c61be08d7befbdf7821f0d0fb6101143d6c61f01cafd06c887e067c3f1fadcf1860ce95ba05185ac8d4f05d501007801e34ab9523ab100f60c2b51b820d5595bc6156778c05adb75de1926f06270061a677421eda7ced8728607503a6e18862ee801014c805ac1146714403c230a11683c03cb570595a2807717144f296bad756fca01acb55df7c5bdf7fbaa28200c4351e422c5e97442a1ec152a6060606262bc2c6026358ee33833e35a9056dc488d0033a40549d3b146f8114680117203c6bedf702068113bd2b7e841034a48b90a085b6e98814aa1408803a10a109c20ed0d803085ec3ee579420c218237fc401004c1300cc3300cc3300cc310fcc2300cffde0b865f78c3300cc11b86611886f703bff086611886e0f785611886e177c12fbc61188621f87d611886e1772f188661188a61f805fc2e18f3856118862018866118a6f15d30fcc2300c43100cc3300cc3100441300cc3300cc1cf047ea319524ce0c048d6683ca313f899cc782204c1d5fd3e1104c328c2af8af04a89c2831a70c105111d0880030c70c600ccc802f4ee1951cc6801381a71041158e080cb116430a0013198b14618fe008a235e470f0850016b836e0b2740f1e47e9fb0d6765e18c5bdf703af30a38a300c459308b2389d4e2754ca8c1998d102120606062626260b71fc01148f0ac1180730dd1b8aa11886578a0f1d2c69e00515e880144a1400cb184c745154c8810f96f080174af080034d90600c2e8e10c93b9ac6f0e2148ea6ef036d00de21a484201931df37ea18a28c28e037c6105257bca277efbd5f3e32aec478f7de343e323a80ea9ca6bbf7de1b1e2166a1e28c2b43f8600935849820a3082e4220630626327210850c3268487012c3d1067943931862cc783768b8f888208e5f18dff77d9f270618630c11d2dc206b37c87b04176310a08831981063a8c801efbdf7def04615017ce303fe5e31b020ef1142ffacd7f1e20defbdf7c57b6f4b0c2e42f0b36318de7befbd21f8f7de0b45e8defb7fff5f871824206b9f039ea008bf0b86e0dfefae6e98b8d0e0b32810043f235820c11fc1900604412284c0bfd1f9dcf15bddd8428c252e420009f043951fa890d6e342a2570ad9fd9572a578e7a3f3baafdda0791f9ee7a3fbdad8e5d474f008bfd6d1f4b85f7b8f94714ff5c40be2763701a8fbaec3f3ac47a63a56978211f25d196b6304c69ae82d20d7fb04ca763238887c0fe3ad7010b96f5fc87debb6f3fc8778ef6fabf82e2787c5b24a68bc711445215d2a8df10659b3a80b63d7201de648f742fcc62fd9bdf8e11781ff892bf76a8a007108b17f947a92da40d7fd6985e3fed12a95c6388a42ee777f822172572bbb0689f2dc7631b527a4e7adba5510f789d78569a0ec1a244aa64b97fbe40ae9c4f1d62c197e3886f891bffd6f954a63b4a1e9c10f04c9efc16f05e2b0a17bef8bc4ce13bbff5656dcf7bef0ac1027bff75638c23f5aa5d218412be4759ee729f184eebd57e8537ddff729f984401004410fc3300c4325a19097d2c0962d9d952e5db06059f22c4e521a186ba309468928e43dea6485b772cfc27c2b21a01618f03f70e528194b3acc501221944dad41aebc2fbc1aef0baf46e889f56e0a0db00b2e5e745de7791f1734481a3763051552c881038513684c288184100323d8981965626052a8932904bfeb7576f5ee1a37e8ec08442a1faa8a180f08c5c0e2defb7d6270404c8561188a22171a583140107e0940d9b7d1859d11a313230c510c30c8eeaf1844f066f01d31c610244dca7e0408c5b8a038461624e95b8c8185b437c6b0d2fd1de300637041d2745de7795cc218c38beffb40308b9a98b28129258aa2082344e54eec1ade8d4146158ff42dc84000cd184388b9011796c65e32ae0871d28973417ad6230309328a20bbb7351da4e7a148df828c0ec8a46262626264646e3003326640d2742c9799c077e5e3c2daf25f64c1b224659c4243c54a8e175697e742b365fc42d422d2b87b5e48770f0814ba5d599232858a15d515b25bb4589232854a152b54c4d45575429d964e8b96ae13c5986f65c5b51e500bb4f4f89ac8e36be3eb6b34415f7ba0afb1c89fafe1901fcae76b62cfd7469e27419defaaf82b25e27c6d6c7d8da6f6365f63592efe8269e16b382e7c8df5c2d79ef5359a9a15be86439a582b1674d82b4afe92f913be86c3ca714ae1a4c209879c61cd783337666ccc7cf133f86b7cfbf6457f8d3085841e3c5e41403fab1a8e4f0fcf8e4b6755c3c9c169ddd8c0b0aae1eca861bde0420bab1a8e0e1656aac75121851c3850386155c3c1f9a719bbf7a6d8b031c5c6141b536c4cb131c5860d55cd53e2cb92e5fb1ace0dfba8b7a1faee52d7817709bc4be05d02bf86d3fd0d55ea6da8c00f432c2196104b8825c4126221bbf76ca8c2db453489b78b78bb88b78b78bb88b78b78bb90312693c9643299be86e3273ff9c94f7ebaa192791b2ad3b7858a37838373ea4eddf83654a79f79511c471a9a7f8fc5c22167be8643d6402aa6188f049589bca11a6125fa8d7d1baa99d5180393aa42da0f0c610262480103201c31c206889e17cff362619cc6f3ae07e32bd6d0d50133f45df082a0d75950b433f04221f7a854f1ae60f1b4d8c2a58b97252953ac5cc1a245162dd6cb92942954aa689145cb175bb8e45c6159b154b2885ac62f68b63c172d5e8072589ee77ddee77ddee7e5784418bb9f42854a952a56ac5c21ddba757777776f4a152b56ae5cc182450b2dba2c9dbbbb7755b068a145962c5ab47cf1c5962d5cb0b897a525299e7577ffab128580b6885cc62e340f447a523ca050e8e6fd5cef020a59fb5dc4718946ca4fb1e2d9ffac7c4276cb1612b45bae5047c5f3c2d4a75279429d96f7a4d8ef92c385b5e5bfa0d1328e22cdf834acb7561463c29515e0aae64921853c2d3e9d244c642d07eabb9ffdae48fa871766c8fb3cf0bbd71361863cd3bd9e773def345ef15ecffa093639f6dd43e5dc95e914736d680114681272f2447fd4c97e88a386f0a8fb6d9f80d662400bb2fb5a1269a76c59daa285b45d6cb085ec3ebcb2a50ad21deac44ee5a66e5f5289acd9ff503046beefbeffc4148c914f89b4ffa96a4924087e47a2bc2b83727fed6bafaa6632127ef8ddcaef77ee37208c1150652241125c81300ffea74ac118813162bf5b8d1dcbb3aa6e753dab3291fe9da7aa5ddb89362400ca5af7dcf35e0a0a4506caf350653bbbc668ad68bb21a6909ee7799ee7994ea4f57c3c2bfef5ac2551e2bd591824de6dfd48d48ad6b13abbb2b78ed5d13a5607d6ee08761d970e8dcecb0c3a2e5d193775fa32d6bc250f4af79e14d477ef2df90be6bbf78408454f14451101160bf1745a63ac89d713bb1b537b425a2a478ce20d2a64f734d63f0dcd38aa6230df83aad4b71267f0545cbc9435fd0075ad15c91bf78a37ecb3867835df1360fcfebb514b42a239a477a3f31972b378904b86ab9b73a3fbfe921f9aba19e237f7bdef525fdcd892838b8e2e363c3d86a88aa4314e09d1f81ed57d03e8c0f0debfa8a55188edaef5c42e28fb9ee78c3043a8a5b1e65c48ef08d01bc0e8bd68b1dcb71f86442ef45d317c305cb95bf1ad625e8dd7840915a3f733788e763f341e4d4b15599a0042a2b350480fe59dd218694691667c1ad6e7b09c8b4743eb589ef7a929c6dbb1eccabb21a6c6cec74bdd7baf779ea7c5e404687d65ed526705ca75e8b841a0ecdfb7d755de2ba12c0e0443e0a2064e740128c69927d269a6274c09db322ee39cc06e3613b6338ae21b4ce3509c0d57e28d81cc4e59aafe70b70c80a5b313c5b0ecc3a9374ecde122de6529e6a12df41b83f5d0bf191bba8cfd4ab0315674dd1ff79ab82a849d287ed7b3d64de85adeb9b5e1ca603de4f179e7d65aaf1b626d683b6b3dd087ce7636ec4a50622d6843ef2c4ccbeb4090757a7bbbee4eb1d7daee6481d059937ff6765eb6b6d659db893774383adb81b7b36474d6829db5c19a60add78921f8bc30c696602d09a267ab58b0b3b6f360b6bb27134f97b23e44fbe9f062b061d75d1defd475b646c6c702e0eaa09ee8fc7ab7007b3dd6fd3aebf957007b03eb9d8fe3e8d6edb59ded8115bb1dd6765fd779d6ee581c2bda54d7751df8c3bed075b7b3395e0b7582e88285b18142e784fdba13ecb59ef52e49f7277bbd3b41ff981d80e7aa10589f81049d67417b430b633d2a5d27be3c0be4d9aebbdfa54c2cfb591be65c9d15726c7702c5ce5a6b436b5fb6eb64e081d6d45d0fc9ae3a9cb5de8d35a13a2b86b69ba153a153a14bc173cfad8c05bbcec2dcd1bbdd095dd759d05e9935e9b0a8afb39f8df9b1d65a8ba3a30144993a6b24a6c2ceda60456bbdce5e3bc4a6d00575393a5417769ff56c673b54175eeb7d9eb53fd6b32c6bb2296b2d0fab4277f2422b5edb59fbb2162ca1bb616f673f94f53a15ace775ddedae0dea3a8b4277b2262bdece5afbb22974a7d0b357bcd6da9fb7343bc41e1e0c9ff5acc95e1a6b32bd503be050c1b2706dd7815d98ed48420e6a88b59dedacb5371efacd97ac61bb2c49fd7100838b161ca4b841046ec060e41081b1c595a862e03648a1826c03eec2934891451449542a122460d4ba1451a97086103072e4044941831384631ef003068c8e1fd5c9fa80618be0135b23013effc55bb13454b88959e96cb63040b5f99c1d3054b1f1c10ab14fadf026d8f02a23f0e0b14f09ff4b84bbe7eeeec3dd95b82f71afc1dd593ea64a803736612094530b27583285a2089e4ee087f2523085dee791902a12e2c84a64812711e8a664ec4d8539a4b607e38ddf174440b104c674a1e9dac0a4001481a5130e29f3dac408d1f1e0f86eb816ec0182a5188a009921a2bba75ba446084b5ba0d8ef35b3c20c42741705efc68b2518c0585a2109141264848af0840861c4d209a625a91b502c0521e126ea5310967a6c9390d8126368f260bea37b0412428877c6bbd9116207539876b8008ae8c589980ef5cd301306dd1af20e578618e1639d829c5c009bdc1d61d010199042c8102a4802070a4c592400225842e164072002c6256331b074828f10a730083c8931de0f11215e0aa720a110446088c4213886829c4c435244668f0c2c99706d7c4ee06b0418f0841a5af5c080a59338440523012c7ddef859d006f0f4f100779032a070a617c421e0293c01068849c73d6232e1460e1750286187c83aa2c405214e622bdc81d9f92192244cdd1085efe5f99852f7859f213485a78bf3d5708166b01f0e4ff5959063124b2f6888078d782ac1f423c48f23281e9175755c1da0039676c45c201f0c9f0a261d37878c8e97c2104b2d1cebc9bc9beb7d0058f5c0849a4a20025ab4b8220107541180274028e923592e633d34d181090e3710252942c39017d00ecb851658f84b8211ace183327620838f1656289c10564101175630c08621195e299090428122c8420310b0624515544851258a1b582fe0b40e00c51a6aa061a4830f7ae00198ba4412a7cc078f53684589293f26187cd1002baf201f136ea04e62980307062ed0249b488ed04024c850020870841136b6f47040021170c0932538fcf8d0dcb82ad072060e3e62f03185e004a2688002531880090100400109484012488ef8e0f142caa6d111a1f372bb7c0f3a2e77071d18df161b83ee059d0b4c5ea45ad0a9a0eba2cbc2934077746b568798c29703e684ce848e047b636684cf463763c71bd3a1be536712c52e0cbfee5acf5ad061643c1c5e0796ee00966e1170c7db1008428c0c58fabe54e8420c84b852e85c1352553c000cc0d22d622ae19483868825530e57074f05d40653621011083c793c684edf0996442c4b379a0861faf1a230236583a56f8da52f85820b96527bd58125134d4c17f2f870be26a490803ac189212e124b322a199577338323d2ccac31c407830814f6f064bc1e62154b9e111d1cf0045eb1e4a14014ae0d4ac7b337756d4e413e18c21c4014c013584bdd48dd30d1984a0873f08a300488827765882fcb520bb56b7b580b29dc574a069cb9d6bbf17edc243025805db824c4111ef94888b120cafb6ecaf3bcce0b3dd1339d725c2fbc21b42193e4341382a1f5c2cb7371ae154ff07008615ae17bc052cc1542cc8017870864886b832156b0f735beec00065fa8404b09b2e066444a4c19129221861f35f5410f705e1865c470071d901c5923052d58c10a49e450716206286cf0822eb6f000062460054ecb0503e076127a05c20fbaccc08b168cc0024f82e8a1890e4c901c11126405154c28218b0d3c91400482000296420e355d21c6063570625b5ae38b1082d06407134a9879c11624f880073070810924418023603de4b004c911225da4800428e00095213288411729d862041ee80003aa10401144fca0cb0bbcf04007b2a00094a56c12199a81e99283306c5082116c400358344089016413d643931d961019e2f1aa9981e922052588e2004a40c9660f34100932c4e31503733d0761749102139060031ac062020d5882005078a081480c3c5e3f3c3a353666aeaf9183306a6082129060041bd0c0041ab08412041800941bc0786822034e4b8d348ad4201343831c53901000932539530c400039250898d6f0be7445f8d2e888203ee03aa06b40678575753a5e8e6da16e3c18bc2f61852e87c511a2e09d6069ae09b604d308366c78e3958189196150489d80ca719a318522187620f87d9e757714dcbd051f4396bbebb5955123bcd373bde164532dcf14f704f4111cc3dd451fc11bb8bb0b3e8259d4bcce3b67c4facfe6a9d3f3f5f9fb7c1eb915af98563e3edfdd6fdc1d0815ac8da0ccdd637c0499b8c77e969e9996f4351f438f67c5d0e3d373968ddcdde4ee475f19a009ee8ef2114cb97bec65eaebf3f3ce19f1d06ab57620e2e090ef8a74cd7be31bceba61f0f13bdd9d041fbfa2f4dc3a9b4f2b37b6fd56d3d75935bf8695cb15a736193f17bed1cd346ffcfa898c3ede2d669a9dc7dd57f0f15e71bdb6707ce5e30de2a24fdbb334a32f533f9727aa7f55657bc55b7f9ea57875b70b70b755b85b2a6c0edc1d878fde0ff7209df7f1eb8a2b7704050105fd04f904f504f104ed04b98274827282828080807e807c807a80788076805c403a403940413f403f3f3f3e3f3d3f3c3f3b3fae1f9d9f9c9f201f209f1f1f1f9f1e1f1e9f1d1f978f8e4f8e4f500f50cf4f8f4f4f4f0f4fcf4e8fab47a727a727880788e787c787a78787876787c7c5a3c393c313b403b4f3b3e3b3d3b3c3b3b3b3e3dad1d9c9d9097201b97e5c3eae1e178f6bc7e572e9b8725c413a403a3f3a3e3a3d3a3c3a3b3a2e1d1d9d1c9da01ca09c9f1c9f9c9e1c9e9c9d1c578e4e4e4e8e5e5b365c8ab36db2bcaa250f271bd68905c403f100f8b739d99c00f0760a772b85bbade2eed7ed134f6e42553ee06e012adcfd041fbb00fc2b16fbd7c92616fbd79665f4ff14abd9b4d9b9fe6f594659b17f99193db14ce3186270b70ae88adc79dc5f9f1b67f4afcf4cdbffd2668a538d5ea6fec6a9eeeef9d8a9ba7f9b175ef88ddfcc47e599e29bbb4d801563a6084ddc5f1b676455d77528495d5755c8dd3b1fad08dc5bad127cb4a3bbdbf0d152714731926acbabbbc3b87fa47561d4c0e7ee26f8687170f71b3e5a21778f41299be9b9669d9e7a6d99aa0da7cc48af4fd6a719fd1e9f8dde44712a4d7f8d7737b83b8d8fbe03d76b6bdb64abbaaef953fc664e57dcceeba7eab9f14eb32da337dbf9fbc4ebfe597aee8d6dab2a7becee9f7b07ba7b0e1f5d8a5e5b65468225e115a75c354ea9a228c6c9ad78353a51771b85bb5bb74fb85b04b8db03b85b28fcbadb276480e285052c20c464821657d460a0043f24a141078a645df088914287582a1d00691921a945042a651c418fa8c204b4aa51808e96114e0840cbbb69203a64a84929820a9105a201b440b9164b4ba47b22952da81f82e8defb20ecdfff010245e183ff0314292ff41599fefb20c407573f4479a16ff54310e09f56525ec87bd32a087125e5856c10e0ea5b79ef1f04685394eb10c794aa134a011144f7e06aa97bfba0ca8550a8174df74d1d94fba8b72a20c4b79d98523d5952459141c87b930a8a142be47d141984ee3b0c0e1beea7bec843a5526f3abd142b647afba00a0aea4faba50e8a0a08d35b710504048a4c6f1f88d377ef42a6932a85237c19c823efadc875ef5a8c2930a572a1930acae9411514d3dbd46ac983024410de9b564bde9bdeb48222e58552efc1e8e07d4a054410de9f564b1e8c0d3045de776f5249b142a6175552ac90f8271594283208995e8a153a3daa53a5deaa50efc10ce1b0e17eea75f01ef5a00a8ab8e489506a0504048a4e6f1f08d377409cde822a1732a9dcab09df0aa586303af135c870756445ae7b2b72f7efe3b0e17ef7455e92ee41d5fd279d8520be0b5a00950282e82ed4a9a2d828178a14fb5144efa77b17b22a299d940b45ca5d41c0890c5120e04406f2c87b275d0bd2b34b50293452661c7d7f3d4b03cabf77e27da808650821ba95931fc8bbfadc5fd602287ff2e4c87ef8f7defb9d156f68ba5e189ac255cd7b6b125747debdf77a5e0d32dd0f35fba6b7e00f48dd7fdbfb1f48f067f03eeffb41fc56dba3e109198aab5a785547dfea28fceec16f06afd6bd3d0a574e4850e5e407f25e7fd17e57505e13dff4e1a35044bc6fdf0791ba07ff5339a1218fc077f2d4a99cd090e06a7ba4e92dcc104b8aa655edbeb872f20319ae8eee83aada5d39f13e80721df6ddf36abe4fa931deff7aa05267749ee77932e1f7c17c0f9302616060be460d9818181893aac68bcc0e285e4c0a464646e663626460625ee6674619d3c780df7b30a954cd979a2f355fbc2ea60babb8a38c8cccd7a821b303895146261c65762cd57ca9f922338e325fe365fc1a354619556d07123233a34c8d0d99b7b103ca2833dab061ddfb19e1675ef47e6efc8c98850c479955cddaf81b2af76a6cac6afbd658a8f745f8e12853f3a5e64bcd176f8b4c1782115e2163bc25abaa8da2f7be020379c5199debde78df72596218cc4661c20155dccdec8487998d3e871ae18db3d9ce7d7e2ed3539fb2d3546d258fdcbed9f2e735273d8acf75bfecbcbd4cfd9bbaf7a9944d95b6b30d08d779a346a7d6ea2dd3b6b6adf833926aa4ea3733916caa478480e4732d5acbf47cbd8c6cb8f587bbe3b85b27eecec44721a35e5babbaf19af7b9e36ae5dc189937f95c770088d0192d531c6c679d53d7adb3b9d3d396ae38a38c74a21876cbf9089684693bfb90f32a4bc2b47d3b697acd69920ab3e1bc613beb9df58a33aa612886e5725565266ccd325a8953b799e26479ed21061f8798b89ea5a789336ae28cbeba5fef5326c3e937f3969d34ed7689bb631f6530c3dd7d7c04a2867bce4e0fae5c8a5f67db8a354e3d91f29a64673d3bb50e2c23a9ebed86cf8de26c308d61682e535ce215877f30717735fd221070033f677870c36da5d20d8ead547abd6ca5d2cd283484bb933e0a91ee1efa28f472f758ecffcbd7481f8bdda448be559337aecc4af977ec785a79d29258af6d8fe2f4755e315a66f33f092c3ea802c50d32d2b931d2b96613a6318a62238d6161e0800866361a0289c4770efd9b0d6f9d6d6751ce0d6f6d3b772e1fe5f2112ccf56dcadcc3827678af32464c861d338e9a6aee6a7eaa7f908ef9c69e29c12927a2aa9eb4de3545b2e5553bcd36cdb65aee5d5cc658a53d314c3724aea7ad36bcbe844350e8a9e329d67f806bbe14c83edac356ce354da3e9376d63b6ba55396d71b0c45cfa39d66a40ca3ed330976b4625b5ecb8c833e6fa43e6f78969eab4adb388cde6ca70da7b03223c16e3a49fd2153d5f506d33a9b6a0acbe7baddfd867be9332ce0c0ce44b0574a2467e2bca264be21518fa0382ccb408458fac155e0e1843bde3a3d6925b6dd444165969e6bde69164014abf36aa227adb439774ff2991f626676f23c6e79eba35245b3ceb314d3ca97c9d43753fc37b5c8dd81dc6d91d6ce3aaf38978fcc9c4353b54c71327dd28abe65e6ac77aa96aff7f9366646526d2693c9744af1e7559565a1cfe5a3cfedf534b3b9aa655e5f9f9f7128c6c1cc398cae1909c9a7f8d5fd2cb87b1133405471b727104d50027700b8bb0e77570288037a6d9930574ba7b5737393dbe78a6f37a86bd62127a41eb1e16c677a1a4952d12cf46367adc9f406779b650b5a89b3927ddace226bcee122ea111e867420420403320404c98f2343302548942819820d15b9010812233026a491d70b6bb31c221a223a378a33e2d3e352938af21146858a2849a21ed1b9141b514990e623b5c8dd8e8074b72230e263a6a23f328a3355dbcfd2333db12dafff43af369c4ed53225575c59aa2979229d40326a84d11323e17c9a1a67cb46db4ccdbc715ecbcf4624eef5a933cec9a7e717a5d90775957d5e71909db5c639a337b399d3247cd39fe66ca47329b6bdaa16ad3987d1473199d5fd665e4f9c93f4fc1bee4855d14cdbabbab199d3d9a9535cfa234d52d3a3f4869a241535fa127f6bd6caacd739cb3edb54fd397c7b757f6e9fe86984532279c56d9c2c3d51f44cca2b6e636cf4b4bd9e468f3fc5af312dc9a66e8d2b5b9fe24fcf3733ce46186de99c91302d876daf79d85e9f5fa4755e4d13ff2c3dd3d9a9518c7392691a0f51dfc4422170b720f0d1a503afb9a7a7a7a7a7a78787878787878787878767676767676767676767c7e572b95c2e97cbe5d2d1d1d1d1d1d1d1d1d1c971e5b8725c39ae1c578e2bc795e3ca71e5b882828282828282828282808080808080808080807e7e7e7e7e7e7e7e7e7e7c7c7c7c7c7c7c7c7c7c7a7a7a7a7a7a7a7a7a7a78787878787878787878767676767676767676765c2e97cbe572b95c2e1d1d1d1d1d1d1d9d9c9c9c9c9c9c9c9c9c1c9da0a0a0a0a0a0a0a0a020202020202020202020a09f9f9f9f9f9f9f9f9f1f1f1f1f1f1f1f1f1f1f9f9e9e9e9e9e9e9e9e9e1e1e1e1e1e1e1e1e1e1e9e9d9d9d9d9d9d9d9d9d1d97cbe572b95c2e974b474747474747474727472708e8c7a78767c7a56304c57b556d3622ee6ee3ee398cac35d68c4324a7e72c1d32f3c6e6ed8635d336121467a21f6b12f3f52acf35a77966cb9bc8d679760271b71fd0e28a07dc6d07dc2d07ee5e5523f27198a6943fb7aab66c7b77375a62dd7368ce381423592b2fb45cafad9c114c6b7c2bb16ccd3b3d6f768ad3d376aea53ecdb7e1d2acb37922a9ebed6d1a27697588defa541ac21b03c962034166e969aa65069295a078e320eef60a8fc9438fcff300c2ed80b559669348bee58a72b90675df726bf97ae575aba8de2a4a549ea8112e09ec76c3af57904e4f8f6bd5af175e7118a6713acd3a554bd84deb597ad2366ccd372097ce0d66563a83803270f79a8f2d80eeaf17eca65bb8b9aade6066563a65ea4e4f0ce4d2c17d7afe3e65bfd514c5e9bca6ee6ef351870e333b791ee5a798b65feb8cbecee12414bf3ebffc9cd123add94c4f5b5ef5dadaa711904b07a6d77c43334ddbb5664f0b80278c407218998f2cd8ecf4c4cd4ea3f2dcd946dbe78a71b4151a50d7ecc3e78c3ebfba7fdf6c796feccec3dd7bf07165e6ad730a5bf33e61367595f98ccf94c1041292dc3e4b7cc33fdc6d06d0751d2a55142535d12c3db53e8d106161f59c4a04ee3377cfc1471513dac6379cdcd669e9b45c37aa2c3d6f328a4b8db3e3022a7390911914e4f229cbac736353cb96118eb6cf596eddfa9ce535cde6f95be394bcde69b6cdb27edac6b74751f2f572b75844957f54dc55ee1f12ee8ec4c76fc2dd62c0bdf7bad7f996dbb067b92be5ac4952f554e283a6f19099ce61349b69926aa2aa5ac2702b2d6f6c9e668a61365c6aae38e98653c236532d614ad886db5af51f772ff251059b99e6ad946165be699c3223e1f4943b393e3a5966ca82766419fbe4f4f0648c7b7e4a1f574e4f8e69649a3c463d3c3f19a7dc1ab7e21019a9a890994db54c876c251333e3346f5ca6ea8fd7cbdd79dc75f0318504e8b575de30cca67112cecf8f0be7e4c87080b20b679edc63feb864403b393c375b35f111aadef0c6e66fdc2d3d7d49994df5477acece15890f1f40b81e65c6c144919829a9779eadb868a7795d713f727acda7ecdcea916c66a29c677813cd4e23a97aea35e3e0ee4d2e90c38ac6498fa2b814e2630e2698f6f8d3d396f7f9199da5a77ed2dd5d3ee6a07177575313071aee7e838f3814e0de42d19ca4f1dba419e99cfd2c3d5fa6feb772288a937d699ee6ebfc32f53569665bde44ccbc337ab3a93fccbc6fb875cd3b25422b3716da693ecb94d4c161a7d996c33798ce1a67342b71f7177c44810c773fe2230a51b8b7b6ceb3194effa6cd4edbe75b6ee34f3fd3b64da6ed34db70b3157fa6ed6ce634df6e98f61ad35e7f523e92aaa7d69928291fc981e5c05c38e4c072603a3894fa34927310776b01778b85bbad808f2830f1597aae9be8f582ddf42ef1cda6fe78bdca6caaa52a4b896c8d8b9cfb4c89f870a2383d830ce5d0db8df4a1315ac2d67c53c2b6a352458d50bcd50d53c2361f3d94b0ad3c757aae5b29c3b2c6466b4ea27db876703dd69ce4f5b20ea051da655e57b5fcada6fad7979d6fe65de69b527e7d7ea6153d8f186c5561267ae28c6266a6e9333d65bf66133d71427a6de97dda4ed4dd52c0e67dae4926ceeb122320d976ee14a72467194ce7f02db7aa1b9b293682e235df90a0d8b6aa47b4c6e80f9dc349dced04725e8394fab4bd5e3acd47ea7ebdb4c66dbc89729962140be99c837a44af2d1c14bff458020cdcbdd56abdb0336ab3715e67bfd523dfd28f628ce24a14974fdb67d2cfd2334945656b3653dce7157f5ef242335246612fbdb6681ad3707072cfce0fcf8f0e8e8e0be7fcec943ce6ce0e0f504efeb9c91baf5b1be1348ede38f5a8ccb412679f331c75b6e21207c5a58ae2ac1a8743d398f67aed55bddd701a966d789595c072dfab4ad3afaa9ba631ed5f59af1929af9f1271b757681a0f494f4cfbe1c3478f1b3692f35a2484e29daa3e9cab4af3013367785537d1eb95cf75c36e3a6fbccd13c5483bcd6ba6a5a7ce48e73e6de73ad33673c54969920a6463d84eb35e87a0282e887a0476b3954a18856dbd9eb2ad4fa50cd3284e67a78f9a20f9662b99bccd9a8d6cb82347a58a0ae18d4dbcb30d966d1a3df1ce40360e89995322395c6613b6cb73dd3aaf3058b6e1745e6fea6a9aa84ad379a56d9899e69bc6e924b3f4448d4e2299aaae49b2a99619c84eb33622f56964abaa89b392dcbad32114a7eab96f484c9c959838d348554836f13abbdd60e23ca47462c4890d48f6e124cab88cb301480ea359494ae4665b870cdd6ceb10772b8108641f353f6eb675889967e6b91a916f6312c12b4ec2ea51661c349ad314d34a98d6799da5678d6b07f736ae1d1c2bfb706a18addcf8a64fd3c499062b9dd8604e6ca686e58db786e5309ad7d7cb96b7ce69587a625a89577cdb2a4ddf704a9437de44b3f49c61adb39122b8b7ccbcf769b3a9e5c9ddbd1c95d8e8cd8ca2eafad9e8535cfec6b45d629de2757f9a6feaab47dcfdc67dc8672a806aedaccf7da2385df356ca8fa6ea7a22a5433c58c00833f0428629c4c84109acc0a0c70e24804f440b9c662cd08512bf011fbaf48c0be4280207585a9029a2c813aa2930ae02448105163766d0188026055e340048102b280a400c3500dd2d04dced15ee55dced03dcad03dc6d03ac152b768a534bd8a6cdce9cb46624d54cf39a778a537fe4194e62668d83e18d812865332592673849fbcd9a588ca5d773e31a9355c500aa98558164ace244c5172aac508184bbb792fc4deb45fecd2b5d713b87e6326dab465af8a758c11409982288bbfff0710a4f0a2f528c408a03489184143ddcbd55938495752b1bddb4cc14ef122b65a27fc5627fd392a92f43312d1b7daa6214e735f6372fbde69d6d78c5495a3022983e354b492b16d33886a2b88cb98d40b6a944af61b3b396d7e791f33e9e8799691a77fbad713400f9c4681a0f89bd4dac55e3a3c37a33c71ea32aedd3bfc9b6732751c246f0c6ac34a3ad1a566e3d0cefda89c556759738888dc6d18abe7593d7dbe358ec65ead6e989436fefda314d13ff9a6f59632120ad580d4ba6661f4e1df3e1d48f4d137faacf5773f988f5d94433cd26aff835a6e5dfea91ad1ec9a8114e6f0072dad69c443d62a637c8d04ca41ea1c14715ee30180c96bba1a66acb1bcf329acd56bee58a52559681e494d435098ae212a591eaba669ac634f3f52a526529112caf181452a088b93b09c50c4e4241e3ee9e22796208de32f30de7f5354e22cdac0445cf1a92f211f3866caa3f889e90d27a62881b51e192694554444065a9cc376dc32915d66cc5ad3775cd3edca432f8e8c4166f9537a99abec634f32c4f1c91bb0bf9e80411a31343dcbd158b7d6c557fc4505c9e43ad1cc489159c68289b6ae923978f7ce4720d3dca8c038a9e466b4e92cb3518c0010698e21eabd13180e905f05200131420a900b5029ce0ee457c6c02054d60d1caad19e9f55993914e9dc65e2ff584dd74ec358ae292f5b11a221692d8bfd40d4b7119dba7528c2846f4307cab89254d745e98e0c2c4164c54c104144c14b9bb8f1ecfc2b7f499d79d9798696ee9fc4daba6647ddee79aa4f3373235f62396f4b19a1f2c24b1bff1d1e35968c5b2a99631ad9a9f9497b8c1124d2c91c4dd5b79e315579646388d7b75bfaa2a593f2ff91d3b76ec68e97c84a2670de312a27beb8633edf50b46b6ac3569949710298165cb482596f669cbf9081b51a287962def33132501ea21223a7f1f615b3657f5d35335c21a6725df2af34d7f6eaff9a6aeb75f01f568bd2a317acbebf7001111bd995b2fa4e7ce42be958f54a4f4fc1497786353a5693cc4cc296ebdfdd6d94455d6df723eb2bd912fd2d266aab1d1bfb40bff2d5a2cafb4fd7aabe9cbceaf617dd6280ef22d7d7eecf32db763b8b5686b1c8bc5f2aa6ea26f6dada299b667b373ddaa524eb55ac6925e76c66a6c5eaf22568cb6755e65ead6274a2b7796695c7e7adaf499625a996d255e773ed7195e33d28996379b363bd1d7e5b9f589a2648f8c691a0f79bd8a6e7965fde34f734edad9e867e979bb6123dfdafa443fe6a3a847cc3c33ee73e83ecb13b5e5fdad6f6914bfcdb7be158b7dcee87726fa56a9aeb71afd82be611bebf5b774a6694cbb61233375ffc6dd505cf3e9a9d5a26f012182a238d90d67da2bdbf09132df88b2c6792d53226a9136733eb24bbc6ea521b5c8a6fe48d523660e82a2f847f77d3e6836ac1f57aa477c60040c8c308111594623b030c20a23aa8c463861c4008c40c2dd6f2aebfff5385fd3c2dbb4f0af9bfa362d7ccafa7ff1b083fb070220488c456881c468840e46cc50c3da388a1aee9e85fb18e5071367330a0f77c79979fdf4bce15fe74c2df2ca1ad392648d69371f45e57953f74e339212bcb129cb4a34de18882a5bf39a7d80a56aaab4f13a649bbd5e45b94cd594062589bb79e25b7a43928aa2421071f7117c84b202941bee4474518514e0ee311f7d10f2e1c68727a209b7a96b109da4a2283904114d74466f6fa63835883b41c40e22c67ffd018608c3dda7b8abdc0530fe7082ab1ec5599b19768473122c87e6e30f3be4720db395aca115cb272c55632aaa3756822335fe6caabbcb0f01b8e31587613bc35413a7cdecc309db254e33cc1352e3e3132ceefe1b7f2e1fc1b6524edd3d1c82e0c1f8048afbf80489fbbf7ee3afc9b85c3e62c160a592774bdc1d061f01d085d7d213aff8f6b3b3a373ea9c7ebd80d8fe2f130be9b57573b399b97c84a3b4614af906af38bc95320caf387ca3336a84d79ca238a4f4cc1bb6b33653d508962b3586edf48465249cd1543d6138582e4fa4356bbdb6d60cb3954a7acde7ba62a331d783dc96dc16feafb7f9d73ecdbce6235c94940be2bed3d269e9dca0382bed9b9b543d71344d631aecb671379ac643b6aaae304dd378086dcd26ce43922815e5d98acb7c233a2ab352d19acd3413a96bd62197a97a24b7cf25fad439cd428eca4cfb91e372ed2461252611a56ca6f8f522d775e808c990121c6a40f27af9f4b88698446c25131f23d214484620b966e0ce43139b54bde18cd46db362dc12b81ead1c9a35a66d21ec2976116f6d9cfa66b69d7b55dfc67cbccfb75933524e73789ba085a0abb89ac2f211deb1239c33f1a8d3968f7a061e9abcb6d9a1492bc5446bac5b9c8726366b14eb106fa1282ef17acaf1d1490c9c20e1ee3c34b13dfe552dcf8d6deac6e134888f4e5208f2f116c6ad895b0fe7a1c92b61dbdb6cdaecc4ed12bfcd46713acf4cdc9af57933a95aa4a4aad523a997b40ab7b189d5bc8d492486846938f3b3d1f388a128fe117b9ce2728a6d4883488b9c87269f6d6ab9713849a60ed9ceb095613380ed077a065a052d6263a4aeb73423a56b4652678f625c8a8d7c2b97695be3d435cf526cd6a8fb4d9c57d6e38a5afa4c4f6ccb6689d1db0fa1231ce9e0688af3d0e48110b1d9a1492b29a7b37455d735ab2b7e13d3c8a3f4a8873b0f4dde3c7f872638af9f3333d299cbace4a8ab91c14393ff1d9ab4364e22d11307f951a4f3112eca5a493e73265692deb0d34c449e38777793c974cabfc3675a91c9643aed34230d9d4bc6d3dd5da67e0e27bd3eb78dc6493d7ca461f13316a3f19136c5dd93f8489ba155a3755e6fe7678dc3653632e2e38c8bbbb7d47d93d7d9154f4fdb9a7736f50b3a3ece6eeefeab2a9bcde02dd9101f6565b8e7f516fb5c24bb2263e22e93e18c4a7cd32f53ffa8c4e8637dc3b43527f9567a7ecd2c3d374e5d55f3d5ddcaad93f519a7f5a9e635d38a64392d9db7b8bbb7340ee3315bf15636ca659ad72ccb4bee2d9d536e32994ead9d5154a69a4ca6538dbe31537ca371769070d4b3d5d2a56ae2e0bcf46d6f1a8b07bdc30f93c974eaa1a40af9f081a2f8c7ebe543e7885ee32feae1c3470dab87ad64e2c35632d93a9b3e7ce0d04349152a99287918cb23466a784b1bf9c124f637ad9c8d5e9f3275a5ed1467b3a928aa6ea521230fbb002fb9bb9ea567ec6f5a35a791911f4c326db3643813b9fb8e8f3133624ec48688d9b8fb0e3ec25430c2b680ed113683bbb764eaefc83655efe091aaa7ba73686ec756d31dfa447132ad7359e2f493ff1a2a4272a4954d6c5353bc6d38d3f6a9a6674c09db62ea91560e45f1aa7e0e3567da16fb35d376a625fd2c35f5f99f922d1b33dba0f8f3500f26e8e187d6f9eafe1c3e336dab1bff9126dd7d878f3c40e1ee487ce4a1061e5c3cacdc5d898f4db4b4f27aea6cea5595e5d09d93d4fdaaaac4c80f269f4bcd15cff2fa1af7b935cf52157d35c528ae3cf78a6f8f95340172f7231f7740c1b843951d8600f17187db3232f2b972678ca2d8c6cc1a47dbad2277b7c1471d5e87137220410e58725892838f91c90c98441999d0e0e312182c5181bbe3e0e312002c6101872e707080bb13f988c312776f658d69e58abb7dceb237f28389cddfe4addaf27ad3a2ddb472ce260e2dd3f37cddb462ae1d9348ec53fc6b4ef34ca63ef9af586ec56779ca729a8d627fd362e93089fdaabe8dba3f5653d36ab1de66a779c549582e26b1cf46e579cbed47d173c9b7b6527ec5b6ce66ec6f66e969a6f865ea0d9746fe158bfd4deb489feb6f9c8d3e876d1a3db14c4db19973fafa5c559b4cfd186cc77e5565b4194ebde1de2666cbfbccb2d8cbd45fd55d66a48fe95836b1cd3cf5abff39076919f9c1e4df5c71528af1cbd47476e63523a9fa8b6066366da59246f336d3acc71b7cbc95c3256a84d77cfb9de29caaaf7fa028feb1716ab69d7bcda68f1a20dcdb00e158395836ca615b7ace4e552d314c9f59a7ea4de73567e2ac64969e669a93e4d68cb3c1fde208c5a0080977b7954a3033cdba282da2bdcdbfb6ce262c6f355532e4eeff5a55592b97e2979d6f936778ebd72fec7355cff5f658e35e9f6f636633cdfaf16fbce68fb97670b1cfb46d63e6241545f1c6e589de7040be95a4a64747279a93be2553df9669fbcd9c935ea7b9cceb6fadda5ee3b75971eaabfbf5e7156f9bbaca5233e71545c96f6974c5489fa4a6479f8be0deccab5a6a9596f43ad3f6dbc472aa1e89bd8cc8b764aa911f4c5eddffad1a14c5e7cbced7f9ad71b5cfa128c6691cebcd7cbbe175eb93b6ff656aa6ed6fad27be7d4d2cf666b661bd4cf5e971bd2b1f61d428976bf896bee175ffce5aeb7cced2539da56a2bb7669c93ffadf3c628adb4954a38b95b89f39ade90571c7ae220669a89ccbce68d9e1935c2e90d19353af79a9152225b3d0224b76fb6a155a59529ce4a34162ad5222616528f98d9e85c4b6d8423ca3e9cda86b39d4ad8a6eecf463e9cdadd65dc3d0ca13254dad6a53e6d3058115a91581121f77fa9fb6dfe655357d9dbc06af88127e1d5a4ed3309564306dc3d051f6b40c0bf545ad2dbb83b10630de3484319230d5cdcd84aa55585d94aa5f484a5b87cbd66d46882862afc5f1bd392fe65a6385596d1ac6f56756314554b186c678da218b6669dd714a7b52a4b4fd8c69d5abd65339fd4a8e4cdb265494d32c6d0ccc88c20000001a3140030401c148a86e31189a4c628c7f614000879a2607a54180ab4288c41ca2063885184000088012000233233b30100870c9771c4d9b9be941a434f685cf0ca7ac45bc35241f2b7651f01d4257b69c5fe74eb15945d89a1a71d105d63e74f3e8f333436695e9ea6b25b8b3f3cc6c6cbc7a955dde34899139fde3f9854012ad40a07bcacb176192a227440bea0f646564f2802d44525ae7f24c0b449ca238db50d56b3aff93d59c9c926dca13afd790bd040cf3f4be05fb3bdef6bfe474038cd707b8f318ce78e035360ad859a9fae9f318a78297412ebb976efb7100eba64ff94d940571941147c6f108288a8c124925de521644b05b30efd83e90cd757521497dd0052531f7ad94e3497ef22979b59620e2bff8470686f4ba4546c0fed69992bf5e73b0a8c5a80216d69fc56e423a7bd35e851ccf76c7ec4597517bcf39047aec257cf947ef1befbca74b3b1261f5c4a3ed0c37c900865b3843dbc28b62387a4f2fb69b0188bbddcde2f02cd6bde2a1b992ee1a639146036a445ada95236628603d307b7c6155aae4d34874b45b47d904d61528396647e43a8d431df40f058382e3d2efa1a6aa14051122e1e93babab0fb937a9222ff6c7ecd4a0a5e7277f1f3708ccbaf16b5972bd693799884814cd7edec2492749410dc35f1904d41137616efd29495874b0657ef35626548ceda0e118403e4c62d54123dcbd43ed193e101e13a6e57124610d9705f746f2f33a952728fd5c07ee0f388474058211fa7a122fa036d053b5527e18194a825c6d08e5e5b347eda3e0118816001aaf2592651318e86d2d15305238143e1a563e4f65768fb2b23cede819486a9a7f5f1bf49ef399c45ba1b9d8dd6e3b69448901691c606d16705ae32c08a27a7a5126f6f49e296f5a933efc11182fa69614b0a3710821f829d94140ff03f9538c5a88db1bbb107abbfcd08885302ef1bd2f9fc6842f25b5001bbca8eb02ad4c2293aba0b6e52cc8906cef233bd05dfbc27bc9ee4ac3b6993b38b712307e22bc3721e8df32e37da4d485a7236c751ee6a8a7e755ee8625e009596b537710ef140207339a03a80e01cf70fb46a3504a9a862da42610b119a1ab13b85ca3bf91ebfa4ef4b7de539b1fb8c37438e6b205e40f2732caec2d229c82d64e65f6e4c52d244a289633db145be359d12fbb6d7c176b50de461b01b1612d5638cbc45be4ac8c101668de7286fb143724148d9acbede41839e6e613d0a40542adb4c0401ae23daf6b1b94e8f3cd27d3e7cb0dbe352471a50169be57907b34077e865d3796cec183a390db3b1f42182cf865a67ca8fae496833c4564b078ce29a1e87a02209df5cf25ae2879a14b185f32aee7efbc598945be01ded3e1d47fd1777fa19d85ec75c6dd43877370c0ad81764d1401dfa1d3893da7dfbea8fa3c29f0d691230bb9b02128bf300c8ec1e7f2e334cb9e49f2fbd1fb26e06a76eaef710dd94d407623210ca34a286a25b177cbc262678d2e79c7f5131b277401e2d8438cb763f91803fcf446f6759c9292281a188786556e8f00236c6e3db67a1fd081ad957e1d930b16d65db6d93fe034ee5cebc0fb2509dbcd99036565847a6db0aa2e8553c42ada772da1099006e13b11e81a997bedd3f0f56578578b5eb42beab221668cd6b8f2961d258ac0a637aaec5f39ffbfda8cfb2bdc206d41b88a20f92eab14bdaba30d363a9092534b33c1b294deb5079d0ffc4de4ef523a4d46a385e5f4e793fde7cfc09ad4c05f5e0b0b382377bbf37dcfcb19a7c3da1b64e89330fa312b20b0137d7848cd932aa2bd900c1b634f42772d62ad91f61346da84e5e9594492b816ed1c4c1c10be092095f7222912738b0c6233d5bc55b2337acc408ec7d0322ce93a174631d3f213a5d162c6d087ca13ad14c4fcbfbc2ca5bb4711a15fa189b656d122bba2f8589b6082fdc2183538a04f14b46b95b3b5e3d92531c949ec19a84ae6a214d33037aa7bf5ccebf2fcbe542e8e0392817549df2ee242ce6863a58f108a3c90ad386ca7114fa21efc3b2bd683ec9c84933314ee63de971273961efd201797814dc618a741d83a38059a7670d9a99c08b03c6b04d004b42383330424e2bfcbd55150cd950c7beeb822e26f14f88d0d082e0555d8137175edde78d7f073684c4904bc4c8914dbac1fd582bbd6687688c3060fd27a6747229108fdd8017aa7e1fe8c439f8a3c0ea9c5d773ca90fe6cd563a94a6c7b6f216de3e6dad87515f9da7470bdcc46a5b7474e50250781ab802c4c6f2d1236657ac5bad1927e773d83555b345d0821c8beaef31b63ae7dc64b9a3808d2015810a2228f82ce8bca1e0b3e8693422316af800d7a15ed544048000a30405b2d558c4c265a2265949e243ed63a844ed214c7ba192fa4fb45ac40c93a41b1af163f272517a35ecc092a2b54a2defd3604e8e7c32a8c8454b39b0f4803dea7081bdc802482d5bdf17a053abf7b0f654e98f56853045994c6efc284b64affbcdef8bc08a3924ad83d0bf9e409bdd693a69a51d2fd3cd0250cb5e05bdd520c1094d1013d83e6a165306bbc70b0e5f68f636ed76fae616fd7ad23a869457a148cdedbb25934adda015b567ad34501a4c3a66e06e2bf413303be00af48f5fd7525a2b14c09c3b438ae4031c3ea050e29c8aab6f1b28b98e3228805a060d4c1f59f02157396723877da112d28eff03f78aa6115d98a770461ced27288410e107277692af29d9920f70513b5f25cf3670d35b3e04808f5c1dc575a4bf69653ac68b1dc28779a7b8e2d2c6d7a18e1467dd3a55822a5b0043146134c55d2c36fe5d6765c7cb60c3ba4a37dee4f0956d9f8239f68d3b1227c0d05c8bec02a97c9329711de047c4160f3a7e57ca8774850c4c88a17ba89cbfe58ffcf10c046d1898a350e5bc2e6e823ed0c40d34d129ce262dc5e6e51e9d92aeef53d362f1566bd9126c9e2357e5cd2afc33b93c3704aea793a05ba46cbf2692760a3367f0aead1055e3989b6a5e5ecc8e52478dd6e9ed25d652c5a81f4be67f4600f81ea17b372579c2a673f9588ea9f16334d58acd710118e5a91b2e3f1824057a1702e30fcd1b6236cfc635c82fdcb24d02ee9490308968f913a3fad57cfecfc7ff399450396a42a3b286d52211beb912d7239dc55861f200f43d12f23d26a6514bff07988c822a6d9f291ce998ffd42a09e0e55436838826afb147bbc4fbabd6e252f16b5568140d2aac8aec316681dfd6c767c38f1e4879833f3e05f3f8553cafc15008f7b8db5df5f1f7a3bf4f9b5fdab9f2bd06713cb448577bf144fa27c2ec14f0719b3a3c8231641dbecdb1be1c08dc7ed8a597076701c152f20f764f5cf8b3eec023faf428a6713cc00232e6243960377f487c4f808fe3f790c61b24761f36d0ee53d0c0447bd3ac7d2d71febb721f0a6c229db8ba1fcefb4b659b58b8aa03f0f96577991d27ca812474416470e5e384116278231ab28b6cb0133fdfacd1517949cc6d10df53383e701190d6ce99e24521238ed5267973f1bb20fc7eff3ecba9d51c24ddc67376d421cc44759369d3c6a54d98c5bb635b9c0545913245f0f2a63621a0f0d8275704e2bd459a5ec8c45249db54cfd109c5abbc62a0c66a267f82228d2a434cc5511bea614bcf3ad1e9be381970098dfe0586c84977dffc3829e4f6cb98b9a75a38e9996e8e3f0b2f7a4271003155624b40d08da36e29bf5aa9ab1eb954407aba47971a69906309fc6f00b5716299c4326a987d20c5bbaa81596067837b01b94fcd591784b54d83a4502670406c4c5597f37778477a72530263938c24c12f6b5d3d4decffa0820b1b277433450f382cf544a7798fbe1e7a6497749aaa8a257f73bc05f3346cca4466361ff72a12904a9a2fd18eae34e7e0daa20bf7e0aa9930dae7e1886e70d02aaae50b15306e25a451b6f2cdbe097b31fa6ef3311f34dcf7501e97138e7583bca8d3753b1e3654560dde0200a9dc79328605d39947fdc9698e064ea648b7ff9e3c539b2420a667f8d23b7424d0b79c9a02fd02adeb5acf9ae713317224781bc1bcf22be29a52f5f2b28765dc3d5337d94543eaa79e4875a5ac36efdd388824443eb2dec150939d847f80300860b43885123039928988564ea47e4327973899ce013b5d7ac4e06513242a6f093abb2aa2ffb92e2fcad681934674dc80adf80952721709e9f3bf08a4666239126569bd63bda334eff87baa2880b584cbc9851ac57c4c7fb43a1dd584a7ee3a547d8bd4da09e78eafeff1d223e1e54647340edb363998f06c3fb068a21e56ed92f19d5a98025bb01dce85a7c0dd8562e77e6d36e59ce3944121c2c1065dc7284cfd9e8d0b7e3f6293b67bae47165bc78e207e810d19638541c035204896b04e1327bc703f4a97582e14c327c78a7beea57cb78ad9d39ecce6bfe2e8ce0cbc5acb44a93452d290fef6138b89c128e0bf7f8fc6a6caf8bf3cdff6dcdcba1c349f33e1beccffef926fdf79850d4623fe60a3f0812bafb30bdcc3cd0bf8e952987c6c3fa4cc659db9f605901013f754c7fe6c63581a7f9faf8d8ebeb287dccfdbf667b51caceb6ff48b6e91350959a858fe5644492c3d4b06e43b27e6c982f9348694785d20c1adc60fad81300023c3a18e0810640fcff3af0d3e39c10e9b8d7ddd0b3543c9bb678f6794266a092d3e5160648f53129a884e762d0261ce7bef877b6206fbb5662dcb2615ee507f50dee51af4f543b4b7effc0a6cf5031787ca6b88e62865a7647a735b65ef30db6fff12716bf2c2e2005f3f24eb5e8fb852760e73295a5bd4e27fb5ad044746d2c3de0a378730782499e246646e2a49942ea484fea1d32fe8be076982cd1201c25969b71b370b9574f4d01f10962ed54af61358b13e6d13dc53ad832055f42712284521440d740cc26b120933d01d83e00e8ad58eef75489ff6527fde4ef6915f0446df6944414d0b706b8b2290d9f3e0f619ea01073ba0bcda73e86eaf442833a8e510cf95da0e58f6decfc07ed4b88bce4c3df3ae733215d84ba97f67bf97a2c2809e3ea18e5627766406cf3e678ebbb230c1f1b1f66daebc2f18f092e02ff44fa46feee4d3c021d318f1fcf4b470e488ac9887afc0573152e9348e1a77cbe682c6b57ad48f8a86b7cbc3bd85d3f5f841b11f8a50e1af4849ed257f14103ada16fc28755a1d7d18fab5545710b087747b12a796b08a6f7efdcc55a1fd4f9839b8f2b508acc5ad5a94c5a4a4d82b568deb49a11694caff76fa859a146990a83ed0a88c13678d26525dbee8f1da8e75de51fd5c6aeb62dfe329627b62f68205ab1c7db38e90b48aa7f8707172c7139cb0297495b963ac621a291455b0e760f8c2cdaf3c9f51f18aed538c7deb2ab3d2d3c6953e9acc1ccdb535a0d16a982130c8d6d79cce58c0968e55bef1f00bfac3c9754d1025bcc0baa6cd968e19f83e9398d1d8cb6f20f978ba1add50e514d312e6671cc8572dac36fe8ffc9eb764b6cb505671d64cb6cecc016d978c6a0dfef4661847f3c9c87486b84dab9246cd217b31defe82073503b5ef64256fc1a9a5b2b665941705a3b941cb34d6bf4f1ec7974d1a24bae25aa8686813eaffae82ff66659d8b8f934eb7eb35c57afc3d58cb9fa19d8e03d7b7a2037a19b5c2813211b4d300e46264ca4440f95b704bb371dda474cec62c1718d93cb8a7594e695ae1b0604d64113481e00e1e0cc0ec00ec58fc58e2f8514d921edd5983a8874f0c6237966b61cde949ad8d9c2f74792c6021d5f151676f9b087315726412f24d6f3fa678c2cbe7aefaf13e623b44edad16c6b7be0a83cf98a114a99fcd8064764cce17a395699134532362b7bf99cf0cd704f6a483e60f67853c4cdc6ec393d0e3047c6cec9f53852902b8d73ca2c946ecb0e3ac17ee14b63f6f1e3293ef96e13329ddeb2ccb7ab7a61ba99d0cfc124c96494f54bba2e9dce7289d6138ce8561be297fe158c2d134734b91cb0ab1c044fc02876d02afc65d131621fafc413dcea769ef6b2703bec65a875a503116ffa4b83388b85328c353805476f3602fc71ea3c61d533e2ee4ad9ad74f5d3048d47c0862352a7e2aef513d3eda2c7900262aa07022e8590e7b1aa14971fff89b525c981a14c3cd75b38b477c00ff80bec8a516e0fbaa924912d47938d7df98b0d1867d0928896bc6ae6ac66c1a80b5286e1283861beac540f5a55eb720e91c990da269d29fc505d0ead722a6c33edf912ee12566c05420887831d0e5be0c64646fbe15c123c45962fe8cff4fa22fa05e57062c02682745b33e6341736608ee0a109a3ff972cde11604cb477247d9c53123fd7eaf3f6991a02a3c7ee77d6dc4ce579f746bd80c0ab0a94475b9f1d0512ddd9424516e537341220a48de5f1de1cb05cc70f4ca214c8f2058d04fb6d59c81709da7dedfde3183a8fe9426bdd381bfb99aa14a274cfe3d847810b50169651faf425f33cee5c4f5fa2080b8dce31d1472f5a00762f3e601a71ec97b69f0c0934350507de832a9011307b88622014a3140859fe641b517ac20f9d47fa1d29505eca14b5a4e32880584ebfcf215be7cd2ba335895247bb8512ef32a695ad18dc003c11582c80b758d16eb325854ab4bdea551d79078548136a337766297fb5ae5a3ca6985a0c4771cedf68d10ea61311dba06b91ea085e5e3cd004d02d05000f9983c613126080f20a72c97dd479b4b1c101b2c4a235f08d41c5e3a45bd539c43af9233a2ecef28a09439a4267c6ae8216011bdf68ae8b733d97db44655f33d129ebff2bb2c11b858dff1caa0b338732f167a3e665bde25a3b8e09b2f9370578e15b01309d153aae086326c528298cfce88cf5867e8616df6e94ed9980cd5293d5f5b5d879128a1358498a768bb971e3cb48531e7578c1842d8139e8e5deb0f1aea28c2fca5b48a4ad99b51bb3d8d2990fe56d4800af236068235e66b81f3354d136f515d4398b9a53080cea0582ae8a1f93e00e63f73255f8288f586456324fc0e0a8f0b46a75be92b80a65a95d4e38d2e67389e9239d199c290de8571497e4dca9ef1901a1f4a7f89c18fdeb2e85a5012fdb63c57e047b4e429e111a6703072d678c51f4fde4a30c649fc6e4ce532a1c8d827796e513b24c4cd4ffcf6a50723e6b006ade3c1f2c715628b6114df5ec91a203e0480849aeed7c8770bd484050851d80f93e0736ae4532c00a621aff8becb599c3f10dad04c3d993cab5b4f98a561fec7252804c4886e77f3e10ebfdd38fd833011b79125c5ff7c7390df511d13e41381e1662f90b3c718e740a27ae22ef071942604b290abefbd85410142c9388f7d78d597f83f32f6782f50f6ca41e5ae61782086e15314ee7d7b5caaf79d0a15e019dbf4b7d6fc4df856204c60dc90b184fd79f9b3813e6f930bba6dc0d686f175f47932e26437207722d8e10350b93558cf2adcb39b432df4d937c8da12bfb4e1e5e79c32312d1de99775a7f6867c56cbe8ce9db5a68c3a4c670105cf8a29b7448b7ee55c93007647f3e4f4e900b710aba5c287d94e5a699c2c17961a156e6f7baa82174cd1c289e97b5ac92a0df713568efa4a7781c7ffb25aed2329030453485ecc2fecdb5522666a7f110f43d9b8d814cf171693ee4627fd3b74d6f72cb30d5eeacb2dc1917a862eef7f245d159a9fce1b6b42dfd039360e866318e1b9c68d17c9769f549d25ca6fda3abf0ff4f0fb397ce4aa51639723d6c5356adbe3e23446433a8b1500fdcdf4081d8bead9317f2734fa908615df5cf34940baabd7dcbe56413e43d0efdb2ed17b51edea1be6e2e03bc454936df84ad2d2ad0dbb44b03d2df10c4092c2b364ed259920e84c81d69e0f2a4d243ba882f68a5758c62d6938e8a68c24de463ce1cb575c9d322d30fe8501340f5e6d4f223e4069c4fe9f2836fbfbd3b37967eabdfd1e8ffdf57331bc4efd77795c87586fff04e38a48439e492249d33acf3e9b02a910d441545a2d291134c5fda08ce3e2294789702eb5506422c0da60a5f4bedc628f52f099eac63db1f6ceb064766af4eac354871d9585fa21cd5ad818a76d52552c17eb0f395fb3d7e005502b45b5d3c392f42734201c36fe8a4b4514f37f0f4be16b0203a1075340b2f3a2b16db15b25a1479d6cb75f4973fa40ac8799fcd6819217df06ef2e8c49956af6fae01a45aee0c82c5d12a9a5efbd7b2fa694e8d4f942839589e278ece1f922d053de16679c9e20c8e4c7136ec3975129209459459f7d0437bc0bd51ad0bf185a507050b8f873cbaf10724e642f6edcf8a7ca89eb34f4f13f11f0845de4662ad8fe3b5f4ac526e8ea1b07eeedaa4471b7ce1050d4d975c6de083a015cc6a1e4977e05010402683ce5b07ea4cd7332eb74f00f3d26e7532b9340a8ae4af379a8ae10c0e81e3e96fe20d7c5f00365ba1c981a1227a6770d41f91d83ef06cc38d133b0f1be6045f425d0ea6669ad99a1241da3621343c3c4085c6eb7858b51a27fcaa991c6a12332f5d82c2807fcee3f95349e1d2c624910f37742619e7eeadce051e5cda07c99a016b65fc73c7ec9b4fb0b2622e279dd4cd15e3dae50ac25a2a3b30ac2e47ec96d768c135a315a2e6bfd464e57f3b106dd1436c641c9b599d53589f432ea8ed17567ce1eba340a161c092bc94e87a9390522f71c5305aed7fcbe6dce8b5b09836f8b4440fdcc3572b7e4a1f24192e2307c67703e2b3bca87664d5df7bdfa88abeb7cdb622d0929f177238d245521bc1a80eec5c2a68f86a59366eb8e73dbd5061d3adb72fea64c5b6bf048da731811712c38d0e4957507645e113023c84c85b16f556926a7e1a84efc355440b744c31bb91cbc5a6cb66308416fba4f2af3b36a382d974461c59de5a12abd2e871f8ae3c86c8f231c7b0951cbf1661dce415bffe2aab18e528c4bc9259493e234e0a39ae9951f8ab041237f740126c47f26ea96812142c5ca66f0d8d89d9576c3d61ed3df8c9d8b9a575a1e121c07abcb9b299b2f765033482d16f59e03a958cd6ab1cd8d5d6089ad289c5d5b455298359af79c864ae0b01be191c484db308a41bc59e953a3d028b9a8ae9bb0b835a82130ca3bb809847b6731772d07d7634814da96ec0c2f16fa3dda7c67a87faf07e744533161bfcf7b3bd1f676530bdacdc4e027b15fe8ec19f62cc2b7564a61f287db6b1de978ff359c8244cda70c1aae3e0774c49076a09581f3bafa1c4f4296dc56302c0e06a460d1c89806603dfd0fcc829113c2fe9b4b32d3844b1c2bc9b09d8e2de2ae569e0caf6ed820ecf3cf8a8d2be86e3aabb5a410efaa677219997d842b086e0862bdbc88f197c2201efbdd2baef219eb28ac12bcf7fb476fed052ffc769b22f7c4e8cdc29536159b9ec54fd15516947753a567226500f22b30fe10ace41ecae056d40ac614f7f1e63a63f2f26312144e4f775546fb3dfb71b21d2f3a5139e24b062031a046f48d3330d498ae99f0e535b44ce0349a0189b83e795500e533c2c5792be580e57f3320ac444d4ee1e3ed70008b42d8aa323db347780dddf49f301eaefb7a1fb6b5249e0ccb48762ce57ddab5d684d0662315424592c1270e0433140d54866606a1677168ed42e335e3dfc81f59725e5cccb93c7c42226cece8b8c5f91e9b823924e8621ec389b73522eebe6ed20f7e079b5eaf9749414667f84e461ced369ddd9e1affac13977f3ef6d89dd88aea0be00240f8145c5eb95f4128f4bc3689ed1d4d06c339b4ea67d521359d9351f09e2536c73c190c87606b22962db576f0e8217042e93e0fb1f8e97f6cfaac7639c360e8696d32bb332b0c667370d7499766669a8ea3b0b5892daeec3018cca17a27599fa9d13894c2966eb2b8e563793204ae9d6c7b4667c3700ad8ba41dd752e815bf6cc4da06dd8b415cb26041b966b6559135a0d536ae5713273d658752fb1d3b0557a3e8383c87e793904cfe156edf5048ea27beae9143f023bc5b7153808ee95b76b680c6d959f43e43cd4151eeef128b65b3a4e9173b4557a3f8199260d24da23a720703c381c0d1a3a198716d01bb4c5d0e3d9eb1f953c908c7bb3ef3f1e9f8aa5a723369e50ff60b9ecc64e696732d76d0570f08e896a13cb3cfb9418aad423d94c53f9bb6162cd5df61aad3c74dc1d0f6ab1c5ae7bc8d837dcfaca12b5075b7ca6a79d58dbd2d01ce9371d1a88fcfdb4dde80a80e9389df447f1a51a904f86fd3098d380b87a249fc490e3b0a1ddccc4981706fd1c10e04a6f83127866921db22e7c2dfa417a482fe9d45f09e0708f2de24f801d71bc256e739aba36e7f4e019934049b86ecaf296024620a85b77512e62f8e0eaf938fbc3c712e0fe7d90b793f99944b3c784fe7b33e6ad566c91e5e841ecfc6a38326d306ace6e8d93dff62cb5e4568f4fc55a7041523aad274a3e72c2eaa3180023dc047414fdead07cda5e6637addd5545a3e3c98a166b3c0e13d8071513ff0c474ef0c5fe9bbd1f092eec5338b43fee3cad09526ecfd8fcf7965c8341164bfbeaf847b93cd194e4f1cf5a0ef16d2ccf0b663a5a1585e36bb187cbd5fd79c45dce63b43bd35ebb1fd686e63e737d6decf10302c1f4356ea572d87e465812cf52039d27382af4ced5defeecd43efea18a6ea42195ffbcfa74aa059e8695ad11e9faaece6e266dc62b002357509acd446a48c455c68ff19316b276186c897efa36311d8661b83504e09d5dbf37dc894ba0c86149a6816c6e5832c66d77d6847673b1a42301a2c4efc69f1293cfa6cd49d4f9331c1617274d8621d75441d1e56ea17e805ea1726707adc52ff8de8e1a7e3978d112abfaa5a132fdd41dd8ade3e1286a9a886bd6fcc0d7aaa5c6a275169e283c7704213b16844079f56a52f28ec7d88dc55070a9aca96b12d755f53b8aab8413fa4c371c5f1c57a96840538fc94c8cd76a30e296b93cf9d9b9f6e50b9105bec55afe30ec639d335d7c29f1de7bc797ab943de5062df31da463faca27cb6746a867ccc16689c0584bd535657bee7c35636a5962ea044149a5628df1f9f1990ac5708325595c3364d9ff6d30a15a51537b72e3b6ce1cca9689edab3ed0b199cfc72c189f3fc53945545a5ea4bf5a492c1c46f67d8892e64c26a029d9acee2d95bce81b07e563720bd7153c1f541c353536988d9b6910f1bfa456680f6477f812c9dda6bf5f576171fed62fe85103bf3647a7370a12f4d96232bc43cb1955686b290d508ad6344dea9ec2228b7d5770f8369edccdd312a2858afe9e1241e8003b5375dc024af6accc816abfb3dc70fb8706d88cca0206d70d96588b43cc4d24e8db6319290695f9307a5bdc5883f50764382a368f24339ee75b4607ac992c883416eebb46d1a803e23d476ce449ede8d3bddd21eee16074f28f2d560762c34889680a9028f0e085ef4df21d8627ead2ccc19218f5ec56fbe3c3877185fe5eb1d696bbbe58753fa3d73de8f55eb5cd5ce182fed10536ff457bc53037fe11b85299f7fa46d3f506708a297f4e88e05f25b4fca5eafd013abd2fc8bd6c591ffc0ec64bf852203dc84cfd6b0fbc5bd377820f6cc54f7bcf9ac7a0e8411acb7d418db4f73b81c51fb9376fc84faf02dbffb51fb29c6cacf92cd3f514b793cacf4abe34f89950f71658cf6d5af1e3fc809ca3286c079c9297cae782202323fbfbf069a601a4613c0cff12afebe9a8b317324b12972fce892b3bb4db6b6907a31ca8856acbad574a126c9be597e9ded6489d36da07eb366bb4121c4f6905366833749b0049b1cd3d08f8fd2069b471f6927e66b817e87110bd7ac98ddaac01ded1a78df96c07f6c3f2cd12678850e5f239b9214ef09794dfa05fc73ca4fe4621f68f4c8db3d6af65d7b10c7eb4cc767b5fe99d1545b0f2bd45efcfc8eda2fa6c1676c03d85f213779d82d39c866213dcbd9c00aef71411cee71fb1fd8f85bf87cdfd54a5fce97f97acb98f09dce1442d70835805023a6dfcd98dce5f3d12050c8ca0846be3ae8c735cef8c0b98cdbbc07ae03fd26123abeff74bc71a3a5e402a7acda2b7260d8f5c736dc8f8f263daa77ce99e58befac55df570dc56f0dc6cba92c14d2d70052e926e72482a1ffd7f015cc3a5f014ecba2b37b51479834b935d2037d27d0f89f9fa3dec409a19829a1697e175585f1aa3a0883649814133a6febe1809bdb28eb4f53b13543e2197438a8900f18757618a6a072b87282a323c1824db2cf6e1a3434e80dabbf370ab318e583abd6fc6516cc753eaec6d599ef0170824fd88fdfa24a591714fa1c242f1595be193b1dec2fd4ff576d55369c4a8bdb37f847c0d0ef82387cfd7a4f7b8326203a29680ab106e5db8bbb881430b68fbde1d96a7705aeef59541d77166f105e3f70df5d2932e2a1efdcf885002b38abcbdc838cf2028eb5bee381df6424cf3cd4735e85050e2ed6c4bb236a721b870ed70b55ad87b3c9925301e97a16288668d46cb4f7bca0c0318a4d02d877ffb973435b2833c050c4bd1a5b7fd1e030d61ed5a6f9141cc97f6a0e64f816fe4bee54367544e71b0c88750b48cae80f79559a5f4d4dbd8233a1b19e160ab886079e353a5f2bd14a033ea362111ce184499570c15bd230af7e9c98797430f2940cdca23c077e9428aca16aa816e0a7c9bd31d9a8cf5f66366224587ac1ef0906c93cebd96b1aa366d44ecde706e89ead486813f7e77acd0eea56fbb64f1e828f21ad0d1c50f3788ad17a95c6f06006e170706f7835ec1874656ae1fe8653d61997d7cb0d6aca926a318ea96d55811fe1dbae0611774f1319ca2c19db71e19839a4a9899b601b5c18a72c810ca3086758bde69308bb6ffa40a8b9e9efe9d354d0422686528703be0d94982ac29a24af7ad940d68cd6bbb14928cc4032a27f4213e97f984c0e5f6f063158b8804f95aa2578ed2ed85b50711d81eac61d5dd0c81e0ef94ecc3f06146ff1bd11176a604fa6aff46ac2d71ccdf0b0c31184b13002ff4553cba7e9be215366093c089e2e0071fef2c7d20d1a9293f92e85a5226daf40726d1a5f7b0f8646eeef5d2055c212718f38a2eea2dc664054e059135894e7c792fd1a57f2e4f0b0a6264dbc562588babcb7bf87a563687c8e6ca06288660f923baf8a4af44e307fd687499c48c3b9e988c7e4f32edcd0a7f4113fc9a756cbf98c150d7ac7ae6154fa9280d1320713c1c2fc1a6af6a9eaaaf75284a3fcc32f7652b864f0475ca3c92cc6e4cbdc31079b0f2f4926ad72bb6ac140312c06ad0af98a6ca11dca780ef2bfaa12f4b6b3d1266e65417f5ac840a27c4808568662aff68bb1851e6b393831025e9e4966667b66eee1ac3f4b67eedc831a0f9aa08b59313f4d2bfa112d82b71cf252da3bdfe6690780ad9d8238ad111988baabb34c629ac8cea698d87e500d5329dda17167b848cc6bf5aab2fd424c6360ac7c758bd13bdf9b3586011ba232c9aace4508925d4ea9b400a4de1e84a2cf421c67550bb8e58c13b66559707616257c33107402c5a4b7a5f0c4162c9623d6ecbeacf478232c77a2a67ae7a2b29d565051cd0810b3a43a00f87bceeaa2acd4f11ab0b4f8adb100a07abde2e909f0dd21762cdb61831e54aac86079fd33ddec930ec5582a81ed5f050d4dc41b09e72fe707cd16c1a302be98cb4d7c3469f168ee720a8588058de21bb8012a436815fbf47d4ae781755e5f2f11d35aa7a09c79748924c40190ae1f8181afaefacb2b420c0e1e91d146e0b33ee4445fe555cd799e7f88a4c988ff16ee8db97461c4a31cd63f09835eee54bd1e6c0896799b9f2cce3f79ea7d19b10643fbe5d84280baa9a6875304cbdc4ef0298762092f7cd7884d1ee901af21781c59a141542b0149c9243320c66dfd56f4ef55abaaba7838b4e38b73eaf56ca1da7fb6f9cc213163dd24cd86f4e793582a44c6c272fe0128f1584f9bc85789120800e0b0161bf1dac1b23946334621016cc086b789c58c0efc237b14b8037e112d515bd4204ebc1147e379634ef070c719487a47897e50b65afcc8dfde2061e2185312300bab271985452266ee4392544108d869b253e55e86e4489f40a3b3099512c8f1d0547c95a18732f742c9534ae0e2c1cf59d76ae227a245e70d29403a4ff281215c12ea312b0757063f9d28dcf45b5a842dfa4b1d741d24e2a8050392e03e04a305efdff0b3244e840f78dc29274188e0d802c7f933858883a16f2d0486baddd7f17f27193a1a750136ae3db4c95052b1c6ceb0f1a5dc3f1805c8775251ba15442e6b2182da96e04daa9d0b73dff79dc1c6017b91267f05dfcc78922bd7724c78c4d993fa0ffdd85a070b14bdee371d8f0dd840f8617c7f5c1d8b77ef69516ba0b8550eef4835522c750b08b69d6764b2408112f8a31cca335c5b0d333545f64740bbb1d47e150b966c9ac1d4a63452a2c283d34c11ee73067146f1b50e607e03c0a3dc57dd5ec0e87bd6c40e89be3f759e28bc28fe099ad2359a6d1723022d77db5b75d727e193d0b7ad51faaa35343fb6e516237d03642dfb0b9a61ea55c1889ec228ca4ef2d235cbe43f51f91aac8b3f1c3bee5a9534f3a9660beeda5150a78782ff9ebff8e660ca82dc744d7624a0f45b8242f43a55e786671372e9775d6d939de160f2b5128d721578fec0a3c872707ef152fea513f1016608febeb59a39170bbaf406519483342f83044c80be9c7aa88f09dc802d9f05ee4e2d7ee4ea5d166020dab03f76c2237714bc247db9998313d383a3ca257acaeaa9a149af101e5867a7e32765562f2849d81e4da7176d20de8290ff43201ef3cc96e881dbd34b6c7d1af96ec2d8ad7368e62284258582fc37b4278aa5001910eed19b6e035f2a3bf8f0ad65f1326dea6403f91a5e6e83de61e42edef9897bcd65ef9445fbbaf9fc350183d3ffa8fd33e6684f947c226f7d16b51cdb5862420d8d03b00b9e2e2d118eaa333663686d0c386dd5ab5e4f25bad426db909da944e152d7918a099825ef8bb61755c696c7024bbd045ad01c379636dbed3fb17245f9e2050d123fe447fc61131ce6dc19ce52f38364a502981dc38645ffa9e114dbe144ef749746e7442a29fa7fddcaba1466b289dbc5888633a9569d4dca74fc43bbe71026eeb1871ebc99fcb8a252d57632598e58585608454c807707cd873eb79e63c7405a677b49f99f9db3de66ec1dfc825cb3e9ea9302c5483d664842da9a5a226a9777b71c59e75371a146ac1b62cf6ad0504b1a0e4138806df5ed7b325b8b7318ef447b1ce23ab393ac580ecd782ff44df88bdbd849f9eab5d11a8ece8b5e748ce7745405e14082f9eec62bcc6259041f115c68b7b0f34b01bd5fb1c43bdec870cd1b09654fa2eb47444ab8dcba6fe549ffba09b57fa70286e46ec558ca4df855f5e2b20953e05e81a222de5df747ce799c96878788a8cca997c7ce1d596dec9fbff7e4e00064558e4bbfcbeaedd0b40752c4a8a3dd1b7ad36544b97266f11233da94e6a428a98696b28ef6a8f5463c3aa8be553d430a0625ebe40a6f13183fe6d2e9189d6e58e34a91e8d9ace9fa861e80defdc2a785ff94ccc0ca383dd25bbda6abed14dc81dce0b1b8e527351b6511601d62c68a8e78c916936e7c211a3327e51b2c6bb17575913834e69d9751d29816c67ad8d92762a1d817b85e56b2379a708e04d05af318b5090c473bbd81a62b5a9ab87f5bdcbb865b13276c86fa8389fd8a2c0e8bbfb5ad99caf009d02dc5debcd70f45de898c3be1190935024a6aa337e893817607ae6b2d32c628816f28ec06132d78cdbb1c6b67ee08e48a9f1f290732e188e092da01cf176b7165292f131b687208513507ed21418bbc67e066c88f40462fc3ac3e3ffff496e7aa71d4e38bf4bba333839e0628d4281b1341d397ba9b7fb51c2afd08a7a460646a47c2360f5d149c6a92cdcf1b7df4732634aeedede2719ad6cf541638709e033329eee344dc8b668bb085c0e8aed0e17112f40baadb9e7e9ac35e0ba2625862b21d0f2fb13da7303e9582897bbd4546efecbb510d07b6d6ce863a3b1e29e6691e6f51487fb3b1845c6ec80e00452c66180dfd17305682f2c73ac47a81ae4cbf2dba610b5640d1132d305b7c2a0cb2a9f534f23c099a92ccd5a80731c38b0f82b0c1627d96ffaeb31382e6818f29f4ae63faff5cd10eb98f4b7bae0acd7c864ae40a78abdb0c322e83c3695807da1d33bf0776eba931332e56a31839a16388b92587bd4527c8cba63ebd8f665f616976066fef2c70424a623374e639b3dfd662c09ade0615645af1faec35c7fb6d943ac8d4fb222b4d29bc8707f71a50ed12f6d0098ea10f4802b1f736deb1968e5737f61334250d4c09c8885c30a51fa105b08aa1af1198735f8262f8c08dafe63408f2f26b4b37325629d1c83033b0f8e371a03ee900e18d8f37983e30bc82b623a627a05faa13419e3958d7af22f0ef06c44fce716545eb22422f8a5be6b3e149c210a783a9ba7be4a7dd1ccf0c4e12f03cbbed1d9c719299ee03a9e21beb6317e4eb09088e8bc2502ba29af76ec775d45e684013c4468b3b77b95db197944b71791a3ed62ef2822741e36d4ee1045c4d5b0457378149a4dc7597b4705c8b1959d0110e73183c87a101da8d209afd9432ded98342790df39eb45af8a932e9a8c6128371e6ed9d7ef12287c42ee66494ad5e7ca011dff4fdf2a069b9d582c93959f818d83cc3611e248fdf2bb2a9ca653ab7795fcd7647bba0e927886dd7cb3aa4e0436dff438d4c8cbc556cb98baef5e54205ae9b76d4030a1dc917a943f2b0395dd32f2b436fccfba488c63967fc7e807ef95401e912be4a61de00acce0a12e4c97a49947a0295d15c4a31fdbf12105663277cc8c0598b5a66183bd1c0fea918ad239501e0cd03bad634bdce5535ff343e0bc643d97981e7817a253d2e79268f793939208f8a718e3bc3333c2148e9a145732f21f4fc64b441c52795c0657f655313e67496e38d2d9e2b61b9b000bb037538b12a3d09b5b4b33621eb87def115708362c22c910b6e265ac7009ce76bae69361f7df1ac9d4cd798bc22ff7026ede05c1354945bb3abae5577eb03520ab6e36cc139343268ecf04fec64c456466638affa2b75912320068a1d256580893682baa80f6fd53116782d4496cf361aa3796117802c1e1977481e49a981dab689b94c6be5dde3e275e490f7a1e873ab6f84ed0a804acacb6ba15092f7f7a08ccfeee162aac0384bf2db0856ab0e600b6d8ffc075494613e8daab9e53b7f24df1dda4ffc0732ec0b36d71df171e59b8877ab79bb5ec9ff14c02a0d9d4f02dd19efa47e619e6c0f0d3575fef48c99f9efa72345cd243700fd8520d6092e737e249657dfe68d0b1c7ce67ce4d42dec82ca62099246e90295ad98a416c3b96e12b655a31097ecfba812eb0424312b1e0510459a5d90b19d67800615373b4ebb452ddd63397dd5d2ad913bc34d5e988501f8b223a4073e8077d680b7d0d7d971304a3e553d218a99aba9e5cff80ff324ff3d7e4310b1405ba9d0320de1aed41dc29ca87d4566ebaf6d66e8fa88f0b89d28d3a42ce845ceadfaa12281ab34a5ee30eec84eabc4aeb9b985de26e4714463304778afe29a5a5df8e6d248ba745c7496fde1f38700b04ec0c950324e08b7254be0935ed9ddb3d10ddbd5246cccb84a932319d06fb83de80dd9afb278aa999396f21fc041f038cf1b4d5739e3d03b975761cc2947103e0d67aa02fa7240cbcf534d8abc6f5e8ec8b4121911f55fb7f638ea9a7800077767a5791bb3fa8623462f755e70a655f3a39d358206ef413b02721cb5d0397a9777e675db3c721b6f4274d5954fb2a5795307b99de59d4db871e3c86f56d0f5b16e5b9a5d9d395d3e6c1f5f4cc7962b3b6f71a024eb38a35001e305b25c13946e98a48d77a560ffcec587f764e9aab37d6b4137e07ba2769e03827dad453f79172bba1b8d60d34c1f5a08fd5799cd9a97ffc6553e7ec5e9da7cc6c42454b3ea83fd8cb7f8a1bcf7bb7db21c39f51335eba4076f61e6fd596333f98f05665b3a140dfba9f46ea23656d318a1ed555b3fc4eafc3656d2a20514dbfa9ff51b175198cc97f8aa55acd98da96f514f67a4a91af2fc66c84c577a750a2da8f7d95b3896d4c45eb77e9d1cdb2967c4ad4d756dc3753a44d147c6ff4b79398c0a16fb11cee83d5c57e0acf02ca043523f614ba6d66f106234cd9ecc5a36b19e9fef9c8a7f516a5debc36adbb862baf429bf331094fb88223a17504fbd5c41706a7739a668ed1e6d6bd4d1902b6bb827656c38496f5d32f0e393ac9eec00c59dadcd49ac7db427a5d1318fafa62ee7f301ec325b29dd218b758c12a41a7550259c979b846138074f15ca10753ee6762055077995b6179b33961e670eca9f9e8565ff558cb0c9321adaaa558c80e80edfaa5b49d5b6894a29f6772511482af7b021186d7210dc8737b8af502937ee8080e8a0fe8f4b92d9e907f7cbef9936311b44277a057009089138008b5d40385671639023d73d59f90a07c88e37d82b0460486ceb357b26cf5a262b3571c7f7a91b9c61a3a62cd73513d7ac10ceca41a39cd88e3efee71c21237ffc50a1e9f0f9d085823977fee0d6207ad7b9e936ae4b411ebffcc2fe3b65d619141935587cd74a29a21dd93ea1637d3643b18603b19695c2c96cadd5bcbfbf7a1bb0ea7b302bd8928b47d1e43cf5fe23b4e4173286bf660073cea733a3d6eaf595077e484a2878ab611f151241ef980a6ee157a23f782cd33f58274e0c91c8cbb325e42ced53cb36caa7ec567a48327a81da7f3214505d1f39f32fd8863205281527b1eecf51c2623e6ca1bf476434226ceec2d14aa6c77a60806107f2bf71e601458ac719dd0a6ea358f4bed81803cc5accae63fd642bfe64c280c050b658ac240a00b42725145924a7ea7fb2b29cb2395d9eee1a8a697e536791baa914cbe87511919ccc4ae5f536e51e484448125103d21cf29bd5ebb9894621cb7ada6f75e48331a037519badc6d61266d4a909ac07c726c4a24086c6c7c3205a53be3883c8018042d3232e5936997bd37d6d8ba10ee04dc788ba48786d4b6c42f28af377b4c2709a9b17bdcd92add267b02066af2bb077c2649b8ffe6ceee10e32d4fdb521af3b4bfa39e3ab572ad76fa1672f64e53e752b343a7933af6d8b17429265ed811cfe49444819f303ef93016e044344a6f88981af1ea9a71cc6b0b20520e2decfc489a8f5605509359c130081d545ef2341d16fc3132e63bf144fe19cc9f7c64d8920b16040f972c9c5aae9b110a172dc4b60ca90815c70338927b6e381321ba5f2ca90430693819684fd58cc6f0bd84500a5aebf28daac1b5bdfa485d248baf63c62819a7353d0bc4be51f3ce9dd76b52713892b2e3fc0f38fba7072bf80ff0b7c1600bf5d2feb99863b04f672c7ed23b1697fd16358e0d64224a85631ac5cab8e02243d0c092fed89f34709c0fee5e598c0f7cd4430a9db87620c36ebea1d9a901c422a06a89b0acb14de64fea38d130f17d90a5e3e94242fbc0bf2b3e8852a9f427696d5197b18462e13e388b9f8dae7dc0a76e1c1dfa6222cd68524473362089ea60e3c8c936a57e9a829f7a3a5d7cd3d46cbd479f423d64077d190e2cbb6db9d4bdb60fefce801b6687dd747c26df663db879065a71045c1581ad863508d5fbf2b26aff6b26e78d0b3e8fc285930a759653d65b0950f59ce24aa0cb273f8e77a4c6cf0accd5d7dacf98f427099e54f5f31e0c4207422262a7bf039aa9f19f18688ccfb647370b6b7dae23d0a171503f06efe62366c9759cee59c0cf8fb159d2afa65b3747f565383d83a4784b21c0f9b7893f82cceb90d52adef2ccce1b56fc00f15645f4e3e3ecc05196754fa3a043b977549e81a261be2dc2b255ff59737f1ef8cc9d5dae3b2fb959324000dc69e10a8a2fe565ad4049de8c93a5d6c50f25dfac8ea37a2f91e54a9dbab14f39d0cc74f70ca148ba5fa21b387c7053d69b4da642a4450268e79c2182916776c174b5d488fd7f88f60a1db06668b6d4d76feefe4932379b6126a7f9aa02eb348a6f0955be7ab692d8aebb399291fe5788f533037eb95e9ce92d9adbf2a3498f15d50783e53223a082e7e61dbd524bb9f867dd9f98c99ed8be0f450f534e8dc7b3e070f8ca4240b31bb57753e025774a4e9a171bcf6031af877f2714fac8eeeaf6ff0f8971f097cb66213341d9341af67b7dc180b1fc48bc880f4f0520dd723b9502571e8a83827ab88d64b21f5f350e9f4bef21347f2f070da39f7f23081bd85e271e1aea3429b33695cf48a333c3ff9f96895228a901d681bcca3bccd238b8b86a19661d79b999d8cfd44f6870e9bd5eed1e7b1d137d343bac8539470b5021996d679c8cb1c580b92ba627b059aadd3850de173b15e29c6e13f30412082d4e7a17a4a2171b04b758bd11e8a20ac2b60d4b284f9f9a8bf1ba0ce40ee68e0ae70d3582b34713cd28dd37cb20716bef28fbbebd6b5f0630342c0c4fc094e5a108fa80797c06ddce727c67d17b713b8835d8b75f13609e84caa333942e268016e7e1f1f599b86c6e413adff37e83c0817b1df5881d6f2f625f77f7469190b52efeb25c3a2dca776ffe1189898dd5e124d2468e7a3b9124f8579d1f5f202e28ef3f97756fc71568bbd75a2e9d9fe137cc3eab5586dff0e9778f518cfaf71cb4954e3ff20efe74f02df0ab6a86bdbd3e883280ba3e0af5cb4cb71bb00164da441ddf06de29ab7403c8691ac4c9e7508c77af9ba6cdb9e828f7354ef3c8b98de0b572e277f79541c6900bb2caf94829e8eab66ddd18190bb5b99fd4298fe3ad71df74986df161aa7ee88235cef89b684c1eb5e00199a529b0701c4dd8c468983aa4f410085d0cd5b41368bc266d729394d19b87070a4455c915b4263b049c6772c8d7c67fac13f4d2a7c520232dc5a4c4838dece517db9de3bfa28e09b9d1ed8e7339af8ae9a3a9b0955d92e80a1d671a7442e10d5eba6c845641374141df5b52ed72ae50fc8a378f096c0ac7dc6fa2dd186033b282fe163701af17a3f2f5aeafd986c819341bd4c0f928078cb0c42244035330e62eba117333815ca6827070d7eb5961e392ba08316906aa87cdf3b6cc376030668708de70bbe3f5d6b3ce75d6b1de7ad7afded49183dcbaf257484208dc83e01a71cfc13ad6bdde7aeb59f7bad55f671de53bebac6f9deb56374ac7afba6c652f8de1a1a4205d1696b1d52b6098ab946f4757004e8524a2f76f50b98b09a51d3d967cddaee58d057da671149bfa4896baeb883fbc9a074524dc4da88da5754032b7a91ea944723ca17fad62eda009292aae4a9932ca855ceec842165541f4eb44fde0c2fd3083854dc7adbf25a6ab4665e80d11bf6ef5150d455542d77db547a098465e9443f5fadedc57bdf8d0383b1de75a81a10248caa54146aee27fa66d5010b0bd66bdfe8dfb01137be890de3892cf10458c28c481cdceef9312cb7731680ea67afa8f643af95bd239b5a28f14bb7ccdef40c8f972a58d8433611e64aee3a064fefce538b8f1b49124f6a41835387228171d6f4761344d3167fa70bfb0a7bde6e4e86bc4de142beb80c743096baf2f8c64b8aa4dd582f536a07682593f660d44f702821b58f66ef98c4c6a5cc0bb25cff7f1390270021538e3c466c42bb500f8e4487e2e748de388df27036ac6c637cb27ea068e8c301ee38c1f029e259dec7f681ed1cce412d4d465eff1110893196ef28cbb5ee94fd2c9cbc8ffbc2b8283830d3c37938ced91a4d6ed638a26c2848b3d304618ae3daf6ae1e64d579f3d8ca36cd2d02d5b3c949ad621fd1ef88a438de3a99d24f515e6b4dfafeb15c9c49351a46bd30fea491a4a2091a119accf60c2c7ebd99d68d6455dc209b9c99e744edf23d1afcc7eaedb3267752735376dc5bc426708412d8554876e9e2f73c89ce6c43141a348d63a60aa1c4eb3452ee25afd5c8f6867a1ad079810cd91fba455e529cea99be1a8081bb4649a64303e4a386df86716a3f3c87919c87f4c6ed46de2e7f45b03f04e6f607a9af8faf4e400d4c367504f9db87397d80149a53bb9b932501b6229748c52b3b112b2685a05ea34e3bd30cde7be4a53492ea4f9b2d69e996528f4c2e93ef8cd9391c60096300e72ff91828afffe783d94bf6668bf3c46fd96d33bc11bbff3c84b934cfcb57d76182b82858fbc53d6544df675772ee04585eb5590f822d55a3cd2b06846d79214be2e0aaf3b25e226a3de19f4f2aab08f82e70e617048d894672831bdb925964a4ad9497ca82852c3423b5a2622a3b567028880548452d3a29ec82eee28359aa8328c927da1ba715185b0dcb2d89d0eae0af204fa69d1b838e1c495412dd05686382fadccf1dbcfd3aa5cc11c5bcd97a724e890d3f7a056694ba98356b50169fd4d5ff190306dbe18ce51792c10c9ac04d85b09ca01e166fbc0f6d03bae1bf126807a4977781dea7f5218e768f98fb31fdfec90c7f3c424244934b7f28900bc04dde06fac9bf72db68b6f9da963f38c7f98ba692148f32dc44d7dc1f5103e6ea74a770a9ed8809f161567c8807c3ab9da81b1c862e4c832027ed35a98d520d94bd0f530b65eb7261e8961ca1ff75815d2fc6a7839ed0c1c417522a1d86b824e80ac0b1183955aadebee4ffa1c21c62e845424f025a120667a092a7647fd8e36838f09a14e0526a054d3cfb0dc7fdffd4eef3dcfa78abc2e949555963217b9549240cff113775c718a0ea48b4ef78b635c71c50c560e9d7bc42dce71c72a58adb2af34a6d4d8179738c611d426f948783e608263131232ab0b6862ceabcd4c76226a0e76f349232158b7caad745a37535ac5c332a284439a87992e39f7a1d8b3ba8b746df22d1ab79d03cb984d9ed7323041c358e98876226fafc8b22f5d327784f94a6b04b3e504f7bc5023f4184ae9a730277b24ff149912e0a5eb9d5173ded9c29b74ad4e74aa93e2b4f7a2d9c76fc8516f34cbc286ac916f65fc7a6052e99e0c92decb15100a7b31c00b9e84beacdff92550420c1d9a20335aa343b09b2656011e051edc1366739ad3211a4570df2a039970d4cbd9f6a7e8a45bfec981d14b7793df28004b805aaed9cb47405137338d6c3dde60457578471645bd0c96a83108436305cfd23ca4fb20ed679a6fe682aae109e34b70e65d4b00f419113d60622227ccf54f25cc7824288723a48c76ff2125454dbcf38f629285c5c95fc87883a7983a1cc1c356f0c215cecad34b7099cb08f7736a0fa93ea5fcaf77e307976a89a18b139ca10fb9124122e4b6a021f407a47742f2590188ab8a4702b5818159c785bd8dcd25d0ff49601fc5352e412b07b0144eb976062331b426708fdd6797a2c1c4d19cc57c6710fc2bbcd895b6a3c6d7f0f0a1c5f500f34db2251b429456490bffcb68312fba1e4fbeb58692ef2a282d84dbe9a1284f9695b0dfd5431f996260c0c2c04398386c6ed67d07074487e74e08284f7ea1ffe06e74ba55ab1db42d3537d664c72d29625f4a600045b04cab0ad1290451db001872b0fce2b3c19040b4f8cc6b3c4775ee61222fba87abdfef06e87c3aceb1121cecdc0a1bf689a1cd63fd5658c8aa7b83f2cb2dcc53e004e9b2447c2911417ec8972cd29168b9965ad5c94622301456825aaaa0e17ad1ab4e540d5e6ac1b49cde24368db15e3a49613ca9b0c2a206b56ecb57bb2d7327cca9c16d858a70157b308ace2dd81a958c067e02c3b60c538bf571b70c063b02ebf938a450092b514932d71cb313aff604ea3915c1492dfa326a7de2e450107a0a3370dd8a3b179a00ee9562cecb259cd8cbcb45e4cb69adf8e5f183c77675f993d5b89fc84b0205f5eab25ebfad73d6cfa43800c1f2f4e5689e3cf43eb6b243e4e40fd93e49b7b7642d168b707227f9f492c4315a5e8000f8ecba13aedd1a09aa0eb8c8144f3261eb447019b56e2377e1130aeedd05be20e41aabe0fb17bc36a3b010436a57d961e4edf73bda76ff2f56101a0902bb948743939a77dcb00cdd1a6829f12a4c3ccd4cb6b1255467a65d5d4587a0a191e32b8fd14ce6f195c434d34e8f87a5a63e3641c831a43abe31595bb94ca1b75e67efe5b40e7a3747ca9f08a173063c5c51f9aab83bf47592d4cc522b066341c3be6c9397cfd93742775e0d521dac9b9745c23edccd4119da54bcbf0b2cbd4b6fc5aac4e8bdb50b836a6ccc1cb1312ba31b59c96e530fbc41b37b704e6faef9901de29baf666919bf399d421bfdf78b8cd4de3842a53ad61d1a3a78bd2e37be52e6a316bb0e712da2be6db952d748685173502582852af6ee1ae2cdcb14b4f7fe1fbde1c063e202cc8db920a9ba925aa09a43483b9a7ae27934964cf9322b3678e8921bca246e0e8045d5ada02703624c4414e48e2fce239ee2d5423c58ea61c96142652ce051c000bcefd2ee4b450447f1a8338f5132cfe4a2770c2d2e1f4d0b73b8500733c2768e36e3a28c6505c9317c88f87a95ec7a19b7af0d1384410d7055bd1a3693c58344590e22890040b8548db9f68a4febbca7ca4f4c991e7e4f2a9179463c92056212055e590594ab94e85b4593aad7b5328c97fd5562a6929fd70c407b17474e52f6a73f61263328c2da9772516e6878ff752bb1feca67b2c944cd296c07ca20f61a7d9406ec8cca1485b421f8a0ff3202b116af87246d530605d625bd0f58494a2f9721e0d710820f62803999257c16ac60ddcff386f88a0deb3da40c771b74f9eb2ce31fea800fa85ef05179709f170968baab63767bd0e35c77c1a098bafc317d4e41b600c789b4c3ec55afe859e963469d3b81ece8fd59d7fa113f1736fafde58e69c8c3edc8021f68a47441c19e37ad97a4c2e10e4107fdfbb08b81964c6b7ef33eccb70c15bdc8866f183695144dc2b02329d91b0755e3b6b12fad38d1b1926dc738242498e825126e042b8e31c3d462bc34312f5d0ede9cb41e65ab2f49500e9e763cd50221fdd2236b61d0a97448d4726b028f937b0c40ceec5fbff91c81c57ce95c7f1122bea9087001e5a59afee0f22e23ef460392a608a02a6590f7549023a4902453bbab424ac73916f676173bd4be6df0920eb813c147d21eb05558576cb2d93598b605c4453a8f9ee87f499e02a4ec76d00235169e2e97869ae75bc8c54084ee65a9319d0bea218e6ef31baf4303164c19701650ea9ddf3a5e0910d02dd0ae5ac1920b5960236ff0fb25b095391d990a9b3b8b7339868511e8a1c921a9f227226ac05a6ec5729e37c996ae31647f8079fe80506640b4a7ab3bee823794bf98a69b3174f0cd59f1f0b8e2f619bbb409989430aadbb5185ccda568c250d3a90b52317afcd741c3b56fe85c3b9f0bc928ca680b857aa18b459bf399a031a0f41204d8e1b542004481708cbe905d22ebfad7afad1fa7ce8ab3e15f824611dffaff4e8944b588b1f54424ee134f119488edbece0425d5cf092a41926b11375896d95225b473bebd2fcd49d4aaaf4e4038e621ea02ce54f4bce4f165ecbf7a08c361481ad93276ea01b02504f3fc257b01fff0d0f9a0f5a5c8cbfc0ac96cc0f9001aec43d0d281ff3dc08a5f5f4648bcb88b999c97f428d042b42506f43923eed214410ae53f087a31787bbcbb6dcd8ca0869c11ba4b9873cd190f32367ab5593950dd4d60e3c4b65fc2ead2792029fe244755c442bac27a7ad75aa60ef6dc0e7b9e7d574f14ab74cb027eba908958039c8584af18d404ce7259af82c503bd32feb43a73488ae1ca2490d86158d52fc48231b8650c6eaad162a77ba1c1793df8becd8bcf9f36d9f059937c133976e67e9347fc346863d548fa9360192324e07cd91344b90a90f00e1d1fa2c50a2c4841526bd9efc722b717016dc2515dd83183214464a8e971adbe4a83286db70f4112df93a96b7989054980a014d3c3db8c02b38210243def567940e4c189dab50138585a2d13bd37d6d1e2a176e2577d8e010bbc4ec1cd49018f0f821e8896922e00f49cccefa9fa4f8af615239fdcae30c6ac301d021978e8a0a84d377cd5f56747075fbb0c28e35603a21fa9ebf0c2037c881915cdd2f0163b89b05bfc68aa70f013b73247a25ae8673525403d593a8f22db2614252d741245591ece5b444c9e9d848d39af369d9de47ee01a22234d80cd3044bfc51cb42745f4983f3e6835bfb9eaf09a9094e81204ef587967c89151774330c4c0bb0e13b3b4685d9297e63e8ff2ab0410a721f45f4f9a91c238eb9bdf109c6738a3784821138c7bba672ee68bde9419324a9a7bafa4c79658a14c64bae5f68d58b8d72d2b57520472590a48e704ebf0112faa98534365f47e3df040ec76b81f36af1872b463b56f423c9ee632e9e9b66f2549f5602cb95ece6b05723bd16c1a639b8ade8e757d6cb5bb804c6051c8482606ff2b3330a9ce4a48ba4efafba0a7958cf4eb25e5bf47ce7eba5cb40721af6be55eaa3297b880176622492be85ed029f060eb19ae0af5db79574428b93ce442dade1f8d2b4bc5e77a21624f57b0f99218bf135ed764b6a1faac25ef677568c1af3ee730af90ff491e5655eb4790919cefac82f1771cfd20315c5ee5f154e122181d3f958b964097c315939b762f9bfcbe8d2c1cd8003b1c35354daf29925ef4dd84c0d928d2f4b0b7326c72c18e8959193e5b9a4e2067eea66f20b4a530c8544ea31c7087244df3e610aaf27d0bf150f1e60a6fe280191473e8c9b102db9b09157e65e8e5243d9a72467d806a1807f3fdc4584e1482b90f17775e2531308d5f5b1b506e4acc67abce3f6bdd3c773252b8f00fd918396e8e2eb616eb909c6b61dfe84234f4dceb1b32eb3a3cd858d6f9ca71dd6ef8fc2004422ad6fb4371a2740b403cd54e3ac3a5590b7a3e8e56a15b6eddea81d4e5506a1910e6303f0af217b6da2e6d37df1307344eb0de69403ec1fa9f7121e9ff5fa7d8a70c343a479639c1c92be3f3fc6babbb8a095e41485c2fb8bdc989b61a20318c542ae64d62ca9bb811c145fd4ca527546be41e34470a758255fa8f562e9bc9284e07a3273069c8c245f66fa279a52cda802dc3f9ab5bc91c55b53f58863c702955efcdec799fbb44f7f3f1a9991bc895d38bdad836297097b72dee01afbc730b420bf6a9dbfced12c7ac5709783e28f305866633925d597132bb7b20a3660ffabe1b044c08d14794f1ebf01490a60af4c3b8107f57b82aa02f219e2f889e78a0d36fa6322060451d9e78d0b67a20d91a2ad82792c7291ebc416464f1d41a262b5b5385b652c6ce02798e4e335d73928fe405accf2997391a1a343798fa02a9e4dea761510cc8b89e7896cd650620f4b4ce2b4f0803ce8d19c80f838317160e2a10a419fa3e2ba29092c5e72a0edeb0cb3ea3860a3771f04497964a2ccb1676602942a703a8132bc50ff499fb06b1ea803501a8611f27743ae260a45ed9c78612c41f057ecf448e0f5010686aa86d24f481d299e056ac808b38011301b2ea401e39103c116b7600140ce8ad236ba48dbedadf5cd99ded088c4e831ef0c755c35b04fc627088849696d665bf0ab97216f8cc015dc271eb9bdd01a3106e10db0e1d4de8d5f07847bc9e8c24c660660131c6cf7b7109bbcd2b3d69cbe97ec4f3ffe1889ca478de0703c51bd4cae76d3b79f41adc48506441ad70286e62a4a0b091e2ffc41d4f74513a85e087e0b7859ed079e287182305821e274393c722799c88c30b5524c70939c1851341628cb91b8199c36112e6d227e1e187a07724044d33fc793cde0d69e28c6dd4c428869a984dc418d3248e249a701141b923619a8c628c4d8ee0f2ffd7453cdf719eef424c7698a82c21c312319620515206254850728290922d94bce47021678b1c2c84c3471c424a2a04bf0dc8f7a094d4ca9bbe50454a2f94a7ef777ee5412e7715b93d6101f348725c7ecef35aa8d2b6ffa3a81dbe640175f2a9cb275dfaaf64f24e2cf9d32c2b9a8a0459f87739cca310143da73398c48e247024f94092200fc8c20366f0009d07f4f000d0cd1e3764dc5ce006099b2dd8e4c066276463d9c4182952cc8cf4ba6eb3912de0138d77262e87a06946c4f39da8f3b2acb391e0275ba4a4f6e8c469a22e6f91265ba4cc925026d9d3f1cf2dd4e3c8ef4b1e0b97f7166e1f38235ba8cf63e15d8d18a19a2f54b36b52a821385238a2289999bc53111846fde8890cbd2e3b7942fe08890a42483892061c59c2910d1c19454a0b3defd324b8692a52fec7f292e7bbed2bad68349a8a0904b7cc711bc5ff3f22da117be447a4726c6c92c893d65d96a17e6b998ddc801b71c2080e31521ec904825986383a64d1249873cf909e8ca43bd2939150a42d045f7ec97bf2793ce17792e7bb494daaee48af4652bc63793dc201394ed364d6be1ce60dd4c067017bf79ee7ef49de8ed14c5e1352d3341901295f5e5c729867248b647971e9dce3b890b6114e2923799d2c444a29a990f2b9ad44f2b6d7699a36440e2129af44ca3d1f6e9d4982a770e39b498a8d660bbbff9d8d8329fd1b79cec47fb4717496f0fc33e01396c0894fb67704049fec0d6ea4fffefff51ce6192ba298a123c69897cc90417dc29952fc7e47da3163a9ed0b65e76d75c8ecf1b9820c1a331f2884648aecc8e81023c549604d8c1187622610f3444c91f8313f320982b90483468c320ba2f3b68f815981cc42305a08c609cc8c947c912f413059a20e9905f12931b4841a325b0204fb97bc803d5e0c98953881123c529ae3bc8f44f2c2fcd28317315e8e08d943880a8484421ae05207a5691328e29f35964a8f9037f943506703b515b0cb5ca994a517cab0cb3c1e9726efb433ffd726efe48db26e317927d93bea3f8a74ea3c6e7ab024f9bbb804e9429010042992e991d520ab40760446077605a683158994a6498efbe799e471dad665c9922349a6fd6d5b725c7e62a3c9c81519159b07734c9665992673e9a4411549e974db973bef93e0d669a8956e53919a26b3b0cbe1a9cb6096bcc332c05d600a84f00917c10688915a5101b38826cb7224121a13d942adc4ccc8ef6c640b05f2fc5f0bb542556c640b250a3d2f09df765e24a240fe20c7e5e8058d29c698b509e4f90e145d4bdc3c2e1b31c69b45bcb93f5021ab8e182d33628cd12a92e5496b96ccc3aa41fdee6c16d1368931da1fa1aa0a31566a54239eafa994a87550272dc1cc53d7081f877f92f0716acae785281b31d31ed30c0d9d21fa2346aacb993ee0e91b7f7971d9bfe4e5e5e525cb72384d96e5709a2488a0ba40e580da289748b5a0116ae909b1a081258d100b172c36c4a203124538420da12374708402568c105ab9620526a4c2478c544805472503b2851090378080408030e208469c4246185144198a88236a2be016865be7b610a4a17e776f92e2b930dc38d93d16d28f4230cbff24e86d4c488affe7753a5bfe3c49859fd7fbb784e06bfe81262eeffc270915212444c41d440021cacfeb1b119d88192274f0463c32878608121aa20721a810820a020a417811849350103884e418a41821594508e630f3eeb95003cad08037420de869c04c6ef9240c5883011060000e2dc08bd002741630240404198020230444144008800031a4803e1450044db650ffe49f1c016e9f2715d04448013109104302bc0825008b50026c080179501a87b1e1b2f43ac937b097fef35464f83821041841c08f1f9010fac10c8affef6d92fcf4a103f0113a0019a1039c4207181d201432401d1104f27dc76300cc072d847c28810f38211f52423dc411ea618d500f2c08f5a0c518a9ee75cf65d06b0912e24109211ebc08f1a0f1c0c28310a11d8810daa1053b6060079a1d7e8891d25a60a89510cc5b450669c942a12b424d422ba19430a4a8e08aa1142ec62b840a60835001465080985001061022c0144204e0224480d28aca933c50046e94fc5168929a46f27034d9694403f02234802e34801923d5d2795d488730423a50a175a009e90013ca218f500e3508e5d0450e301a48d2648bd6912412b27b0dd2c84c3bbd11eaf44fa8cf13420816982e73f96db9dbfe7b92a97b700b72d254691b814ff236da9b4ee77d4c66bc1afe6149c9c788125d44fe342f92059b5c405108004528190280fc27fc6fa8e3bf0c24866e5023523334b22674c328468ab4491048b8490f942cbfb371464237846c40810d271b5e4236fc1042912384224608a589108a6491dd0349de7e1d3e4869e0e99f848f1302551163548921504e088480d0278fd0a78bd0070c7d1a108a6fc41895c45004435126a4653c033fdc3e267a46b6682c1a787a2361cfd7689245eb3619c8f327d133b2855a5101f9263afd932c034f6f24cb7242d0db124652e0974edd2665640b35027308ced04879e2c2fddfb6c2e52e3f4905043243235f6f616792e1fedeff7b8ecb7b055439fd93d33f41426a5ad6449da781e1ebc8904652a3fde507e5e9cbdda679783e0f9461e99ffc0eb837f0f44f4020ffa064e26da3cfdb1bc9ebbcfd52a7db4edcf75c5260f7bcef8666098c57737a231c3cbd1124966023c634f810a3fcd0fbc08feabc2deac3491f32bcdb9ee080303711c7c4bf531263c4020d258860c7e37546bc90e47dfdf34e5ca9848622110d3f9c218e18f919c0883c5f7386f00c2a14ff5308c29ce1478c5530c3193146be89cc9045fcccd0a4c50c33463ee6588151e1838bb861f818c5c8070c1f92e26f0279cac0478c3192f287a4321c21461e1c22fcffe364a8235264502393410a3230600c6f802d9d7bb0a5f3bafc75f27b256328c5530ec14df69d6de7338132f4ba31c81823f5797b54816f32678f3390ec518a3186403af03dbe874a947af001c61123a5071931ced0483d281066aec7125e8d1e3ee064d9cbdec21c66598e0ba7c9b29c2ccb09031e61088391307cf278421e5ee4d1f3400018de8894e68d785a7ed324cf0919825e491a21ffbb9141346fc413a33f4627771989fc51f8a36d224950f3463c49c080040c40c448855f287d41c9178af8c20f3ce8c0430378607884f0c8c10b6a78410c2f18f1824a8c51cb9a6cd1844850932dda0a48b5484a450a915b932d599648c8924442ee3c92e176ca3ca5adcb24d0c4bbcc23bbbc4dde29dca44eb7997a89fb11cd4cf764963377b4710704eeb8b943665af799b448932dd48a8a9449ec90811d243b4476fc98a30b64c4d136793939c83fc93014f879bd0e3662a47e6763a9e30717b0c0051a70c1e3c2dcc215b6c0468c9102bb8d1476db16445b08b2851f3c79d49974b2e4f1384e0b56fcd7b500cac2199f271f0b76602108588800168060215ec1095770c115b8a869523b65d2f7251328c13cf2bc4eb268afc97fb2719d124af3b6159260850858a1a60a65a8c209aa60a40a4450218f18294db6506153418838a6e0c61476a64004c7650e2aa1b4eec948c10252a0a460041d48a083c78a2974c444010c2588824c141800053ea08006143628b8c4182919440b41ef4606f91b9981cf3d24e126ff49feef490ea9d0a4b71307caff4edcc6bb7cd21c0c37fd5cbefe4c9e1776deef78489ea00635871e73ac31c736871173f8e004203841064e70e2841f4db041134ed0841cfe60b8b304b7cf236d5ec7e375ff4ff2c2cf9325930c9fe479a5cf5422799f167e1e8fd434196613d80da1f8494b2b30010d2680c1842af84b2f945f7e8e093ec8c1871c2490c32487ca12f28891d2bc118f265b7867fa4c5d82dbcc12ae250880064ab880129048821a924046125090049b2fc038fa8891f2a4967d9a0cc1fc9c0c33cfdff75d7e5bd83d0df57da7b3819becf27fa7f0cba5161e070694c441448c14297f8ee65d66f9902042c210241c71843e2275e27e677b52c6a9a9f9cee3b20cfba983a148de115c8ee0430f8c0003233031820a158a308222401123a591f2872090278d767ed93d994f5ed86d21683ae9ffaf4b5e9299d39b0e11dc20c21444003204398630c6102e308424e03083919802470ce0e022c64869e1e3845b673269f2a42575e278f7dbd749b9d3640be585f2d4652fec366da57b8e424276cf514fca9d8a3c02092dcb9c89f4799d7fdedef9cb44288d6fda8fc23794f046176f68f186cb1bd60a42d88010b0206821082308824c107e08831b6fb881023722e086e646a6add050d324186ea4211468fa42b0db92e0ff79bde765f7536c528e421eefd369f91e3449cefbc2cedb20f79f276786c82eab689acc323479a62fd43cd96964983d4ecb0f7328474c64a669b2e5c152e6388fc7e35e4bfedbc44120bf9347a78ef411e93612873181204dc7632379bed3640bdf7e7f1e118d82a1a1b8fca8f014f3fd4d085226ef24bd5052fcb74ceadedec0ac25f56da310942c3334f249086aa79d65391aefbcfd3872232229504a1eef8857d3fd14de47e441251d0d087e176e4c788ef1be77a2db90f01cd329f96d06f46abacf14c33993c7e4f303214888317edd46e2f93b71a59209ec369208dc402ebfb87c22707b52ee384f934e20c865d2b69f238149c2b92f829365bfbb0f3d2f094f4ef2ffe93cdff9ebdfebf4feded6f9ee3d997f225e0e132e833146207850450f527a10798005e9c9801fc53b130f9ae08115c1ffe497bc2df393fc4c70b26cff12fe9948546343839364c812d110266092d8e4e08844598cf18718a3ca1031881db0c428e2f2f662e462ec40063e4a88f19384183f71c4f841428c9f23c4141da891a203338c10e3a708427450e486fb9d3f52f27282ace1853590b0860e22f8512da088b47bb2acf348246f8bc0efb72feb16d2ee59a38a18bd1909ca246b5c6bdc358058a38728fa9ee35d1e89929019ff24401357fa4c9225c6c8851cb0e17ddf4b2107447290e540c6f879dd2622ed9e2c23ed1e1c88010746887145c4659979239e177d1e0e4a110733839907072931c6a8861c306a9820c698c51435788c5478d29cc3700ec37f0e1048b7dde08c1b64117b64e71e949c677903fc79927f9893061f11270d325ee7b96d67fb4a1f662e6ff065d2e8d2788931ec3c2f64e1b81e2f86e3f2bed4f4f292e3d26d46602ec2715926cb726cb000349e80461694570333e214343002153458990114628c4bc4941978310326ced8e38c219c119ea173860f32a823c6186a9b14853dafc9164db6dc482a97bcf0d3648bd76da70e464a19c4c4008f18b071c41130471c2129fe9dc765df78bc9164d13479d25ec6440d4d4d1218261c178303c0e008305841a49ed3b9f340edfb4e89193330e389192b2fd0c20bc078c19017d81023e575608ed132d5796106b5d23602b9ffb6ed816096524bb00574019032be50c61b658437c49432bc3280284307326c40462643a60579b4008c1654a0053163ec1123953add86446636333639ddf6955858c00ddc348ddb3211cafb7e0aee6ddf974e599b9a7cd01482260898bc93044df23f2026efd42991d48aa63d29832cd9a4b369529699a6c9164a6f3dcf752ffc9dd26b2eff8ed7e3b5689acc12a4b4d2737acbdd261fdc783eecf2974d3a23f0bf2eb3ec787209678c98316e60810e58c05980638cd47799479e7e142700401a21c8a51021727f2091295f6ce8c11a7e88cfbd4e0d598851666f0505a86c112247d4ebf007812135a870af6b22874606e6064646bac81efe803474017ed4e90bbb4fa2944949fc7fa106e1c4187f24e9a30231caeca5d22c9b3b7509cdb2b933648f18e712baa453c2ff65c505f480fa7925efeb9490b652fe72b26ce6bf2f1223e84682361f6eddd67f2646500db73141d26d380e86731b93184147c01841463a538f11e4004e132388c6c9a5d8898d1154c43211718c202297d6ea94bf0f467b5c0cd86d4648bbc9e77ddf10feddd69f774a783cae7f61a784e34c44788ef929369c9e8c041c12e3a70df09f884eb7d57835cfe91c7a359cf38a0c7971d9bf84b47b38ce54439bd4265513dbc46a729b5c4d70131084810937cc10229d57f3e17fbbf36470a5266c7232abbd2627b5720068a656dc5e90cce99fc4088a99f5f4a737c2b96d24038209bf5c8a11b4c4760a372e7f26ee26fcf2cd897b31bf376f0988e4231282f98f843024af7b4ef2ba9b2e8f72fef390d4cac4694edc8b09b74ec9ef70796fdd687fceef6c3a7f84cbdbdeb8c9019ca6e6d4c1c40852229332683282536343932353a3c401a2263048443be8514341d3144261d840e42fc5141b18e61168fa0d8480ac912d4f7a1e993bf7a0269a2f202137708931fe00058931ea0ce73baf266707795400fca87c13636c8012316261444c944016038813a0014358130618212fc0018c8ec084be501363ee3619a4ca2264f7dc94428290dd73572841080f2e9ed37aeb70e001071e4c24cda978e1f9ee06323e1353b465ff0ec76512e80519a3c80b36c41845fffd8e3c62f47a77c71c31461ddc01468c113cfd139115f1fb279fc723ba637413c13b6c04ef0022c63b6c8876ec61071d40b0030d3bc4883d76f4c418b928f438d08e23517a618e01258bcbe711e1741600dfbc25599665a2ee39df46a2ad94452510e49bb7c4241265d9e77d5feef24106884a94cc90761319d26ed233247f2698fc9960704adb08ecbccdeb1d4d8c20ecc26204e11841d78d1164816c1523a882a88c4c07002ad818a31531c60f1556f426c40b03164060478cf143460acab8e1618d3794f8c013365c64200c1dc4183f5adcd18095ef069717c41841478628a1052d8068518618238a0f5bc4f1051274a10325c41801e08508f8f8c891a9618918e3270b63f040157d90000b578cd1862f341c4a30220204a81063fcc8a1ab1b5070400a29c4f8b24b25182f27fb307f9b080966993f138c0b787a23282d53f082f4051344a4508518e345a9d9127adeb786186394c228c638a94aa9d9d2f1789f1e81792485192947602e32041d44e889213a66c02446fb43197eb224837ca6fe5ce60d6ea4d2bf918f498c3b7801688c1330f122823ee0715bf6846fd291b2e4794c0220004aca3013098000a8dc75c9e5535e899ff8b9891f2c7eccf0e121463b6274c2139af4bc170e61821461443ae62842a4b6f46a2c27c411c30ddcc20c8261f7deb7331249f5641211d245aef46412114948a1c26dbf6512528af881f1c212116443196e90827683ce0d5b503a9df7f1c8b07b1e4981da048e7697bf981b84b0953a7fd06443cb8a8a08dc8228411342d06d5ce77530f163448c18d8f21706f1a42699be2db304bdb0db44fc896542179f9af8794288af24e5497fba00d91092e38d1841334650123182a818412d31825862480e2b4272f4808e40126391253411638c598ca09518412a31c61f2020e047ede75e47caff85e0f685f9e351021f5166a5fcf1482f7c90114580888835430811846c00880151441bd0026e40408014f0c38d5012e411b294b788739e142244aea894f23649f15cb47f270990f3760862911899d80134f3b9417c8208df3744935d5e5129e58fa73365598c1f3886f0039400100202a004f4438ca003b4808c1c5880049ebd719d7b500a71917c23c50832c019201f6250630cffc9de42d29639999e124cf838451e078777bfc19fc9cfc9bc803d9954f2bc1afa795b4f26754af8ef6c3aff3dd4df79a290cba39329a6c8873443b26cee7ce9148a443d99f479e18b4b8f179365fc7b3c9d6521e891446116f14df4f2b2a2b249de47843fe8713249ba2fd9c8f07c4d89f415f9bed7b9e342da4db28cee9076132eca32d2ee9909c17c441322447ea68d12c48aca134f046ed40a28ab5811491650c5882a248be8a445220a050073c051871c709811634c028a030e2a463bcc249e1f8e9437e8786305313a8142869c09343d0105f546166f14894ea0904f404109a18e9e238433628c516729040cc408c3bfbcc16d06864810d8c809020a8270133bd3076e3a5fe6a4f6381d84941829bed5b8a146c88d518c91db463c12c68d1f110cc1923c71405023c6cef4fd9603042d22e5d53cf76e7e40861fc4e00753fca0c90f7ef8a08e483dc9db2c1c86d29c745b93cf90368010613c2640afe613233d9d4f1095366e8c7186ca32ed094de34cf9358ca4bef366a47c8f87e209ffc4715ba8848792e09620ff9d0c4ade659e3d4e7bf279a404330fe88df22775bacd0b75961ec8e59085e51bedfcf949dc870ffef63de947a5a736d2163ad1b42740fe791d8da438d0931d8c544276def66d5fe844d39e90df72eabc4dca4cbeb779c0df4e86ccd8c8649988e39ee709274fb0703fca2d9e0ef83b9b0e8ca43c9073bf75169e69246873738ad946de77a3b3c5785e0e4ce8d5845e8d57f302500fa01d6204856204a5c4082a408c2002c4081a408c201d6204e5102348003182021023e8478c201c6204010064438c20941841a018419fcf1a62fca821c64f1a62fcf411e3070d317ece10e3c70c317ef888f15386cf1862fcec11e3478f183f6288f11386186d889f12d8000734b210b50fa05103992ccb322cba37014d8bb1480d8a10a92e530331e208cc2ed8974412fb035b68c082188350421385af43fd13a176b68fcb1bc9eb4e9c57a240b0b46d5c8994354d9648262d753c1c4995b6d00337ae54ca4156909041e41172a5b47d176d2a52882c6da1287c2ec84a690b553697b748883c85cf259184640941d3a7699aa458564a5ba8225b4edc97b98dd499be96b0cb5bd364969da753dac21c6aefbf8b34f95c6947d33c214a5bf86d3b42c80f4d32db68e1c699483032c60824469005248045ecc924de793a064bf0ced372c3400d1898602023a581dd86442b791f18769e9c3143086650c08c1923a569d20b358dd32b5ae577f26825ab502fd823c6cf5391a1177c3146510cbd8007172021c648e9ef75f8cb30c350ff9974b62ec14d671b75a60fdc54bcded1700e53c3f33520cfd7b8a0880b64945d76414e197594a1468c657411412565f494a17d193646fea1d77d88901147ecc92432cc88f20344029d0c97083ef93269b4bbd7b2337d3208d8939164598e7c91e0264f9a04bb2c29275a4f46a23df19c02f31149812b2ca75085650343af26f46a501c20cab2100bb4a03bd20b4d5c923eaf7f5fe2f98e0540c448016159810b5650b3021b62a4347eca244f87ea543003156815d81865429397c4a6389209fc24296842280556c49217822878020ab2400115e30b62e0408c2e22a5c9168eb49b943249669a265b90c83401c5a84ec0478c91c7d00942a06d2492b7ff339dc00813ecc0041c4861bcaf94fbf73c1e2761a8d1ce25d0043f4261882114c60662d4bc5072ce0b79182b61e81002430c31c68f213038a05139cc339ae9db78bed3644b92ff3eec59eae4d20b182a31c62fe24022d324f4c519f18b1e4a82322729223b982fb42f96004d540c7df123464acace8b2cc418a9279e0cbbc709bbc7c931dc968978c1458c91e7182f7a628c5ecc1b2f7ec831250003157a1d129926dd064a70939f47811ec8c1484ad3404d9379db91fc4fa50cf2df1b297727ee815a865be6919ce769aa25ff280c2225055a95655daf933cdea723c137914c4c24a5695de6b2490a8f27941eefba770a4ba41f25c1693a6f833761d6f94f47274b49491c2f87b49bf01c93631420821e624409825204ca0e2100021299262d37a025c800810f92778c36ec20019810e0182308cc10299d6ee3365052537859b67f27cb78088a4ae07fdea6018115203812637402050884f8001df10332f800e8040ac959ba21433c50478c37881e28c2030ce0e2095cc4808b1670a17161c41664d842093632d338059a349969d42993341c0a7c9d5cda91a20a2cc4185f384d690ba96e5be2dd7821e7bce719ed70e301e5f384e1f6f17cb9db641eedbc7fe77b1cf9fdd66d4029382024c620f89723daf14aa29e4ce2f96b8ad49d2c0bc10dfcfee6c90ec17ca4db84dd93403073320fc8014bf9cb799d7c93c33ca3c51c320b4d9e1668c418b5a822ca4c8b9ca805057e544803270df0c8a2012234f0c9401c313a814266208c18238544a6091110fca8efc352e6590486b2a040dc220b95204edff65944eab1a88302b1602384c58685b661016e20b861911263943cdf6160093794c6e3759a4625125acb287c2e396edbf979e4939d2528c3079918e96c453c2f8773ce068e18a39398824426c6f852a4f336d0c4ed8e86f421cd736e84ac50811517b0a21493b06226c6a892d287197d74a08f9e0be8118fe46d094ef747408e83e1f16a606cc0d31be1e00d4dad94807974e37138bbc9f76197779efb24327ce6b927f3dc93e1f99a12693701c3ee778670bcf3624e5be6fb8d2b3d91b0e76b9e2b6d5f8e97c39f6fdff73b364c4aa419ae93c33c53227d45be679c1ce6199ebfc892d3f73bde06b7199a11988b3cf932e9fb3033796e774ac2c7e1db0c58520286603e02cec084603e42012062d4e3538034443e3e02084d60831fe575317ee688f1e3041d9a10e3870972701192c00a62043f107c11effec9ce5af4db17c6334840a3c02d7f335da4208c1835b0e50008a0f33c508299779d0703e24103794011ffee491e922ccbe1f13a2ac0a0620354d829eaa8c1142a9802670a069ce038a11163a4b4f04191fc7f92c32ce3db8c26bba72269e76d2bafb5f0713a1b4d764f456a9aa69db43ce51f957a891be1742446f0c5e5a489704239713714283b0fdc4c1e4bfe4c30f2f38848ea495bc8e90dec1e9419dc9e7cde83de68cbcfe43521a92f974ad9c4bdaf248f3822f37c8ca44025c2d709f13c8f4b8c43c8304b9d6ecb32d8e123eebc1177ccd8c922ca8c45662793ce3230ecbed3e93650c94e4ead62d4a0d8f921468fc331dd5103c2e8749b4eb799b2e8bc2779a0a9894925c2847d44aa33e9f07c4dd8e37530218e14f7bb03eb88310601b98836a0162970e53f8fa4224f5d0665e8ab23f27cffba384916afe6d3be9418b50c817432478a3a22f579b24a7146e4a468927960a450a172985f725c4c52e492cdcb8b8b67c45b40170745ba01e923dd902c89871049009c13381c709aa34fe88831b6b468b285b7741e0456362b3061db6273d982d87c183961948211384242070a3a5ae834d199d1194057a3eb5007e299f062fc114e061e05ae05bf21beb2a1b0b7d87b17a1e3887145d364df5424c8e20446e609c9228fd8c2ef1bf7792ca40fb7ac85d25a281349d2cc26099a151c8984c4d1f138151b4d45e23cd7d2e384132a365af78c905cf64a9a264f7a5372147a5ab2b080602eb5749e12d942692b1c972512124763f9bc0ddc6c24a5514d9eb88f4553c2bbac22b72edcd9ee3ca9811acba6c98ca2a86cd164f772dfb20ea28fd03964373209b2295bda16b40fc4182568e26e64cb775e8d8c99912d948ce45d764222219d50b1a1feb9bcb399a4a04a9b37e2912b2a12147d3f0a5b327f1289a62723a140196ea51516158984b49aa4be0f339765f7252fa706f46a789e88e7e57ccf3f9b6e139a6cc0df3e2f11f84c016bacaa30fed9ba17563795c0470a56bf305eb16abfddfb273de51bd3870e8db165fd55a9b6f69d1875f28902c5d6735b5d9c35e7b6da50b02cbe70d5d755e9acf6d2a029cce1a78bcf132ccbb16adf5a3bc63e735c3a39eed95af5c2f4bdd309f6ff2b9da9bd305eddcb1a6519976d3e4db0f4c5185b18bfb0b678dea3974f545dfa8709badecab1d617d5dc5ad67ee4a86ed5ef578aaf6e696df528cbb22ce6b3044e67b5dee257b5ebd3c79ab810f928a1d65ca7b53496af0b671d8aba21fd9348f149c2be16c6b9ae184fcb697f172fec68b21b97ee1347ce7d57754ecbda17d77ec5f82001db17b374edb8dafbbaea3c82c56bfd8b62da5ebaf6498dd035ce78de8ed57ae5b9ab107c8aa02d8bdb6a7bc5dfca773f11a66531bcb59e94df5d596b08bcf6c7aecab230bc2d6be6519681db169af0078e59f5abcf7a2fac5bba6eac8bcf1b955e5eddea6e8bf3dc79cdc047086fb5d67af73aeb4535c796b01871c932097c8260dd0aff65e1aaf563d3c2dcc016affb6d652dfc98531c810f101e4f8bede4dca2f3ba98d6b01471d9e2f3030c57d8b4b0eaaae6534daf157c7cd0e7ad16d57cff6fcc72ab8dba71a6d5d5f1dcd7d5f31a6559f7ec878d4d3756ed85359637cf5863e0d383bbbf627cceab5ad56fda2fe501d77a3eaff2c4f8a97e8bf33cade4b3838d613c6ba5ad6571be3be5c04707d45aba7fe597f5d85ab68799f479443ef05983575c556c625b6b8ecd8be500a396ee96656d6b614ab7c541dd9363acf6af9aef6eed0d7cd4c814ab6ac62e6acd7d5dbab2e273038cb3757db73c5bd8d63b5fe093c655cd3a6fd6745f7e73bd36d0d6ce1ce3986f5a654ef9078d5e5dfd74e7cba9c62e667d6ad0ad8c696c6acc66dc279e2e10f8d0e0ba2e5d37bdb85f98a6f839cd053e33989c5af5edcdd6566cd1ba93651f0c7cceb02afd135ff7e669eddbb70caa0aabd8b52e7de94531c62f39fb1383bcad5d656ab14a6f8beaba12c302a3b2e403039d27ed7beacf4fb1655dab1601753e66fcadbeffa5d79ebc5bfb386e7c5e80edca5e73da0bdbd59a177681852fafd6a517bbb0bcef8fb2ecc9a70c4cf3c9f3be15c572dd93e743c6bc2e8b5edd5af435c5166f41e7afa7de96f5ff7862d518da62b74f6bf1c5f0d5abcc82a9b17a39b555ad575f93e3b627547c56d02f4c71b53a866dafb069c38f0ab6be97575ca7ed95eed38229b8a845359ed49a3a77ace228c856adf5b23e4f6cce8b5e6258b75f393f369f5bce3f27e0955713eb7ad1ff7d656c9465a68f09aefd0adb9a72abb27d7f9f30a89d7f2de53d775ae7f60163d35e5df4f77531a6d662a32cfb6262135f9bee9a1f7bec923e5e5c6a4d5d39bdf879a7b88eb22cf4bc12f079b3be2ecd98d698e6d728cbfaa78bb9339d97a5ff9b5b98d6a32cd3f9902063acbab06e5db4d79f5ceb8cc0f64cb3adf3e7b5f5760ce41f11504ef17d9eb9e6f4fe858db28ce7ff406f9465ff0941b56d9f5d579d71a5f5e3519669f10101c5d5ea0a9bb4f37bf5ccfb27c1c0e703fa3bc6dfad8a697bf5aa1a65d9cb0b0be88a8f077435ab8bb1bf2cafdbaaf3c345efd6f5f4eff7ead279dd2db2d6d3cecf57d5b199abee40a7b75afbba9e6baa2db63e1ca015cfb9ba1c57545bdab19ccf06b6cd7c5717b69c3eb6d91a6599149f652fbf370ea726cba41872936525d2ce32293e5aec4e2ba63663b3dad7ccf3012c475cae8f06f435ada517b3b3eec7d81a655997b99be75e4d963df7ba2cd39c7e324031e6995e19b3feca58afa32ccbb2972d7279f2c9824e4df5e7ac314c53cce6222e313323301719817934e473810f16d5ca385fb3db5967c7398fb2ece5a548961561c17189f9edcbc9b22c137d985d783e18e8fbbaac7aedacb6cfab7a9697d31b1981b9088b4bcc0c922cd35c74fa3cd2933e657cae98f9568c5bd65bacf26adf519685af83c3b284c5884b2923296512fe5861e7ddf4d2f75e15debadfd17fa2e774cee1c949b26c89cf05a8c618c35cffd531abf22acbf6c70297ad73d6ead699efb5d87e2a60617ff5bc2d8c678bd6aa7e2cf0a1c0c496f75cabcf18bf2896ed357125d29633019b2bf657c5f7d4fa5ad694005639b52e2c633ae7f5d5df64d928ac11d06fd9ab69cdd8fcb96d35f27a976522d104aaa8ae6be9bfe8febbf5d5546cddaf6a621bb3f9efb4d6cb14f9ea58ae745fdb3946ed75b2ae5e314af59cd7ac1d7f9765dfe35c3dfcb238b5fee68b5d4aaf8a84e7da586575aa31dd316c5a1549d43d772a793bcb5e9ce43c51b3f33ae76cebebdabfe2550e41176aba976b7e7fdeea2febd63dca327b4da207bf5ca2a1bdb3772b4f8b6137efd971a50e00bbb66cff5c71adb762bd8fb22ccbc2c7b9be5bcd7a5dfb56fbdad575ed7325530e26c56bec5acebbded3a2d9ea92555913c3a6c69c5eb8cad8b37d636ceaaf32fd79693eeae8ae3056f599f9fc2a639422f5a9f3b61553fcd762fd238e626d6d3edfdabc7aaaad519665194ef684daaae3afcf2d4a757e6b9465150256a5b08ce1b739db6d5dd79cfca7d8409349ff910d5fd556565f6fab6b5f161ee998f473d197f2063fcb5ebe3c02878cb00babb2cef36279775db94bd5b930adbaa5ad8c2b4673555f7a388dcbeb74394996bd4e973f07748bbee67c62d5ea69ede5f471aefa779e7cce8b716a39d68f2fa516bf7a85f35537d6d7c2f2ffdb7b557a62bd6dff895d17b62e6e59eb6178bec93210275fd9b26aa7fb71e6b49a5aabacaf365b75de5eab3be928cb4e99a3a2892ddd16c7b02b3f9db5b64451b1c9af9f1856d9dcad5ded2ff53ce5e4d67adfdea9bbced7da58112830bebe764c2dae70b75895651cf77bc813d8faeba293ff57d6c4acbd8413bcaa9fbfda17bd98f6aa6ae25e98e2cb2d9b1f738ef5261776f5fbdd527da9d6940a617255fcb2f6451fa317d519bbcc2ca970752f9fd54577c71aab5589aeee674caf5e29e6b9d23a26fd3346b8cc9ccf14f36a57beafde579ea32c135d3817cb7d5a55c5b1a6bd627694652b49789efd3baf58578eab4d4759c6f2803eedb6da569eb16bd78c636eaafedc2faaaffdb6775e6daadebd7a3ae7b6b4452f5a4377b6fbea15ade6bfb59d77af04920ad376773a79656f75ed279a3982595a553d31cb9a9bdffd46aaacf1a4fcb2d5ce9677ed802a3fc7bab236c659e7ee3951cff30e8686d77dd989617b61d5356b1e65994c91cb73def94e7b359ff4ce519671f9d3f95cb298c8756a6a75c518ff6dcd6a94657c13bd9c3a982c3b759912b9fe6217c518a3d55b6bd65196bdbcbc6093cbf7218d8b4c96f1df4a59f67db819e122eab62cfbc2923784771b4f67128566eca5af69f1e695d3fe161f6599bd265148ea49c85cb85677bfd5ebb679df3aca32f0c65c159bd4ba7b5a1afbbb1f83d11bb3ee7531deab8dddbe84cdd8a5fcd257678c56b38f5e6a6592992b81db0c57226d2e59463275354a54ba71c6bd5e169673c75796bdbc4cccda93f7abb16ee56df19190a9e9bcba5fbabaa6e5b51a65d9083495449fd7454bb8eccb318b4f8a2dae56e36b94655f1eed2041f4c4e67e7eed8befbcf48eb2ec0b41d10b13c944862692112e5956afb5fffbda6b5b34cf1f6599e8a330abf67a2fe7f5a2336f0c8fb2ecc3ede319025b7aa985655e5d7cafaacaa32c2be29a96dfebb5dd96add3ca9f0e751fab35df6d3b9ed5c43a1d6599887759e4f12ccbb21718169e9ca4c62279de0f7b757afdc5e6457565d5fca32c0b3f2195a516b6a97d5dd5ebd25d8fbc2cfbddd97444b22ccbc09287d56e2bb639ce56adfc52db4759c6e59d176559b75d6a7db6eae67f6dc5cfad6a9465d5b418d5bae216565d77f77e8db22c2475d1d67dde6e4902d33b7f7d4e6b655915a3a32c13655996596ad3ffc739eb59619545eb28cbbeef5a2ceca2b8facb7b95abaf7e946520ff0745a2f075b2ec2549963dc9e35dfe46d9056421799e48e713897e20214ac011db1385a0e9138908b052840ae53f04903a841195e46dd17f22117d72ad5ada7f15c19f082afa111043f4d0245a80102a418880c8065091c7218001720142005189a60280244005012a3fb01c0088018ef061f6b0c243f8e51004b203888050f5bc2f0129471420ff970002306000e1eb20400710881ca88a00aa100150c00f0e040e3d99a4a3e3710d0080bd0bb8a1c7e309196003ae14e55a5524d2e9b6119847124462c0878a3e2fcca2b0e781883aa8210078a4f17952ee6c08001e3d20a20017dc4a5987cf153ae410dfe8420d982580e10b7878e10e3bba500717b6a0852c60e10a56a80215a620053a3e51f840e1099f25c49404f0184a03141f3e72886f8c800d98941b180b1353ac16532c0a9234c0887800acf6c494ba454ca9568829151031a50a1253aa8f29951631a572414ca9da8829551d31c506a1430f368823866c40470cd9008f18b2811962280d0384d2b831948603760889008a1812c19318124104628ca11c0670c30e392041434ca9d121a6d42420a6d41411536a928829352e31a58626a6d43089293550c4949a30a6d46020a6d47420a6d49420a5873a624a0f6188292a71c4501a33c6380002840a1072c2460c3931420c39a123869c8021869ca42186a2f8118a222586a2182286a2c03114850362288a2762280a2e86a2a022871c7ea47c81464cf9a2075f3421a67c418598f2851d31e50b31c4942fce10801f3910e0061c02d0c61231a50d9a943644296d481153daa822a6b4818198d246085490f2c510dac0418c318700f03084083134a4093134048f181a42861822f22386882820c628801b04a0030e38a6b4a1134338c4c4100e47624a1b2a88296d9820a6b4118218c2a18998d2469218c261c7942f86008036ce882969d0624a1afa017488028831650c2da6a4018ca1317662688c0cc4d0182288a131581053da282386c690410c8dd1831ea20e2957502086aec82286ae002386ae202386ae402386ae682386ae48428c51071e1290851831250b33624a166bc4942c8e1053b2b823a664e0861f3655a8c1646611001bf24d0a1f7088f12304567411800a34418102c42c8152478a45464cb1da8829161f170131c56222a6585d4cb1b28831222088e843022214318284883e37f0a2e05f2a6d5f08662430f3b8946c301263d4e9c20c8a38f0a3c01c18194e13f9d80185023664c0862c6c98800d12d801b4871840628c6a8010f05943042911669d6d277f4436e8c1f3dd0d58043a2858585e84c8951ebea984fd8f64493e9bb0ff1129a5eca0a042f6f04df43afc454f76fe9cd082316e20c148c84b7fee061d212e5224e29c871225709b099f091908a01461ce6ce55a75ce98638eeb08078508f6d238db3c2bded76bd1448232047be13bebb4545bcb31dc9da0c0612bb6d9525de96a6f8c62a32c7b4357ac631ae76bad7f016b5084c0f3c538de7bdfce6755e15196bd749420f4ef15679c3f77ec6a5e474350dca8d9ba6aaf179bd3d26b95508090f955f5ebfb55bd5c4ffe82f2838ebf669bf7d5fff2cbe987e2833d7fdf7b59135f9ce7a76d58aeb7bef69d3573aa731114362c7ebbf3ac985ed8aa3c06a50715b3bbaab6befab47b6f7e42e1416555de2bac5e6a228938ce84e442d901ce5655b1adf535f9bdbd92b61148ed50414511141de0399f735be5893dff8a8fc070cb5f0e87b2c66571c6269f97b555b7d6cc41aff7ab8b694a2b8c62f7c201adaecf16ab32cf8f59538d8d2f562fddf5b25d5b1a63941bdcdf97d2ead297ed96c67d94652f61cf101d9434f4ce1d6397d65fafcd671dbdb87c2e8062037d61abe36a635badaa2d4aa1a0d16fae6faf8ad19a3186554c506aa07f5a97c6f0d4b457b86e141a58979efa7a7bebbcf2d533b826b6faddf76e9b799dcfe3c97c1de50cacaf3db18a678ef385e12983cca9dd9ce34c37c52e6e516290ad3d31ac1fef5e050a0cb6b6d9c2d69a169d957559e1166306e717d3cfd6724c57ae31ca0b32debdfe85f55a2f4c2bebf2282ec02e8c29c6e6d5d3ba302e67d9452923e3cf17b69756ac2f2cd751969dfe89e8b3ec05858cfc1c57b69a99f78dd9aa1f41694195af8b2fbeae79edb7b87628634cdbe7ed15b5d79cf8376541b530d5b35efb5ed5b57caec076dc297ffed657d676aa025e6bb71dd78ecdae2b5ca540ff63cbe9732c5b3977cb434181bdb8f2ebafbdabe65fcd5196692862d09a316ad57aafd795ad7c9439817282fdd4e2587fb626d5ddf25196e97c4fe22826a8f0b42cae6cbf93726daf519671f94350f48433e92c93d1e93694302cbd6db6987ef576d77bc1b8f6dcd5625a57d6dabff617dbea58f7cb3e9df4c215c6a17831abdd5835b19c7bbdf87e9b2c23014a09b05ad55e3db673653b86e55196ed3c11f5fc9cc848cf7f243421c9b2ef9f7c990472014a179cd3eab2f0ad34d5b85a15096675e1e715866bc6befa1f65d9cb8ad73b1a1615365046902d8d77e693f39eeb5f2d022c5bdeb15bbd9db6639e4759a6831282cbab0ab3df2d9d1c5b7da340010186ed89ab5b5dd7ead6f71a9a907c1fd24881f201ab63fc5aebdbadbd2d4e4759a6d36d27ee851dcd11140f600cef6a65cafbeb9f181db9ec5fc27199844351b8b02e6bad5bef55f3c573e66197775e9204650b8b799e35db9bbfdacef928cb3a9e5cca281db8fc66be3536ab75dfc2f809140ecca797de16e5735beb9fbb6c205fec67d6755f9ebf62598b69599765d1de6fcdd7be540355e7f4afbfb3bec6f3ef28cb94a064a0df2a5bb7e2dc56cb77af461913942ce84fbb37fd3b31fcff00142c28ae13ebfb1dabb456d41ae51041c1c0c4d5c61a6315d5f35ab77a59c262a409942bf645315af78561f7caf5c5c9cb0a8bca131640b1e2ed755937673ef35f9dd652c974015a55b55617cfd67579fd3eca3211efb62f9d725896b01861f9d229c7a57f92cf07502cd037df6feb9dd7f63b2b3dca32d1cb0bcb0b36652459f60903a5029c7ebdaafcf65618d5da42a180f5765618bdb0dab1c66c5f83ae5665d58d5997ce56bf9909901aaecfbbf36d596f33bd2ce7721ab0d9ad9bf9acdb3e56efe6a03eeecc98ad2a7afb95f9ae580784066a5999ea5e69be2cafaa7a86f97df2a9edd33ab3de55083243afb0af2e86f5cf77e75e47203ebe578e5dd6fe6b5b7ccd5e067be7d37bfbecf9aaf8a664e0bcf28cdfbab7b25ae33a067bafba2bc7b65f5d7335f7d8d8a69ce66927a697adf4a819db5a2f8b5fbbaa13e32031e0d93bdff8abebdab452fea900280c18d5bcfa0a7fe5f6f68a4759f685a01124ef23b24179586b4d9cedc558b658453718aaebb2a845b1abce51967db76992b7b32ce70b1ddf3db3c5ae4aebbc6f4702c2c3d65d5d15dbb8cf7aeba59f80bcd03be61cd3daeaf7baf6859d00dd61ad4b6dd7f9baae6b29c64776ccfab6eabf70eef8ead382bab0affe957e6be9dd2d8bdd11a80e8e51cd2fc6f5ee745f6cd980b890ef85fbd49aebaa624e2f0e680bd885b3d567b52d5dabead6215996bf5702d2c2b4ac6af3cc1bd369d1fe49385016faa5af852b4c6fadbfee0d84857a619b62aaff5af8e2bd6799087485be2f0c5b0ce3d8b4c26b3cabad7abfd5da97f751962501aa42ad6aa5fb9e6f5db8534ca980af959f5e16adea85ab074de1f65a2bc757b72e6e7fd2151597099202b7aa4ce9bc6675e18e7ba6c3aab3fa8af57bfb6b3d3b0d280a57a774e3ab676b61b5d2161432b630ec2b7cf1b716d3f50917c656bfd33ecfbb3fa6c139f4acb07961d3668b5713db4eb8d6ee1cf76aababc2aa4e9bf0385b186b4b7bb62ecc2b252026bcdd9dea5b556bdd6b6d95a3dfcace8e5fe73ca7c5eb126abfaeeadad6b5ed754d4b37015282d65665b18e51caf1bc7a4e024ac27ddce9cd9635b16b6a5cdd80e2b83466557e27c7f0bdd7c22012ac8bd97955acc22e8b6db68e70f7a518d6ad8575955f631c9011ba75af4eb1e5f96e6e3b56844e2dffabde8be29d5fcb8088c0315bddb9f735abaf7533011a02c766c5f6ba55b6aec774c3816985d58c59f5766d4dfb46de3cd3fb6fadded55afd009010b0ed964e4cafe595f77a839027fe8d2dad565f3ab3e585dde6851d8d1b7df7aaaae6a5f3a26f61d6080808fa5eceed85655eefc5f57f60ab8ad29d2b56edaeaeadf79c2534448890bc8f489665221e900fbe3eb759f75d515d4dcb12898680dac02c6a6dc758c7d6b5f1c66c7caf979531aeb3eabce31ee82bd7fdd8b2f9d6ac39074ba00b0c8807d3561cf3ae298673cd131b659928cb8ec0c4d81c6122cbb2ac04c6807640f59c175bf8da76dbdf73f3963001e9605657f36abdfd7dcdd9f71ab656d6ea16e7553fedd3e600b35a63ace297c6c195a9cd56df16fe795d3dabb1ab8b62d6d5f9da17df4d2100ba41be7def2b3fbdfab18cad346eae70cf33bfe6f75e1ae34036d817b716d7aa2d6c5fd3de81d0b8f0bdf7769c37363be57794653da01ae82be7593f63565579ce9cc3218168505d6a59b357f5efb6747e029a81ee15a6af6b695d61f94eeb5302d019dbf2ef14ab6f73ad8f611200c9e09a18fe3eeddc76667be98f054031c0d6c5b0fc18af16cf6a6918e4797fdeab2fdd2dc61d9b71ebaed8b5349eb7eb8bef5196894e5a74e24a44402fe896feccbffebc2cddd81d65590422f09f09f4b84d051559b6b3f119900becd417463bc6f7376659265219f362d8dcbda2d5ad70e73c5f2032acfdcaba9ae789b3dd778fb28ccbb2b0db94e86c315996815ac0efbdd66b7ee55bb5ee7694659c28dcba2dcb28d01878638d5915d5fcbab2beb24c96b93800c482eafab7f8cedb9a9faf6b5770d5af18be1c5f9f2db6ec8a8a0a2aaedee2d5578edd6ad50b94827b59d5e6ebd2566f7df18a02ece2fcc238ad77cfaa766cf4f29dc7c964d9771eb761588880c4d0945e3e7545afe7d45696080b8d4b29237119814e402fed966379d77b7ff64bfa3c229f779365a4cfeba730834c60e9bcaea52dd667b7b3ff28cbb2ece5858625c7a5e6fb9086e47d44f69770b2ac040a83e7cbe9bedb5e96cefada60e4d718b6f2ec56eb7e693bcab2ef4f5f962d01fac2d2bfddbad5ae6a95e7c5bc9895752d7be189f54a637b5d90804ac07165e16b2fab57eb35868db22cec3965261e4f4e10501795ae7b765c6fbd7aa5f9740244020b6b0b5bb86f5e599cee091a01bd9a4f8eaf6b2b9f15a72011e4ad75b6b2beaeadfeadaacbb2971b9770e34a385f1805280455bf5a67fd8f613cff678d0c92f3041310087aa5d7aa7a956fe757cef503b9e2d3766a71cbf2da2feff922dff378472a90073addd3aaf8a6f8e67be7be02c485a5efe7bfd8635ad56ad62deae557d757c595e2ab2fdd00a8036f652cdb5a379e7a6b5d8db2acee3800c481f9b6a2175fecc2b8ee3d411bc0bd669befb413db7bd52a03d2e2b236b57475a9beb8b5b1cfd1c0755d1cbb2a5661fa93ea5a03ca40afe8ecb9e67cefc66ea56f405964abe2eadad7b5315aaf6d4759169a4aa1c926078485a516ef1bf7a92dabb17d490084015d59ca31cbb3a657a65c7ba02b7635b18b62bb2ba7b6ea8e03b2a253abaaeea5d6c6aebf7d8f4017c8bd5bcc62ebbeadaecbc2120059e0b298625e55179b1cd74c4115783b2d7ead5bafc5796e0c44810a5b5c3de5bdfaaebbe6a32ca39f35d0f9d59c18ad2edc2debeb8cc0470df6e7a51657abea98ddd555c5270df4c2747555fdfb63d6aa681f3b5fb672ac6b45abcaba2c45c3be72c5b0752b0bc36cd57394652f5956e47306aaebfe6d2fcaa9d5ad8a7db4f898215ff756955ef479b6b2cbf7e1a3ef3dad89f1e5d763dc564358725c20f02903c6d7eeb7169e17fbc96bff90215fabe2f5627a5f578bad31ccac73b71846a79dff9447e0b387e6f56f9fd85fddea4aad4f053e7ad8ea2fbf9552ab9afcc2d5ce470cb5c2f4d26977affdb9bd9e7cc2f0d3a236bf75f1b6f655e12c83c0270f5b31adb4b2b4defc62ab53f10183ae57eef75695555d189ed5e84b22d1cae70bd6aeac6bd6795feb0bd395ebf78347edf7eafd566c2d7a59bc8fecc70bfaba6ae71a536d73fe7a8db28c7f96bde878472498bd2325af26cb743cce057feed818dff42bc6b55559bb2f983f765456b76c35f99c15c5b7d79e4f172acb35b6f25ffbf2ff7d3f7568acf3bf796216c574be34984737fac3858a6faef7cc955f98d6cbb7d067d5f639dfb9563baf7bfa68c1aaf63fadfbe2176397f3d1270bb65f975bd4726be58a4e5cc5070b15efdcdabd6bffef16b63f567cae607bbeaabb27362f4d279e3d1f2bdc5959ccfff2f9766a8b83dee692f3a9c2f598a567b698fe7b510ca3c0870ab366fe76578a59d845fbe5f58e26a691a8e4b2e6c68196c40c3206000066d50400a310002030241a8d078442d178525b1f14800159a8589e563c1689f33088511032c828630020041042666668689c005c149ede1230b7b67190eae794153e2967e036c437e4678548c68698720183c58ce5c710431d6140446665d70633986a49d4b09a06ad7e125265a14301dfb9cf353bb2b541006552f6f1cc393764785024d212b8a05380846179da13e5fec0164ff7d8b9bd86a82d943ba5965088ed7df9340ccad92dbe0d904427871ca08a2178545c7b09d3526aa24d9a7fe8ca8ef687e5cf76ea33a423dd1aed8fe6fa960718d388b510842d46e1154d7be434c8b96e0d338cbc47635431df99af2c71ad770f65c220e0fa9996da553a02e9548b51c17e0e1b46d522244abc62ffa6a08c21d2aa6aa7efdf8d187896a189b88d957956a97d9d43ce559d3255d655120df26f66e512c85a7b6261e02cf78c105d1998cbca201ea7a6157379adefa27248536a8b6ec223dfde6da27d9075029d248e5445a18bcd387eb22292946cb0df98e8778091856f3b9770ad14c9e1d8404237b5908b35a88da0aed53de312093c9040df08481ccce41ec12925c5fbbe0921f6903cbf375c0f73c6b778a0f862f77f11ce5037dcd7f9d76b55a6b0e859cb873775548c677bcad2344de88bf71a4a0f3a6d753c60a007194ec2188718bf686b2236d56f0a532699689b2fa2f2290dd2a22e6d33afd116f351a99a8b928389b25f5366e60f377156fae3fc4d59f547ff680b1c10527ed7d2d2481a96126936e0c5e1f588e5a705d7ff9ea41fe4a28f547dda145f067471039f928f490a57da31defc0d61ca6a9f9fbc5d8f26f671daad2e68d5e21f5d43d1ee130fb7a02740a09cb63c1534ced3ab795b3cb3ce3635c7d215b60a6560ada38a5ddb3eacfac51c17569409355e7066d9cb488342140419907426b0f7f07f237680583b1f8a04b780d1b91ef212c8ffb135406afd463ccee9feb2850806cda5b5b4aebf7276d9e3198bcc7a0bf827a6158c149c5547dee7e1b543c9085f7a9b727f2d2c49e56b4810a0feccb9cc5ba5e0d4cd9ae10162f8ae24e4a86c40f20fd9d09d8e0a988408b630810745c5f4fbaa3434d0579ab2887ddd77604b8e15780bdc77de293213042e3b05caa31f5b1f257445ae0146a08cf4d531bbfe926f348df27ab264cd831fbac0c9bc0b766050fa98674cf7a54ccd236b2cb0aa343f82364f9eabeb0a01c34db4da2ebc40f8dfe2846ddcac029ecb507debac0f57bece0b687c07d80759bf2cdeef86e587540b4f9c1f9115037e7574326ec398491dd558f255167ab4eca4b17bc049b640795e20568a2e83d34e5b9789fe4b75e82a69782d1a036b336b9232c07e6b96fd5163e40b4a5fc5d1f6356843559eb4bc7c0c28c54d6eab1e5607e7b328cfd59d1f61f881ebb00439d122f8a98a3669bbbc493b8c0a501304d8a1cceaf84d1d258b3a3f51f0be221691b82100be1274211e94681107f34162cc5d5dd7cc2ee5894c9bf49bd4589d612aa44b68b22a2ab3d4e603d216e396c56899354397a3da00399a0bcec1766a0029f4b5b9c0df5a8d517ab102636e937e832e27d693d6ede00bac1c285ad9fe016350a88638715bdbc03e7c67d11da65811b471d5bd52592eeecc1f7a29f45375adab5de6b21a6fa04338978117b50b489b2064109417a4e9a9841eca10efe96f7c9ddcfd9bcd7d95992b611544129c2a8f287a76e88fc44079229172be03e54126abdb717309d1b93f5a0c2e617e87b8ad04cc526c2aa9b0e0caa1ea032bcfb88ad094116841fd5aa135dd3601a9b0b5bb1a8acd163dff5371ac76f5868e5d17eded87850d2b961afcd45d02d67dfc79739991559576b56b6c22f8e0f4e8a18ef1bd62e6f4e25c6ed1bd66a50426ed9b6709166cc6c680767cef1edc017cde9e0c71b310c8c10e269618f78b79601eab067399df731f420c0f6a1e149944f650a26f03ec8b7222399833a4053d230acc845edd49603a15264894ea0a9bc5aeb2686c92af884de50ac4f9e99bc82a3034756ff85cb8f59e1485687cb8b20c0ea64c74ad54266ad51ed5828238d59365f7446a109df912236635e072a577542c319cd41d7dcbe614a650b66a037b752f767c7b82c66f2aadb4e2cc84fb3554aab8710d83ac03290dd69eba59467a6c30d12574eeaa6295545d2feb771204d41ccdd8bb1d31f16699a3619b807e06dac79478b11b472770697d785e536671ac363d8f7ba1a0809b07d0ab1406587bc4590c76f6d84fd4368f97bfd6a1fc143c9ad7720d38a03c8ff7d4aafd307d8f2bc58709f91125d29c1ce67b90903409fd11358b97dc7909dc31049b2a3674d249367a40b157c7edddf0117d4a75526012268e77a46b3a7c8e7442f02ab2261f58183844fe52bedc2b13d0d1aaed46f44081fca7678bfd1ad1565b7439d01bf1ba83d2f35c8ddee60f7d2b8371a4f72f2b1da5ae57f3a1516ab2def13207604c01ac1bade555318e74572fc444ba7653713184c51536a0077a5b8731a1fd239a06c48035cd7e4dba8de21a6c294da3de6392152c6f2039570c52e306270a19fe291a2e2232547d19b2bf09e309ea3432e662337833ac209595201ce4aa82bc46dcb741eff1382edf824ec13311e5755942d70aa183d5a7a4bd18e7a7a6ad0eeac3c9e2175242e32f54b91270af9167fe1ae6e46edcbb0325bed11e627843a7bf02cb6481a24771cc2360661bcf3c4b384c6e0871f29b9283e974f2706acbcbd0b61f8e02174b1e5c14e68a78eec8c75626ba4c1037004833f56bc3f7070ded104d2615ff6ebe17875eb01f5dfee50533d3caf02e60dd5a1455b39fae27935f6f214a783e15dbe185b005cb330d00594eb4dfe01115b6848fdb80b3e2d9ff372bbcab4fefb97e35ba42a4e25ae7900ee20036e6f64dfe4e780bbcd39330002dfaf197b5b3fdf35c9a6e070df3e26ed89b1a55410483fe5a91fde41f9ae1d95bd181b9805cff94a68417ea3bb5f2d93109bb20ba14154483e5b680f9d8302a81e98748110f6f56030a68999fd7154420b0f393fa08a6f3d768ae37c224d8d208452834cc9eb0a0085fe74444abb4633a6ded10c455605457e7723e28928a9b3ef252e58703d00e28ba7dc14941eade1401fc3ab02f440ab4d557815380ccb0ae32d3bad96fbc2fc797a7fc9502fd93a10dc9bd58f4dd11eec51910aa285f2ee6d4119fccf7c1d0230b81f39ade312d0472ba6c2a266997e5035f2a979b8673d1356e97d6e1e96916d01ec41d82edec5fa01ad9d1602fbf9a74504f1a037ccdfa28cb26feee0ebaa863b5ec4dfe38cc8567a98cc88f55a015fc1adc917a2b2c8b60c7d6d1b6226fc8885992fd011d6dd99d551914624734b48a1df8b4fb9f0624257c60dfdce85f4540a5233c1cc8f1a95c729c0d9f49bf26ea4a4aefc4177a1d12ec6062e9bb467b348f898a687eba88d29b38b32adbd2860ed9d0631e2464b47828f84b498c6357b33b10e0a6f1d3ab9f6c470dbabc83de3e8b2a16799e59c73b8803643261b1842e1c3a18385761d5216b85bce9961dc6d89b26b9cc90f5245089cc6faa286a0693bc219eed6bb371a6b8fa9577689441e99f13fd6dbad1f38292433883c0d19cef833264cfbfea0d7490aef5114ef7d8cf17928e2e7cb8fd1d63c221b37fe24920bb7e596ed5e6f08d40213775df1c177d24ad1899bfee963a4c3d8d69daf3ff8e329f175d6dc11a8ac7aeea0390e8f024bda3997819c588347af87db522bb33ee056477df6411501fc71490a655296c1451c7dd4c4e186c74790aca81420b9cacb6bff81f877702099834f43cb3b77ae33b2b04bad922d0371389baa38479b1306ad88493034073a3ac2c40fba31430a7346024e16109e6162de3e3d2135d513c3c2831e721ec0f0c79e2e7789cdc04d9abd146341a6bdf75f8bda5124bb7636535e9999c0f5213837d2f9156f31db9cf8d6f5e7a204e7646253f8bf463228fec84e47d4653a7b7a994313ac207a1dfb9d4df9e64262c86b07f4704ce6d66f70662531db15f50542d04ef4c32ea3251c22f1d9d557c74f51f6e74598a2e8b088a45a0ff7a6be8f2c39d2621d0c2e6e4bafb17e7e026dc1ec990c3cf50df39f92f36397f1f533c0d7a886d0b10f3be8d9f74cce05e0540ab2174b48358a6df2fa8ca51b76b5a1de052da10d2ddf5ad28b597b345397dba64295561a88542481dced53fac2e9e69562bec7d3351bf0017fa438b17e8fd72cdba261b94b22bfaef6ea85bc4b0445dd2bc29566f8697621555652c7183946f03f63c4d4c32714f1ec9950838050a03b782297ec9bba68ac9cdf8a6cb2abe9389f8b6ee6b0bcc81ee321541535001536456a687aa849f6934f061660321e5a05bbe2939c7f74e2818c0a6aceb6a0925765aa2fbe0847999655c443720f3a4f659e9b76060bfe296bc0bd790579ac9a2099623ffdb001c2298db8199126ed07884c9e815f2895114f7e3104d55d58f553fc4db3570a12da12a709cbbcde89be66cd61db6d69237bf2ba9b304a458564619fd010a6ba465551c8ff03a332d4d7362cd7fdda140b347bc206ecb3d73a1be0a48170595d990b4522f8c907b4a4f425027c5bc5b6002289d135d1cf2222fa2102bddee8bb46edfb4483241db86b3848e3ded0a14176e544545bf45778f3330510d4e055aea3911e2b1bf95fc9460ab4e5edda9b1ee6aeaa50358929d674fac51c4c6ee099e650a9a41f55d63bd78097dff4a20317aab90f7ef4241d78664701593f467e3d9a769662c68dadc71bf759919381d712328db498926ef72d954b07caf917bfcac77da59652b60f6c22aedec39e54e11eeddc6407f8cb3edffc3aafd88fbab1bfd2df5c5ded527c0251bda107a2204c06fc9df57081dc0b829842671ab7c218e2b564081ff1a33556a28810bd1a02ead7eb8befe5a53ac65d1558a546676c70022f6a35bf54cd0aa8a80b7478db82bab14805510a14c48763e5d36ade3898a462d6f5afcf9d26bfb5f0c907a89f7163f585386e54ec59d5d31ea36fadbf30ace1b7de64455c1d7491f5f41c793294d31ea8cfe62fa8e002838044c9f55d3dd25318a14aed858b4313e93c3cf982fab3644801cda4a157e846b496c5626dd34f0709d80304e45c294d0357d26c20bbef77fc1f00e5b4df4e8d16fa8d16f283c8d635d7508c3cc4ff23745bc10285f4884d7e7b8b59b571d17711f54bfdc4cdc101ee791de2e231a9b2e88df4e227403b024dc07e8d5a756726b8061dc201a3d12a7855f4f709870ca41adb2a4d7e4fd68e6925dde52f22452ada22a338666c1651833de02bd5e68d6b1658ae886e170aaa8b8380caf118e01fe911e09cae04e5735cbf9270763671575817d106928aa1a74791ea0bb540d7abe916a8d469d6ced70a9339f1d0e287d07412b8d9d649c0106f6a63997208fcc8130d549431b3ffcc15ea10f22c926167af84d692628503a351ecd28c593aab9ebb1fb07f7f8f89bdc8491c6262a1ce6c467482432a3f49e63061abd5d1eb39c3d988154010aa88d7a82179206111568038e2f87861e9486e3ba25106766410e2d4e0f580d60afc941054cd0cb46627cccbc93d95f2eec94438e92c10e22f68afa04a262cd11f7d5a1ef57aa14956699b32d774effe0c609758eb6ece4d13d7817732c0bba3dc67b7add14d9014d26a746bf71d0fe9295272715bd8edeb967d5d81a0fe00cb351d05f6135a788006839f24d32b313952b07181eacb9960e8e4b0dde2fe48435d78bcbcab91ba893d2167c4807b317d92dbecd1565d80b72e3fec3769166b53b44564ada646e38e8b2d7be413e660528a80d1bb210d221a56f99c359417b95a83441db30ac87bb1cf853421d1973e9bc30d2a13435bbb38bd33b2b39584007fc316eba477c19182fe7ada1a0845efd0dbbce6f4a8c2d6f7a12d8aeb087b70bfb4011cc9447bb00e554de2447ff147a746c811bcc4e80db886ccf1eb1be210d5a3aba45b2f8f05ddce1f0eefc5558f44a90398f97751fd5ec8ed0f39290580b63c504109f461ab65c58e7b46f3d54437a26f7f3dc02c6d2b528ac8744c339a10dcd0077befed425a2d6c0bd8778b21af1ffabed98708f20d72215772a6e5f13d4a2e66bbae0f92bf1e2c89d463b5dbd6699bf0e4de362cca410fc0656ba0268ed834cf399941254df5646d4108fda9d1f66e50fffdc698b90d2e4517afb94f4b6cd789a988ce691e7689e584147efc05a01da3b20bfa903c064290ca63d6bbe1f19b9f5f9f69fbf4a70e586600e9534a832ea79b0fc1b1b76b39e167f032ce6e887495a2af320ac097c95f6c1d682657c990a24a2888a981feead850d3a00c0cc391553206978919f32290a09fa4ac413c4c8c15b3156a58812b0580671e26f39e8ab31339d4ecea5d5ff21657425a65474c46bc681810f09d264ebb927516c1c58bf1a9190c7233302f753870141dd7b4902204d33c3e0d5f8117c234fefeeaea88c0f604520df64c0013d37196f00304c1de48527f7adf60100240c1971007c873449e22c50265f816daaf99aac13181333ce7968a9e7f8dba8f181bad0569ab14e7b60e9d149951b907254af205262691a6b16ee50beaf4fc18a091ec68a7f54782507bbcd124d5330da157a04704b1ebb983d1a5372b4ebd06daebeeff5ea46fd7c6a92ceebfae40ed5ff93217c77fdbbedeacc346eacacd07478934317fe8b0af2712f1739a1579a174657144b68f3d8fb185a9d59b5adf922faa4ee7c64fe17dda9f59205e5fcc0979c3c6ea7a33700bf2edde88fbfa907f5bd2d4b7cccc71f989f68c8c8725e9d1d6fbc95f75e692ed7f5f9df8e09ef0e9730d0d0574e47e751c56f4e3074070bfe2d269fc5d73c6a7821b4f713fc10b69c94ae9f2840b8b97f7cf179007c29e54abbd0164696bb2d6db7d6437617a6f62b8d4c469b586c4a515a54805ec9dbdbd1f663c4c675897377d996fac9f0010b58eca12befb57300a01280318061846d7c3d078fee011cee3fafcd45997438cdc2f5bbb56d09ef2870263ebfb639ba3ec00788d4c32f78abd939252e87063bc68cb3a4dbead100c41ce24715527f81e92d2daff994f465db72b1afe703b788a4543665f5ff4813dbc6b0526b167a44a5b791328a6bd33092820778bcf99d5db2f3fb507aecba31a16dd643f989ac00dfc5f135f84adb068d3f3abe264ef2cba2048e95b99e0a6fda661cb43012270a7b91c02833ffe56ec58131c245ca077a32ea596eddee3af477e1fd21543556a274ce3a1714fcdf43016e220f0ff6d1a8d2aafcc389c32cf125d17d100cc97c2fff198ec57d523c4c55e35f155bda67a3f51ffa541ce1c0c94901b1453b2033a86f0e315a633cb461c0f8b31eb235535c924ccd471cec23a1ee92818f98f3f57c81d9a21930fa01d1709f65ffcd8914d59f785d1b3276be4717ac79172828a0ef2fa88c7135ec8a3c7a5cdc2bdebe362b16b0217a758755c581a517dd0cece667c3c4734b09254c2eca98e0e62a5cfdf0b487832fc9ed1f667700e163fab3794ad267da3a63954d663d940d017cde822257dee163cbe7fff9e05c92e114e2beede7b161692bb24412cd1ed8e87fbdd14055885d56dd724cdf4397e3015098d32bcd17bc6f445ebfce7dea4f291a2069355c78edc8fdf835321d94eff2eba4a4fa6e2b585521fda2b3aa624d4458ac3dd795286af32ab2763ceb50378ab2a1bd56ff3d5daec33aae3be7314aeed18b547ef7efe2c56bf039c350e8cdc1e006ed88aaa532d8b2082f75eb95f21f5dcd1fce3fd3f101bee7d99b7b6f5f69b42748ba02ea3adfd9105358724bf54e8aef8d0713b9cd422991702067f4b5207cc1b364413c7c9a449578cfc160e96aa7bd36da58a482b5246cf5cb23c8b44351ab5241bc4babe9711a3641be8ac7c07e4cb7d7a041fe3dff0e1a53573e703e2c48469bfc5e2ab75a28970b13254fe615379d026d4f861abd51e5b014f794161ebaaf47d815b34b31cc1550a26ed75f61da2352e32ef80c45a752d63600dced862a9634bcd66d609591fe07becd6b0a0de3e4b6d554e3c6df4e4437f250dc6e295caf94a73fb3af6570b82f4bde8e49449a18931149fb5cb326e4d15eb38b4267b00f1625096c6ea1e21f3f60c6a97e34c81f01b4becfdcafd5f99d10fdea9dfd5ed2e24ada98c4ffe2a79b667ac789f2767fb92dedbd9b542f71b5f7b955a84ffa1d75b294e8bb5f7a38697e039a95b7fe1c7f1c97c99ef026539403f0e239c28f97b129d2872cdc1ebbefde518a82378747cc1fb06a4fc5f8bef6b14a3ea11222d60dd31a7d05177f24eba81b6f202cd15cd1b519cc2808f99bebb34e18628e8b5aa0e6e211cb819e23a9ecb9d8a01eb97a0a2526c94032f37c65a7ed82641240b1763411f4b7af87264bb22ed508613e6480b21ab6e7ecc91e280ac4671de80395f671789302cc4725d36bd5e098cba46ad0bcaf9687904fac7b13ee16858fc9a7d790f25ff557bf575e597676add47d911bfc9992d4bb4b133328d731eb5ca82fa2fe81befd994bc8cfd83ae0ec3f20fe9d70379e4cfd607490c2795db13a2b18bce7008ce579f887c0b48136187a1d1905ce20444267fa42600c402add28e90070259355abf16b4d81ced516596f2e290021fc9e17423da6e3ecfcab460a0ed222f0bb63947d409ce070cada24ea1f2d676b83b98d2ff41a4d9c53af611fb49e6852b51adc8dc882a18f85c1df6c3cb468b86d05c88c39d7353dbc1ba27f5c5d8729d1caa4037ce66260d0a2dd9465147def6eacff9b7eb62e707696fd0965e9570b7f04c039f2737de48f2ddd5fc5c92649695b2f750bddcf4b7357e56e8d90eee89141c32c663f66eedf1b54aaa8508f8250a1ea650f53cea3b15097c71176ce7eb63f369c381385f0755e483e844969e7db17749110ba5eeb424c5e712036c4ed63aa09381655a73de0e5f0f91d794dbeb5f75e89f78ec009b4c697c43b4445eeae1565919dd77de00d90396672829d43137bd66bc9118541b984148560769b100ad7b8e488a652b8930044f56ee1c997821b00e0305bfdfc32ab7c670869ea2f5c55213b3fd1467090f9091855da9007f17a33bb0514b03560e241ccd4993a3314f13ac865a178d5ced302883c7a825d854286d691d52be02a36c483285707645a88eef500cb22ba9a249dfd705aab88d917d39f1975afc5a5475c34e968f45c36f6cadedab04d2af522c7acf67407e47e4b25e85d6dea49006713d7851094ab2e857ce19177a808d8d92b09879f21270d85174eac20237cb49ed314cc4b9871594e525a9f313c4dc3b8f104b47f78f31e0a017e27d37a61b2f85d46ca094812c31bd8ac870c01924611a5416283c03b65b294c93d68a4cd80e53b00934b3080d472e77247580134c60ce8c7977c0240c629e3f4f462da59be8c4136436a3bb14145723ca65e6334476cfa9d480d6b0a06ce06144b6fe5d6c290a8c5f4e679eeee4089833012e89f3a326bdadf347e72f39f04f3bb823b774e56da60584fa6b45c61ff11b4a0ed541f433bfc3ff1da74bfca9ca3edf7e5db83effc321fbc1792f6857788dcaac8a0b9adfea2deec8434e7e23846ffbb0e7773afd42827615c1f2dca07b88dc48aac25575447bdc87fe4758559250f6ee89a51fedc6a314fcb1fe207358ee723dc8115683c952958b16b36b2d5df632a713d99b5e7371aed60ca02d21d019f7ec2b01ba571facb2970d26985e29d5de7bdd03e2d731558800246c9cdaf5908e1689eca7225c625ada37f23bbd132cc6d2c83ab41493d840b8c584cf07ea353519509dd21d4d26da490ce1840e54aa585f512c8b8ae96e5dec598e4e355cf4c4c72b6c0bb8e4e31a5588e13df27771d45a45637c9dcf3e90b16f715d5be79e4c7ccb3e87c643500024fa7805462fa0d9ea12158f38edd2e430d5e6529c0cee96b6cf2e071e811dd8ff027743eee51fca80b0fa86b8d53a0772ad3e77c48b39fa16e1dda8149e4d8b6531a913f4e95e80ab2d73b07e5b01fd730f237fd5843efaabfd88989cfab1de3b76b94fa49c6726c5d9703dc40bc0df83bf4c53e33ee0938bd18ffc5c533ba15b2fbdccc812e1e1e727f59490390309ea1c76d39337b8ae10676e79d8003efcf38d7fc529212b22c0a2ad05e985d7f29e7b75349009c16c66445e7098a7158a1be32d2766d5df1cb30ac86dc39a147acbb1f3a9df133d149d594ac1bfa5f67a3a8fa6395831cc0ce9ef1f904323999ca5b6f3eb742190f06ac7b6cf4b96b7b4224db2e475ebbec0bac41a32b8e585cc262eb28764ec0fdcdf6e1ad65c42f2a38cc48ac47f0ed3fb9202d6e6427cce153b073d5f5b169d93a323e87bea7d92f930d7ee192cfd94e4db00760b12962e318d2d280635f428eda363556b197e99701bc3dc898ff3412673af3eab3ba20cc0ff3496d3a3d75095c9f1c06b783729874bbcb17ae901be22f0755d210ba10408863a83d4296f3e5365e4195360f771bddc2e7451a744eac026e8fe6127faef3cc459fdc1d99306eb77b6eba3e7ff828fcc2b66935295f867fbb3bfc42cbfe3b3d0796b6c9ea95c29602222e7f7a061410d887cc3586b3b4e2183006fdcadaa43818692ad694ec0c28007770ef74fec8599f5e0d109425b2cc8613a3a647c6af62787a79d057998fa59d9d987df2ead9a72a4131b24b035c9a5f1395c3c4fbae745874142f374db8b84ef4677c0fbcf0960ae001301df6fdc082a11985cd7bca40757f36cf9febe7cc3ba6fcc35025d39e2e8ab81eddbd7632022f5eb4d4ea73a3d6ebb02cbfb7e1df9b98819f7e0c792da0f25cc89bd1a465409ff10e7f00c383f2317795ae5ab44e040d27eff88843ca86c44d2e6b98988302447f2dc3dc39af417d5a9e3f9131f5a406bbce95e821dc338a90d3c670c4d03afe9868a6d93ffa69da6033ea9da88b94b00b332198880141c3aecfcb4e6bf98fd2741935e0ead83797c9f36f73c95101efbd09aa076c322c55adfc34b2315e1deb9a95b74eced0ed768d4be776b05a65a19d8dafd7fb74bd437470ab2761e38cc3f29cf631e93e50bc749f908aae1f7928f5d9cec83ccace9a915b62c0c928dc39bf35ab85dc7918b15196d264aede92d8aabf9773d1a9ad58e6c4fd6553f969521021c3e61e40e8c12fafe8fdfc7653935eb2b42f81b8dde3098b480352ecab98117283a68fbd7d558954ec75b3f808881d3b8bb63a1135b22f8d3a922b3f994fc70517c6827f4ce27b9f5f52c4db63040957d290d96d035974ab6586a21735c6e148d63217129c1509e9fdff233f721c4625af83867056189ba00ca79195feee7304b5cab0a1aeabb73e5061ace047b93a419035b44726fc2d00b21f0821260d905fc3f75a2def94e925f75976ffa138b66dcb647169dd59131ec02efa7254c0bc097667f6e4b3d82f447230e2564c240b443f598aba763b1d00ea5a9dd13fdbdc543429270f8cb38cd3f0aaf831ff564cc1948811aa751cbea38a79010e41cc0b91e271934de25106b6174e91137f9da568b25db4ac7fdde0a596d3af5cc1380a2a20c1e541fcc3a92469c14e4ee455f26d24b87917f96b458b740570c7f99853161343f8677559b832890160a0976b3187e906bd891d407d98bd1ba5d0a781141777b8ac191d3241c87df30311094316566600b822927cf721467ae88ccf1ea5982eb2a0f8d41a8d394766300ef82c0d376497b6d2d0ff229431ac09e93c4c91018eb42bf0ab0c58e35d6f1da01c21f32c41f39bfdedc4eb876756373363ee2c1345e2fc733a293903e3f3a2aa53712a4e25f927c4efda12f2e8b627b1271bbec7b1d585359635c763887f3de6331e18401acad026166bb3a4045cd8c3a10fac5696070a1cb506629bcfe68e49b385a0fe479cf879555f90a0fa263bb272efb42e68334ad1484ac8bb3d32d6bea13177205709140ee16ece90afd9309a89919294111733d1fe21ce4248e765615b4f92d4a9bbd0df17bb65dc2a091fe800501172a123d57483d1718885b0187b6260c97bce09928dd43377a226dcfea73e86f5c39beb32e362a67dcc34c3bccc6161f41717107c2a5beb694d2fccfedd4f8742b7b0fc31842c1b4e395cbef8dbdb01bc1705e326bf834cc157b2747f068265ea9e8f6a57480073d71005c0136851b7c65614ba48360b0d0eb113c7cea2da30052399631fb31fbfbc95d3c1fb1ac799a3940d411b026a4f03e39803f326887893bd891199b5e75a97fdc46d3e84a01e22d4324edb7b7352985020916f8299b5d82080d3b49f759c803872796d1ff1e6160b108ed284253c1e521027b740d50cb5dbbd16b0a1db91683016d979117d069f6fa4ed54b55b299184babeadccdc814f7150c380779e8c17f96409255e2035239a2c1d5458845d3759fc95761b6507370c691a6a03f542b9444e3b256fca807a7decb90018ca6d94d92f893646aa0aca2638c507075b40bc89dd57cf8e871e8a9800da1c30473d899a1db28c91421ffe3e439313e12717242cf7388c79f4d2e9b12b53cd39584dbd9080d39e8bb104dc2934c22e46f1ba9a4d04d1f1730eb1b70953216f671cffcfb9ee80bb750df36006f06eeda6560c8d33d38fbbb961adce26a1d9e3438828c027ae425e3061d34690181ee3839b44a97444155e72e8eefe84078e9c9665e1fd4e355370e598aa6ab29285d21d7fb85029436871e282ed0045282662e327cb94923277268ff1c91e1cf1501fdbd85f19d9ad1149f8c40858f300bd2487d1d0b66609bab010a15057e977a01738ff5ef0a2f0a086eb5c1684f74dccf3b4f9f41841ca3d38fdaaf01cfbb123ecf7b61b6cfcdc55f0bfbb1cf7b00a6881a4135b990813517bfbb3ea8fd7a82e92675b9adf29349cadf49ed60a7b696f4f7b48ea36601bf15d8c86fcb09323ea5ace023973916f6fffcdb11d0215ddb87f2e7f52d6d94a8f23be40fafc154b4fa30f4bf12aa46e93513c6596c14922cdd6d43c515003a9000e4b5d3cd993a43de9edae22b77adcd50ab5ed7dd045ce9d0a22c0208f5b2a39c2435260e5c7749c3f12ba629c01302637d060db440e0e1b6889b5bd1aab9734e51cad898a48d0d0b307fc7f8b7b836a7c2f705b0c061d470ff0bad22634bb3588a6af6271bcb144c5226b0cc22f871a844a07c9128392ab9a11a85cb704c8ccb8ac7cd2d26fa150473c47b57fcc046ba93b7f193c811d3d13aae0ffa96d8ad2d79d484546b5364ec944fe263020977d1c60ca1d5226e6eb33c84f6cba163bd5065df9c43cfceb2caebf302add7a9be08a1b59be95166625819e1bef76ea589683b0f6511fd288b70e6374fc395be93431c87e6de9af99166fd06cedc5d23ba57c559322bcce805392bc722c6689c342f8451d7c5fdd5ec588bcbdd637b7bde644aa32b71c0ebfaf25f833f39791d6a829e09e28ed8fd4d390297ba1348e28249cd147dd04ec467a93a182eb480fac02bd77529e84b9e302f569a64411e034bfb93d3d3264e7de43cc1eecea134f8eb07bdbea4111265a9683b9ac1740213d369688b98dfd22915ce80c3e51d77f940754f1b28088c492a7c93d810d65b1a67abc3c53a9bd86905e1791df14987732076677bc04097fd125da162f46fbc010362cbd2477ee8d5ab1fe899b6ff14046f5a42ed458563967a9173ce33adba3ca378178761200e66fe2f526a476ea42f4dd9a23118e25937c59a69aa3427f48f54ed041db8e6dc8f5cd1aa4b5f5b2b3333b4decfdb078d1617108774dc57744eab8732a4608df311a226144771686c9233300d3f249568cf8b06ba420bca4aa8dfa8519655d66e6b5ef26f35b873977817d39a9383dca421767b2c206065cde3a8a80d431fb8062ffdb332773ba38e6e6e00a9a5ac9fe987ea11f9ceeae1bc84001ab3e5c667aeb9dac380db8691eac52b56b1f330e196fd6c4663d44840a243349b468b8040dfc383ac1a027fb2308b0a119f4f7e8ed455af944b57195a60bbfa394c4897fb1452002551e93e86960061a564073d52585c03fa16fd88e2d2082b7e354a47ba24d1cc75ed02e3d5bc5b16674053c0e3f07419cb103b1c9ed44f1d85dc7909e84bf882cf01fdf83c67fbcce2ab778a39bce29f918d85359b604ddcf51a526e74460df7d9cf2ae435234b97b48af806a980162810f0b0ae17e28e8f0fb6b1148dc3364995556cf15e802f06ccbc8bdc63bfcc5352aa26521060ba00f0ccc08d92965207629e0a3f86dccae80125060bca79412bd16efec7008cbbcd9a9358d5b87aee773f64e41788325b658f688b61b63133b293bd47f592b46022f9fca7042a9de10e3a8ec4415b45c96eea71edc9343b279b950ff3e27617272e950c40d36f78b8b3987d39ccb0b50bb075213a7a684d10d4546c80da4d091b6f1ed7b078966f0f15c744d066a0f181a72017d99cc88609fbd716edad4b05a4f5c335e28dd7606638e7aa7a39046122f8d72efda3115a3b753767326a6d4605beeba285ba5b6b98801a06e32e999c2de562d3d6649e9a017cd516c0af1f845f24a49922503d31047f242191c7dd4560e518591b2e7f35425487bff407bfb9f1ff59aa3e3e0aa8398d43bf52c2cb2a3a324029cb43298377923a0611dbb0a8da2e2fdb0ccc75592cb00bc48a14b11fc0e059f2ccf510f19d29d1bfa2e4e93a29a3b22f07e9cca355eeff0150d017fd0b59f8084ba8d08cfb09136201b7f0e8582e3de83b8bed7c343c1a9254a7e9249b1852647ed77fc9444244781c827d2ca2cd814f482ec4fe762144b36e9d0876a3f89bde7191534fd3140b6a5a869084ee2781e32dabef8c14d4df9afee78bf7f1f241b8c9dc495306f659ef5d00987ebafd27ea22ff450b1a97ae4dc55c682ecdc41b56dd18d44983e65d92d46f202337d0364b8f69d95d25c451d1de08808275dab5505391a52b4d459a3733899649bd3a99358517b0a8adbe187a76884510d4f5fa28274bed8a4b8d8b7664c5a0ca8b6e548d01c323fcdf0dddbfa2aaae16c3a9f96478be3b32107cb90244e6256b3d1f8b4535b453b2d6c435107d9460baeea77021153fa31fd1bfcd7c66d685ef00b9ab986d17b5de08f98bc6b583c5de73b50f403080a62ad831a645ebdfe9fe41a1a60d010cb703f500f71674e13a28ba34fb4ff7e11af8191a3f4135f541bb49ed352da68300fde085f840a4db248c021094b4a0ff4f8cc0514dc4737f8af9e015d199a61ec717be9e6c0d07cef8b5325915088f69a84d87ae63f6a13b2cb6cdb7542505e9a4fb5f5d80fe1b616eb9e4cc4e188aa6227ab105ce1e85b9a02f9d70a5d71b9e8d69baf6081b29b6392e591d4af213133e9c32e2835f67c028bed43ac45f7b7f9eac0442fd625a58e684dbc36823361e31223552894d113310625f25119bebb6227203ce8fe586f9d146573568fee4620d722915562b10dc76eeb272c4cc3eadb9ebd751d6c3f782310f5b39bb5aa03d0ec1a78fc32222ec9d51d903cf1dd25b1108ac2ba1e4ac86829a81d43a361a0ea910fbcf4d72fccd65fd8d9f4c07f4b004275d39da2baf3d6999ef168e441922295f41310157d10edcea5f3ef0e31a395ae001db5c6a2e904c4fe7449ab5c74219ad8873c9fb62b0cb067542c2afb93f38bb9d5293d45fa3d0efb2131f126b21a758b87975b52ff2933ce5b8e1b18559d5c6e187ee717238404a6a061c66a1c794fa52a6f0766e9943ebcb3caf2a10051f1668a73fa005cffdcbf2981cfbe1fc31f97c6e3df5df61ec0cda34300102c1047eb7e789e5a16727c44b4017db664ce0089e20595226ff766d37e8f2bd76a6bbf8ef3d9a98c1702c71aa4ecb7ac290d8e3a9247e7cd53bcaf70918175dfb6f42738a57d15dcfc5af81454e9de42d731121b3e888bf388b00c970427d0a979ef23868cb2518c000519d1f2975c22ba76622285261f0be90fcf459d84997e978061ffc8168504a5768a5cd6404c5bff21e2029de2a217acad7e1211b03df3216a0c5be3f0ce8e847a18e7bb4f98247d4a4b0cb6108531f865e94ae8a2e829e6eff54343de48f268450b922c06f1b83d91da0fd39bd9f15328470d9847a2b35734cee16202a52d28960f8ff5e3fb545f3be13bdceafa952a1194f93454fa8e2ba18ba86493f3bc455f4e7ec1add3a6fe096b1b7f50b5ff3c3f73cf6e99deedc4cc3dd606a7b9c42cc779286c314358dbb24008e5a944a485020a9269afdab74818435c63cffced0abbb40928fa22cbaa842ed1ec587fd31083f747aa5b8c697714038ebcda58c7fed2add589d9925f1f884f7a44b467fc0735bbf46c99c0f2abeaec0bee2a6aebb4d3e5b99fcb0e64e311712571f607d4138eb924fa0e936596a78017300c6e153c118699f20c0a05d3edaece791abb2ca6db0252cbb8b80548012e933fb99d4e78b00d8be07a8031826dc3db2e3c8ab54e51e051c69c8fc9012c57a1047ca79f57d25de60fe1d7dfdf1e78596dcf1adb56b28fbc092456e55d3d961d1bcc31fc98209fefe79fe17fe4f872409a9c2461223e264d4647ac7036059da1621ddd5d787fd2da1b270d6ae153c2757ad3239682b3af341a840362e105596ecab65e89cefff30179da29afc6d254f1d5452d2e7c273d98ed5d2bfa31e749e3f54e69bce47b24c2dd66bb312d2eb1941856793520e8ad055c7f0d7a2a671e133b9076b1690e01b4e289bef4f81666ebb5b9e129fb748282d81bd49ef69ec218f485653d763cb7c3d454d35cfee9070a8c6dfab212da2e4cc539aa2441ae3b2a212fecb5d516a9509c884e77640551a6cff3555b7e63e21cb251e556d41fad3a4522f42403f8bb495995ae083062d0a7dfe47f7c49902310a483a83315e426022e2ae04a2c4fa2b0c85eeb068adcd7b399af2c774f03af2b2fff435ccbe46b396fd645623edfbaecad4ff5b3f0121bc8e71421c789ea586238bebe08d16e0cf513cfc6471b372ff3ddba2f87e2829e6318da3404f947f96e2180c5b4cd7ab3d82af337b593a80d2010a0973b545a290dd509218885c20fbf152c278ee1c3096ccb0bd39cc9727e1d0ac7713c08c739c8fec9741be102b3e485eb3bfccaf81e2caca75b628b30ab8b53e74381fb26e13413a434d04bb97ce09e97759135dec9945024d7032b1a1098e9ab4b37e4698b7a4b469bf6e2efb157527c44ef6234e0916f883d88890be667556e8d436ca40b084dd45cc81ccf8722ee3aefa5b40d68beda65037b2249666b29279b40fc046a2306de9961d03f0b835c24205a5194415b394e05c28c5ccef7026bb53ebc23d7f4caec893c0de4f3cb4f787cb0e0a342f4dfe0f5cdda85ceee0cb1bdf901d4fee7887fcca69fd250d32ddded0ee660eff25d91f98703a097f23337b2a3bc0e7f8c9798a7d39091b915c30c30792cc3b9223f3b3c3bc1a512fa738ca9bd0d1a7b46cc02e5491cc6f2863c88e351848847e6c61944b77d208bad642349530e5104870c07a0c12a693a985742939c90968a52efe1986488e1dfed6d056778bce63d7e29063d128a11dd631fc5724cc169f3c5dee2003a4a350b91339e51dca7e4736b1804f041682c0c70576f5c34d95c406d1f39f6a12fd621b39900657602d5ddfcbe1021271cea0d3a0e412819a2086863bb58e73b32f7ca174d1f63d896b161d2e170db0fa030d34b26b886c106e083f2f169b6d0fb9138b1eb65c277605f59352f01525c6eb03481972069ab17236592821a0b65d44415111701c0729d39c43888406bd03f0c61a839707ab456c6d87bceee6a5fdcdafe70ca9d8882821d2f778444ef21d59a1fe9e167cfcc253447ba880df17d890ac167f8c00f05d4556a167f07995fd715800688578fc57326896bb0355687387c62a08e28496d504e93be3df7865a9b629eae71456e1209bf7d15354180584636fb6050454f0ab1604aa5aa7fb046866a8f8138e88a50292152aa6845e0932d37e0119c04032c45bf51a23790c615f9073696dbefdab783abe044450dde6ae9805b8b12b247896ca5274c71c0a204425b93e948645a41b5f63ac2b4720866b11a7b59008bc72dda8bdb8462bc593b99688c661e2e07fb033b88f95d334a8ff0835cac04598b2bd5a4cf036e2b65c800f091d24202b36d8829dd29d7d17eb5db89f79f8bffd6265f930d3ac16ce05a64d7e268405b7e24e45eb284d5429d8c4f141314e956870bd412acc36a9318b8ba8893a25b2cd304820db3c84120572ece7a18f60daa38a7762c6c3691bd2a17a36cae92cae333da8196d1d682dadc854d782bd9e6371b07513773b324c0c0fa0611a8b8d2576600bca090cc14aea60d6f33fc8e6b1e539b7c75555ba2f9fa1c05d2e9d4774662d3aea9d57e43f8af0c0a4dd0e69633b8abb10ce5042ec7063d96d81cc2d534c6ff0ee41fe461ef79dd844b8b0b9f73b22fe8ca4eef841973e056062b61cfbedb0aaf6aaecae248d2feb503bad197073607c883ca6c0319dce6b3f22c29c7f83fc1f87ea4dcd8f7b743c4cc0e3a1caaef8712d71ffad0fa052a83afd3dbefee85377946ec9654e94e1b449a614fd14186cb521d6f6f891e7168c84bbaf13428827dbb157a3ea08090c320a76694d9824d3ee618cc145b5fec671198e0d1c39762065aef07abee58e0ee670eefdfcde45df42689728a1e13f40dd645a748f095a0c15ff4cc7957a0dbee9ee80913da27d00be9e8ac06344614856bbdc15a07bf4942c07558c300b41f7a15471b9e6d61a25353f03e8b873be7db28aa1c5086401d922d875395e703064f107961fe943bf1586905d6ae2f4af1553308f4660a8543a18c184d06a56ce16e53881961502c531a2aa0c7d79fceb27f483a4ee2aca9e3fc170e301341144d1146800c06ccd91edcf2d6bad16439d3e87aeb41c37eb459dbc2f2d4380dbb02db681073f340d0fd3502395aa35afe3dee3711320ef430ddb9fae65c98304cd0161c48ef4ba39f26fb1e8be0601cf406f78d1c64be9ddd5f2d6bff04f0f7a53928ac48e6d5d2c977b7747c526c3b271f458aaabd1443a02677ed8206d14552eef26847f060c4d5d849983af31053418ebde252a79d20b76b701793c50a8c53b4c9233ce9d100c6662362ce844cbe296fa7726ef63213ca573eac840c0d6bc62697efc1282051232bca60bed0b73b35f1ba64ea5c176ac2943ad5ef44c67f6a8c1fa5b7512eb298f4f0729c06621d9dbdf787726f3671d66ec8cb6dcd500fea7accd1a85d1e018f77fef7a98cceaed97afbc7c4395719042d20a3798c3b8d3a3e1f3dd9d2d4bf3a827ff95517ad0206808260c77dd6339e2f12a1d47fe6f8338c6f8ab5f714cef21012327a7cf577412a2becaef06ddda4f9d44e59f5a7916cdb9a5f9e61769bed58f45679a8c8363449dc05893859ff93c0a1612f801744cad8ed610ffe8d5301b7a3f0503ecfd09e283d508c0d41e5de165dd03defd8d7b3cc8e61a08283fa41287e72411629841a1f18a8cdf90ee12a10962629e1eeeb3378335606c53fc8ac39c0fd3215adf22c3cef45ae4f4d419d73ded20914b63cc5dc3004aed3004edbc7f376dabc9ec48fad6964457fbf6eeac0667ed02173f6f69a12944f6c0fd21a2a36b72120c5c82e921abb5ee01db7060f332d3fac17b42e186b7991e85f3fb61e830e0b7822a1d3e6ac837810d8a97175a27a12b3a703f18288b63503ec8d96f32c672eaaa623e66adb8c535fc2764060f77fb9a6881b393d3742b709a8b5286cc3cf323b7c3698629743ab6d48c1eeae1c0228c64875003c6e62ea019000d543dd5a1f4bfa0ff1bd503886c4307eb70c46bd1d9ee6918d6694a79eb0f7213d0bf9f8cbdc4bbae4ef2a938e9441d80e1e11471f0b986834404e1f03bbb5c37ff5bce6f79d767695ebe0fb8b06fa5881cb441c6741de1084b32b787dda6efbb5470395bfaf71241243220747230841a6ee40d8ac545c94e10aa475f9a694ecb72dc246fe4046875d41e47f686496fdff2eb13836d8f45ea18fd407fecf7bc9fbfa82ae8c4b6d07997b6cdac016322841a35713cfece7401209f85658fcb1937066a504554f3c7896d86e03b587fc1b0ba298ae623dda3fe0ec5d06bb048be374a18117a9c6d8c6df1abe3b54ee62ba3c4fd73e7f8abed9611a8c830e686cd57ae021a8ff0719c7b7cd27a2ef8be49f5fb32521b1b5f70b1fbd78bbe706df1b1252fa39103d72ffacad8a04a6d03e1db4d01bb2d5666cd6f45cf418ed02e4d18b85cd670f015cd87518776accb8868086bca9fd16f68048f435ea5ed53f2124143fbcfa0446a007ccc54b4c50088262682041f8a1810347d6bc77652ca1738841ad3ae5e90d4f43c4da88282f9ddee9db344e9ce64528bbc3b0b4d437fdc10c35ac43f591456837357d4791265ea641f1bda365943766d92965570be1531baf0542efeb7e18e7369308ef006c5830d052e3d9d64e36b5cd6c0d978d2d3241aa38f66e966f1c613fbe743b709507aac4ee882546e984f2d65c4fe195dee94008290c9ca651c03cef3668bd603cfba080213c61e20ffe52d2cce5ddbceaae7620af0d2f28aa28f61075e9a8a615452e166e675a75c08876c120fb3c8bfe0fdbda999a07751e70151472849eead80cdddf01663190f2ab7a5256f033203378789baa144bbe4cafe0830533ed2a2689970ca22616bee14b3fa047bf581ce79b27050006585eaa978ab1f5abc15ef32fe4d587a70f8b1b1f8d948722449543c9671818867951dbdeabe019430ef7d9cc2fed9ef82625c7b8127c327456100cf0d60b0fbddd275171a8535b36a4e08b1e4a42d39ef32291ad5285aecd8b86d87302509cc68fbfe86c62dc3f0b3984044a2b5cffbeca7fe9ed013b38c1a0a4f445b355a49d9ae84f600ad28b402acb7a6d2b8ffa40b05cd15acd91e725018365d52786832b23681e486639cf6d271ff9fc977278d7b8de72f5ccc7c5eacce7bc3735d7e975576a072318137ffc18f67a68723b577bffcea64ca14b338aa5c1ccb73a3bcf312272d55e1c2c9c90cdacc776185eda59b3acbaa64fce5854cfb47d1a512f67fad25458ae82aa65501f6218468146fc21f26315d3b849efc6fa2378460b17608ecf25c9e1760297c4f343c18ddf9374efc28de671f45c3cbf11bca47205c7b2d281e9518325fb6290bb023194c3e064d6215220dc512254b40b8d5b988cd7719ab079c96872cdf042cf6cbf47095a08ab8d40584f160961f3c0cbff0f72db16a82bc06273e308df2eccca83dfb438e225436f68e1d79d89dad9f47535e0ba0767c18100d30ab6e3940a45016ea37066fc039cd355d8dcf0ca69dde005d95c2e4c5ef8d0c61f467df5ca5653d93821b34a99e5de6f5c720e6071476322ff3bf274568c16f2439b4871803103c1eb8fb3646e3f4bc1f39e57f7c74410d7d3bbe2e03fe8a21f6545b316f52d40f4f816ce11e948e408ea7a333506fa0547fdb4e4dfc19f23bcd5fcc30d28cea5492a8addd8ba59305fc510daf68da3f1515a766064ed3f58818ee4ee678d86d8e06c6dac1f3e2905dc7600e625285a1fb4abbd2e92f9b92a60ce9a035df561290568d71fa275b286c4bdb3d8cf9b8d2521442d652f6ebbd818568257010e7f9c8186ecc7e1bff3e9172b121cc05a6ac184fcaac66bb5804a87f2530fe43853824de78b4fc1709c533e5d170bf4552674b788cbca387a849a9c7809e44056bd9141a2fee0b37be5a4cbc389af5d48089f4990850278e924702d55859208350b882c3c7a7654318aa1100aa8afd6456d0c0e47aba8a8f8b43a6d37f5a7f79a58c80e18c7d12a535b4cdde0959f6eefc5367b4fcce453372cc3aa3bfb2a562ac1368cec4d7fa2b2cfe747456362e70401dc3694ba1259512bd520eb224fbc70fc852b2bdeca3d569644021df0ff0b5a245134923d35f7a5bd1966a1bcaf7ff5c4fdf06818831fa670583d20818f505a878be496b8653cdff0a8e56b77bac685eefef57cf2452ce83a4227cc6f53b1daa28a0a2418d453aa62841f7c97e9c8112244240331251b3a5e922d92f51adfc3a19a2b845f85b158e99ce6bb7e9d77fbfd3879a1ee8be451884a112c3677dad330d6956360e587f733d042c6bd967688297d1056236ccdbd0a2c59a87b2c2d4f84d3caa5372f540dd52b080ff9b9a35f91730884f1986a2279d2ea06911db6dce741f0c260b47a9cc5284d56fa7a407ce71a3d76c27a7649846c586f5ea5af3a0a1710925e5b83da7ce272e28061ea4ce9b9920e0caef7d5cf55d061a3e5ac3452daca240e174daddab736a4e6d5b06d80cc96a44d6459e91491467f647f8d0ef8e34aa66080f73ad27073f8078cf500f37417084aa23d9c90ca12d442b2cdafcd48ed74dbf89b16d0d6183ae5b3b573bb96689c6bdd43e22fd77a473b5e851a7aa2c5e23039611e32b08ea160d02584a4f2a3809b296e5aecbd8bcd5ef82a1a92be5ba1c22c002f5260a82aae9085c4ba6a0dfa7556db0bb3856b8c4ca13b360510eefba52e68344c91a68946d7d11bf7e7e1e6f0870851f7aec2f8de84c8acde4ca008c74c11201968484986654bf092fc76e3d98c2f244cdbd198c626c21bcfb499db8b147fff4abbc2cd88c58fb7c504e6584596e030258873791acd224b9afffc7a261b4ab2c6fc056a92a9dc3454f29a100a261d6247d1ab457770a689878e6ed4b98378dd46458acd7fdacf4938cbf730949d65364b9acb14949836fbf964bb93eec5456e48a90d8f57037479e04d7a00832ac5befb614d556fa4d5ae491aa5b3079fcda72042269c9ca466c4097fe28088978dee7b7bf7accad9a1196d819695f63cfe2a8bde28fc9c2fe2e1eeb6f5a6f56155b6e93ddca3635be8d8571b7c9f81925a421b240be54b12c3150e73f2ef25072e080cb41af66a6ac81dd24ef825886e03f574caf9df9474f1193a09d7650364fbaec3e0ad70d9ad02a7a38d51a0ec48305ba5b8617e56777cf80a66ba3a3899c5f54b96ea11719d85f447a3d0c1bd46e7bb1eaf67a1713af7e450b22de89953209d61c42c5ee86a851efac38b5b436b9c8aacb84293315111083d64e3aa931f859ef48bd4f26e369546fd3d98852c5dc1cca2e427ccda7288daaab84ab2c6501fec642de72f6be8568963d8576a1e7d2724c50435317aa73d4e5dae5fb2c4de2e5de850ade5c0457b919002170a8d923aa94b0863ac676963f2f26801bf0b7335ede78e689b9dde0312f81e2d2b8fbf7fa8ab97ab67b55774bbbd23b3029c3c9d5e8a93087e8a370a99fd5cd8ead0f87b2c001739844f740f0b3ddcf591ebb10292a4981207c345a7dacc8228accd36057861750df28cb877381aef0d3ff625ba745dd2cdc04199ff9890b89d71afbb7fdf632363e4c51402140910d1f02f8ae85851ef333cfc3f4807fbe6a6633e9a4062f4c57986835120aa8d7f4f7fa9654aea9f8662031ee05410478d644607a61c2a7f42633746aede0788cf7c3dd2c1b5b1d8d7cc1ef982cdd21ede222463be9e31ac3c81d46aaecfa745ed2962b246b4edf92efd01257328d3c2c15d77c6c180754d1f963675d45be85ad43ee134808975ab4277c2db56fb2bfe8fca8669504938efae0c57647e67858778d6f7fa747997c9436b9d3e621fa04c0e981f003112d92dacef4f4225f02ffd60995c9023fa7111f41f26a04ff3b58778d0463e0c2dc299937ff9df9f96f9ff2510aa89f303023dbaf3f2f365922cab0a4695eff46f04bd9f1fc8e04d62d5f1fa0813fae4ea1538a35f5b500c28c10196b90de6fc44535841fb5df8f2433fcf171993b5e8601626e426d83a0f28ee785d090d60cf3dfb3452844e232d97236d22314c08873837cd1f142ed01cd341192c21d7af05e9aea56e2c2fbdf556b8ef15d75bdc79c3327116cda468c8a1a7208cfdef1a0d551e107ea5ad832816c817efd81010c278c09ccdf22e3d100ce5dd1ed712d6438ec4d80190919215c3a4b70d1b419e5d7e511dff88d5b1c990418d663eb31c51701b657ae5592b57608f05facaf6b15201d0f282695fc1edb93b4c4bf6feeb0818ea1abf5af5392b7737401204e5ecaef6ff7eba78f64fad68f066a416814755723d6d3df73baf46e4755817c2745e593a913c0a73c1f559e6a3ddf4bb4518f84117c8ad708159366687d871f22e67afaa14cd73199b38d0d8f09b8398e5e1d0e1c30bd929398b527305bd45d8ba57c8573f6d36520e9e780f67ba5d539a4976841ea6b0d8673e0b62ba5bf14bb14b982151d6e8b43e6fd5bb679029cfe80fae589b832918682436feacb9fade32641d705a3796580d0a77bee6cc5f0c25ffd03c9f903ef1dd39feceef660a2f8e403ff218ae63ff1f5c88e62e54b8825396aa05b762254194d1367a122a22e70995759c8c3f5da8f76fd41775155d8591ff278ef560fcf05936bb404819a9f8baec42dee62852949576af6c719dc8b9292b105ea36aea9744bf40942de630ffae4ae55ab1b3e8cea045e742df2a8ed63a20cf1cadf5e80f73d96e83ba8f494ce78a9e4e9221b58c3b1b6a675c13dac1824cffc1c7e1ea33b04f8d894242c38b111587fb4dde8f3616368208779257c1ed64298bcc3a5a423f4f410d2671c310b479d1515973c31f83d9c545bb99913767f627ce46f0bc3967cb05d33bc79018172447cdb27146a0a0c830a4236dc877de8f5593366b256307c0bde1f676c7b17e9444d4c68f7477e8a40418106723e1ff0a10902a93b3a72ba30f5a9f07816e9e609aa9b7ea573b62449797c41ea71973e591cd90c9309b9b1d70eb243b19d9ee6b2931a83657e6911b67132c4f9099664720e3332da0d03048e3c1e96cfab911fa0b6db711dc292b062146406d97ae3e36e585714e890191d7aad654b7d01324c4b60b6b2ea693621bff411e97c46fc76e9bef73c940441ae391263c7acd80ba25612020e2134c034ab23fefd98e8c76795ab1ee4e3dc95fcf2ccbc2ce95b8191b8991f292f1448b825c2fc35b587228f1a624db0a8f93f692a46c1088cbc53a9a040cd3785d035b020d2db5e52eb5abb47fbd4b98e49035f94913a95268f9cb59eed65f845bfb86e0b1e2609d41254012d74545fbe3146c8cdca226e4663f081076739e83b9b0a38bfd467738488bc4758ad4f5c5aca0cc092cdedcc25f6729a841e843807a55380db9f88c18dffb2431237a7e02e3d35b42a0903a0eecd6e1db4dd2b11514d05a99d6851ec9bb2f608c25c6433f2fc1fc9e6961aaf7c02a3ec7fc7848beefbd3bd41a5938764fc5d07306b2eded698ccd2fe73e4d00fe0ad85b7b6da2dc3903efce6da493abe560b6a541041f3253d8ddaafc031ad16a0107013524af422986e069b591ba4319af2efcc4bd5d25401727ea361479674db76fcd128ea398ee7cfea85cc99ea776a852367e432a215d6aae41c9392ad649caa3fb5572b63fcee93c639335f8fd567eaea6e0836de040ef96ee7c2aa8adbc5b68679ed81d91b4fb35f244b75d65747e1de3117a928670d605330a57511b8757e1de8d60b946b2437124b2e84669185ffeb6cff6825b2b53b51424cbd3d0846171e2159d23922f8f83452803481d5db775947204021df81f86feb6bb111f7f9b7ad0408e53dbe9f125f7e5b7c0a08f59a7b9715726f5f79a910bd95f8b6c58ff1cae7655f2229bf9f5707c9ef485102a33a59845511542349ac1b92e8bd2a5071d6bf0a13288d7790401bab7d4bbfaa82804fabcfd287feba30b666c0f378aab34f76f28f6bad1ec29a0e71c4ffad982d03df17f5b0ffcac23ed13becafbcb929518a2a317d05c64b8ba5e7d871050ef71b7e2c1af9483c04efe8e0606a8e93cdcd25fae39cdb8fdc97756d6d2eaf51f9fb0f5e314f875f2c6859923a9f8ba8970641938146bbe12ac1f99bb418c6382d5a03847357d67c8f6d5e77cac96bff7f995fdd905f9e0c1a9e4b718a5973f6fc203bd28038dfe5b1efb5d4884fa38ecf97c39583cd0a46e8e713e026a7658333eeb9ca6c76557c86cf6b1e53e8842d7e75d2ef27f3b7526efac7d43c6e39bc02c34f2575eee74fd8b3d185b283f8968df61cd53333dd5fdcd2d8dbe6d6845ae06e4792ddb89b0ce2dd3e16d502ac5a448eaddaee7ea59a85aa7525dafe9c79cf7fbcf22f5ce616f139cb4e86cf3812572a8fbea08a0d836c079076a6c07219d1327fc10e318a44917401617646165f061c3debe9f8f1b4c365fb08f938a6e3aa671c61b7cef8fea282486fa02d5d290638566755b2d4cf04901a48d3b8a567b324f03585b918dec646817dcc02e176cb38c878a061223bbf8e27d4b10c3e0fa9f5fa1e4223815f47663f150c7c1c1048b942bc60558a0e132889a8256a4d97ad9ff7408b309e2b72f58f06bc883eb101314703e1b00557eab1f1e402c7aa6a78b20416c5c7b9dc53b52b67295bdc494486e49225932d0d5108776bc5078f0797e8258e3fc931c4e1fcdc4cba19a1e15c89d2563b23a5a2de747ca3fa88271d9d2817606593498157b64894730ffe04bb92fe9012e1f4a761a88b07c20f892a3ea5d6819b1662fd4dc3b3055397ffb1cefbafbcc72145e9f594cc82a3dbad0b834ddb8c37a160a40d345e424603d74f98a7b3967c6b351bbf2ec8367ed839f7dfe4fbc47e2d0a1e0bb63f38c669743ea1cf4630e5a0e8b5d2c1bc2677d26226f2d8917ce1dc688c15e298771c205a8cc10997a78a2c6e5b405b89b10a88b321e40c466809da64c4b34e0cc433f924cc37f860d002ef2dd7afa162e5a7bc2bf290d3c8d416169c162cbf41b1fdc1aedf0cc4c2db0d4bdbe47b1ff1ca950770e1758f3b086fa43d27c2f56bc88134c4ad1938870c3b7374294c44637b2c87e67abc65bbb3895041045d1a9dfd7dd0ac3bc93bdd6c75c07911f4024a6e8e63b0a6ef9a37ce44f73fa5b14f38d2b3ba2b3393222cd4f584287de60157d7eebaab2dc382db84a49fd56a1d32537fe414df215c011a30283242cf4062a1d8a94ca499c227d28ff995507d62a237d1e4f2a8e5d0da60b1abf9d773ca14c1168165ae60ea3849c9490fa06f1930e8217d16012567da6cbb7983bc8cead8b3a3f92aeb2848853265b9a05be638a7f87d76a8ccf528c3160c8ca4c7e1742418ed1dfc462098d719ec033cb85ac9c59e785058bee5297df209f94aa566a479a386ab144dc91c24db44f1936bede4fc464ceb3f706d24aba698295492714870c3c09b2d3857ff77a14b879bc23ac65a2f86e26f57b72d6f81cc38f0dbec41097828043b64db7d137440362e50c8a2baee6187282058a03deb642519b405b960da73ff18f986eb22844099f82bffbf4be9a7ab970a9212c634b30d54de6cfeb1702cec640f5deab77843b78a03c6582a65912b29052b911dc22daa09562a43404b79535634798595ef8e30f9d8cafe147e6e0810420145f258c2c3574348f7829cc640d0e6dbf6fb8d827aeb780fd7dfb978dc2d7a1ff5f0234f6a17dd0ff123affcc29be8cc0bf42447497d5ad6bf15ea26f74dc740dbe1020043a7d720fb35e49583a6ecca029737d2d77dcbc3add11925546187b723c410c0fd636fbf7b336032c5bbb6bb78af77e91bd1f6080268cd994b2ff880807a9496daae284238e5c14c0e1e1850b4b4fd9fd90f09d214e5991c730cb6e0748f09bfca2bc6df58efefd2b795f03e851ff207bdf9e6163f5ee7e8733ac288a525fc795bf722c1d64ffc3b974fbca8a2b953efa66918e4281ca589618a760f88c199eeff957a9d1fdaa543c74c2d6d1d842e53b5f3efd69a785768bc938f3379c5c9a8458b2ede1206c57694e1d9ac7efb598347b8f4b43c966476ca53b3e82463a25fef659cbefca93852cb845e2beb54287056e29071aa7daa2cb398cc00545b22597387c2d663964a1e3e9b28d72b762bdb32f1640cfd6a02560325779dc05e206490b2e3a99fdbf3125e1fba422cec746fce94d9d1de734405df1bb686cf37520074db7ab9a5435e28135432a107983b15f9a18dfde45ec2ae41e45aac9de69361bdc781273c93fcec071e30eb80e4189465fc16b2e87b854a83a030881fc7369b2247878f7a9ede5c5e16fbcb60172fc7a428bc7aff7db4ed3fa04bcd314c0d12501791775b2da29167b756cd2bf1400ea36f023e22d3122d4d2b1e27918d8be87b0b8dc9ad3d67ee336e649d6c3e2b4fe0389c1f315ae01cdc82fbef3816418772c1ea939388a84447ddbd7807c21915fdc9a3c2ffdf9e8333d047b83c81bcfd38c6ad12cdf6bb6ee7709d14ee1c946495189c7c0ca8e2f0f66a58fed7b285b74f15a867d7caef94e8029b62fc87a251cdab29be7ed24b8b41f5807e4a917a5640bc6ce91ced9dfa96bd5b18006f3f320d73effc97c05396e269acfca17c8caf6c5d1a9d4e93a96402c4b78cc172a7c59142eee9a37f01fe7ed2c48ea1f4d67ebc0e02fb1242ee9a83f3e0b8378e1629794fdb55565cc595a66c7fea8f842080138e3193e389acfe176a76bd95535bb583229301a8506264140bd33d7a0445fbcadbc9598f904f3a27a2189132f570ce702006f1dd02e1e8f7c3b25105e4e96d4a2269daa3a3f6709782df44c21bd454c990c77704e81289202f81f48b6d3d0d2b834c8d4d383c8bf8621d8e3c933ef546ac4e670908ad6c49e496b8f0d6a1ae333c6a2ef8936eb839761ae64ae3c6a685809293d3b961398638a61afde34f65918b4e91cba2902db8cee8e540c84e3a2e545250a1d1f699c5e4f2baa538ce39ec527e72f9445beac101131f0eaf492a30319fb56fb0b5dce971d68750680b61149dc10a31b3ee4012e1cfe33b710e40fcabdc45b748a72c10e86fd7b62e411f29753938a7bc26d91471d9ef02544d1d4a9c37b083c7b4d5ca330683ffa4836c33438479ce0a4cf89a558ae46ae962b231b68f4b86c78e378a40e0f9be00a3d5eef8eb4abe10e1bb43f2f1ccd3cfa4f13d4339374ef40ca7e05d7eef26df8ca057de997a46d1aa3cca67a32d952825bfcc0ddab0733b2e2905d3fe98d0b25adb2c7cf87ca64eb6a4b806f9b89d5a74530b3a7f7f027b6f38c0908944d039a0b7d437e6c8f11bf049e77b9e83d88e8369ad693133a6d918b464210cf183a7d9487a7b6f055bf54a514d5df77baebd3ce45c1fc461c41f288f700a7110fc922da83bfb5a1f8fa5dc69fe2897c3c4a3ae98e34e33779bec8d9365667c0b77ff4f99b9ee72946796a9b269f6d56ccd033b98b05207133356aae51a4cfc4b589a923c23adbeb6f7d4673defe73e92a505b1555bbd240208259df931a04770099e220f8179c70f26adeee7fdfd8adaaafb434701cd816d7256796631658618ca854e74d8a6ec9d1a4b5edd283c2eef85a2a6e6791e60a4dcf41b02c3cdef21eb8226deda47e9b38d92100a8e84b7039bd62ae0c951c60f8888e7c0bd204aab16d9b00a13b1d61306f870abb17c3a43c8adb06874cb2020d47422c332fcfa4dc832471698e99a64f1cbd862e9fa2c0fa469b77be190fe9e1f18154c838950e9cb4b7360161a7096b74c6df7e982c87d700e4f8b1ba8580cb3b1f1f9585da8128b09139fe371fccd3cf1075126c3dc534a704333fd83791c8543f5411dfd2cd9a02fe1a62002392606d01646134dd32a0eef75baba56626f41370c1127e4ca5f47d3f41739f664dca4eb8deb75b371184be7f4b0dc22a69dd98aec1ce80694e72b1eaada24587489408d707d66136775fc63b0b746e3b5423677485603975a78c29f956b2f944517bb2d66fde31a877842cde163c094e2eb0bd9298b6280bef17a46d80b59b25155df3deb9ec2f395ea177c4cab596e7b055f69ee0cbfd06b83b28cd7f32f62e2ff2cad698f36d1f46f5c4e2b74c22975e032a29969b8146b480211371bf95aef87642395847614e4eb190f2261938b82c089537394dd02fa6ebfc2749ea027925e3ce45f24b8cb80a1764c435105da672ef1d1a27dc776c1ae256069ea71beeec0774855f1cba35a978ad67adac1549e811c833f4e5618218a4b141916f17221165786913b724865a74f38e48b8a950b8d68d445a1b46304455384d19efcab4700e2877182bb2df0b34ca98f6935e8bdf12649d2562051baf1f6484eea18b4cc303f71fbfd852bd91fb9f08052768c22eaec7f28c75a77917176a010572c1cbf3e098e0b33236a8d73803e061be5da3918c5eda3c4c93424dc0763ab07e417158b77255efdba0fbc1eaac4ae8806a2eeeffc78d2ab1189881f1b6d1e969750916f67c3212a4c87000bed3206b84e6c50bf4a49da93683bccf1f5d441879da72373e7be91ce9d323e393983498a649509c932d976e9f6d062a093b72367c1a0f73e31d62592507a6510a0f9cae5c3106daee23e195f248228c4dbe77c15a252586a556e4bd38a16cbbd7632b64792c0cbae0b5e260728566b844b0d798b824429b6100aa61af3707c7c8607a414fe90bf21be37aa4de51b02dd4f68781d92c3b568f21f60d0207bd58259f3c6b286779d6038af61641c4dce9ee079b68bfb10e63bb1c6f25c580d57f9b4e6765bd1b9aee1d8c4feb59af48fc59b4e3c1d51dfcfc0f52355cf3f0bc10e260c162782ac1d1f3bcb0d61c4c9c58f08dc93a638755f97d4c8cbb233593d5228690a62803df1e7a71cb805f5f112c47d3e40a82d0eb1841855470e77f84974b87ca876bc5ebe975f6c0e8f84f9374121204f3c814bb28af37fad69593f05e7a53d682601b485619a4002efaa20d2f3c13e4a0160eb96228a5e76785538a64e642c65de509d3445a1bf31244910802537d45b2719574be08f2df6ed140deff11e2e9bcf61e12663475fdd586d66952d2e95521c78d9e760d9d3d8f401d14aacd064fdc8f98fa939f1368274157699a6a11c642ca0666750109e27073b670dc4d460cbc16b0ad16c3e6b6a282cd6a03a3dcf171855b6096a9b5c26aad1c557cf9dd6bfe41a0da9ea3a306a330b4d71023bf70f00aaaa89e21749de20e2fabef0788521fd21aee5f716a090f4e33c223384eb74506372692b778ef2e18f57f6bfe728d07b76ea5a5db672d94b731312053c75af884bc5a241897a0c211095d25928da8256a5a4c70db4dd234fcba339cfe71d00fd1e9b8a17bdf61dc384cd9ff09a1f0cf212c588e6d270525cfface497566a26963c70f1af08e685ec557ceb0e3f5f7ac06dcf70ecead6ca81740de11af46c419a13a2bd323c9646d7150699b6cc672690bda7f154a80774352fcd11487cc8399ba29f96b2395fd67f7c8ad4c2828aa028f3ec00046964f4c83db7bb7869611f1fb7b7be1501fb1de4c25606a93c32aacf80185c9f448fe0da912f718473f2835a381fdf8fbbb05857555a9896e95cc27a4fe9c5d76646a4d9d063ba6e208f48f5ce8346d4ee5d64d123a7a20580ee480ebe605c90e0d18262df2d53ae4aeefd3bf1c9e3d87130fa2faf160d2b94be5e4f89b628d35131082076e1fed36871f8203bdbd6d949db4f73969342164cfd1cbb86aac8c627c73d9a10a2990984bcf4c32618e8c9ac65c339cc283eb50706adde5a7d901d92c57dedea6ebb6eed8c5d37fb95d80d76a867b7bb9b81bd8feb47b0fded31155695b22012b192c2ab293f08a0ade9a6ebb92ae752f0690383e59f1af91436ba5b1d236e18d01f37bdf3336f815db8ec8eec46368fcb4567d839541fec30d14b960faa539f0f8e7dea1ee3635db48a3fd02562f8c6d059be7ae61386137c6348c40f925f46072f241bec28efba39965638ac31d2329d9f3c5fd3c22857e4224507123af02a4c02e84f4182b2197c5c16fe9b485b48d7ea6cee6e3cb84fe64b30667acfa421a9fd546dfb43044c5f102781bc4372867e01e3dcbeb251596d5e8e31f70deb1157fb0ca69a1b4a338cca966d5efa47c324132ad1f7e186ebd6723055874ec9959cc503fde976347c3994594abd212081c94f628f9e224a941e2e1f6252bfa397be9ad4853ff53c4f7dbf0c5e15d2aee3aacf44772783eb6f7c981b55d6ff4f9768834ed432b68c90f31e88e7dfc8b00a05fae91de021fedf36ccac7c1b0d0b7d504793132d91519776b49aaeaa5a0c268aa83830e85efb43cd166d2ee870224eb0413f1e41527b7fcaa757b1c6d28a6b2dc1f5d3fec1150f4be3432acd38070ed5190f50859e696c3507f2cec74ae964aed4139344d3c6d61d9cf91d5a0d2734c030105b9c942156320baad8c15ac74d0341d3a506dba491b6b03b74fa60c26ca8ef06737e941fe60c9d77eda52010ccc51abaff963967407aa3f2d5c221822d5326ad52e90c0ea99bb4dc2a7be40599a1b7f2618bab2fd030de49b3fc84721dfd0f994e9cd1902e481810139cd972d477d76ebd92b04eb6874c8fb62292f3c0cbf739699337fa4bcf733ddf6fd1bb89de543ce8dbf81bc219b37902680b36ef002cda1643879920b05e0fe697a68b9bd37289807951acb3226b55e848ccd3daa50b1eea492b29fe9d757d6ef6f719f24d2b1256bb12e0cb4f5ed3bdebd7a509b50c61eeabce60c497652202bec5c32dc9da86449f2a53d315b7da16ef574cb15bbc9432f961a484924ebe8868ec28d236f3973d89a3c3d1d20b11f639209b0ae4f3b684609055fbb85081fe9f88acf0dd80819ad156787767d4789751113a227338bde2be5062991d707bd91c63bcde0d4a2c39177d348fa33ae596f55414b7eb11c0e31a2c39bf021772b81d16570041dd823fb8a57cb339141b51d0c3fa0717d124fd43d9d5a8cffb0b149c8700890fdc310907a886b600bd83510976041a43fd0709218e2f414d386d6d35fb24ac13d56dfb13fa5470ed7c193fbd422b7f0975d73519434f7f935419276f2b4534daecbeff91c747d91263c79cfdc3c09eea909af0a138fa043e75c7454ce3f80073ec6edf6927e1508a4134287465a17930f38774ac50fc6602f66a7ad7bd9801c587bd17801d96ac689f7c62a9261d9f74dee6b0ca8452758a87880c0cd693f7a85a27edce50881dc337e5f9a99267437991b19d83f8490266a0f46a95d98d516995e968a2981eae28526e81dd8dd7f299d799301fa5bf5747ebb9b9a419ee4d627e140e4e11bda80283e6e2e1c015aa57a868c1de7074d9c844632aa4e703b4a69ffebedff34d4186671b912eed1a5a9ef6fb200c0e69496adbf7378fd42e3b411c37a3047d0f7a30d96bacb2332928df558796fbf7025482111032ac964675e108536ef017d5d99bba973eb21e5705ef78f821ce60ce72f9e79a806b50d7b5c8f39f83161a38ae8c093492d9ea6f3b7a931ef860099bd9d5652c2b70ffb6642b91228cb7720eece733193a7b469045b273d5c9a8621210ebaaaae28056ef222c17d070cff0595c9676d70f7de9b2f347aab8fe32efbbdca06135b2c508d046fd7afc46d9f3de6dc7d66bbef3f70fcad1804432633a02111e691f15fe11461b893de8cd1a068a5f2185cd9dc68b36dcc36d9e54a2b816e2eb69c44ef2700a933f1c4c266389994550a0d1841d97e50db67ec37fac7d8c8cb00de62ce5d58aecda6bc8940e459ed25702c8682f4cc91742bf47ece1626f9f9c6cf3fbf6ab863e4226b8722c72c1181f5d0d65a19812e6262bfc30fcd1f712df45bc3e1ef093e48fdd1aa4ce71bd58ef826a5f003ffe8b2a80cb0fb67e953dfc2c6f2af25abbe2c3dd5f2e273d50fb815198951b59505397c80374a1c0ebc9baa9f5b9e3d34fb4c18c3e01c41e237090d21679d33350afdd4a4dac8f84d79f71ef945825b309a231bf94c5cf00633de9359c06bfacf8b7dae4197f37e62f1ef6873ecfa6c72924b757affe544ff870fa8b3901478c3b675c3d4265483e162df05eaf3bdb3557d31fce0afe49c288d9440b3d23f5e87f8af664ad2aa4f769ee431e3e0036f5761fa6be19dea838df59f7a5dc56b82a37f68dc4d2936a6956f0f7905ea90d41b8a09dde4dea84f7bf3edbcfb6689f7047150923b2af98771f7ff1b923a19b508a9f9e185076e9e9eadaa4a97489b8fd28e7c457adbdeef36b0193dbb179807435e816557cb4b387d308ecab665deb4cbd4529e596f8c14d3a04c2e2b84c436c38dc95295a9852657acfb839ec145e80890127469b55928cd9ab5cca7dc5299bbc81fed686505156cccc684a1a89e91c2341f2933260e0e6ac9a0a97268b1936d0ac17f086e4e5f8a44a3c95cc4dab0922f4152f23a329e6861ee5eae378a7c4df8767659fbf4b3aac06dbf067010b30e193ce489c60cb7dbebf05067f9f7a5ad1ec51914c860ab5999345106a97c3d921c8efcf8ef7a0c9e91a8c6555213b7429e35cd06ddc967a81e5ce33926138c366ca0475b1004b0debce77098182a9229aa32da4943db892c0b54d1a01130180e1428150f97a80fb69df7aa5fcfea6debcce2ce9585a9628133808d6759f0a904013a20602efc5058fb932f1222e80fa316d7c5313d1d35a3b23d82d1d59931edbc552f33444acc4920adee4000d4412528e7b0f398ce9e139f805e68da1693b8b7ba8b470a2e1c8617758f4d088154b4e6809820747f1fc5cb5e4d1c615dfa7c535c81901ab699a6f336f475ca4916e1c5390630f298d0fa2df68df0569ad2977d3cc270d44eb1d8fc0dac71de2d7617d8940599e36d5d07c08ad337b448b5a5173529951fabde116562c34d9219e0f23285bccf41263f34ac04f159be7d994a03e8a1e70fe1fbbfde13fe27316631434226f4b5a97af75fde227a75ea292e16963686062afdee4897443d610f275ffeeda8ee67028caf576874f5bb1196318594fcfacc71ffa850b7782a86efb8391a20240801d6ee257ce107723dbbe407aa29176fc844ab2d3aee0c235afe235376ee96d87fdd1c428e31594b39536540049f3e1c7aba4847511ce0663a87517eff45b3f81a48d66b4bb606661d0d586136a335fddf700bd56d180370e5fee56f56d35e760b47137f56a773c70304640622f1a881acbf197eb4d5fef14c35e3c73a4c41b839868bb893049dc105300ebd1422881d65742accc01e5a4a69dcef901878c5d95e1344cafdd527c26c4a46833daebbda3267dbed7f5bddebaec1cb59df98b4c338e4ef02e5044cfaf8b59c772f06c8572a21dcaeda871908d83ac4f7d8c4055cd7a01d533eadb2cdb4552926ff82262c6e0e5dbda2675228745a68f56892441d84fea41f5a3d2efc261dba2bedda38ee7f2be94c2c1d3aa155d0236199eff6e15fa7bdcf6d74fdb33d49ca8ef8a42d723f48e4a767200acd40806e1f6e031e21bdbe9b015a6239a937abbd1823e3005d06b6f44e4a103c24687687d4470589f6c757aefeeac95995f2a86869526cd7894da96ec4d6604a427a8f030aaf4fc8c65bc15a2696bd253215134c2506ed34fc4da690b734154a8197a003a11df3e2068d6c58115062e12ae9ab1f2588cab0e31e41d69ec6f99476c6ab28ed415a0098b1f61e26aada11cd6a6e390541aa97eed5710e259aa6454a26ec1b00f34435c7be86a50ffed53fef342e8663c9ab1023904714cb0fe2a3fabfb95c9d14065457454724ac2851c4daf0a3621d9d7be029744547dfd9696e40ca79b93a2a74c7108c600ec7f16fe371e7f90a2af96db67e7d77c297521f2f3098fa87c3adbc9126e673144b33c5206bea2e3ebba5f4cd856e69394eb914f8d453c7c63bfcde87883901f7771aded2a3e249e760317d129437004fda7aa67102d7d8719735de3e273e7a7217772b38068acdf235a6f729899693a761250c0b65202c979a880f53b1289c427b015b660a4951c1875cfba0ab58c3a13cf1bf2a5746a7f89c88ca5379dd53099bd72b25744812faa8fd035dd831ed6e1b4d1e7a0304c81a88344442e6036a5eb9f688d25c6caf2302f203e9e87930d201cb77673de8c50031c99533ead74978fa9b4313fc1badd4782625dd1bebc4603d16f3d4a2eebd2c6e0f36195ada944d44721e8143e417550bb3121fb2c0b31358c7cc822c28db4c2bf1ee0be48bfdea21d6f3a7016c86190bd42c5876906345283499f460003a7cc2e728859454a7ee1db413b53e6d89585848ca8b105be8d91ab6d9b44ec4ddd828c3f9301fc3739cff33ef5879715458f7672db81a10fcfcccbb3082a5b0eee706497edaf17ac58031d2f1c8c928724e51e6cf1bc142b3966b355efd8b34942683cc2ee13ea75dfa06fb261486ece04c639eafe2f2f94ccc45efb3a7bbc39bff9a19afc8968163629278977da7dae99c89eb82122bfdc6f8f4c9aeed19f0264547c7d5db13378117e01cac7ad68cc7ef607425c7b5ac9a7474c1e0e9946722369d52b53c434408227afe91b7da5b74bbd30dadc08a75d0811af98ce7294e3007e1791adb2b6db350ab7ce8d74de9875759ba7a0733b16decfda99c4e2f61c59e61776ecb06d7319629b3efa7b564828c5e3b75695fb0e809c5bab7e59cf0b5b6e16fbdeac339b839ebb62cdf799c0c641757203d8a7780381ac4ddb35496a1a9e216d0439cd4c68ffa85dca73ecfe355e502150b67852c555b498f12b099e01094347390a7b95d024e696bc3fabf5d370de41940a94093ac272a08e901cb5bec786dd1180633b10d95dd0e1221a92a5b8c6048cd636a9f981efe0514772a3ad6688f2953c4534ee848a2652805fb46684e5f706b333e9a90f9f4ae3652ffa60388e90c2442145d0d1633531951529429c8e8bd6d1e36b2ae2357ec5d995c8c64a06c5f0e77dfc80c34fe2717ce5c0a56ae202b14343fb44a8683f9ccc73a388de9d3140ab9e2b5d0cd4e0eb7978b60a436adc204beeec300475cea3ecb81e6e7511eb8bf71cbc73960fa119adb2f2eaf599956dedf15cee1a397ec28bec054910c3f01d34d5bde3c524aa0e522972f6cafc2b41d6e37d01316a5a53f037e6a055d0e3430ae26e93cc3333cc3333cc333460f9abfb75f5de2524a298933f452ff0f22774a49ca44b10e06fe6f38085fe181d66dadfd56c36d0e080e020e38d820f20a43ba9ea68b869a2cb9c2973d6fcbebceb62485482b9e6f31e4957e1733e3ac3807799945bee72c08fd2a92212394de5fcf2a8f2a1ab1f65e1a3a8fb89754ac5e32a8d3d93325362adc607e59655aeeacebe88ac82990ef8278b15d8ebec91f66ac2996adc4d397cec718df4a19273dba14685952665e3aa6b66e376e440002387e7825880e0f502859102185da9d59f4df536414e9317fe1532b644bda193e821b421011c5a65327a5bec3760c5528dc11b73e5d3a08b53950a8e1e2a5d1ebf0f4fa27dccc31f6ed2e3e87d2136c50da1ffbdf7374e90a851203914e1c5a2ea5267e1d4dc739818a298d67efb209ae6aebb66531cb4b214dd831df9db89e87d07299d8b2d23b5e6e8508cd12443091a79bbb1da532d5f3dd2a72896549d8c83235ad40c4126649c8d9dafd789ac4150ae587fa0e868148258eb983c9f867fa99cb0a259ad3f13fba284bffe0164426d15e7ff4587f512ab640441276688e70378f26d38b8248248e598ed6c955b329798b4082d568675ad0922fa5cc81e306228f40af86c8709ba2746950c411d8aaa61aadcd27e61c81482352265ad4984e743c7de1c8800823d21d05de3f753977c8ef8d9aca08441681b8fc0f9d29633ebd83f4e8a1821e8828c2d68cf1f8f9584ae44a0e1f3d7e748042f1d1e347874024117df956e6fc219be52422ba0c17edffbf72c9f323042287d04ce828175e4d78529df8103184b6698428d982ce389e1e2285a863492df74f97cd26810821f6d20f59f15c6a4fae502838cae017388e1f3dcae017804164108530e5a2a9caf4f5311141a0aca48b99ac644e5f2b39727000c70f44029132d9bdb6bc73298480e8425e34c375ff5d50854231227f48ba34f3161244fce0cc7e974acfd69ce20f0a2587481f18af519da46688953305227c38ba649a6ead3e299d17d9035a963f64d4cf3b1d9d4a19fc82e6e12ba81bc603bec38719644000c70b44f4b0f42684c9d9380fa68b51b44769571b79a840040fe913194f5887173b4b574e7a780b82fcf01de480b59201913b6442bb4dbf725b3ec9021c3d82f018e302227638b72ce2c5c5a5bb501f41a40ece6a4adb574da3ad8bd0a196427510fd79fbe322328735e6a4d4c8dbd6949b1688c8815751a6deae5516571ccca1d46485e9382f6b2270c8a53d7922d5dca5d6de70e79616734e671d565576ecd0131fde2ce206a44bf7ddf3f29796a60df77aa7d12f2d226cf88517dc6c4b46e6b50431e304385470830438fe04ce2300541059c3729d1e9d3658e528c7b8310511359c74949e91a93f53399c20928605b59745d31141c32fbededba989ad8f2267c84b966b30352d85ce2b22665812a37cf396cbbaa02e034acd566e6739cb221132eca3c4837677c54b3f901e68096e98d5193e821be5434be0059131d47d2e69d2527cb6f80e6d1e3c44c490b664d24af63b2853876111e962c8884cd7eb80c1f9785ae637f505617fa1ce52cb76f3af88179032b71b32c38f7291481796ca36ea9cff8e92db41840b79cbba2de82ccb6cd22d9ce1059939a77259934e440ba78cf7a52caf5e38d9c9c98d1b226a10c9c2f295d01f77170b82e88e0f50283c3c4810ddf13f44b0801af96f49f75693b55ca1bc763f93a94454da225630af6cce66f163cca811a9825ded92a7ba58523faca040840ae9cc19f1c9b494712432855b6a39c4e9cebab59b881416aff47d8d089935b5225140b4b71ccee482423a9fb83b552d2e652cf28435bd29111ea369f5a888131a3b3d97776ec272124a5d8990d172dd8a19404e44988076532f0b3a63d04166cf1059c252e79ed116e6d26e501c449470b5f0f132cecc0bae8924412fef9c3ee6643e1241029a62b37d38b1217367032247c075a3cb26611f34781633322062045c9eadede8fff14fc4437d0707820031a3032245480b1fe6762d3427d18a102119e62a73fb330c731aff6c6f2d66f81046dba73c95daa942a1840463dda0d26c4fd88b8bc038938d09e59aa977c42684fce2b1d5bcb194daa77f728c7123004c08f1451f364be32aa362f7e21359ed635accfde1059ef142eea47ccef25da1507651f5e5bd24d3d3b821ba28e6bdc636e6c9acf90a85920b749039c76ec6aeaab642a1e0c28e9d4995a696975e5cc706426eb1d678aae9dd1ba16e8542c940882db40fa66aee65391708a90572c24c6d5b834ea75768f1ef6ae61332fd8f882b14ca074266910ce3b25a8e0c6e8320441667ecd1b3594e2d66aa2a144a2c0c5af334e7caa453b0e833e9746f532e0d444f3410f20afef64c74fcd798a5909e6020c41589b6db2c888f659d7a854269c52a1ec7ecbcd47452aa5028160861c5e2b7582ffbf267b6708542f97192c303377cc7ead8b1439fc718405c052767fc088223005a0859c5d7eda1d533baacf20ae5e48c1f415a158c9c1af51df3b40733157577c778e9341da4a8d8cd65b9aa5445f48887192a083905f6b3615a96335010628a839c8ea6d582fee408424a715cf1bd76cf973e0e8490a2cc3b9b2d78262dcca642a1780a1945262d35aaf57d74fb2a140a10128488a2dc53255f96ca3d5758a1507a74074242b1776c676893a5f3862a144af3c0105020ef547d18d3b2982b53a15036e41368e1b37f963e8be1d120c413b76c9ffccef83176b272d289e5acfff2c9f88f2d27329fcf1e2de87e6f1387cd2033f34b2f4a6e2a14ca090c4234f1a9d99596e5fc0cad5528141684640269b1214c9e3c358f1e3a4e5a1082894f5378d0f112e69eac50282b08b9c4732e2f8b0ea5bde2c5db1266613baa7d88b2d7e013422aa1650efadef3827439cb308379e8a044aa64d46ed0593ae73a892c932719fb33325baa42a1b0204412c87b6530994eeef78b8990489872f49b8be7667c411090b1831048785f371e9312a72bc48ff045f1524d7e6de55e19421c7116f561469614d1fa3682f37441cd09cf9269ac4239410823726f29bc948713c26517610eff2c9b8bb525b45404fb3a4af8c775ceefab109208af25399dc535e5cb398840cde871973c97b56a789ce046f3d031821b3770e020e41089ce589eedecb33c9621da6b49cfc99a3e0d7e2112cf79fdb34943354b8542d9c10fd744082198199d46f7878a593708538dc7e0d26f9016626f41a01e4eb36f6bd0252027cc43470b420281fcb3f7dc2054e6d84200714713e71b5bacfb13fad0324e7ef408a23308f9c32764ee39ad4906d9f97390810307853288103f702f2f8a0a7bc9943e5578f4414fa3367c14b742a1f0212d878a7859ee7bf57e41c81ef4bfb67531442635ab42a19c84e861cd5992593f5a2a148a06d18e41481e967a8476f9534a78c6d420040f957ecf1cf4ddb6e0598542a140c81d147b51b3309649144a8e103b18c4e9db6f6b49e5572175e8ae93f430bf6e9fca41081dde90193f64fc74b555c81c1671a7c326917b5e2223440e7d8e793da585cc5b323742e280a80665d52fea7dc873e42003c78f1e3f7e2c21040e97bb9d18f115bf8d3969e7c1020aa58710f2065e64cca7f7ecf217aaec588d41881bf2cef27d7bb7a7ca741bb00eb52e679a4684101bfefbb76a7de95f6a7105216ba825295e1bffa5abcaa881f71e21ba4f9e86acafc673aaf5dc820e1ad22c5599d6b57c32e533b819ce3357c6ef1fb119ecabded3d59957ec5406fd252de6e1af3dfb4b064d940ee9bfc9e5e01903c2f3d4c8f65d0c7a99e6ce146a4365160646747f734bfc788b826113328cb72427d6844ec817103b1bf37ba64c695c5e38ce89ccd351c34b2e5e5dd8c5d15afae5ea03215cd8b427f99f4b8bf392bb055f479aca871bcf3395163e99e37e4bfbf2b6fc1915846461b1429c7ac93f6589bab0f08a8f52fbf94ff2722a14ca0542aeb0a03ec698c73563fc4f8fb187102b98692efaadaa82632e8bd75f7e6f32b4d33108a1422646bf26b1f4327d0a6c5dfc67fc5442ceec8210295c32f7c7a510d2838a4f42a2d0affad69ae65132760f8102429379901f932e5b1507214f58984f1a43944c2f67614188138ca34555a78ee98369406010d204469d751213e529c592410813be538f9fbe9e39e9173b66c88007214b30e588d3418cf6ea8fa9e80851c21fb37d16b46cbbad9f9024743a5989107af2b91e104290b0a60e6e1ffe2683161f841ce11837599d50da345e6e4688111a61e237731ab9d22e4908298259b3a485cd9c5edd414308214297f9e9731a21b4bf2013c418c6316851a525ed50e223f340450c617ca52e49d913a24fdfc1705e1637798899cef0aa80d17bf6192d798c6739f88b5eb0de109ad39b8b396788e18b4ffc9dec673da57df5a273793d4b76c9e9e7ab788176ec32f521afc5cf316617e6946d1fdde541865e47104317da4817638b1ea35fff200e040812c4c8c582d906a54d84150a8587ef38e9c1e3c43520062e6cb16cb3b43eeba77dd52d1ca5b3c6e4f227399fd121862d0ebac74a8a07b1fde255b5d85b7a0fa75fbf4f472088410b566d647b98fe182ecea2f620464b8acb7a7c1143169ab628a3aff12b4c7c03c717c488053fdaa3ac7c85ce73118a010bf4b5a4bb3e5ac55acb2bda582b51a231d34703b2430c57e0bb1b636a51a328737120462b4e6abbf5548d878fdf12c460c5b2b84b2a74d69cc3b20044418c5558ea2597641615115da962b93f6dfb75122e42940a43369d88e7d15bf6a204315061cea4a54ca9f9e4e5ce0ec43845a6e4bb42bdf23dd3a630d79672ff30d6492f314a714e2f7856cd3106c4208541495119b3a42088318ae3d8956eb7a4b307e1988118a2488fb8bfc90b77d51f8e7715fc102314a5c76ca1646a49e756397ae0cde3060e3588010ad66c94bd1cef197ae421c627966f7cdd25dd22f4596278c2d09d37e5976b1ebd83418c4e2c3e1a4c5b0aaf8aaf076270e212254e94581d9977408c4de0b6ad7183145923b54a0cc4d0c472d499cd2c9f4c5a6a8542f911a404373870830c1c301023135e888deb1ffef26407138976f1d2e45c7661cd0a85c2831e0f04312e7126cb5d4f2ed899f5150ae5063c7400314304625882794b4d4d31a1413f2c46257e6f31886d265342f84a10831288f5d499be475cbe5402312651c892356ae454a1507e98337e90110028882189c326ad0f1eadfbce1d81189158cc92fc9c1fcde355554e82f80d02f68ba9710583cb62f6bbde8be9d9ac61853c8b2b5fa365ab21548900046ee4c8110108e488000442b050a30a898a8e3e76265ab6ae0615b6507ac254977c713d534896b44f919dbfa4c7526874566ffb912b14cac9193f82a01a51406490ef22a4dce878310585e5dab64d1963b32c7c42f2d14cb52c5cf356359cc07fcd968e597e41fc2b53a309bddc2d0b2e4bd660c292e75a353f556142b684368b6954afba1c3c7b3594a0da994cdaa5f2f0c9ae910494dccefb7c4266c6540d247042275955219a1a47e8840a69ea5932d929ab618446aa8e6e39c45efca703480f14dcc831860928142010c8458d22f0fb1947f59fd272546b10e1ef60e5269f848b291f19c6eb19d745d3f1b1f11b11c6c1f47f505a16939c938130128c5d8c752a1f6fc3ee69041807a5e4c7ac9117e7ffc82f8cedb77749a4c8d2e7882f9013b627aa4764b0da985ef8c2a68fff2594fab9ce18e1c5a7bb444367f6977637db05da47f46cb8f8315e5ca58bc5d7911b5dd0d059bb31b9587e5d7339f63f820bd3c72b73fa95c878476ec15ba816fb0e7f29a423b6703ff58747b37413f3482d4e7a4bc6f4ccb897f6115a74dea7c50fa3444bef23b3d8edb466398986cc261e9145271e2f4b6a535f4a6f2416b54b42e43ff49c7a0b2c9697c3b8585264ed3423afc045b1fe90416b64d923aeb065a95c4e1bf7cfd31e6985599019afe9235fb3b861459bdef3870f17d377c4c82af0cf82d06423736b6554b1bde792f1d28f8e58a9e8b36be96817dbe7f40a8532828af48cd07d9df162dda63a5a00641223a7d0bd6396b4c8dc280032c61f464c8138f5b3412869735a2c057a64e60ce6212c5f122976f58fa9f194282d6623a330cf934e72b4934e1f34220a5ed6e4296329251f4e23a1a8d64ce858393a48cf8d80821d2deb4bfa6e45eb69e41328e1c2df7a5d9eea6ec41387b510e9fa629c91d9914e582ea86b17c4adbc293981fa31996ce388d2edd944da427fd249a61734843461ec58e73d7ab6c5d14826909d4c6892e3726c494c285e2ea59e698a98e912c9b02f8636174cde258d5842ff0e6db5efd2c80e8e5422f131caa5deb01abd28b18b619f53af558dd08d4cc25cbb2ece6ef87ac78c4862e1ad84a93c7d2e9d3912093dbbf47315d293957c0412aaf6f5bce8a157ff8d3c42973f27cfb4d1d07133e208c373b8ecc14db778a5914624da622c6b8f51fbdc248c3002f9693769b599ebd88f2c62c12b3b8615d1fc4e8e2842eb6b0db22ac4349f238948a74db29aa984e90c1a41c4a7c73d5bb3a43cb65ea150de7f9c0c61e4108aa97097a5158d4d194334ea633dcef345c8af1009afbbcf7b2d66933521509f3fe6f82c6899d1574606b1e82d6dd68c5271312808e49d898bfe2d8cece84820f4b89e5328a9215dcc3163041058063521662eabb71af9c369a63aae36e5076c43fcc855b52cdbf561f394f9ad5cfed28267840fdadfbfbb6e902fa1c7c1c81eced00b55916f595e3db4f2beb99debd5e5063c748ce4019d7a7b3379deb4bd2a140a19237838ecf76588b8acea5065112377f03aa7067dfd2c667848306207834781b41ce46ef4df12fad7481d728da2fa3e5b16f3cb1d18a1832f88972c733f46e95800a0303287eac3ac347f4b85053c4e40a194a1e3062372304893a13a524cea9e1eb841060846e290cbe7a2872ea1f326e1081cae12cbd1b76ab9e496819137bc6fdf3da276a45918821137d4f9773b7c4bbce4c991369ca51ccfca121b69a31136e461b354a621b5c5d9d7708c23469f8b65965d55c3969d4dbd4f655a8b8da4e1be0c3af3313bdf722a4146d070c9d2e1fe9378a8924d307286eaccabb4898b5b403a30628635b664a6119b9f91572894e6e12be89132203b9f3d4bf2a3fff365840cfabd68799569bf9ee363640c09df2d93a6c546096b440cb9741f73b720e2e91e41788c81829130f89ea4caebc9b858a7ca090646c0b09cad2511dac33bd836f285c6348b071dd2b3f758f14275dab42c586e7c535b2547ff380185e2a30c0ec14817ccd94b899abafa9e55a15018051f18e1c21e5c64fae039c7515904235b487810d7ac9ad6bfaaca881652cda09a99a46631fc0a855219c9c2416bc63971e2b4dec4d186112c30a3cb53c89930dd625d18b9c29723da622247df5f1c7418b1421b6bc2b4436612dd52a15070e4b881430d235530c76d70d70eaba1ca613f18a1c2d154898c575b42c85dc6c814d099d244c3efe9f18c112930737ebe797ff73bd4c04814f8fa2cdce89831960c14be103bd36a42c5f365980164cd0042a12c234f58b435fa4b62ed1c38809480423901e2150ea265b48762c409974cb55956dc329ecc4813f497a5509742e4087da930804209c018469880f6dc39669da64f0f8d2cc14c11af9625296a771b51c2a38329b939d4dd637c878f3274004942dd41658338a5464817ffe1e30323482863ca12fb2fda210a65032347a8f487df9d4ed9718c11231c76344306253de6735b305204b4b78f6bd2db0811b857fb2ccb39bc985a960a8572022403348661e6955ab628da317fa5073484d1c6115bab6dde884043e00b3482b1984b27253cd8ed7849021ac02873ec781ad75edc74033734808342e1a1432bfc0beb85df1c3266fb19990a8502e402347c817c9733a14c9632158d5e945b5a1a3d59dd624a150ed0e0c559ba455c94139f2d3fa0b10b8476de94af994ae3d685d5a9748b7ee9b8bdd0c805aa6469507f49decb9a131ab8b0f72c84ff9a7661ad5b2ceb27773527f1bb8d862dd092095f1775ae057bb9018d5aa03ac89ad1dea2dfc54a408316dd0b2edf235e7ccbf42c8cfd2993556ff8cf96862c12e229bf418516fdce310c1ab140c7ccbcb3d3a0b3486181944dee418b1e7fe4f40abd4d633ebd6ee45fae584c3c69416aae5ddb5b81d0533a9febb22699648a4083159f96e473563cdacfabc893740d197b448b46a0a18a656d4fd1c15bcc92bb0081462a922e5bd56596ad7af44e010d547423f775ad72fe3d758a64d2a66d62ff832e8d31a6a8e3a5cfc8a8b5765d29d0d4f21593691f5dce193448717251db2e6877f09a4771fa0ce6bf213baacea230ea4b7ee95953d1008d5028426b524266d7bdce4061d0f9a2cae519255f92c6279ef92aab3b75399f47c313ecc907d3f28acc3a71da933a5a1942df7e4ef0653293c7ecd28b3dda446f5df69dcbe5b691390d4de49a2d4f8b593613b8a89e3e587a66d1843ab0343071e7ad781ecd12193697b0eb67f53cbbe89965093d6fca935d518542c951031a95d0e52a939d74da268b7da0a30c1d417cf4e06106fb0e4e58408312ea8f6f499379bd564ec2b3718d51ed354ea02109dcf47cd2a5f44fa0118934e7b7e9708d9b2fd67142031a90785e4f7cdb7594cd1904c840e311b694df9afda47e727147984187929e333e068e203ccca8ac8075eca0d108c53f3f4b324c748edd0e1f27dfe3644f7a30c68f13b4f3e0c1097aa0e363418311cdc7ce26c33f34f5408ac6221e99db6577bdff19a3085b54df5f7439bab59508f7a377d41c73429616442c7bf61f5c4c17dcd615dc20030785c621dedd9c4fed85a813cb1066e1b5a5d4d1d5527a85d8e25fde7c5a3a3a7b08d18b69b6ef2ca696dc93406310a5cba55c107fd321a60f6808c28b919a694ba671d50291860811f19b7f26361a8038e750da624c67bbcbe0f8008d3f18e7cffe5bceb5253d30a0e107be3aef69bdfe7926f5211d3f7e8e2fbfb7f462f8609efb3d359b64aa8df7c0a596c9ca133ac9ef2a148a5985861e9279bff4af7fccd89ea2910733b420a74e88b9f8bf191ed0e23126eb129e4bc45577306ad02ceee19d3d78c6d8c1fc3442c7b511d6b97180461d10725a2beea5abfa91191d14514ac5facd42a94ed51c1859774a7f731cddd39083e1c50d1bfdb6c7bbcb018d386827649306192ad4f370e875d5376b925e1bb45ca0f10644fe05b5eb7bb7eaefa0e106e374d0a6b3ff33d068c37deafd5e368d364299031a6c5892cb1dabfee031a672a0b1063c567d6869bfd36ca3a10635c3cb29d6acca534b8322f633e7e6cda08186a58c62ba5f92d1826f950ad038c3415a8bafa7bfd2bf6898e1d68d359b64e9a0b72dc35eca476ed0159f64eb021a64408b12f2b29c39a32991c618cad60ca5573fe9d86f854279010d312c9f902feac9e8bcff398d30acf5a759965c16b58201edb2195e8c395cb37c61d30e531dcfca4fdd5e38b6346e3e4b85ddde05a3bafc21e47c964c2e34b8b02ca8e6be7b4e26b644630bc93519d44cd5bb280f6868c18c2eb65c3ab9ac27721a59e04c6d38eb927f9777a547ef82061614ef9cec83cc30a76aef2b2cd67b85725153f5bd154c5255548bb40fa3131ffec3c7d2a8421d2f1b2ebf4bceb8542814a641056392f7d95ec487eca942a128d398829ab9cde3bf549d9a8586148c317d5016a3c39eb6547ef4c08196710244078562011a513099e66fb8cfe9d32a85b2d08082effef2b81c4f89c613d0ffaf22f6a6c5182e1a4e30f799b90b2f9fe1c126ec1ed6944c3dfe1a634c48e6eb50e2a348ff522e8117b6c4ee6ecd86ea42a0a18453d966fda42ead8c9d04c342b628a663df61a781845f5f94fffc1f814df51ea5fe41da65348c70e60b8d9ed521e45d68142193b1edb53a982e397dd0200232c6f7ab6f49262d7c86d16b7a51da5ad4db2b61fc9b4ae77c3ef7cd4b3056edca8f3983a826cb0c22c0d805a1ce5eb24e17dffd22a52e79e8d2d95a2ebf036910f1457aebcc5c1e8f72f2d38bbf5e74bcdf85c98ec789082ff49739f973e9e5726617bea42ff5eda9adcc175da494d8243b8fae486f73b17caa733c8a0bf27cad5028273a4470b18dc7983f735f5a8fb730b620539416d47ffbdaeadd22b638d353580bab5de2712d922e8d8a0e95a62595836004374280e30c1f01114468b18c3e4bf56e592e6ba950284964160b7e1dd38c5499f1fa061a446481f8ccb9fe451b6d33071ac4043c7820120b6b4d5ff47bc7cc921658dc1ea684eac7ec51a61b01d5d8bc5cc6bad4ce14a17bc8f70795ff31074d409208d3261dbfe5d53c768904114bdd82cec7d86f9b2692431c3acb1b836e3a21375ba1505640628844675efef417dc84ae107cc8d492b6702faec92a94931f3d4e82f80d38404288b36c3a2fa64e4ebbaf50283948068186795a8fc6e872273b34488f931d3ecad0610a1241f459963f994e89673169478f6e0a05c80b480261d2322ee72cb91cf7c501a16779f4cd6d4a6a8e567ae4c831060e2037720461f7f1011c384c70020edc20e3c60770f410c02b48fef0281dffb2e3f74ae92b140a0ff4870731c347194148fcb0a037eb6ac5b969cdc381a40fcf28fb173f6b478f27024605374c0a6e1814dc3027b8614c70c394e08621c10d3302089c04a00a247cf0ca337e3f0b7b624f7b40fb35c7ded1b93bb87a6843cb6250766b1e10f3f40a5d756a9a3390e0a191253c883615b1dedc813bd5f0e2978d4b266407bb5fea702d8775f8f577375e8ecf92d2a281840e9d59b86cf5f91c0e97317df46c519492c961d99169c428f91e84290e6e9c6e4d3feea5410e87e5d272d87069d46416f3066cc6f45b54c5cb597683d9473c8d701591696f033f2f46178432fba41d1b70598e2f670acfb3c95dc3b2dcf2a7cfa206d4a750f39c5d5b2c330d5dc6a073f66c61d40b4203da4aaf3fcf08559e3f03a36573eae81a89194e37ca6cdc5b8cef7c1910ba15a754ad78960f939041ff9735884d578f231a8341fc7590a6e34b61321231282ba2b7497398719b240c76ae8edca90b18facfe8c267b9c4769099e40b7dec399dbd4f67e33b5a478e1cbea3c7e071020a05480e7af4a844c00789173ad1d91d3bc4e47523e9429db46abc9fd1a2acc3010917daea8cb3cecaa8e7926ca1976ce55d3e5521bcad50283976f820d102a629e496a68e571efb0149161297c5f377d9c7d2bf20407af828020916fa182ea6da502d2621572814f73f4901c91596e5cd2e59e57676fec3470c48ac80d0f6ce8f2103071448aa9052393b1fb72f5ea62454484dc5e5a0c465fae852a15072e0f01dab6320998231e95376ba5eae01038914b030791a54f56578903160401205364b563a7e98b2fb0a2450e04c4dc38b964b8f9f60fd688dd59e1ced9138414f3a35943cfbfaf1489a807ec5bf389b322605244cd0fd5d1ccff5bd5b0e7af4a8ec681d582059c2d1948ce5ae6175835fa150729028c1f0ac5b2da66145752a144a144892907e8892f16bdf22299020a19b6dd5d2386f93b5c2e3041ca804d1e102203b7668e0460b6edcf01de87802c911cca5f45f85d233551f8911b8935f77e9b26c9e42c9415204d3292f99d3b75e50222142b722f5ec336b0cb1c05b100023d81806627378fe12d986307a4993b23b611e4693c148df0ba6225a4c3a64dd6103182915328beac8bf58147d49e7f72cfe27f545a74267b91151fd1b29d8e8c562aab555e2563c79bc389febba878be9abfd5d545a397aadfdf477d445da056f3f19c3dc5e938be5aa7671d43685b8122e9699fdd292e9da5765cc2decd80e9397353cb0618b25fdd1dbac7b4a645c0be4987849c429dd59ec68d1a7c87771b37bdf58b338ed35c4b7ea6cf62c8bc7ffce3f6d7a878d5820fa774a9fe794d67260b15c6f2d6e791efdfc15e9794edfa0c7da36e80a736bd7867f8e0c226ec5b27c5a3fbf389e36bb2a56e0a55236bd9fa68fcc2a4ea7ee77ecaff74c5385a1948a67d02672839d0ab3270daab35c22c425820d54a4e77268c9eec3858b8c39851e646368d1944e6d5a4c71fcbcb81a722f4e7c4ab1249e7e5f6e621ea466a448b77b68b69c446b5855a370bcfc93ceb29ca9836c8c28b2150b799ef4af6859150a5d8eadd3d276d0a7696340a18bbb5eef797674e66c7cc2f7ddd91a39df61f4045abc4ed92cae8f9664a3138595cb62b8fcdaa6554ea47347eb545a92f5b9dfc4b9c45c882d8faa9f99614313e7cefff9b266e8ce582610a7ebd64d9a86b0920f6c60e252327cf8282d98e6ce0f6c5c027d79fb53a8b899b978e81881a1810d4ba8b35e5ac3a87b8cbf031b95487d6fcb39e797bf346a1b94b0ad55e49508a134b54ca2d51cf3364c7f48af5c6043128ee9d7df50323d739648147b1b1f646dd5b7aa1cc8810d481c33b818fedb739b2f21b801821b1fb8e1811b1db8c1811b1bb8a10108ac8d479cd3a6b19fef24a37b62c3117b78e944a85d074dea4620c3f38b714f574c6765608311e5c586d6a912f7595b041f7d3ec8d71db1f071604311c6cdee60a6dfddd46723118d7041cb9ec7175e5b1081db9b7cb4df92bee721aa9031897c399698b7865896b3df9cc6d754db62a31049975d5272b3df7687108bd9a5bb538e7e8fd2201e11a625ddcdf2498d0d41eca2c7a0c1c5b9cfbe0502cf82de1611d263d85d870d409c3774892f6537dee71ff2ce295fe255f66cf68359ea33f792b90fac8c92239f5f3c3f8b0f6f163c7ba82e95a1e61ad8d8037a4ad7eecbbf614e480f6839c3dd4c937e31bb79584ee5d5878b3419e12125e4a4cd8dacd0d9bac3624ba11bd3b36c96393bb461ea62badc2519536ea30ede5aa62b17e3c97e990ee7e0b126fa322fd39e8359def74e4296f8e8cf0c6cc86197adf934f511fdb662230e98ce7d69597639a56cd4061cda345da1f5d3cd73ae0536dee069b67dee74a7bb25d760c30d7516a576c30b4a948bb5c1b3f6a81b6b2193ccdfa800d110d860c3b993347d2563dca7890a36d6f078e6915f2542e62d3558ea2dd9cd8b9ef262ba60230d95187f1dd5b30fba4403d7f28976b08ea7561a0347136c9c21977ef352c54ffc8bcca0e87c96c4b635452773c03d6c9441cfb0d95bdeb20736c8603c93695d8c1d323c09878d3134762d9ffcb81c83ed64d81043d91a7b5f96c7555ddc46180ee1971e464e4debbde1011c65d8008363263ebecb69af367e63c70ee5c00d1c144a00ac60e30b7a0b9fed54a80f3b9f870d2ff8bdfd928e51838f6b6c74e1e4e9b14f4e435ecc63b0c185f7bf575393eecc030c36b6b07690eda632c4644336d8d0424a88fc984eb434731a33d8c802ff395e90a1378e9b32881b6c60a1f76419a3e90f1d6c5c6179f6ddcdb50575f1b26185c65cd239d7cc68398a40f860a30a779d7a7d0af92f1ba58249796a99c2696246a9c7bef29897c2e2fb9fd498ff418b1f05931674fe8de9ae393528bc2d77be1863f804345cfd975f8a9f2905b1e1044b7ea8f5fd531390b9edb7b741dcedc60c1b4c58f8b45f13fa65c1a3ed031b4b30a89349dec688d49645099b0975a3b3951c3d4a1b49e005ffd40612509dfdc473929943ee368e601099fb93cb2553be201b465077f48a7bf28a800b5237c9a0762acc638308b85ff5b77ab6cd2f358c2599958d29efa349a908358471eff5c9974a264ff17dd40806da74631419a15c8e31c0384beeb6b749891bad7550e317fd9d8b95a245b7923152a8e10bab74ea8b994bc7ce632ffc1d3d0f99d76ba43a851abcd873866e8e396e12ab7a506317c87bbc0aa52d67d4d0053a97b8929926acfb450a3572c19db664d91bc2e37eb8d0df651195f733fd596adca28d1fe6b5ab85fda411420d5b988410727764fe52e60da1462d0e769fc51279b1af846871bceaa03b7eb2d4b0676197ced2498eb671b10c420d59a044c5cfb36c5a9c5d81502316c6edca1f9bb97377f1420d5828328b4198b9a4af427d85b2793cae851fdb2ce80b355cf16b85cc73cacae4c782d46845f6fb59dadfa89a6a07e1e13b60454a669a5cc89c2b64acb18a3b89ff2c97a58a339d879b1beda06b948a3ef4c73e9ddb9ba48c0ac537c660274ca7785396d6e8f3f70f962938d7f8cdf1176f4d2974419a703995f6b82226c5729f32a6ec8dd76dc9428d51a4a39b9dbaf95fe7cd0a6e94800b3544e189be205553febda40e455f6ae1ef2954774c51a8018a3ba6cb10d6d5ba2d9fd82d43a4ca6e8b7eef166a7862b96643c67575e5ab5fa8d18937bc6f4ea3ee3f0b3e27ccf14f6fe8d9b4ceed269e97c42775317f7c999ac05a3bef996699f0ed5a63bfba9c9fc776420d4ce4ef9fba496a56cffb12dda746bf52adf13ec612b92c4277a8ccb92f8495d864e7142536a579a7fd774dc6971a93488b275496f28ec9b45f43127f7adbd14126b12f1d0edc78418d48283a4f799e0e241899314ba671d3ce8d8f703cbba4be45db7c458e38e9d2eaa9aa94ab961a812a9541eacbd9d3271323d096c6c7b23f6996c48bf032dfa596f918a3cd16d450849e31c59e9664929f6a2250b5ed2183672c31118158ba2cc5cb9d4de43ec4796bd5762f0b362f1a822fd77331b305d99c1762537a64d66a8a10b9c7eb71b12c33b6981a836865637ca991417da88620d021163247efd8502310880e9db22563d261571ed400849d7a4bf5acaad35e7fb0d484de3d19cecb647ea8e3538a67d1a742ea35fa90bbf4233a9f566af0c1387ba525bbf3a464660f87d679e1624dc8bba90935f450fa8a882f5d99e5d6f370b0ce6278616cbf465f030fbaa42a77b73d2fcebb8319354b2b5bf4a839af6187fdd32eeea33d068e1ecfa3461d907bf97cd7b5715b920e2633b12a42fda75fbfa282ac31870593ede7a1abcd052d0f6ac8a1165476d25d1d488d3870b126febd1f5e2c1727d48083b9dd7434312fa897336f388fd493b57946b7996ab8219d79c35fa7d1221bd66803b7255db48b2f6c58ce7ecab3082da617946aac0121c665414e065d50430d67b23b39fbb7fba053230dc89041d4734799744d0d34a4ccfc5565ccf38b9d3378aa4cff252f25f357c1a86186db5c6367416e9ed296322cde684187d1efd17532f88286b54e973ac6ab31a4c5eeb896c5ab5f8c961143993a8e55facc9a108561f13e6b9e4cede9db89430d309c65339d74ccc152bbfb0262b48f1a752d67da1d3dbc70657a419476decda31a5d386c67f9fc056d8e1a5cb05f2ed90e532a53630bc896cc4bb6fed58a26071036d4d0422e06b5222c8492f9c52b148a0f6a64c116e672b46c9f4a54851a5878776637c860a211483301642660668c0110e031014301430a9403380810337e8804e08c9d80090082003143052101f01ba81937e0a13b6a0800c80f1b2c00c03939a961128cafac5daedd531e634c65b132834229c37f9cec4047ef501dec3e8090c004183ecae05f1c1d4176a0a37d717404d95101a22727364c7a717404f95101b2e3e4c486092f8238905dd030d105abdfa3c16549fa28592e104a7769f5e72ab83894de7b17c34659d34c6e9185ae972a37a6e80c1f5c86eb08f2a34c6c717404e91e6598717262c3a416be831e6594e1658c98d0e29321fabab59d45a3346338917959985fe3a3843a5527a658ac2b9f37dbc91ad1ab0d4c60a16779392bd14ee99abce2ae1b17e4bd28031357207faf4588eae48238b5c2931e3ca835b1516613569caafe25993e63c77857b1689eef5a647c2abd573c074a068502c444154993e95caacd2de6fb26a948dd6e6bc631abab978a092ab6dd51da3a96dd6a6b720a94a74c72c47b67c71488188430314599227e27fc72cc2e9352e8d2bb2ce8a83906395a0b4c48e1c7b7be2c5746cbcc9a8c022f59ad49eaa7461b8942974e47a130e78f7b0b9eb41c3e061495ded3ed24f4bd9c743e61c634f178a1f1444a676ddb319983afa877e8708149273acd39cc9bbd9ff896138e0efbb131c7549a69934d1c53ac846c97e5376f269ae0fa3e87ec127b618399c8844e32e69fd3976bc3c452b9b659dd7709e36f10afd6ee62fa688945cd6877d5ecd28d5562d9d484a8be1c25f6edc08412aba8516fcd3e2663e987c924d6382d8de5c7a70b49222573d67745d4cfed139844620ffa922af9d5db2d0812478d33e155429ccbda23ec3125539d3eab2b9d2a4798c3a5d34c19c7e44f9346e4d2bba869212e5fbb3d306144ca63ec630b5eaa6ab388f4e80d1142668e0e2f8a68e47967aa54d9f73411cbe9ddcfd6a3b59c44c4f9740baa2e9c964a8b39c4297490a1736e8bb0d20f45410f13437096da234779ea8c9f324c0ab1fc2f3266bc326fedc384106aa7e6d4d06e3ae88b062683b0f4d7a5de34994f4c82b0f4be6acb49be7f8e4920ea3cff98711e3d7870c004104b75a3ebffb946a9e60f8ccaf8599c72133a0781891f72d1e1638b5d324a464760d287349e7e39cba77498aff860a8153fffbc1b8df11eacf7fbbccb5ab90ff5c067972d3dc5377a6ac903665ba3a32354a97ff160eb4bede13f6edab14dee60d2f417ea2e968bcc182676e0cafd4bbd860e657b101e3d7e3c084cea7016e4febc649feec080091dd2490a98cc81d1b39fae43662207aca47dc96aecc8389ac461c92c84eb6db24ce0d08c58c717d36bf877fd03266f30e73b1d9a94d471394ddc909b272d6831c86cd2062ce48327f9e229f57554809c241336d4a94787ef5297c4b32e305903f39e8426b9d18289d1440d9c8be9ea4c4b7daa799334745d21cfe49eef2a3041c3f9b4c68b8cb1bec50e0e4cced0a78fcb765912a1eb53a1504ecef0119898c154f7ebcc49e9fc7965b06af3c5b1edcff01c04312143163245de9a6bfcdc8ea1747b4fe2fdacd7544230110362ff221a645c8f3a082661b0ff3ea9b91b532647433001c31e5e8c252fffbe457d60f20537f4acc98c1f2e4b5d828917b4fd513245f494e991074cba50ba6ccc5a9fc385b38fee705bfb313e5b4847dd3fc579fee8f25ad86ce3b966c5f5bb5950942a2d89cd4f63a38485b4e849fbd2be4232dbb26eac8cf9bc2a384caca0e87d6c757984fbac265538abd8881325fa46df265430d4cf7cedbd204f3799c272e88e6b30751aee3591c2f2729c8fa5dd5b963b5148da887497e54e2e8916139840617341f7777bbefb78750f133cc11bd9710fa6d1d54b3371021bbf3e631219e271323e306942f6f287109f656360c2845774b0cc2ddefc96bc073a7e09a9b479b9c547b8d5233051822dc9d8f082fecaf44d128eed8e9ee7d7f2db5aa1507c9051011324e8b2658e08e4a0019e1b10c0d1234800b86072844c8f79502d8b0c5a0a9918e1d0fe39b8e6a7b3d0f2a3c7490e932298e7f43577632ae9711322a4f3d2058f4964a455950a100d41c9302cff512a446c88bdb172e225c2a8f32817f34b2ded6cd723c84949301acbdca139433bcb75efe871f281126070ef69bec46465384f094a7ee1b998d752b3eb66ecd016a0125ff0d2cc8d78f3284aab4a492f0a11d594e12c327004f1155480680852092f2ca534e76cbe6f616a1e3ce8b10bd45c28f92a63faeaa542a1fce8a1e3c40325baf86be54ab5d4e5cb2bac4c29c945e26b74f9a67753092e2e9dac738c85c9d261c92dd2f7ded2824e295a4725b6c84a333ff3464ebe4d86034a6ae1874f9d3c476d644e1928a1c571a53ee8e052cf6631b3583e47e878723654cbaea04416c5dc8db211a5f582a68292581c5f4e66b926c92881c5d5fd22a21b3a41c92bf0dbadd22e6f8ad14f50e28ae363ceff57eb2e6fbe72328392565419ac6cbcd3950b6be5048802d1c0063ad0ceea630567f8085e50c28a545466416fcef10e130325ab686f4375b55c4afc73941255a4fe397ae9134a05ae22b54d2b46c531e7c5529e94ba8c9e2269ba39b598e4ca6a5330674209bf19254b3527394a4a719dff570791175d3ea44069faac677de68c9251fc2f0b2f9ab4c51846480325a2d0c2e2f3280d02120a77c784d2d09e5d83a672d23c74879ef0f851020a46ac4ddb537ecb2e6a860ebc031e28f9844964c7923b3e9e63ec09a49516ab1f353de9e9444ab8f05ff676d2d6aa40a08413c9d120e43e8d8ef89ba8e73bc5ddc8ceadaa26cc2c87d951520572868f201397bdaa6f5e13a64609138b6cd269f4c44b2c23f69329f32a144a0f203c7a70e08c124b70a2712142e75d9bab12977ebbb5ec9272972d4ab02f78744b11eaefd39360f7c5ec176d2f9104baeb4dcb62c529bd5349243aa534746e8d293d95150fc2436f008993ec79f6e072c8acfd7bf4f8e1e311e7857baa0fb1ee33027144420b1f4cbf1c47c94f10203a7678101d151e9c04f11b34e29c644398f8182f3488116b7bb99d9c3f7d939f78101d3f7870d2ea3f16b194a15b164bffb39c931245ec572d8bb11f4da19c9424e2f01b64d347c6b3f3a183073428414442863b131ac3686f9107cec37b5072086416ddcce752ddda6a88aee2d3ffeda82cb3819414e2f05e99371ada7b44669410e2df164d9fda381e37e647c920504a8c1a31ba3b5bd682f8654166c6af3e2d7fc604422f217d732cf3f61f1068b78ce789aabdd2ff80c6559139ea47f78f8550e2073fc9b8cddaf6e12cfa2f9996470b27d7f1830c324af860a611d3ce2ca8640f59a9fcfd1832e62c881925d840891eeeb917b7ef5fecf34c95e4417f9df7d09f8fc9a378409e16ad0daa1a734befd861c66f2004257748aeee998d75763033cab98e76320da31d257548775969cd2fb8597874b0257159ce27efbe2e3e0773d0d18ca39a5b3455e5a404257240ddf5c70c32cb26e360906b27e2eec3bb076b500207f4345588fdcae85f97bca19774d4e5a71647f9a9c40d293bd7d2f8c29fbe9747491b6ee1655912f3f2e754550f9c878e12362c9ea6c50bdb593465d6d0464fcb90395f3c976f50a2063faabe954c19c37612084ad26008557f6e2784a91469a0040d694b5977ff7b2d2ee8819233b0b5769a25ad4cf26486e3cb891a71b24e6f30505286b3a548f92c6f922fbb42a17c0919aed32dabd6b8974c104ac6707053f1265fee848d72502206a386cc3c95db5cfa5339290943bbfd92a9bccb198352086eaca0040c6f12a6d40665e231ab151b947ca11342fb6676963c08b752468917140f2dc98df36d1793ba0b4ba5f46977dfd0fc599250c20535bc68d23eaae3644f7ef408b28210e008d2030ff8a0640b8b0ae5a3af614b4b262d9cde2f73fda3667cb9240be775988b4f622a4d4b0916ee1893c79a53a5f4c886922bec726648efd64aacc0e6982c112236c6ec2b144a0588193e78b4a0a40a87ec9693b6fc2ec81c522839566002203c64504285636f9e8ffb5225c70a4cf0e3044078fca0640ac5dcf9090df12c9a540a8fce0bd141eba8d560e5e4478f131ee88f93207e836dd7f123484914f86a932f6d6cc1cb254f7ef408a21d288182e79f4deec83248e5063a7e98a0e4099f165f2e1962ba83582b5ce2844473dca4e46c8ed261dde1a30c5f414913ee7d13e671e53a562b61c26de575f2b446f5ee031da864095ec7b62c49996fedbe44099ece776ad6e72f6a9504d3a591b1296ff43404b22548307c72396f5c1415a333f4c70f0541c91116de94b0d262cc7aaa122364da65bbdd2a13524b2545d8b39c35d9a9998da36a4110337a9ca12450420911fab8f9e8b2bfa27bcd91e386ebf8414604ba87095805140aff606f81092020803a900c030f23444c89064f4f6c40220c437e165c6c7b97e38b709441128c46c58876ad5af918cd813b90109000e3ec17a358a96641ec9e8304383240f28b74743ab9c9738ee7487cc1fe9752ea5d0c3229bf42a1e420e985e6f2c6b7945ea39a0444779880c70c4878d19c5a8b5f551ea33d925d78e2db591661ea42ad8fe934b7b38b1feb11e4a402c40c1f2420c9453ae8bbb7a61a6d211e6390e0a2d19ccbcc1a46678de528c10d326e7c60043742a002925b98aebb6452cdeb61671eba83560a25070770e48035c80a7ea480c41606a5e37d66693f5a65f80e27a9c559b657b5ba5bf7dc567c9ce060ef1e1cf0ee6102125ae43562c4ded2cc4eace4f0201ae40524b3a85eb0cf5da1c329fd55964416032089458fe73106072440028b0790bc22ddb2d8bfbc2c7a103a24ae38d1e143030c2069850e1f1a70e6d1430124ac5800c92a1a40a28a131d3e34e0820690a4e2063750322440828a53a4e50d3e7fbd16a341a648c74c9b2fc7ab3431030142520a069090020124a3d0a51be1e259ece829cf08a283470f1d6e2011c549024842410012509c1c80e413f8e9de9c5cd49e3037bcf6877197e35e72dcf00249270a40c20913924d18804413273a7c68407f98a181039064c2fa60326a3db49e3081c9b0a5327fda77482e715215f1928fd612dc6d88cfe8a712811b102841042070c3ce482e482a91ce26b447d5faf5dd29a1cb9eb7d363a6f47a2199c4396ee6643c659e650d8924586f4f996352d55754790149248ebf1a4cfc857f97aa3c4e70830c1c2490e8c2d3bbd822f437ac8f5876a93e6a65a742a178101d2db86123b85123c0e13b360b248e603fb4949983c76b85481a615a912e85ea7b06256384ea49bb707bed77d752a1508040b288905ba8145264d150180c05426130180c0004581c0b00631100001820220f8924f2a0602a4f7314800143322e66522c20281c1a0e07239138141287c3e130200c04838141811445722c8f22d135a965f4f41bd49e87bd5d7d2e6f32014811b9f526bed06b1ba0917b8e1e992d1d800728288ca9e9f3790cfc04fc4cf75b3b413e7a16e1b19f8531679bdc385f03035d3ffc2715aad12c7f236a84e4bb73c7aff3ffc87fc50ebb64891e7c58570c7a51d72345ba4f25ba5827b918c8a86ee45cd4c7c0bd185dd188f1ffd2285f977f7898468806a0112f363427d683a581971eda95d3d76377dcae9f863367af8c084ce31ef918ce0d5d0296aa683fbfceaea845e76ed97963b64cf3e1d8b0ab120fc494d222004b530fdc74e04169850983ca25d4f90c68c3f77011aaed56123ae39b61a4e14407534a3533bd89ae85387d78acbcfd2c1aa3e285157f9c027c2515f96819a8a60f499b581e3547f170fa8c7fb508439413ef5aaf734b95e1fedf8c8491fcf186ff9f993417e0b2419f5d470f698eb808998a1c81701e1b53bb7cabef910be31f463e46e50a3b1e565c76ab5ee9d2cb2caa67b3f6705c7bb634e7dcca81fe511cd52002dcda81e9c490023e405e86ed0ca0da41bb3af073ce122f946f61400af9612025a98424a4123cf81260c666b9b0ff1b7070ee89e331e66a60f66afd72cddfb6796656cd96cd4236de1284ba96231395d05dd8d5a0fa39459e6ea2e1daacb2e73a1027d501e977c7f9c4f88a09aeaa22519d000386fb26379975c59c04db17d8a435407ea6c90b5eaf1fe266b81a0a5d7f2ebdd1ecf5093994b18c167ed840165fff2cb82257a2a0ddb956aaeb71a9403f6375dcb81ea65bfa0fe949181516dc7b686f490edd9bc374ab63372a67a5225900a9435c811b112ac0edb0f04a8ce6228c5c634ba44998ad7ec5c8945cfca968c4388eca23e980459019e8cdb02bb541312c15d1c696825b99aa78aeb036a67489fbc486b1359a25f505b11fb8e208519bd21b440612cae07a535c4e64ad6215a42575fc65c3ad16d49af81511db13b29ee00003fe28130c4c774c7f98ca79f248d47f3df07c27d730f82b76472fcdfd88bb4e276f0a44f0eba2da997ae8c61b48d989aec95a3cb49ecd2cb87818cbee60e9e860ff07826943703908287e05fd7b2075104008e6b44072330059c04a80118a48bfd99cb2255c6243372c94e600036c3354811f495185669eb614a029d77dbe00ddfb37caaffe667caa840a44706c0d8ba10ba054a57def2391f221e611950416384c8e11d496abd9845fd0c256e5c177e8b8846eb0617c100b798a2f63456b29b02507209c3c811178440bb10ac77a508ea3255749f9cb13250ed7f6f74ae40e23849e8ab14150aeb755ff137314bd19fb0119055282bf8a9bf397715fc30313d4801c63fd968b4e807862205944e710fea6d686fa6659a84ce013c21a1d4c492544876b8edd9d2b3c45daa5031c081cab04c3271453d95f7c310e211d9e1247610564a4b35641869572698f10cf43ad589ee8ab74201d8b12227de3190c4b6548bbd3f20c93e5f5b18b4517fcd5220f387d5a3bf4b339166296a8b0e39e5775648d62dbf928d64633ab91a75c91193301a5a51657a4c8d49bc245361e5ffe4d61b0eefb746fcfbde64f6b33e55a182b7736d813e9ad019e9aa4d1876b95e0409aaf362614c57b97040a6d6f2be2abc41a95fbf222aa6d510b6821b7011886fda389a1c2aa64f44d14ae9fce33d14871e58a47d7dd0f419005ebd477415c382d5c3baa0bfc53f2677e1ba03e606d8d98273afc911045ea53ab2919c75772dcc980313818ccb8e9dd01bf84f8f867916b112fc9ee95936b931ea0c819839e3fe85a9d8c231fba6e945a1f76a61442340f975e8010794f354a482a16d219a1a41af48476d4da504e82a5228c9a20023bc8d1b86c0201f417f7482d6f838f16698d01aabda65a09cc40cf73e58446ee9faf40834ba26349e896a54239cd882f92fac242f888cb717f3eb9362d31371f32de9fba9f6dd61b4f38fd6d3eb5845f1c07d57d09f6549758e47c8ce33ff6739188ad01d1854b560db58143c70c09aaa2582494bfa990fabe92fba1ba5dedd4cb878301baed0314ea43e2a70f03a8a262a7e58daf8d86fef030b3337c12332fbb1bbf8fd4ba28ff8a0b598fc0f72bcec9391853a58e93d3a1ed297cc77d24c9db424c7c5543570bad0baccefd814e9b27eb352a56945304bd7ace7feda1dce90a5a634393f24a6fc5ca88335190f44658059ba262b8976f65288b69b216cb2dd00847f28bbc124cddc43172ef9e79e70ddea923ae812cc6a7cec9d736ebee0a0446de3d3f7eb4f170712bb02a17cf6dc9b39e3580b0d1f513a3fc0361cc64444869bfddf02a575b9fcf5a684cd51bd524eb319b59fcdcb23a4ae2569aae184334e10a3b2eb578ac66e328438d9611a0712c30a4d527d45c61696934c3d1500c24e7021abc4f152b20b0c97e04c783c3b5d5b2381005fa008c18de79b638da64a0373ab66d68ec9e2a34fe2e4201e08356ea8ae7c639c22f5948c430c19a209dd69ed8436b31afd2f54a859582cbfc02a7a9fa05a236a131b31fc5177f2605129a620edd0bbcf6b3eeaeb1c2f9ba8e47a4a535b0762616d681c1ac0b055bd1639e7442eb587191d660ac531853d6f0e0b9ff56cf5c4675e17340ad628336645fc6eeca4289f827e4bea3982e672d8d2c6fb2dc86775041fb4768ca4828d4f106ff00f9652b685fff8bdf23bd4382de54b9902d36df19933d67a3f0e2cc433cce308b54844a546db0fca441c838b0fa7daca13135cf6d58485754e8220a96865d454c103d90235a0cc8c31481facf8bbacae5a76d0fcde9a91e6b0f326b81fc6e5c84f42477af18d811a5054468ec54c300f490879d88b5cd226f0085ae910af8a8d92f59d64b8ed5c25f042c5d4a1afbeb93762b4f143b04cfc47eb3819dd46a17d39c190f1b75e22d6a892d0fa6e24dab60d154334554a8119500d2b4b690659b4944be108dd345f45025a14e09f6ecfbdbccdbcf8a9067558012460b20e361edb692857bd7c0a0aecb9e8900ed4c49ae450fcd2ed710d60633c407aff72a48ac5d023edd0632e946ccba396f33d2820519d66d655be7006e335bf4e114bb5aa05b810e8880fb59766b37ff56b0d51ccacf08352bce428d0cb21a375e4c9d7ceeeeb5942c96b0b851b0c3d04d000471dc1b8e8a12ebeb2f0a0604346154136581f2eb26440535f409601f7be00407c5a580be235835c4dd31073b37845354d04b6faf1056491ee4cd69799699bdaf895151a07162482b7fc364d4ebbb1c26136af850531b0f3a21a1ed7626eb03360e778c73d71b5d56133c813fa5053fa6de81c007bb123687004e86acd8f71c0abae475edbf2573fa0ac140ea14412241d91e69de41945b1415c0ffc0419a4f24b79c056c08ab3100ea6e8657b977ab12ca388e05008c81efc35928610414f80c961aaaa6e02415b8f956719700824a0d34e161fc929e44c3c12eb3b82c1d5cfc8a8c49d0add3129eccb1d3efd2c8c787850b7a1c3f13bc3b7e9e4d356950af900ff9c3d4cc89a05238111277fb9ffac95b8d8bb2a03032f0766b2fc26844de3c2af9fa9b40d184b00da4accdd13f8df1e01fdeb20fed65172b3c4c5010a3b63410bb890718224198444d12ac36d0a8ac0f46ddbc47cbb04e7603b5b147e173c171b8985a244eca38ac14685d24d338620019d54130a82866bc70c8c3155593daca248faa654380c3b3c20a4638783b8e8f108ec89943f885cd02e3f0e0506263904b4ac1512b47909821055015be3df002a955eb5dd5ae03c01063339b7523f6292d89853038339dcd38efda926daf5d828f42ac37fd70402a4064358028d437b741c4660525df4804d769aaa9509a7d07424baabb4d4550e156c798ea6d4e09e845a0a71e2adf9da2e5dbc7820367f8be5cb395d532f2e69362965a530da2ceee80fd272575684db530228d68e98388b0b626018fbaa736754213515600d0c6244e04a235c45d250f32743f2f0dac8654ff8d9f219c9f863cd3d99e70ebfbebe7c7ab73cade94a8975883297cb23be22268c1540dd34d362e584423eebf75330d78dc2624eabcefd49b64a082a050944a30336ac7681d52976a5a3c08195121e38eaac1eae5eec776abdec2eba1b50f1099e17846fab8c96d32dc6640eae6ac9fcf1069cb2a027357b656e63eea29d3615c2171edf1840b29ea624d98ccf7774eb2cdbc0d3f1e292181c0a4af113f4b9e5e08a58e185821905d335c6b8244ca2e40638b12ce6ab42aa148a4366cfb175a77646ecea79a5307467072a38202a54a605dee1147e07c1150a9d10701e6629ed66ae85e2ae3b7cccacbaffee4edcb579a9644bb43fc952d86e92b96017a3c68694a6977c0c0b25e6a048d1791cc8646f14bcbb586fe1c75b5c51adfa0227a95fcd15b1331af6303251d2a10d367dcadbe7d04efa3af48ec65eb3bf82faa6f2904b43258a076c4890f76ac176c083fbe708693a6a8655ebba68e597423e405dc7e140455509fa1829d91949db8bfbe84b0745330f483b260401fa325983232c1351f53496a16a5346e0e17b500114a35330b843e18180aeaa3495b152a02449ba6fc7c00c45251e5a4d082bb3170e018f47718dc4a4f4c19db202c88148f623eafc27bec7dec62232f2c40fd5c25229277514567d3eb717b6dca95b81290c82923badc0d4bc9761950b2c33836a8a426d9578fe7011bee7fc69a2fc4d9ca545bf3605ee20fbdfea9c71f00c6f56f4ee4ff700350d278a62101baf91f27bdad201a7029f86d69b9230d5390ca6df20c083e3ae684be2624147f382a7f2e26e13fde7dc6fb09ff49f163e20ba7ef4d1facf3e9fd8fef0286c0847f5ba43ee1df51f9b1721ee232441622527fcab19e990d3f10812b370021302bef3c33e742c083beddea31f8ef816b0a40277033e6ed73fbbfaa1ea40b6a9b95c94125e026b294fa832e55b28ed13d9dc64320f115e63e69472d8e4f638f7538d72f1999464e2c5f531a89cdc98415e0821f007dd7f6d2b582ac9d2c920b651af5d970b42ad13e5dc4e77ae9ffd5702a1ff80bcd2bf6c9cf2a3535f0d353d46d88542c581d3d0c6a21e75d52e4c6bf9f75f1ac76a9cabb563d83eef06a44356f44a63a31dd71acbf684198bf8eb31cd37bd7a9156e59e15fecd18f6dcf1e6c294024df80d1bb71f75ae4d6c7466011346f22a132e00832c20e9173ad8df92322999ab6ba1707a520c391f664e8b90fc5b981ae6588565c11489fc0d1aeb8abfeefd17bdd34a15b5c4482e0205acb036e4978244a3e30ae1e9eb97050cb8919674429780c0decb855578f620f0caca922f0493f81ef20098024f1e5983c62d7eeb057f9666635ae707c9e6522195f3d0b06f391d598667190a72f85024fbb1954ad9028b127492ce672c2c43d7c7003c3557d9369af8dc0ca3d28ac73ad83d4d3c875957b8bb5d13e22e24d33dc7ef7074e810c9f3078ca75134476853411e5975c7ed9dae8eeb833bc1d27abfcb465e85f12bb09066dc77ea4e0f386020db76a94ce2f0e51941b230087491744a0407d8b6c8cd0bd41927347737c6499b1483257cae7e79290c4aacaa39aba3270208eca1a00d1ac67b56ee08df879223d8573744fb4ffc951bc2ac143e10327576614111269c758769d48980d398d5ae67353e165c3d0afad0e3ca44a7f2a47e150a15d631454329c288d8d352767e97ab898a3904e4f27cb4f2b650ced68a24c95bc0bc7dd4aeaa7629ca07774f3d6e2a4f8ab204ca5b2032ccf7354c3b2387158f459de9334bd11824201534a1af705a59fbe7d7f41b8f8d73c9e943919fa4cb8ec89baf564999e89725164798a9511282448e0eaa60f20b5c88d6b686a09ab1c69becd933e19f5a171dd6ec70e5655be49a59c8a09087d6e2a1a16b6f80364d9387f7f77bd82fc451275422059f108cf32626d71841dcac622cb68cfe62179980056af46bcc70052077220442f543bccc633d8d6f138eb5ae6cc0ab77aa835bc6cb4b768818c8a765ab319e58a8ed4905734ceee07174f4ca88c8c3a75c314866dab3d666a1974b63554e8f044afc011e7e185fa9c48f8d0de00b4624d6cb306f14357e925d05664f0fac20406457be012ae66b8311627061ff8d9f04c51aa0ff63b6035d2cade07e0d39f70575109ba42a18a8a615273b4af9645691231fd7f58136d076fdc292f86a89a565184ba078a933e5aafddc98da0f1148b0eaf58bb22212e78bab2cdb3f66e564c31596c5bf7b1eb5cd2d64881a967eaa0d05bf7c4fb4a4f229629209a3ecc02bd2f44797a437c94fd8de46539b60441691de5f4e91e2e16a3d3042e8bfefca548ab29e1257158257de0f8d817be4bb4441b8f1630042c951de6e8c8e725fcf348f87e7de3769857aea6e62e5b82ee90e85b60bc231e45cd602e6d9faa8a99d97d4f562cc735a1485c6a497f5b8c0a374d3cc23e1c4a5cb65378387b57e159a9873839227b3dc23dee140d8aadea48aad947c4915201cc9086342cfb296a2c83b377a7a0190266258a7d7f092b728dbd86f28978aa8acfc7c252245a78ea891d030589a2ec0531b6cab01b4596192b145de7170df6fefcc6b8044e4751ff1ef57076e2fd12ad3533b163b6f9b92eced378247449b336daebe97c01cdabadf39c9932736e0d99f82cf65040ebc3dc812612ffcf1cba2028072022f04e8c921a82747c6405c24a33ab15d9da3575e1031e91e2c37a1178b3d3ac991b0635edb33275b5c1f924ac3872f235a304f42a464635fac2a694f9f157df7b4c3bf872e8e50ceda89e213563a5d382e81e9c9b94624751f73af8c285ba1f035f7330b15679417534d21435d1f8d606047c6bae97874340a054d527b1c28c1350d1c0e624e7961282de50869baa9b1e33d7a9312c3ac9caf06b4af8035a31d50924a2f61689d54ce6bf954f137af5eded5e4485ace00fe93d682f6239eb59bb12180ecf4f3bd2bc230e2b12628f75672f0247ab31460a85d98a834adbfcc1ffe57c281d416b2b9b23c4709656c94ced5152bbbeefee34ad17d91f5c5ff59d263bacda7195673fe096f60cf005ca1128d710ec4a016ef2d5debbc48f9faedb1bce9674daa0c5c7d54323666c34dd692917c4634e667794e9d673af2ad9bafe62804a761c197f1e27ea6573c9edf2502a9e81d8e17353d60285ae3a127cd403d29d8b90cf1bd740b23d7cbbe10df3c294773bb84fb4ebfd519c84818ac977d2debdb180f8634e964597656f6479e270f953bc78a1208cf28ffa9ceab55ab14008d89c60882f3f5ec8e1a54f7e7fe00533eb6eb8d8588a46263b982c237ee138843d0f8887148e4e940fe8858c6a15840bbcb27ae2b709e80e41fcf751d97869f100d40c355a4142e579d8e834e8c69b50ebdddef09118903cd8a43e838242f1317ea629f1fd16077113b7b0fd2dd74b91d17141e75554b148c4e1580f0d3af1bb7f3b64c4250dd0c8e3ad303fe79e27d8b8ef67aa993830f96f11440516da8c685b7fdf9af730b65b348538f18e2f5933cc84486e299bf01d127d3484af1ba261c2ae87fc514111092811a841f83036e58f7019390dd5fa85736147a4866dfb1f984997dd47828fbbc5c7920293a37e5e23640c3e573c78594838d7c9bdf0d1a931ce361f4db3b64aa8918bda753c41846ff58836cb5d3c10af5719e343c40f21904e00f25802badde411af8ffa16ef7f737195dabab5ab270a4c7c20a1c01265d77f29a8db1f912a7f217de4be92b2a561122fba1529ce62f47c5e5cbbb0d0a30651205fedecd753de60c4fd7862109de58e0be82aa15a59c6a29f0faf03bc2933c566253b10d838f7b917301b760997aba090f7456d5f21f8c5e06432068a3a56326c9d849afec524714e052e502934ab929ab804b9011559da8c7fb4a2a250f2d08bb7679b0a6c57850677d613bdc67e8ec88cf0c437e3045f081c239f7cbf64d1f79b36b1d9e247d346348950701991454a5d03cf11dd41b850418bfd974ec6e3943f5542c8f7322a2bd66b42f6d48d8754cf1afbf88d6f7a60065a2389482a09d481b02344d4a51aa9a40f0072499521962c44a9efd426ea198024666972576df205329bc834971690b92dca894a3412b1c601bb8698e7284dc6a6375e17727ba37d90ef93b68150fca599d86c02b89bad89edc8cf96da25b88e3dc61092d975d4c466092c160231328b2a075ea7ff70ff5090521afb35746d19e233595388f48faf56eb9303fe28ec4faab5cd316c9e8abc1bc1a4b5d0d3ae602a0d64cf37cf2a5a1833a1e5bdb831d12ee9392f66d7cb0e3873c58ccfb208700f994e0c4005fd1b48da894d147f209338eee5b23339d536f89744049ca3ee3e0544bf820a1168f9013460854af3d647eb342c784b006e9abf2be89ae6824059164c01a90fc65299625f8af8f2541d31db5c424e7a6e305434cc2e783003c56b917e363007243693f1ba24abb7b29351b578452b0bed4a4ef37888de3dfba71d8e496b8dfe1cc2e71c6bf48ee1ea34f4f88030cc1968653f78997b4919041305f23083ae1176455845b6588ca9af250fd8f948a95045c04bcde86684913fb469b181b241804b74b74993d0dd64d296c32ae211afc09f159cc39b065538f007540d96603fc86e8a4ade97f1ef1c70823d3e7e03d643096be273317add1cce3c9ab96b50ed4768fa1adc6bf9cccfd13cf19e2be0eb56525f9540829479fe60d8d97dfc275d93458e6c106491c2403dd51280390a0e10130eb2de7342cc1bfe8f0ae29663e41e07d313a7cb55b31a094bd0ae0024277105d5930d2175c4a53502c8683ec3bf32caa193df0e5d6a0264df05f15ff630394b2268100341f0a906fe3001e5f0bf70e73ef4a03deb417dc65c41634a1d26542a6a3346d01572f0ecca8903b6e12858f5ba7f40cd750d5b8baf7381499926c11118c21b9348c66937569f05728844e9860c1296af6431bbd3856dfc64a013477267ed24ff940238bed12308ef617a89216ca0f4679d116f66eaf2bb117b82267c1ad3472d605242ca8000c1909a811830e2c077644e69aa9bc0840ccea754a4a3ceb26cd70abe84b9e8259e60b5157516b96c6fde1a2bed6c419b8c384fdd6b56db737ec6c8c0a2f20a86387d52060a57b4edfc45a2b669091ccb2485a616556563e20fd003a8136614d646c4a26e673580a29bc6e9b2c6d3f56980bdb9632aecfaa32ad44df38550f53ee6043afc18d6c150c31c0a84427c81520ed51ef2139cac92c55c57ee617a105167f7aed39cf2e7f59a8394734b65cc2778ccc102f41130276444228e1e0257c78524c68e9c39b51ca29be66f5208475168b459b5b331d3fab124439d37879ddedca1fe7437a9efcc21cf6891a210cd56186e08e5bd957388ccf5a8efe6c339aaf13f6c2d4fbbe422570d5da5cfd2df0f29519f385e8742c9aa53aa4af1af990c6827078f337e7fd9956a3e55bcc40986873a31c3351ac022cfccc490418c0c2e134083337079ce33d342cd92453b6aa757586d56d8b480a48b0c80145a7ba95661303400977f8f95a54b37ac502f0fd38ad6b032f1d53f10cceb9956950d73e25115e8620c6a9c7c1594ea50b6713b2152efa3eabd18f48b4553f4df8d2c1659bfab6b65643207060af756bb8154cb050414cf4807570e3ae05beb395fd9842417de57e51ff7101b1f367a5ffdcf2e00f3949497129a5f34183dd1154ec436f9157144aae4121522cc3017508e2d1599b4611eb3f9394471a91a997ed37bb2b62c7b7c4a11c102df96fde2c2520c476fcea241cdae311c02f53bb1e04205743a02c5cb0f10a8adb763c071bffb7bf5ea58b4610dbc539810d227c91a7a450b27868b15f4f8e22be1ed91e17af2fa42b2d24e29836f47db6c41a4d69c043734ee8aa0e093e6312d39257d06154c8aa4a3d1545cd463e229d0d7c803fdbb39543baa43d06454021db966dc1ece30527bd9f0111ee5882e7aee74cc6d0a9f1556976f37352c22a3725400fb16e7559e42cb4f9696b4552cbadb8142378df128868deb6966580a103da1fa99f885c7fb31662a77065ec86b79b9a3f4d61f64b59d32eb0b272d67c6d16382f94598f3f09e577650e7e467f8756cd7da6a1ce95a5618c6d228397d77712434ff09c563800e7dd051278d6759293eab2cf1e41a877b440d4bb9817fae323fd47d2f1f223eea267c4a9e9c25e213610e90694946d9d25e3b71ccd2d8d8c8abdb4cdc43d64bf9b6502d8b37556a8c48a8621b3d597283a650a34d56e03d9b0e4236f8544c04ab226158c04f15865cf42f2f848f15b146f9c549d6c0b3b7d03ba193c0209f04151c200cf50ff6d59cca72aa54c84c05483105d5a224119e09655c48976f224f2545dcaf6f6a90ccd63387741e0f1d69e89c97c1a9e78e5ddc67448cf47622ee67ef85301c1f3e5dc875628dd363c1ebef814ac27f87bb34a3693caaddaec93a86ac944952918039ff0637360305d181a9d94365dc30acb4c7f3545d7e1f534a44409516f8808b186f537b7b1ab15a46b58476986701884b54e2fde0f2f9d2830e7792f3811d430519ecb0872eebb8df7a8606baec0f20a9170375633a7a7227004f21a7a0053e0117b800294c7efafa9ca7e882d7979702b310341f41d06a480e26e98f0f00d9d6a21156d43d7287649f1f11cacdd1487c76f70ff2e54bf52ae79afbe5d7c45bd6efbc89683fc312dd2cdcf5aa4b0defa0080915291e086aec7ad99ee7fe0d83442cc99b57d111e8bc80fac7f9a41dd113a230cbdd09a56bd87f62dde76e08aa3b78e1545eb69ceda3d301c9c232a78e714464668b581f8704a16844403c385e9db751235091c13f12b8249b82cfc213ed959351fe82862f959063cb737032c1a25ecb8d0da630fb8e3fa473220c0b083e6bf9c0b646d833ae0e0966c7d12612b0f7cc626778bd19320dfb8b79fb5b015b64895c01cf3e61e3901ef1c0073242a28478b5f053623e230447454c691ddc27abc2c31176dd3104ed670265833b4f42e1532c7904756893b8a037bfce97be453468265eb92c603e6003a8a536296dbe5bac8f999c624714261b52f15c41e62320c6a2d637427a6ef0343941e17d6a3d6302d598fe597c0271555311b4a00b6e6d1dcfb692e1ec9e63c3999d1ca92c0817c7aea3d6396b55ca526553adc2a7f4ee8b1d7fd2df467590fa184ed9d690d6d28bfa8c2f8e93edd656d1337fa1a31d7caa80fa35227701d606dc2024a66abcf4579dcd0023274816c0aaffdf10297eb8fa268741f181d357069c40da48f14bcaf24ae915b07e22670451dcc7b87a4a175278fab22e2ffcd1e88ed9f13f58095e794c7569f1cadfd6a182cfed1f342ada56cf816e2bb1cce9efb7180b2971ddd6f6081d21904f0f337456895cd450071b16e7716e2ec269c1f1e573705b57240437b0e70e2c2b38b368cb5806466ad21ec208a7e9e1ea217b093b5809a72b67f224c33845d22f89cd3084d3d753bc094589a02bb8eb99df3e91b7d796af83a66145b0ae4a8b6142369996c48c6077c35bd16ee4ee2f5bf22ba6ba3e882724c959fbbbdc364ad3aaa5f71be59c35697a2368b04eedcb8225396845ef18f06f931c60c0b171f02d42c71326b2e58767746b091085150c72127fc384514245f5987e1460cadcc777730496b13ffe38e70f487cdef0f48aaf67392463e6c315a1c26c1b72e6ce4d7292b3189a638eb6dffc667f74ac311053438d88589200b10082dbd353a20af3a0de89e838eb01e6c8817d5cc00fc2d97dfb21cbd931b14f56abb32dbbd0040ed3b34acb0c7215904a28569088e8a09c6dcda1097154dc5177a0eb4ec002ab61d9d8cbc2dcc9cce21f339b20292d19c370741cd082646ca517fdf523e133c6830d85644e615eb4094645789a7a6b9a11dbdef7ec79be8aec90c235f1855299f11251a1081f2bbab29174edc708f926a9035de8dd6d723f40bffeb1aaf3d9620339285e03dc4ddf4700f0cdd8af473dc464806b604c2b3cf281fa563895f9e0263a783fe327a204ed58cc16df0e93123be5f62881891e06622a3642bad30ff37b7c9802e4f6cfd868d9ccc20920ae3cbda914ad7c5dc8240b13a60a6fac277d93418121a5784077c541761949542a9a0cdf11f14497cf7b8f78df07f218bd1c86c526bad76da1f2b743253c7ee816884a540da0f90928602b9149f9a86146b94a4213e3782483e5e6311ba857bf938d7bd35de90b38e3f76c7b5df42721735e1fe017aeab87d82ec2e1d51d46b6bf25136688e0b55468ec320c5b5b94f7dfb34617be35afd1b985bdf19ea911d08467c874e19f8e7402ba33987e04a9e8484bf835556b71321b894164d02f63bc9991bccc18f90ab0f7b0368f78753baeda1aa70628b0b52088bdb4d192702c85532431eb01d03b2248d489a86e7e117783738715c1d4f22b84fa6364dc108262dbbddabc76d44969778a7247c8df8e8dd74f6bc8772783a54cdd31c72114b07852265471fb95aec4468ad29deeef7277a72250f9c02744bf24370df2d6aa0989361f2d6222088b434dd413bd72b9379adc891372cfb23bfa2db82e5653e47cee701a81806ab5cf0f8b74fce277c5a8831915f019bcdcfef639a86497be55acd20a9c05c5f9ed213d7eeac525d5b93316a10bb31760cc37db63fbb3f1e923422b9885b628a38802f8a251d34e4928f19f9515aedb8647629b207102672e07802e2829e1fe6c81916c7ac1cfc36ba994f2ba8b0a03c643cdd724d95f99672350759b7cccd84b2138001524620f3930ebc4b928eec573dd34b209f40072fd6cdb95aa5dc6b7461b6ac10c92a840e1d985f848ae07980f1d016522d99de3df1b6d3e2cb601561c7ee974e868039f8d0ce62f7e6e4ac3a1e9122500d3d0843b2c5379e04397d7904881c5ac7acc8def09478787929cf9340f754b86a1981c44fd441d6c0f4a375000c91aa5002bfb7ba44407cb4bc8c2e952e3147d92f31d4f08578da17db65ec95e8548ae4a57851522bcaee9eeed80d40b53512985d6ea95cf6cb0df3afd5364c09ca02121255fc07c0115bda509b13c217929ef423e7241cbba6429cdb45903124c09321f5b0479f9fa5a54aba1c2a4b3162b2cdaea56e6dd961f182aad90ac6694624a4470be8bb2869934e1fae858111666f639008b1d41f17ada99d0aa3bdb4695af65e358252db957ebcf0bfebec7f0062900adc86e3b95dd2330ac1bdc9690af796032efd025d3a969c3f20d84aa436735623c4dd0042d09c81a1c5f852f9b2c08013fddae3807101c5298cc5ee9392eb75940dd453ecdd421a5781b66bad5f9fd3a9a5a447aac2a0a0af44496a5fb4889744f4a88fdfb2b54764738311524369f7eca94c21d905d9f99f8a8f2ccf93f80eb4eb497c82ee199eaf5dbbb39d748219a5382231e5ab1e26d636a3139021812e3ea4cc24c56823dd02ae41d898789a0733a8bf0b536447c3f19a2ce88b32937bcd6cb5310dd7a7f68d9748309a5ff14811cae038fd19c345d7dc86da9a23244b03048acd528e8ce2d8a7b4d39bbeb36bb83059cb80539179280ae8b31a4cde90c4db6c843d77e1b0d644f983f33218ce7dbab0084e0b6fdf19cf1fea1c2d1133425ce50f226f61095f806f58e01689251795747e89d4821be50242d2af6c488d948274476f050d50b0ddeb33ec020670aac250de712217a54083efd3472717d9ba86ce177fd922e229fa5920c0c01a81cca481250e7a61a54e69dff3de125de5bac90b3d1c1ed4ad4520a8b2b8c1059a013e916d1e1d93fcfd596a9ad57a85a08984f966800049273bbb061e0e7df621b4639199730469084bf0e68085d86d07a3d877d6f8d976fd75a571409a6e60817c50698c67e9032c2e1a2219496c481a263dd55f2c080a92930d8defd85c6e33e161c35bd2cad453882720d8ed39c653624624e3bddcfd1a6e0584471b95fcfc4a9c1f0e0cf719d5d17280a1173673e3efe530e49b9721f82b549915279e54152905b77ef5c3ceb9ead5b7b0438ea2e30441d6b860485c9ca83d2bce2f4c72ec221d1b259b2a49f6c10dccc0813eb7482aca1a67572de2d887395928d7bfc690280fea7a3e28ba58f80a6683b5b113748d2496a4322a3c5e4c8aa9077813a4b8a7fdef3e7fb213918b061c45466ce2c11289ad10bc0236677cbd519b502516c6a5cf3e3b1b82ea8090e9fdd06739e46c3cea4a3a341fe010a688647910e027939259a4bcbc589e519389fb52974cd34559367ea3c020be5057ccbe18b5a81928c49d73ab1f70f0d83cbf4601f04e8e60ac4c225fdba05c2e59521d34e8ae8ed43789b349e0641e5713f862d9f0b48d477729d2515c1b4a7dee126311a7b9cf8065ca3880b119ce79a2738180035ba8596c3b508bc7d91a506a4b1ff81719db9db2b66a6528a1f9cb991d482b9a72309d8128ff019cfc1de1fdb1c922dff5c4b371e2ac1becdf9bad1d05e1b3c4be9abf0f19551db4f35f82d31257141967e0bb7add1c4a78e33b28c5764e7be027c4bd692d8f7362c1cbfdcfd09f6a8ca86223bc06c708860398a74e174aece3c6185c632a404e5d373c406118d1bfe651fd9566b97fa31a75a3cbed87314553db6213efd00eecfca3a2bc8f5f8fddea0ab1af1c9b754e33cbb7ef2e2012b931632f6a167c449d6203b3d73daf0d71e0b7f8a811538bae7f677662f8825e89b4259f28c338c0199e1cd283ebe98c0e6a8c5172ed62eab06a280b02a2143c60a54ec7efc13b40836fbe2b966b23dbfeb972a95d295742129ee0a08c8756b05f7bc7aabd375bf9e97d8eb1a493beae209edfa90a3be18aa2b2f7402fee529d086078a13e8c9c409bf179020fe3e977561ab8c52cf20f12fe6f6b9bb83928c2bc8ae087d8675a07b8e85ff9a5bf6af98fd0d970afb183ef5df261688bf91c05a0a59e96ca8e7c3fd00c6d604d2b15fc2f2214c44948e56c050250798f8971824a3ca5d94094981c4a0e20611ab4364383d11368d5c755b109d477c0df787f3c458d097f90b8c51a9d6f624db101fabd2e26e72700edf9ba48496f3c1d1dcf4bcda3ffc6b44b220ae61fec885b0c5945e96475f85504294f51df65a5044db4de586f814158cc9f5b1141b0cd747050e1c0210995c6ce3d217cc6ad4c034b8904ee4d6135fbc22ba8d0f084c04849c5050090e0068bf5612880a9c27182804eed2b44ea2af03167cc5fe3ce8669252b19c9b30ae1098d1c571377c197ecc00c2471c34c7a0f10dfb1ec49ba3466f84a0546917f71605c5182504931bcb8a0c47d26d53c9240f2152e92f0d58af85da8432a9b51e8d7716307842f5623089f553660ddddac9a8717c526f403951bdc3b545fd4d1227b628ebf4b5f1af9e093f3bdc0306e0bf34a79230f7ba68b10b0520f6ee76fb33c3868b21fc9cb709f1295eea301d0f627aac219125c4eda5417d68ee639fb85bf85ed7204d1e49f990c5338000a7c9025a3d934543d138559895227c244613c2b3dba2f28ccc43ac87b9c4f0181aed1dce5f6bf9844a9a3bda94df38ac9226a03f076f1e39daa5ea18368b002fc39cb13306a445a152738d273c41103a444ec7679bea0d8834ecb8b5d0df7f8961b88b7beaccd77b3ce306826ca83f35f79b27580bb48e20192f928dfdae3100f4f94ecf5016d227d6b97be94d01cbf5aa80a323dd89a146169628bc23d89364b0049c7785dc2afdb3536ffeef791f520cc9aea30147e3464b3b1baf161be92d74ab91eaa682624cd93eb010c61c5d2fd79a9e6efa752461f206f9376f050321835e13ab3b19913db5fc61cc77ab05d5d987ff68786633846318b245eede4df4d325a7840419b057270956f448dc8a3ca5cf5e0ff4d63cf0f5889199a52c800f3c3e585ba562c854f64d501bff55481e6378c0e2b3de4307f97ab80d8543736cfbc824a8377f982200051eed0b50fdf473ce92f8baf471de9e4588355a3f1c142ed1efd4a61c93b65dc2919f98986dccf94360860b1e12ab91eaafad8055299dc2b028a20c9744571ea3d0dcf4bda99b30965372fe0fbcb68c211e2a457f08fca10ab78ed0a43467f368a71e44724238f16e4ffc7efebef4b23d17d0d028185a2d78b47b851cfce56bbe1057334ad845a1e82c50073d2dbc900f87dd5ccb14f5496423f325bbeb949ed25f5fce1a98d53cc6095acae6f76dcaa77196751ef6f3deab3a96b9be6ca3e050ab725c2d426b0c6e1beb3e6c0fb6c9e765734e0c056989e45d46c7d6d50951f8ec9927b57da21ba2b39c453927aa529745bacedc8873a5685e4cc57b6758fcab63d9ceca84dee5deb62e0823c6059ce39457ac68c402652d6426e430d55697e7e244799b8d4f2725ea2e7470e55c399ec987b0392c297f951fc79747334261416e54f9fa2978ede7a9512546e015bcdb4c831fa511549232d683d49be7443608b3d3d91ef32825f8af6c4f8cd7938a1a01c02ab3188490835a580de91c885e1b855db98a8dcd9905233a0cb50c798cdb0e23cbfa069038d9a4e4641c37c5aecd23b9dd151e808d918b742f550a9cf6a944f9480ec2ae36c158417449c9363f395c3da731a2f9385cd4aee3c0ffcae53e3a480c75c1b690fbab3b474f73ba2b03a858036e9703921e1d35f17314c4eea7059fee53eb4083b671ccd553d78bdccb7618bb9fdfe33e62fc4a4cc5e3e1d74a7d50d445407aa209629e8b5fd16b363218bf113e3b4357e756f7f56273d5a24444996dd95c7319c7442550a7387f45bc1060", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0x5e8a19e3cd1b7c148b33880c479c02814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x682a59d51ab9e48a8c8cc418ff9708d24e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00000000000000000000000000000000", + "0xcd5c1f6df63bc97f4a8ce37f14a50ca74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb373285fbd4c6fce71acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0xacf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb39fec29fe06b54a1c58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3a8f65c4e14b8c350e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0xe803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3fb08f1ab6e14e0d4fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0xfcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195037606837a8a4a9086175726180e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066": "0xe803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19506f21f0983582bc906175726180fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123": "0xfcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195096f8eb862d21fed0617572618058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f": "0x58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f7b1f8ade68c95ad6175726180acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69": "0xacf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x1058c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1f58c18106775d912da3fbb93ffb0b68a9734f009a231fe47fcb6164939b828a1facf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69acf59a303f7444c1c494331500b5448d714b361db59bc08218e343eb0810ae69e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066e803b1d97726c36cf938a374bb5b0f0a6da528cb63ac2d4b76c669a861430066fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123fcde6b948191260c67521879d9ab2b4576abf3321655c3d754a75e7781207123", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x02000000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index c1edeb98cd0aa3b50e1c8efbe47085144f70900e..8c8091aaec3c4a860a6e879f0b6d5e65eb05b3fd 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -30,6 +30,9 @@ pub type AssetHubKusamaChainSpec = sc_service::GenericChainSpec; pub type AssetHubWestendChainSpec = sc_service::GenericChainSpec; +pub type AssetHubRococoChainSpec = + sc_service::GenericChainSpec; +pub type AssetHubWococoChainSpec = AssetHubRococoChainSpec; const ASSET_HUB_POLKADOT_ED: AssetHubBalance = parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT; @@ -37,6 +40,8 @@ const ASSET_HUB_KUSAMA_ED: AssetHubBalance = parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT; const ASSET_HUB_WESTEND_ED: AssetHubBalance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; +const ASSET_HUB_ROCOCO_ED: AssetHubBalance = + parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; /// Generate the session keys from individual elements. /// @@ -54,6 +59,13 @@ pub fn asset_hub_kusama_session_keys(keys: AuraId) -> asset_hub_kusama_runtime:: asset_hub_kusama_runtime::SessionKeys { aura: keys } } +/// Generate the session keys from individual elements. +/// +/// The input must be a tuple of individual keys (a single arg for now since we have just one key). +pub fn asset_hub_rococo_session_keys(keys: AuraId) -> asset_hub_rococo_runtime::SessionKeys { + asset_hub_rococo_runtime::SessionKeys { aura: keys } +} + /// Generate the session keys from individual elements. /// /// The input must be a tuple of individual keys (a single arg for now since we have just one key). @@ -643,3 +655,240 @@ fn asset_hub_westend_genesis( }, } } + +pub fn asset_hub_rococo_development_config() -> AssetHubRococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "ROC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_development_config( + properties, + "Rococo Asset Hub Development", + "asset-hub-rococo-dev", + 1000, + ) +} + +pub fn asset_hub_wococo_development_config() -> AssetHubWococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "WOC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_development_config( + properties, + "Wococo Asset Hub Development", + "asset-hub-wococo-dev", + 1000, + ) +} + +fn asset_hub_rococo_like_development_config( + properties: sc_chain_spec::Properties, + name: &str, + chain_id: &str, + para_id: u32, +) -> AssetHubRococoChainSpec { + AssetHubRococoChainSpec::from_genesis( + // Name + name, + // ID + chain_id, + ChainType::Local, + move || { + asset_hub_rococo_genesis( + // initial collators. + vec![( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + )], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + ], + para_id.into(), + ) + }, + Vec::new(), + None, + None, + None, + Some(properties), + Extensions { relay_chain: "rococo-dev".into(), para_id }, + ) +} + +pub fn asset_hub_rococo_local_config() -> AssetHubRococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "ROC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_local_config( + properties, + "Rococo Asset Hub Local", + "asset-hub-rococo-local", + 1000, + ) +} + +pub fn asset_hub_wococo_local_config() -> AssetHubWococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "WOC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_local_config( + properties, + "Wococo Asset Hub Local", + "asset-hub-wococo-local", + 1000, + ) +} + +fn asset_hub_rococo_like_local_config( + properties: sc_chain_spec::Properties, + name: &str, + chain_id: &str, + para_id: u32, +) -> AssetHubRococoChainSpec { + AssetHubRococoChainSpec::from_genesis( + // Name + name, + // ID + chain_id, + ChainType::Local, + move || { + asset_hub_rococo_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + para_id.into(), + ) + }, + Vec::new(), + None, + None, + None, + Some(properties), + Extensions { relay_chain: "rococo-local".into(), para_id }, + ) +} + +pub fn asset_hub_rococo_config() -> AssetHubRococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "ROC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_local_config(properties, "Rococo Asset Hub", "asset-hub-rococo", 1000) +} + +pub fn asset_hub_wococo_config() -> AssetHubWococoChainSpec { + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("ss58Format".into(), 42.into()); + properties.insert("tokenSymbol".into(), "WOC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + asset_hub_rococo_like_config(properties, "Wococo Asset Hub", "asset-hub-wococo", 1000) +} + +fn asset_hub_rococo_like_config( + properties: sc_chain_spec::Properties, + name: &str, + chain_id: &str, + para_id: u32, +) -> AssetHubRococoChainSpec { + AssetHubRococoChainSpec::from_genesis( + // Name + name, + // ID + chain_id, + ChainType::Live, + move || { + asset_hub_rococo_genesis( + // initial collators. + vec![ + // TODO: add invulnerables? from Rockmine? + ], + Vec::new(), + para_id.into(), + ) + }, + Vec::new(), + None, + None, + None, + Some(properties), + Extensions { relay_chain: "rococo".into(), para_id }, + ) +} + +fn asset_hub_rococo_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, +) -> asset_hub_rococo_runtime::RuntimeGenesisConfig { + asset_hub_rococo_runtime::RuntimeGenesisConfig { + system: asset_hub_rococo_runtime::SystemConfig { + code: asset_hub_rococo_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + ..Default::default() + }, + balances: asset_hub_rococo_runtime::BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, ASSET_HUB_ROCOCO_ED * 524_288)) + .collect(), + }, + parachain_info: asset_hub_rococo_runtime::ParachainInfoConfig { + parachain_id: id, + ..Default::default() + }, + collator_selection: asset_hub_rococo_runtime::CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ASSET_HUB_ROCOCO_ED * 16, + ..Default::default() + }, + session: asset_hub_rococo_runtime::SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + asset_hub_rococo_session_keys(aura), // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: asset_hub_rococo_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + } +} diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 32e363aff74be201f176bdcf2eec13cbe2dff6e9..52aa1c8bd574e088380500c3655ad65f3229e6df 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -42,6 +42,8 @@ enum Runtime { Seedling, AssetHubPolkadot, AssetHubKusama, + AssetHubRococo, + AssetHubWococo, AssetHubWestend, Penpal(ParaId), ContractsRococo, @@ -90,6 +92,10 @@ fn runtime(id: &str) -> Runtime { Runtime::AssetHubPolkadot } else if id.starts_with("asset-hub-kusama") | id.starts_with("statemine") { Runtime::AssetHubKusama + } else if id.starts_with("asset-hub-rococo") { + Runtime::AssetHubRococo + } else if id.starts_with("asset-hub-wococo") { + Runtime::AssetHubWococo } else if id.starts_with("asset-hub-westend") | id.starts_with("westmint") { Runtime::AssetHubWestend } else if id.starts_with("penpal") { @@ -164,6 +170,31 @@ fn load_spec(id: &str) -> std::result::Result, String> { &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], )?), + // -- Asset Hub Rococo + "asset-hub-rococo-dev" => + Box::new(chain_spec::asset_hubs::asset_hub_rococo_development_config()), + "asset-hub-rococo-local" => + Box::new(chain_spec::asset_hubs::asset_hub_rococo_local_config()), + // the chain spec as used for generating the upgrade genesis values + "asset-hub-rococo-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_rococo_config()), + // the shell-based chain spec as used for syncing + "asset-hub-rococo" => + Box::new(chain_spec::asset_hubs::AssetHubRococoChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-rococo.json")[..], + )?), + + // -- Asset Hub Wococo + "asset-hub-wococo-dev" => + Box::new(chain_spec::asset_hubs::asset_hub_wococo_development_config()), + "asset-hub-wococo-local" => + Box::new(chain_spec::asset_hubs::asset_hub_wococo_local_config()), + // the chain spec as used for generating the upgrade genesis values + "asset-hub-wococo-genesis" => Box::new(chain_spec::asset_hubs::asset_hub_wococo_config()), + "asset-hub-wococo" => + Box::new(chain_spec::asset_hubs::AssetHubWococoChainSpec::from_json_bytes( + &include_bytes!("../chain-specs/asset-hub-wococo.json")[..], + )?), + // -- Asset Hub Westend "asset-hub-westend-dev" | "westmint-dev" => Box::new(chain_spec::asset_hubs::asset_hub_westend_development_config()), @@ -249,6 +280,10 @@ fn load_spec(id: &str) -> std::result::Result, String> { ), Runtime::AssetHubKusama => Box::new(chain_spec::asset_hubs::AssetHubKusamaChainSpec::from_json_file(path)?), + Runtime::AssetHubRococo => + Box::new(chain_spec::asset_hubs::AssetHubRococoChainSpec::from_json_file(path)?), + Runtime::AssetHubWococo => + Box::new(chain_spec::asset_hubs::AssetHubWococoChainSpec::from_json_file(path)?), Runtime::AssetHubWestend => Box::new( chain_spec::asset_hubs::AssetHubWestendChainSpec::from_json_file(path)?, ), @@ -332,7 +367,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -368,7 +403,7 @@ impl SubstrateCli for RelayChainCli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -391,6 +426,13 @@ macro_rules! construct_partials { )?; $code }, + Runtime::AssetHubRococo | Runtime::AssetHubWococo => { + let $partials = new_partial::( + &$config, + crate::service::aura_build_import_queue::<_, AuraId>, + )?; + $code + }, Runtime::AssetHubWestend => { let $partials = new_partial::( &$config, @@ -509,6 +551,16 @@ macro_rules! construct_async_run { { $( $code )* }.map(|v| (v, task_manager)) }) }, + Runtime::AssetHubRococo | Runtime::AssetHubWococo => { + runner.async_run(|$config| { + let $components = new_partial::( + &$config, + crate::service::aura_build_import_queue::<_, AuraId>, + )?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }, Runtime::AssetHubKusama => { runner.async_run(|$config| { let $components = new_partial::( @@ -836,21 +888,28 @@ pub fn run() -> Result<()> { info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); match config.chain_spec.runtime() { - Runtime::AssetHubPolkadot => crate::service::start_generic_aura_node::< + Runtime::AssetHubPolkadot => crate::service::start_asset_hub_node::< asset_hub_polkadot_runtime::RuntimeApi, AssetHubPolkadotAuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), - Runtime::AssetHubKusama => crate::service::start_generic_aura_node::< + Runtime::AssetHubKusama => crate::service::start_asset_hub_node::< asset_hub_kusama_runtime::RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), - Runtime::AssetHubWestend => crate::service::start_generic_aura_node::< + Runtime::AssetHubRococo | Runtime::AssetHubWococo => crate::service::start_asset_hub_node::< + asset_hub_rococo_runtime::RuntimeApi, + AuraId, + >(config, polkadot_config, collator_options, id, hwbench) + .await + .map(|r| r.0) + .map_err(Into::into), + Runtime::AssetHubWestend => crate::service::start_asset_hub_node::< asset_hub_westend_runtime::RuntimeApi, AuraId, >(config, polkadot_config, collator_options, id, hwbench) @@ -876,12 +935,17 @@ pub fn run() -> Result<()> { .await .map(|r| r.0) .map_err(Into::into), - Runtime::Seedling => crate::service::start_shell_node::< - seedling_runtime::RuntimeApi, - >(config, polkadot_config, collator_options, id, hwbench) - .await - .map(|r| r.0) - .map_err(Into::into), + Runtime::Seedling => + crate::service::start_shell_node::( + config, + polkadot_config, + collator_options, + id, + hwbench + ) + .await + .map(|r| r.0) + .map_err(Into::into), Runtime::ContractsRococo => crate::service::start_contracts_rococo_node( config, polkadot_config, @@ -949,13 +1013,10 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into), Runtime::Glutton => - crate::service::start_shell_node::( - config, - polkadot_config, - collator_options, - id, - hwbench, - ) + crate::service::start_basic_lookahead_node::< + glutton_runtime::RuntimeApi, + AuraId, + >(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index f7b053b4b6a9def2fb7c4dd76f757213ca630f1d..fa61f534784e0705bf1df9b0eed6dad967a268dd 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -14,11 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use codec::Codec; +use codec::{Codec, Decode}; use cumulus_client_cli::CollatorOptions; use cumulus_client_collator::service::CollatorService; -use cumulus_client_consensus_aura::collators::basic::{ - self as basic_aura, Params as BasicAuraParams, +use cumulus_client_consensus_aura::collators::{ + basic::{self as basic_aura, Params as BasicAuraParams}, + lookahead::{self as aura, Params as AuraParams}, }; use cumulus_client_consensus_common::{ ParachainBlockImport as TParachainBlockImport, ParachainCandidate, ParachainConsensus, @@ -31,7 +32,7 @@ use cumulus_client_service::{ BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, }; use cumulus_primitives_core::{ - relay_chain::{Hash as PHash, PersistedValidationData}, + relay_chain::{Hash as PHash, PersistedValidationData, ValidationCode}, ParaId, }; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; @@ -43,7 +44,7 @@ use crate::rpc; pub use parachains_common::{AccountId, Balance, Block, BlockNumber, Hash, Header, Nonce}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; -use futures::lock::Mutex; +use futures::{lock::Mutex, prelude::*}; use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, BlockImportParams, ImportQueue, @@ -53,10 +54,14 @@ use sc_network::{config::FullNetworkConfiguration, NetworkBlock}; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sp_api::{ApiExt, ConstructRuntimeApi}; +use sp_api::{ApiExt, ConstructRuntimeApi, ProvideRuntimeApi}; use sp_consensus_aura::AuraApi; +use sp_core::traits::SpawnEssentialNamed; use sp_keystore::KeystorePtr; -use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT}; +use sp_runtime::{ + app_crypto::AppCrypto, + traits::{Block as BlockT, Header as HeaderT}, +}; use std::{marker::PhantomData, sync::Arc, time::Duration}; use substrate_prometheus_endpoint::Registry; @@ -696,6 +701,188 @@ where Ok((task_manager, client)) } +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. +/// +/// This is the actual implementation that is abstract over the executor and the runtime api. +/// +/// This node is basic in the sense that it doesn't support functionality like transaction +/// payment. Intended to replace start_shell_node in use for glutton, shell, and seedling. +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_basic_lookahead_node_impl( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + sybil_resistance_level: CollatorSybilResistance, + para_id: ParaId, + rpc_ext_builder: RB, + build_import_queue: BIQ, + start_consensus: SC, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt + + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + frame_rpc_system::AccountNonceApi, + RB: Fn(Arc>) -> Result, sc_service::Error> + + 'static, + BIQ: FnOnce( + Arc>, + ParachainBlockImport, + &Configuration, + Option, + &TaskManager, + ) -> Result, sc_service::Error>, + SC: FnOnce( + Arc>, + ParachainBlockImport, + Option<&Registry>, + Option, + &TaskManager, + Arc, + Arc>>, + Arc>, + KeystorePtr, + Duration, + ParaId, + CollatorPair, + OverseerHandle, + Arc>) + Send + Sync>, + Arc, + ) -> Result<(), sc_service::Error>, +{ + let parachain_config = prepare_node_config(parachain_config); + + let params = new_partial::(¶chain_config, build_import_queue)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::new(¶chain_config.network); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + sybil_resistance_level, + }) + .await?; + + let rpc_client = client.clone(); + let rpc_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend: backend.clone(), + network: network.clone(), + sync_service: sync_service.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service: sync_service.clone(), + })?; + + if validator { + start_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + sync_service.clone(), + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + backend.clone(), + )?; + } + + start_network.start_network(); + + Ok((task_manager, client)) +} + /// Build the import queue for the rococo parachain runtime. pub fn rococo_parachain_build_import_queue( client: Arc>, @@ -1206,6 +1393,247 @@ where .await } +/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub +/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and +/// needs to sync and upgrade before it can run `AuraApi` functions. +pub async fn start_asset_hub_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt + + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + frame_rpc_system::AccountNonceApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, +{ + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + |_| Ok(RpcModule::new(())), + aura_build_import_queue::<_, AuraId>, + |client, + block_import, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + relay_chain_slot_duration, + para_id, + collator_key, + overseer_handle, + announce_block| { + let relay_chain_interface2 = relay_chain_interface.clone(); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let spawner = task_manager.spawn_handle(); + + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + spawner, + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collation_future = Box::pin(async move { + // Start collating with the `shell` runtime while waiting for an upgrade to an Aura + // compatible runtime. + let mut request_stream = cumulus_client_collator::relay_chain_driven::init( + collator_key.clone(), + para_id, + overseer_handle.clone(), + ) + .await; + while let Some(request) = request_stream.next().await { + let pvd = request.persisted_validation_data().clone(); + let last_head_hash = + match ::Header::decode(&mut &pvd.parent_head.0[..]) { + Ok(header) => header.hash(), + Err(e) => { + log::error!("Could not decode the head data: {e}"); + request.complete(None); + continue + }, + }; + + // Check if we have upgraded to an Aura compatible runtime and transition if + // necessary. + if client + .runtime_api() + .has_api::>(last_head_hash) + .unwrap_or(false) + { + // Respond to this request before transitioning to Aura. + request.complete(None); + break + } + } + + // Move to Aura consensus. + let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { + Ok(d) => d, + Err(e) => { + log::error!("Could not get Aura slot duration: {e}"); + return + }, + }; + + let proposer = Proposer::new(proposer_factory); + + let params = BasicAuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client, + relay_client: relay_chain_interface2, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + slot_duration, + relay_chain_slot_duration, + proposer, + collator_service, + // Very limited proposal time. + authoring_duration: Duration::from_millis(500), + }; + + basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) + .await + }); + + let spawner = task_manager.spawn_essential_handle(); + spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); + + Ok(()) + }, + hwbench, + ) + .await +} + +/// Start an aura powered parachain node which uses the lookahead collator to support async backing. +/// This node is basic in the sense that its runtime api doesn't include common contents such as +/// transaction payment. Used for aura glutton. +pub async fn start_basic_lookahead_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt + + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + + frame_rpc_system::AccountNonceApi + + cumulus_primitives_aura::AuraUnincludedSegmentApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, +{ + start_basic_lookahead_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + |_| Ok(RpcModule::new(())), + aura_build_import_queue::<_, AuraId>, + |client, + block_import, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + relay_chain_slot_duration, + para_id, + collator_key, + overseer_handle, + announce_block, + backend| { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + let proposer = Proposer::new(proposer_factory); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(ValidationCode).map(|c| c.hash()) + }, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + slot_duration, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(1500), + }; + + let fut = + aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) + }, + hwbench, + ) + .await +} + #[sc_tracing::logging::prefix_logs_with("Parachain")] async fn start_contracts_rococo_node_impl( parachain_config: Configuration, diff --git a/cumulus/scripts/bridges_rococo_wococo.sh b/cumulus/scripts/bridges_rococo_wococo.sh index 1117ed6810928b39ffcbafee27b26a59447412ee..4bfe9b32a83606c4c9bdbe0436c7019d5a810b34 100755 --- a/cumulus/scripts/bridges_rococo_wococo.sh +++ b/cumulus/scripts/bridges_rococo_wococo.sh @@ -1,44 +1,129 @@ #!/bin/bash -# Address: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY -# AccountId: [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] -ASSET_HUB_KUSAMA_ACCOUNT_SEED_FOR_LOCAL="//Alice" -# Address: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY -# AccountId: [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] -ASSET_HUB_WOCOCO_ACCOUNT_SEED_FOR_LOCAL="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" - -# SovereignAccount for `MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }` => 5CfNu7eH3SJvqqPt3aJh38T8dcFvhGzEohp9tsd41ANhXDnQ +# Expected sovereign accounts. # -# use sp_core::crypto::Ss58Codec; -# println!("{}", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusParachainConvertsFor::::convert_ref( -# MultiLocation { parents: 2, interior: X2(GlobalConsensus(Kusama), Parachain(1000)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); -ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT="5CfNu7eH3SJvqqPt3aJh38T8dcFvhGzEohp9tsd41ANhXDnQ" - -# Address: GegTpZJMyzkntLN7NJhRfHDk4GWukLbGSsag6PHrLSrCK4h -ASSET_HUB2_ROCOCO_1000_SOVEREIGN_ACCOUNT="scatter feed race company oxygen trip extra elbow slot bundle auto canoe" - -# Adress: 5Ge7YcbctWCP1CccugzxWDn9hFnTxvTh3bL6PNy4ubNJmp7Y / H9jCvwVWsDJkrS4gPp1QB99qr4hmbGsVyAqn3F2PPaoWyU3 -# AccountId: [202, 107, 198, 135, 15, 25, 193, 165, 172, 73, 137, 218, 115, 177, 204, 0, 5, 155, 215, 86, 208, 51, 50, 130, 190, 110, 184, 143, 124, 50, 160, 20] -ASSET_HUB_WOCOCO_ACCOUNT_ADDRESS_FOR_ROCOCO="5Ge7YcbctWCP1CccugzxWDn9hFnTxvTh3bL6PNy4ubNJmp7Y" -ASSET_HUB_WOCOCO_ACCOUNT_SEED_FOR_WOCOCO="tone spirit magnet sunset cannon poverty forget lock river east blouse random" - -function address_to_account_id_bytes() { - local address=$1 - local output=$2 - echo "address_to_account_id_bytes - address: $address, output: $output" - if [ $address == "$ASSET_HUB_WOCOCO_ACCOUNT_SEED_FOR_LOCAL" ]; then - jq --null-input '[212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]' > $output - elif [ $address == "$ASSET_HUB_WOCOCO_ACCOUNT_ADDRESS_FOR_ROCOCO" ]; then - jq --null-input '[202, 107, 198, 135, 15, 25, 193, 165, 172, 73, 137, 218, 115, 177, 204, 0, 5, 155, 215, 86, 208, 51, 50, 130, 190, 110, 184, 143, 124, 50, 160, 20]' > $output - else - echo -n "Sorry, unknown address: $address - please, add bytes here or function for that!" - exit 1 - fi -} +# Generated by: +# +# #[test] +# fn generate_sovereign_accounts() { +# use sp_core::crypto::Ss58Codec; +# use polkadot_parachain_primitives::primitives::Sibling; +# +# parameter_types! { +# pub UniversalLocationAHR: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(1000)); +# pub UniversalLocationAHW: InteriorMultiLocation = X2(GlobalConsensus(Wococo), Parachain(1000)); +# } +# +# // SS58=42 +# println!("GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusParachainConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_WOCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WOCOCO=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!("GLOBAL_CONSENSUS_WOCOCO_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Wococo)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("GLOBAL_CONSENSUS_WOCOCO_ASSET_HUB_WOCOCO_1000_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusParachainConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X2(GlobalConsensus(Wococo), Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# } +GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT="5GxRGwT8bU1JeBPTUXc7LEjZMxNrK8MyL2NJnkWFQJTQ4sii" +GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT="5CfNu7eH3SJvqqPt3aJh38T8dcFvhGzEohp9tsd41ANhXDnQ" +ASSET_HUB_WOCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WOCOCO="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" +GLOBAL_CONSENSUS_WOCOCO_SOVEREIGN_ACCOUNT="5EWw2NzfPr2DCahourp33cya6bGWEJViTnJN6Z2ruFevpJML" +GLOBAL_CONSENSUS_WOCOCO_ASSET_HUB_WOCOCO_1000_SOVEREIGN_ACCOUNT="5EJX8L4dwGyYnCsjZ91LfWAsm3rCN8vY2AYvT4mauMEjsrQz" +ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" + +# Expected sovereign accounts for rewards on BridgeHubs. +# +# Generated by: +#[test] +#fn generate_sovereign_accounts_for_rewards() { +# use sp_core::crypto::Ss58Codec; +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 1]), +# *b"bhwo", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 1]), +# *b"bhwo", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 1]), +# *b"bhro", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 1]), +# *b"bhro", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +#} +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_ThisChain="5EHnXaT5BhiS8YRPMeHi97YHofTtNx4pLNb8wR8TwjVq1gzU" +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_BridgedChain="5EHnXaT5BhiS8YRPMeHyt95svA95qWAh53XeVMpJQZNZHAzj" +ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_ThisChain="5EHnXaT5BhiS8YRNuCukWXTQdAqARjjXmpjehjx1YZNE5keZ" +ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_BridgedChain="5EHnXaT5BhiS8YRNuCv2FYzzjfWMtHqQWVgAFgdr1PExMN94" + +LANE_ID="00000001" function ensure_binaries() { if [[ ! -f ~/local_bridge_testing/bin/polkadot ]]; then @@ -87,8 +172,8 @@ function ensure_polkadot_js_api() { echo "" echo "" echo "-------------------" - echo "Installing (nodejs) sub module: ./scripts/generate_hex_encoded_call" - pushd ./scripts/generate_hex_encoded_call + echo "Installing (nodejs) sub module: $(dirname "$0")/generate_hex_encoded_call" + pushd $(dirname "$0")/generate_hex_encoded_call npm install popd fi @@ -103,7 +188,7 @@ function generate_hex_encoded_call_data() { shift echo "Input params: $@" - node ./scripts/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" + node $(dirname "$0")/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" local retVal=$? if [ $type != "check" ]; then @@ -129,7 +214,7 @@ function transfer_balance() { polkadot-js-api \ --ws "${runtime_para_endpoint}" \ --seed "${seed?}" \ - tx.balances.transfer \ + tx.balances.transferAllowDeath \ "${target_account}" \ "${amount}" } @@ -200,324 +285,148 @@ function send_governance_transact() { "${message}" } -function allow_assets_transfer_send() { - local relay_url=$1 - local relay_chain_seed=$2 - local runtime_para_id=$3 - local runtime_para_endpoint=$4 - local bridge_hub_para_id=$5 - local bridged_para_network=$6 - local bridged_para_para_id=$7 - echo " calling allow_assets_transfer_send:" - echo " relay_url: ${relay_url}" - echo " relay_chain_seed: ${relay_chain_seed}" - echo " runtime_para_id: ${runtime_para_id}" - echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " bridge_hub_para_id: ${bridge_hub_para_id}" - echo " bridged_para_network: ${bridged_para_network}" - echo " bridged_para_para_id: ${bridged_para_para_id}" - echo " params:" - - # 1. generate data for Transact (add_exporter_config) - local bridge_config=$(jq --null-input \ - --arg bridge_hub_para_id "$bridge_hub_para_id" \ - --arg bridged_para_network "$bridged_para_network" \ - --arg bridged_para_para_id "$bridged_para_para_id" \ - ' - { - "bridgeLocation": { - "parents": 1, - "interior": { - "X1": { "Parachain": $bridge_hub_para_id } - } - }, - "allowedTargetLocation": { - "parents": 2, - "interior": { - "X2": [ - { - "GlobalConsensus": $bridged_para_network, - }, - { - "Parachain": $bridged_para_para_id - } - ] - } - }, - "maxTargetLocationFee": { - "id": { - "Concrete": { - "parents": 1, - "interior": "Here" - } - }, - "fun": { - "Fungible": 50000000000 - } - } - } - ' - ) - local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "add-exporter-config" "${runtime_para_endpoint}" "${tmp_output_file}" $bridged_para_network "$bridge_config" - local hex_encoded_data=$(cat $tmp_output_file) - - send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 -} - -function force_create_foreign_asset() { +function open_hrmp_channels() { local relay_url=$1 local relay_chain_seed=$2 - local runtime_para_id=$3 - local runtime_para_endpoint=$4 - local global_consensus=$5 - local asset_owner_account_id=$6 - echo " calling force_create_foreign_asset:" + local sender_para_id=$3 + local recipient_para_id=$4 + local max_capacity=$5 + local max_message_size=$6 + echo " calling open_hrmp_channels:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" - echo " runtime_para_id: ${runtime_para_id}" - echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " global_consensus: ${global_consensus}" - echo " asset_owner_account_id: ${asset_owner_account_id}" + echo " sender_para_id: ${sender_para_id}" + echo " recipient_para_id: ${recipient_para_id}" + echo " max_capacity: ${max_capacity}" + echo " max_message_size: ${max_message_size}" echo " params:" - - # 1. generate data for Transact (ForeignAssets::force_create) - local asset_id=$(jq --null-input \ - --arg global_consensus "$global_consensus" \ - ' - { - "parents": 2, - "interior": { - "X1": { - "GlobalConsensus": $global_consensus, - } - } - } - ' - ) - local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "force-create-asset" "${runtime_para_endpoint}" "${tmp_output_file}" "$asset_id" "$asset_owner_account_id" false "1000" - local hex_encoded_data=$(cat $tmp_output_file) - - send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 + echo "--------------------------------------------------" + polkadot-js-api \ + --ws "${relay_url?}" \ + --seed "${relay_chain_seed?}" \ + --sudo \ + tx.hrmp.forceOpenHrmpChannel \ + ${sender_para_id} \ + ${recipient_para_id} \ + ${max_capacity} \ + ${max_message_size} } -function allow_assets_transfer_receive() { +function set_storage() { local relay_url=$1 local relay_chain_seed=$2 local runtime_para_id=$3 local runtime_para_endpoint=$4 - local bridge_hub_para_id=$5 - local bridged_network=$6 - local bridged_para_id=$7 - echo " calling allow_assets_transfer_receive:" + local items=$5 + echo " calling set_storage:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" echo " runtime_para_id: ${runtime_para_id}" echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " bridge_hub_para_id: ${bridge_hub_para_id}" - echo " bridged_network: ${bridged_network}" - echo " bridged_para_id: ${bridged_para_id}" + echo " items: ${items}" echo " params:" - # 1. generate data for Transact (add_universal_alias) - local location=$(jq --null-input \ - --arg bridge_hub_para_id "$bridge_hub_para_id" \ - '{ "V3": { "parents": 1, "interior": { "X1": { "Parachain": $bridge_hub_para_id } } } }') - - local junction=$(jq --null-input \ - --arg bridged_network "$bridged_network" \ - '{ "GlobalConsensus": $bridged_network } ') - - local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "add-universal-alias" "${runtime_para_endpoint}" "${tmp_output_file}" "$location" "$junction" - local hex_encoded_data=$(cat $tmp_output_file) - - send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 - - # 2. generate data for Transact (add_reserve_location) - local reserve_location=$(jq --null-input \ - --arg bridged_network "$bridged_network" \ - --arg bridged_para_id "$bridged_para_id" \ - '{ "V3": { - "parents": 2, - "interior": { - "X2": [ - { - "GlobalConsensus": $bridged_network, - }, - { - "Parachain": $bridged_para_id - } - ] - } - } }') - + # 1. generate data for Transact (System::set_storage) local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "add-reserve-location" "${runtime_para_endpoint}" "${tmp_output_file}" "$reserve_location" + generate_hex_encoded_call_data "set-storage" "${runtime_para_endpoint}" "${tmp_output_file}" "$items" local hex_encoded_data=$(cat $tmp_output_file) + # 2. trigger governance call send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 } -function remove_assets_transfer_send() { +function force_create_foreign_asset() { local relay_url=$1 local relay_chain_seed=$2 local runtime_para_id=$3 local runtime_para_endpoint=$4 - local bridged_network=$5 - echo " calling remove_assets_transfer_send:" + local asset_multilocation=$5 + local asset_owner_account_id=$6 + local min_balance=$7 + local is_sufficient=$8 + echo " calling force_create_foreign_asset:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" echo " runtime_para_id: ${runtime_para_id}" echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " bridged_network: ${bridged_network}" + echo " asset_multilocation: ${asset_multilocation}" + echo " asset_owner_account_id: ${asset_owner_account_id}" + echo " min_balance: ${min_balance}" + echo " is_sufficient: ${is_sufficient}" echo " params:" + # 1. generate data for Transact (ForeignAssets::force_create) local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "remove-exporter-config" "${runtime_para_endpoint}" "${tmp_output_file}" $bridged_network + generate_hex_encoded_call_data "force-create-asset" "${runtime_para_endpoint}" "${tmp_output_file}" "$asset_multilocation" "$asset_owner_account_id" $is_sufficient $min_balance local hex_encoded_data=$(cat $tmp_output_file) + # 2. trigger governance call send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 } -# TODO: we need to fill sovereign account for bridge-hub, because, small ammouts does not match ExistentialDeposit, so no reserve pass -# SA for BH: MultiLocation { parents: 1, interior: X1(Parachain(1013)) } - 5Eg2fntRRwLinojmk3sh5xscp7F3S6Zzm5oDVtoLTALKiypR on Kusama Asset Hub - -function transfer_asset_via_bridge() { +function limited_reserve_transfer_assets() { local url=$1 local seed=$2 - local target_account=$3 - local target_global_consensus=$4 - echo " calling transfer_asset_via_bridge:" + local destination=$3 + local beneficiary=$4 + local assets=$5 + local fee_asset_item=$6 + local weight_limit=$7 + echo " calling limited_reserve_transfer_assets:" echo " url: ${url}" echo " seed: ${seed}" - echo " target_account: ${target_account}" - echo " target_global_consensus: ${target_global_consensus}" - echo " params:" - - local assets=$(jq --null-input \ - ' - { - "V3": [ - { - "id": { - "Concrete": { - "parents": 1, - "interior": "Here" - } - }, - "fun": { - "Fungible": 100000000 - } - } - ] - } - ' - ) - - local tmp_output_file=$(mktemp) - address_to_account_id_bytes "$target_account" "${tmp_output_file}" - local hex_encoded_data=$(cat $tmp_output_file) - - local destination=$(jq --null-input \ - --arg target_global_consensus "$target_global_consensus" \ - --argjson hex_encoded_data "$hex_encoded_data" \ - ' - { - "V3": { - "parents": 2, - "interior": { - "X3": [ - { - "GlobalConsensus": $target_global_consensus - }, - { - "Parachain": 1000 - }, - { - "AccountId32": { - "id": $hex_encoded_data - } - } - ] - } - } - } - ' - ) - - echo "" - echo " assets:" - echo "${assets}" - echo "" - echo " destination:" - echo "${destination}" + echo " destination: ${destination}" + echo " beneficiary: ${beneficiary}" + echo " assets: ${assets}" + echo " fee_asset_item: ${fee_asset_item}" + echo " weight_limit: ${weight_limit}" echo "" echo "--------------------------------------------------" polkadot-js-api \ --ws "${url?}" \ --seed "${seed?}" \ - tx.bridgeTransfer.transferAssetViaBridge \ + tx.polkadotXcm.limitedReserveTransferAssets \ + "${destination}" \ + "${beneficiary}" \ "${assets}" \ - "${destination}" + "${fee_asset_item}" \ + "${weight_limit}" } -function ping_via_bridge() { - local url=$1 +function claim_rewards() { + local runtime_para_endpoint=$1 local seed=$2 - local target_account=$3 - local target_global_consensus=$4 - echo " calling ping_via_bridge:" - echo " url: ${url}" + local lane_id=$3 + local bridged_chain_id=$4 + local owner=$5 + echo " calling claim_rewards:" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" echo " seed: ${seed}" - echo " target_account: ${target_account}" - echo " target_global_consensus: ${target_global_consensus}" - echo " params:" - - local tmp_output_file=$(mktemp) - address_to_account_id_bytes "$target_account" "${tmp_output_file}" - local hex_encoded_data=$(cat $tmp_output_file) - - local destination=$(jq --null-input \ - --arg target_global_consensus "$target_global_consensus" \ - --argjson hex_encoded_data "$hex_encoded_data" \ - ' - { - "V3": { - "parents": 2, - "interior": { - "X3": [ - { - "GlobalConsensus": $target_global_consensus - }, - { - "Parachain": 1000 - }, - { - "AccountId32": { - "id": $hex_encoded_data - } - } - ] - } - } - } - ' - ) - - echo "" - echo " destination:" - echo "${destination}" + echo " lane_id: ${lane_id}" + echo " bridged_chain_id: ${bridged_chain_id}" + echo " owner: ${owner}" echo "" + + local rewards_account_params=$(jq --null-input \ + --arg lane_id "$lane_id" \ + --arg bridged_chain_id "$bridged_chain_id" \ + --arg owner "$owner" \ + '{ + "laneId": $lane_id, + "bridgedChainId": $bridged_chain_id, + "owner": $owner + }') + + echo " rewards_account_params:" + echo "${rewards_account_params}" echo "--------------------------------------------------" polkadot-js-api \ - --ws "${url?}" \ + --ws "${runtime_para_endpoint}" \ --seed "${seed?}" \ - tx.bridgeTransfer.pingViaBridge \ - "${destination}" + tx.bridgeRelayers.claimRewards \ + "${rewards_account_params}" } function init_ro_wo() { @@ -573,7 +482,7 @@ function run_relay() { --rococo-headers-to-bridge-hub-wococo-signer //Bob \ --rococo-parachains-to-bridge-hub-wococo-signer //Bob \ --bridge-hub-wococo-transactions-mortality 4 \ - --lane 00000001 + --lane "${LANE_ID}" } case "$1" in @@ -582,93 +491,175 @@ case "$1" in init_wo_ro run_relay ;; - allow-transfers-local) - # this allows send transfers on asset hub kusama local (by governance-like) - ./$0 "allow-transfer-on-asset-hub-kusama-local" - # this allows receive transfers on asset hub westend local (by governance-like) - ./$0 "allow-transfer-on-asset-hub-westend-local" - ;; - allow-transfer-on-asset-hub-kusama-local) + init-asset-hub-rococo-local) ensure_polkadot_js_api - allow_assets_transfer_send \ + # create foreign assets for native Wococo token (governance call on Rococo) + force_create_foreign_asset \ "ws://127.0.0.1:9942" \ "//Alice" \ 1000 \ "ws://127.0.0.1:9910" \ - 1013 \ - "Wococo" 1000 + "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Wococo" } } }')" \ + "$GLOBAL_CONSENSUS_WOCOCO_SOVEREIGN_ACCOUNT" \ + 10000000000 \ + true + # drip SA which holds reserves + transfer_balance \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$GLOBAL_CONSENSUS_WOCOCO_ASSET_HUB_WOCOCO_1000_SOVEREIGN_ACCOUNT" \ + $((1000000000 + 50000000000 * 20)) + # HRMP + open_hrmp_channels \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 1013 4 524288 + open_hrmp_channels \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1013 1000 4 524288 + ;; + init-bridge-hub-rococo-local) + ensure_polkadot_js_api + # SA of sibling asset hub pays for the execution + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO" \ + $((1000000000 + 50000000000 * 20)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_ThisChain" \ + $((1000000000 + 2000000000000)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhwo_BridgedChain" \ + $((1000000000 + 2000000000000)) ;; - allow-transfer-on-asset-hub-westend-local) + init-asset-hub-wococo-local) ensure_polkadot_js_api - allow_assets_transfer_receive \ + # set Wococo flavor - set_storage with: + # - `key` is `HexDisplay::from(&asset_hub_rococo_runtime::xcm_config::Flavor::key())` + # - `value` is `HexDisplay::from(&asset_hub_rococo_runtime::RuntimeFlavor::Wococo.encode())` + set_storage \ "ws://127.0.0.1:9945" \ "//Alice" \ 1000 \ "ws://127.0.0.1:9010" \ - 1014 \ - "Rococo" \ - 1000 - transfer_balance \ - "ws://127.0.0.1:9010" \ - "//Alice" \ - "$ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000 + 50000000000 * 20)) # ExistentialDeposit + maxTargetLocationFee * 20 - # create foreign assets for native Kusama token (yes, Kusama, because we are using Kusama Asset Hub runtime on rococo) + "$(jq --null-input '[["0x48297505634037ef48c848c99c0b1f1b", "0x01"]]')" + # create foreign assets for native Rococo token (governance call on Wococo) force_create_foreign_asset \ "ws://127.0.0.1:9945" \ "//Alice" \ 1000 \ "ws://127.0.0.1:9010" \ - "Kusama" \ - "$ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" - ;; - remove-assets-transfer-from-asset-hub-kusama-local) - ensure_polkadot_js_api - remove_assets_transfer_send \ - "ws://127.0.0.1:9942" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } }')" \ + "$GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT" \ + 10000000000 \ + true + # drip SA which holds reserves + transfer_balance \ + "ws://127.0.0.1:9010" \ "//Alice" \ - 1000 \ - "ws://127.0.0.1:9910" \ - "Wococo" + "$GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ + $((1000000000 + 50000000000 * 20)) + # HRMP + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 1014 4 524288 + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1014 1000 4 524288 ;; - transfer-asset-from-asset-hub-kusama-local) - ensure_polkadot_js_api - transfer_asset_via_bridge \ - "ws://127.0.0.1:9910" \ - "$ASSET_HUB_KUSAMA_ACCOUNT_SEED_FOR_LOCAL" \ - "$ASSET_HUB_WOCOCO_ACCOUNT_SEED_FOR_LOCAL" \ - "Wococo" + init-bridge-hub-wococo-local) + # set Wococo flavor - set_storage with: + # - `key` is `HexDisplay::from(&bridge_hub_rococo_runtime::xcm_config::Flavor::key())` + # - `value` is `HexDisplay::from(&bridge_hub_rococo_runtime::RuntimeFlavor::Wococo.encode())` + set_storage \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1014 \ + "ws://127.0.0.1:8945" \ + "$(jq --null-input '[["0x48297505634037ef48c848c99c0b1f1b", "0x01"]]')" + # SA of sibling asset hub pays for the execution + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ASSET_HUB_WOCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WOCOCO" \ + $((1000000000 + 50000000000 * 20)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_ThisChain" \ + $((1000000000 + 2000000000000)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ON_BRIDGE_HUB_WOCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhro_BridgedChain" \ + $((1000000000 + 2000000000000)) ;; - ping-via-bridge-from-asset-hub-kusama-local) + reserve-transfer-assets-from-asset-hub-rococo-local) ensure_polkadot_js_api - ping_via_bridge \ + # send ROCs to Alice account on AHW + limited_reserve_transfer_assets \ "ws://127.0.0.1:9910" \ - "$ASSET_HUB_KUSAMA_ACCOUNT_SEED_FOR_LOCAL" \ - "$ASSET_HUB_WOCOCO_ACCOUNT_SEED_FOR_LOCAL" \ - "Wococo" + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Wococo" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": 200000000000 } } ] }')" \ + 0 \ + "Unlimited" ;; - transfer-asset-from-asset-hub-rococo) + reserve-transfer-assets-from-asset-hub-wococo-local) ensure_polkadot_js_api - transfer_asset_via_bridge \ - "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "$ASSET_HUB2_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ - "$ASSET_HUB_WOCOCO_ACCOUNT_ADDRESS_FOR_ROCOCO" \ - "Wococo" + # send WOCs to Alice account on AHR + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": 150000000000 } } ] }')" \ + 0 \ + "Unlimited" ;; - ping-via-bridge-from-asset-hub-rococo) + claim-rewards-bridge-hub-rococo-local) ensure_polkadot_js_api - ping_via_bridge \ - "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "${ASSET_HUB2_ROCOCO_1000_SOVEREIGN_ACCOUNT}" \ - "$ASSET_HUB_WOCOCO_ACCOUNT_ADDRESS_FOR_ROCOCO" \ - "Wococo" + # bhwo -> [62, 68, 77, 6f] -> 0x6268776f + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268776f" \ + "ThisChain" + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268776f" \ + "BridgedChain" ;; - drip) - transfer_balance \ - "ws://127.0.0.1:9010" \ - "//Alice" \ - "$ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000 + 50000000000 * 20)) + claim-rewards-bridge-hub-wococo-local) + # bhro -> [62, 68, 72, 6f] -> 0x6268726f + claim_rewards \ + "ws://127.0.0.1:8945" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268726f" \ + "ThisChain" + claim_rewards \ + "ws://127.0.0.1:8945" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268726f" \ + "BridgedChain" ;; stop) pkill -f polkadot @@ -681,15 +672,14 @@ case "$1" in echo "A command is require. Supported commands for: Local (zombienet) run: - run-relay - - allow-transfers-local - - allow-transfer-on-asset-hub-kusama-local - - allow-transfer-on-asset-hub-westend-local - - remove-assets-transfer-from-asset-hub-kusama-local - - transfer-asset-from-asset-hub-kusama-local - - ping-via-bridge-from-asset-hub-kusama-local - Live Rococo/Wococo run: - - transfer-asset-from-asset-hub-rococo - - ping-via-bridge-from-asset-hub-rococo"; + - init-asset-hub-rococo-local + - init-bridge-hub-rococo-local + - init-asset-hub-wococo-local + - init-bridge-hub-wococo-local + - reserve-transfer-assets-from-asset-hub-rococo-local + - reserve-transfer-assets-from-asset-hub-wococo-local + - claim-rewards-bridge-hub-rococo-local + - claim-rewards-bridge-hub-wococo-local"; exit 1 ;; esac diff --git a/cumulus/scripts/ci/changelog/README.md b/cumulus/scripts/ci/changelog/README.md deleted file mode 100644 index 5c8ee9c9b914e634e07fb6030e89a7188f1f3aaf..0000000000000000000000000000000000000000 --- a/cumulus/scripts/ci/changelog/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Changelog - -Currently, the changelog is built locally. It will be moved to CI once labels stabilize. - -For now, a bit of preparation is required before you can run the script: -- fetch the srtool digests -- store them under the `digests` folder as `-srtool-digest.json` -- ensure the `.env` file is up to date with correct information - -The content of the release notes is generated from the template files under the `scripts/ci/changelog/templates` folder. -For readability and maintenance, the template is split into several small snippets. - -Run: -``` -./bin/changelog [=HEAD] -``` - -For instance: -``` -./bin/changelog parachains-v7.0.0-rc8 -``` - -A file called `release-notes.md` will be generated and can be used for the release. - -## ENV - -You may use the following ENV for testing: - -``` -RUSTC_STABLE="rustc 1.56.1 (59eed8a2a 2021-11-01)" -RUSTC_NIGHTLY="rustc 1.57.0-nightly (51e514c0f 2021-09-12)" -PRE_RELEASE=true -HIDE_SRTOOL_ROCOCO=true -HIDE_SRTOOL_SHELL=true -REF1=statemine-v5.0.0 -REF2=HEAD -DEBUG=1 -NO_CACHE=1 -``` - -By default, the template will include all the information, including the runtime data. For clients releases, we don't -need those and they can be skipped by setting the following env: -``` -RELEASE_TYPE=client -``` - -## Considered labels - -The following list will likely evolve over time and it will be hard to keep it in sync. In any case, if you want to find -all the labels that are used, search for `meta` in the templates. Currently, the considered labels are: - -- Priority: C labels -- Audit: D labels -- E4 => new host function -- B0 => silent, not showing up -- B1-releasenotes (misc unless other labels) -- B5-client (client changes) -- B7-runtimenoteworthy (runtime changes) -- T6-XCM - -Note that labels with the same letter are mutually exclusive. A PR should not have both `B0` and `B5`, or both `C1` and -`C9`. In case of conflicts, the template will decide which label will be considered. - -## Dev and debugging - -### Hot Reload - -The following command allows **Hot Reload**: -``` -fswatch templates -e ".*\.md$" | xargs -n1 -I{} ./bin/changelog statemine-v5.0.0 -``` -### Caching - -By default, if the changelog data from Github is already present, the calls to the Github API will be skipped and the -local version of the data will be used. This is much faster. If you know that some labels have changed in Github, you -probably want to refresh the data. You can then either delete manually the `cumulus.json` file or `export NO_CACHE=1` to -force refreshing the data. diff --git a/cumulus/scripts/generate_hex_encoded_call/index.js b/cumulus/scripts/generate_hex_encoded_call/index.js index 25e094df9053a8e81ad8c9a4147038f42f2de2ba..09f0e6aaf619a44642bfa4f065f3bf69f0bb7a33 100644 --- a/cumulus/scripts/generate_hex_encoded_call/index.js +++ b/cumulus/scripts/generate_hex_encoded_call/index.js @@ -106,6 +106,20 @@ function forceCreateAsset(endpoint, outputFile, assetId, assetOwnerAccountId, is }); } +function setStorage(endpoint, outputFile, items) { + console.log(`Generating setStorage from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, items: ${items}`); + connect(endpoint) + .then((api) => { + const call = api.tx.system.setStorage(JSON.parse(items)); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + if (!process.argv[2] || !process.argv[3]) { console.log("usage: node ./script/generate_hex_encoded_call "); exit(1); @@ -140,6 +154,9 @@ switch (type) { case 'force-create-asset': forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); break; + case 'set-storage': + setStorage(rpcEnpoint, output, inputArgs[0]); + break; case 'check': console.log(`Checking nodejs installation, if you see this everything is ready!`); break; diff --git a/cumulus/test/relay-sproof-builder/src/lib.rs b/cumulus/test/relay-sproof-builder/src/lib.rs index 69a82d05d81693247f0b47adcbb98dfeaebcb068..fbd2692a36b466827376e0917adfc93aac10a739 100644 --- a/cumulus/test/relay-sproof-builder/src/lib.rs +++ b/cumulus/test/relay-sproof-builder/src/lib.rs @@ -63,7 +63,7 @@ impl Default for RelayStateSproofBuilder { hrmp_max_message_num_per_candidate: 5, validation_upgrade_cooldown: 6, validation_upgrade_delay: 6, - async_backing_params: relay_chain::vstaging::AsyncBackingParams { + async_backing_params: relay_chain::AsyncBackingParams { allowed_ancestry_len: 0, max_candidate_depth: 0, }, diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index b8469cb66a7475f17a8d06f36d198d78f515f8ff..c996a01a12ed13003939f38b106a0a2f56c57716 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -11,7 +11,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } diff --git a/cumulus/test/service/benches/transaction_throughput.rs b/cumulus/test/service/benches/transaction_throughput.rs index 83981a91d46f0803d3a77cfb71e36ec3ee85dee3..81ecc84db7bf211d5d684f7c24bfd9a4abf10c6e 100644 --- a/cumulus/test/service/benches/transaction_throughput.rs +++ b/cumulus/test/service/benches/transaction_throughput.rs @@ -21,7 +21,7 @@ use cumulus_test_runtime::{AccountId, BalancesCall, ExistentialDeposit, SudoCall use futures::{future, StreamExt}; use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; use sp_core::{crypto::Pair, sr25519}; -use sp_runtime::{generic::BlockId, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use cumulus_primitives_core::ParaId; use cumulus_test_service::{ @@ -117,7 +117,7 @@ async fn submit_tx_and_wait_for_inclusion( let best_hash = client.chain_info().best_hash; let mut watch = tx_pool - .submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone()) + .submit_and_watch(best_hash, TransactionSource::External, tx.clone()) .await .expect("Submits tx to pool") .fuse(); diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index f295192c3b10aaa28d359bf2e91085e2f270b04a..9235a0c45c58638f3966c28b031c39382d157396 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -278,7 +278,7 @@ impl SubstrateCli for TestCollatorCli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -322,7 +322,7 @@ impl SubstrateCli for RelayChainCli { } fn support_url() -> String { - "https://github.com/paritytech/cumulus/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 72007ba98f7fa1b8962ecbbd6c631449a7c18576..c77d350bdfef6b81532496d1d3a8878b66c3aae5 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -4,7 +4,6 @@ description = "Test kit to emulate XCM program execution." version = "0.1.0" authors.workspace = true edition.workspace = true -publish = false [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 9fda0632bae40639651f9d1a776cf952affcee5b..caf73ae1e41ca52b5e6645060c9ab72e26b3d38b 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -26,7 +26,7 @@ pub use std::{ // Substrate pub use frame_support::{ assert_ok, - sp_runtime::{traits::Header as HeaderT, AccountId32, DispatchResult}, + sp_runtime::{traits::Header as HeaderT, DispatchResult}, traits::{ EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues, }, @@ -61,6 +61,8 @@ pub use xcm::v3::prelude::{ }; pub use xcm_executor::traits::ConvertLocation; +pub type AccountIdOf = ::AccountId; + thread_local! { /// Downward messages, each message is: `(to_para_id, [(relay_block_number, msg)])` #[allow(clippy::type_complexity)] @@ -90,8 +92,8 @@ pub trait CheckAssertion where Origin: Chain + Clone, Destination: Chain + Clone, - Origin::RuntimeOrigin: OriginTrait + Clone, - Destination::RuntimeOrigin: OriginTrait + Clone, + Origin::RuntimeOrigin: OriginTrait> + Clone, + Destination::RuntimeOrigin: OriginTrait> + Clone, Hops: Clone, Args: Clone, { @@ -103,8 +105,8 @@ impl CheckAssertion + Clone, - Destination::RuntimeOrigin: OriginTrait + Clone, + Origin::RuntimeOrigin: OriginTrait> + Clone, + Destination::RuntimeOrigin: OriginTrait> + Clone, Hops: Clone, Args: Clone, { @@ -219,24 +221,24 @@ pub trait Chain: TestExt + NetworkComponent { helpers::get_account_id_from_seed::(seed) } - fn account_data_of(account: AccountId) -> AccountData; + fn account_data_of(account: AccountIdOf) -> AccountData; fn events() -> Vec<::RuntimeEvent>; } pub trait RelayChain: Chain { type MessageProcessor: ProcessMessage; - type SovereignAccountOf: ConvertLocation; + type SovereignAccountOf: ConvertLocation>; fn child_location_of(id: ParaId) -> MultiLocation { (Ancestor(0), ParachainJunction(id.into())).into() } - fn sovereign_account_id_of(location: MultiLocation) -> AccountId { + fn sovereign_account_id_of(location: MultiLocation) -> AccountIdOf { Self::SovereignAccountOf::convert_location(&location).unwrap() } - fn sovereign_account_id_of_child_para(id: ParaId) -> AccountId { + fn sovereign_account_id_of_child_para(id: ParaId) -> AccountIdOf { Self::sovereign_account_id_of(Self::child_location_of(id)) } } @@ -244,7 +246,7 @@ pub trait RelayChain: Chain { pub trait Parachain: Chain { type XcmpMessageHandler: XcmpMessageHandler; type DmpMessageHandler: DmpMessageHandler; - type LocationToAccountId: ConvertLocation; + type LocationToAccountId: ConvertLocation>; type ParachainInfo: Get; type ParachainSystem; @@ -268,7 +270,7 @@ pub trait Parachain: Chain { (Parent, X1(ParachainJunction(para_id.into()))).into() } - fn sovereign_account_id_of(location: MultiLocation) -> AccountId { + fn sovereign_account_id_of(location: MultiLocation) -> AccountIdOf { Self::LocationToAccountId::convert_location(&location).unwrap() } } @@ -365,7 +367,7 @@ macro_rules! decl_test_relay_chains { type RuntimeEvent = $runtime::RuntimeEvent; type System = $crate::SystemPallet::; - fn account_data_of(account: $crate::AccountId) -> $crate::AccountData<$crate::Balance> { + fn account_data_of(account: $crate::AccountIdOf) -> $crate::AccountData<$crate::Balance> { ::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) } @@ -590,7 +592,7 @@ macro_rules! decl_test_parachains { type RuntimeEvent = $runtime::RuntimeEvent; type System = $crate::SystemPallet::; - fn account_data_of(account: $crate::AccountId) -> $crate::AccountData<$crate::Balance> { + fn account_data_of(account: $crate::AccountIdOf) -> $crate::AccountData<$crate::Balance> { ::ext_wrapper(|| $crate::SystemPallet::::account(account).data.into()) } @@ -1159,9 +1161,10 @@ macro_rules! __impl_check_assertion { where Origin: $crate::Chain + Clone, Destination: $crate::Chain + Clone, - Origin::RuntimeOrigin: $crate::OriginTrait + Clone, + Origin::RuntimeOrigin: + $crate::OriginTrait> + Clone, Destination::RuntimeOrigin: - $crate::OriginTrait + Clone, + $crate::OriginTrait> + Clone, Hops: Clone, Args: Clone, { @@ -1308,8 +1311,8 @@ where /// Struct that keeps account's id and balance #[derive(Clone)] -pub struct TestAccount { - pub account_id: AccountId, +pub struct TestAccount { + pub account_id: AccountIdOf, pub balance: Balance, } @@ -1326,9 +1329,9 @@ pub struct TestArgs { } /// Auxiliar struct to help creating a new `Test` instance -pub struct TestContext { - pub sender: AccountId, - pub receiver: AccountId, +pub struct TestContext { + pub sender: AccountIdOf, + pub receiver: AccountIdOf, pub args: T, } @@ -1345,12 +1348,12 @@ pub struct Test where Origin: Chain + Clone, Destination: Chain + Clone, - Origin::RuntimeOrigin: OriginTrait + Clone, - Destination::RuntimeOrigin: OriginTrait + Clone, + Origin::RuntimeOrigin: OriginTrait> + Clone, + Destination::RuntimeOrigin: OriginTrait> + Clone, Hops: Clone, { - pub sender: TestAccount, - pub receiver: TestAccount, + pub sender: TestAccount, + pub receiver: TestAccount, pub signed_origin: Origin::RuntimeOrigin, pub root_origin: Origin::RuntimeOrigin, pub hops_assertion: HashMap, @@ -1365,12 +1368,12 @@ where Args: Clone, Origin: Chain + Clone + CheckAssertion, Destination: Chain + Clone + CheckAssertion, - Origin::RuntimeOrigin: OriginTrait + Clone, - Destination::RuntimeOrigin: OriginTrait + Clone, + Origin::RuntimeOrigin: OriginTrait> + Clone, + Destination::RuntimeOrigin: OriginTrait> + Clone, Hops: Clone + CheckAssertion, { /// Creates a new `Test` instance - pub fn new(test_args: TestContext) -> Self { + pub fn new(test_args: TestContext) -> Self { Test { sender: TestAccount { account_id: test_args.sender.clone(), diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml index 80b398ac7240058fe12f460e069d35455a106be9..d83cf13607daebdb9603924ea7b659cbbb0b67dc 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml @@ -7,25 +7,25 @@ default_args = [ "-lparachain=debug,xcm=trace" ] chain = "rococo-local" [[relaychain.nodes]] - name = "alice-validator" + name = "alice-rococo-validator" validator = true rpc_port = 9932 ws_port = 9942 - extra_args = ["--no-mdns --bootnodes {{'bob-validator'|zombie('multiAddress')}}"] + balance = 2000000000000 [[relaychain.nodes]] - name = "bob-validator" + name = "bob-rococo-validator" validator = true rpc_port = 9933 ws_port = 9943 - extra_args = ["--no-mdns --bootnodes {{'alice-validator'|zombie('multiAddress')}}"] + balance = 2000000000000 [[relaychain.nodes]] - name = "charlie-validator" + name = "charlie-rococo-validator" validator = true rpc_port = 9934 ws_port = 9944 - extra_args = ["--no-mdns --bootnodes {{'alice-validator'|zombie('multiAddress')}}"] + balance = 2000000000000 [[parachains]] id = 1013 @@ -34,71 +34,61 @@ cumulus_based = true # run alice as parachain collator [[parachains.collators]] - name = "alice-collator" + name = "bridge-hub-rococo-collator1" validator = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" 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", - ] - extra_args = [ - "--force-authoring", "--no-mdns", "--bootnodes {{'bob-collator'|zombie('multiAddress')}}", - "-- --port 41333 --rpc-port 48933 --ws-port 48943 --no-mdns", "--bootnodes {{'alice-validator'|zombie('multiAddress')}}" + "--force-authoring", + "--", "--port 41333", "--rpc-port 48933", "--ws-port 48943" ] # run bob as parachain collator [[parachains.collators]] - name = "bob-collator" + name = "bridge-hub-rococo-collator2" validator = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" 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", - ] - extra_args = [ - "--force-authoring", "--no-mdns", "--bootnodes {{'alice-collator'|zombie('multiAddress')}}", - "-- --port 41334 --rpc-port 48934 --ws-port 48944 --no-mdns", "--bootnodes {{'bob-validator'|zombie('multiAddress')}}" + "--force-authoring", + "--", "--port 41334", "--rpc-port 48934", "--ws-port 48944" ] [[parachains]] id = 1000 -chain = "asset-hub-kusama-local" +chain = "asset-hub-rococo-local" cumulus_based = true [[parachains.collators]] - name = "rockmine-collator1" + name = "asset-hub-rococo-collator1" rpc_port = 9911 ws_port = 9910 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - ] - extra_args = [ - "--no-mdns", "--bootnodes {{'rockmine-collator2'|zombie('multiAddress')}}", - "-- --port 51333 --rpc-port 58933 --ws-port 58943 --no-mdns", "--bootnodes {{'alice-validator'|zombie('multiAddress')}}" + "--", "--port 51333", "--rpc-port 58933", "--ws-port 58943" ] [[parachains.collators]] - name = "rockmine-collator2" + name = "asset-hub-rococo-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", + "--", "--port 51433", "--rpc-port 58833", "--ws-port 58843" ] - extra_args = [ - "--no-mdns", "--bootnodes {{'rockmine-collator1'|zombie('multiAddress')}}", - "-- --port 51433 --rpc-port 58833 --ws-port 58843 --no-mdns", "--bootnodes {{'alice-validator'|zombie('multiAddress')}}" - ] - -[[hrmp_channels]] -sender = 1000 -recipient = 1013 -max_capacity = 4 -max_message_size = 524288 -[[hrmp_channels]] -sender = 1013 -recipient = 1000 -max_capacity = 4 -max_message_size = 524288 +#[[hrmp_channels]] +#sender = 1000 +#recipient = 1013 +#max_capacity = 4 +#max_message_size = 524288 +# +#[[hrmp_channels]] +#sender = 1013 +#recipient = 1000 +#max_capacity = 4 +#max_message_size = 524288 diff --git a/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml b/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml index 9727b4a087fda438e15b3fd8e4dbfc4fdb0c6ddb..76b368cfa285a7b9190bfb0c38dee03025151f8d 100644 --- a/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml +++ b/cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml @@ -7,25 +7,25 @@ default_args = [ "-lparachain=debug,xcm=trace" ] chain = "wococo-local" [[relaychain.nodes]] - name = "alice-validator-wo" + name = "alice-wococo-validator" validator = true rpc_port = 9935 ws_port = 9945 - extra_args = ["--no-mdns --bootnodes {{'bob-validator-wo'|zombie('multiAddress')}}"] + balance = 2000000000000 [[relaychain.nodes]] - name = "bob-validator-wo" + name = "bob-wococo-validator" validator = true rpc_port = 9936 ws_port = 9946 - extra_args = ["--no-mdns --bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}"] + balance = 2000000000000 [[relaychain.nodes]] - name = "charlie-validator-wo" + name = "charlie-wococo-validator" validator = true rpc_port = 9937 ws_port = 9947 - extra_args = ["--no-mdns --bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}"] + balance = 2000000000000 [[parachains]] id = 1014 @@ -34,71 +34,61 @@ cumulus_based = true # run alice as parachain collator [[parachains.collators]] - name = "alice-collator-wo" + name = "bridge-hub-wococo-collator1" validator = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" 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", - ] - extra_args = [ - "--force-authoring", "--no-mdns", "--bootnodes {{'bob-collator-wo'|zombie('multiAddress')}}", - "-- --port 41335 --rpc-port 48935 --ws-port 48945 --no-mdns", "--bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}" + "--force-authoring", + "--", "--port 41335", "--rpc-port 48935", "--ws-port 48945" ] # run bob as parachain collator [[parachains.collators]] - name = "bob-collator-wo" + name = "bridge-hub-wococo-collator2" validator = true command = "{{POLKADOT_PARACHAIN_BINARY_PATH}}" 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", - ] - extra_args = [ - "--force-authoring", "--no-mdns", "--bootnodes {{'alice-collator-wo'|zombie('multiAddress')}}", - "-- --port 41336 --rpc-port 48936 --ws-port 48946 --no-mdns", "--bootnodes {{'bob-validator-wo'|zombie('multiAddress')}}" + "--force-authoring", + "--", "--port 41336", "--rpc-port 48936", "--ws-port 48946" ] [[parachains]] id = 1000 -chain = "asset-hub-westend-local" +chain = "asset-hub-wococo-local" cumulus_based = true [[parachains.collators]] - name = "wockmint-collator1" + name = "asset-hub-wococo-collator1" rpc_port = 9011 ws_port = 9010 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", - ] - extra_args = [ - "--no-mdns", "--bootnodes {{'wockmint-collator2'|zombie('multiAddress')}}", - "-- --port 31333 --rpc-port 38933 --ws-port 38943 --no-mdns", "--bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}" + "--", "--port 31333", "--rpc-port 38933", "--ws-port 38943" ] [[parachains.collators]] - name = "wockmint-collator2" + name = "asset-hub-wococo-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO}}" args = [ "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace", + "--", "--port 31433", "--rpc-port 38833", "--ws-port 38843" ] - extra_args = [ - "--no-mdns", "--bootnodes {{'wockmint-collator1'|zombie('multiAddress')}}", - "-- --port 31433 --rpc-port 38833 --ws-port 38843 --no-mdns", "--bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}" - ] - -[[hrmp_channels]] -sender = 1000 -recipient = 1014 -max_capacity = 4 -max_message_size = 524288 -[[hrmp_channels]] -sender = 1014 -recipient = 1000 -max_capacity = 4 -max_message_size = 524288 +#[[hrmp_channels]] +#sender = 1000 +#recipient = 1014 +#max_capacity = 4 +#max_message_size = 524288 +# +#[[hrmp_channels]] +#sender = 1014 +#recipient = 1000 +#max_capacity = 4 +#max_message_size = 524288 diff --git a/docker/dockerfiles/collator_injected.Dockerfile b/docker/dockerfiles/collator_injected.Dockerfile index 0c9ea1e0ca833fd51c0553672ad85e2009ab7d3c..999203b93f0ac593aea3b8b9a5c260890f569097 100644 --- a/docker/dockerfiles/collator_injected.Dockerfile +++ b/docker/dockerfiles/collator_injected.Dockerfile @@ -10,10 +10,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Injected adder-collator Docker image" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/dockerfiles/collator_injected.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/collator_injected.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docker/dockerfiles/docker-compose.yml b/docker/dockerfiles/docker-compose.yml index 8dc8540353fe0df08c55c98e660b3979c56bfeeb..0e34e54562aee333130b1d6b0210f49391a72ebd 100644 --- a/docker/dockerfiles/docker-compose.yml +++ b/docker/dockerfiles/docker-compose.yml @@ -61,7 +61,7 @@ services: genesis_state: build: context: . - dockerfile: ./docker/dockerfiles/test-parachain-collator.dockerfile + dockerfile: ./docker/dockerfiles/test-parachain-collator.Dockerfile image: "ctpc:latest" volumes: - "genesis-state:/data" @@ -73,7 +73,7 @@ services: collator: build: context: . - dockerfile: ./docker/dockerfiles/test-parachain-collator.dockerfile + dockerfile: ./docker/dockerfiles/test-parachain-collator.Dockerfile target: collator image: "ctpc:collator" volumes: @@ -90,7 +90,7 @@ services: runtime: build: context: . - dockerfile: ./docker/dockerfiles/test-parachain-collator.dockerfile + dockerfile: ./docker/dockerfiles/test-parachain-collator.Dockerfile target: runtime image: "ctpc:runtime" volumes: @@ -100,7 +100,7 @@ services: registrar: build: context: . - dockerfile: ./docker/dockerfiles/parachain-registrar.dockerfile + dockerfile: ./docker/dockerfiles/parachain-registrar.Dockerfile image: para-reg:latest volumes: - "genesis-state:/genesis" diff --git a/docker/dockerfiles/malus_injected.Dockerfile b/docker/dockerfiles/malus_injected.Dockerfile index 762a2e442c82883316a763962f4f5a39952a5c57..dd8702ea101b5b53e568a6933a08397ce81ce5aa 100644 --- a/docker/dockerfiles/malus_injected.Dockerfile +++ b/docker/dockerfiles/malus_injected.Dockerfile @@ -9,10 +9,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Malus - the nemesis of polkadot" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/malus.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/malus_injected.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docker/dockerfiles/parachain-registrar.dockerfile b/docker/dockerfiles/parachain-registrar.Dockerfile similarity index 93% rename from docker/dockerfiles/parachain-registrar.dockerfile rename to docker/dockerfiles/parachain-registrar.Dockerfile index 00908395101f98652ab961f9054717794dd383af..594bff44906dec6fc871ab9318c34b290f5a15b8 100644 --- a/docker/dockerfiles/parachain-registrar.dockerfile +++ b/docker/dockerfiles/parachain-registrar.Dockerfile @@ -9,7 +9,7 @@ CMD [ "--version" ] # To use the pjs build stage to access the blockchain from the host machine: # -# docker build -f docker/dockerfiles/parachain-registrar.dockerfile --target pjs -t parachain-registrar:pjs . +# docker build -f docker/dockerfiles/parachain-registrar.Dockerfile --target pjs -t parachain-registrar:pjs . # alias pjs='docker run --rm --net cumulus_testing_net parachain-registrar:pjs --ws ws://172.28.1.1:9944' # # Then, as long as the chain is running, you can use the polkadot-js-api CLI like: diff --git a/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile b/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile index 75cc2b9e629de4b9d8bf99e2a7bc866d3160a95a..f249612e776419edf78304351656e6b234f5b9db 100644 --- a/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile @@ -9,10 +9,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Cumulus, the Polkadot collator." \ - io.parity.image.source="https://github.com/paritytech/cumulus/blob/${VCS_REF}/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/cumulus/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/tree/master/cumulus" # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile b/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile similarity index 85% rename from docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile rename to docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile index 4d110d6af47286891c726485efd9492e2554a023..b56b8c1a1ef8fc50548aa2c21431cf865e62c4c4 100644 --- a/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile +++ b/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile @@ -1,4 +1,4 @@ -# This file is sourced from https://github.com/paritytech/polkadot/blob/master/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile +# This file is sourced from https://github.com/paritytech/polkadot-sdk/blob/master/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile # This is the build stage for polkadot-parachain. Here we create the binary in a temporary image. FROM docker.io/paritytech/ci-linux:production as builder @@ -14,8 +14,8 @@ LABEL io.parity.image.type="builder" \ io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.description="Multistage Docker image for polkadot-parachain" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile" \ - io.parity.image.documentation="https://github.com/paritytech/cumulus" + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/tree/master/cumulus" COPY --from=builder /cumulus/target/release/polkadot-parachain /usr/local/bin diff --git a/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile b/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile index f8dc374a14aab5f196952f9c33e66fa980ed50f0..7e460bb22e892a30d360a69815e43b8c197d0fda 100644 --- a/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile @@ -14,8 +14,8 @@ LABEL description="Multistage Docker image for Polkadot: a platform for web3" \ io.parity.image.authors="chevdor@gmail.com, devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.description="Polkadot: a platform for web3" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" COPY --from=builder /polkadot/target/release/polkadot /usr/local/bin diff --git a/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile index 7ad092476fec6cafbbfc3d7489a79955f2e80b99..529c82e6af69db7fdbf82bf1d0292904f362e731 100644 --- a/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile @@ -11,10 +11,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="parity/polkadot" \ io.parity.image.description="Polkadot: a platform for web3. This is the official Parity image with an injected binary." \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" USER root diff --git a/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile index 80ce82589873dbbb75504a8a424341fe8c9d9ba2..55d23f3a80529db9e6ba62977ec6b7e679ff7cbf 100644 --- a/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile @@ -9,10 +9,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Polkadot: a platform for web3" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk" # show backtraces ENV RUST_BACKTRACE 1 @@ -28,13 +28,16 @@ RUN apt-get update && \ find /var/lib/apt/lists/ -type f -not -name lock -delete; \ # add user and link ~/.local/share/polkadot to /data useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ - mkdir -p /data /polkadot/.local/share && \ + mkdir -p /data /polkadot/.local/share /polkdot/runtimes && \ chown -R polkadot:polkadot /data && \ ln -s /data /polkadot/.local/share/polkadot # add polkadot binaries to docker image COPY ./artifacts/polkadot ./artifacts/polkadot-execute-worker ./artifacts/polkadot-prepare-worker /usr/local/bin +# add runtime binaries to docker image +COPY ./artifacts/runtimes /polkadot/runtimes/ + USER polkadot # check if executable works in this container diff --git a/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile index c13f2db982a147c28991edee2d6e9aa2f1307291..2632968f8a2b07dc41639a5795ecbcedb74d1ebf 100644 --- a/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile +++ b/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile @@ -11,10 +11,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="parity/polkadot" \ io.parity.image.description="Polkadot: a platform for web3. This is the official Parity image with an injected binary." \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_injected_release.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docker/dockerfiles/substrate_injected.Dockerfile b/docker/dockerfiles/substrate_injected.Dockerfile index 2d825f5c6bb34c22665db78150650e0504f3ce8d..47a917013a8b530e25255842a02802727cd8e93c 100644 --- a/docker/dockerfiles/substrate_injected.Dockerfile +++ b/docker/dockerfiles/substrate_injected.Dockerfile @@ -9,7 +9,7 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Substrate: The platform for blockchain innovators." \ - io.parity.image.source="https://github.com/paritytech/substrate/blob/${VCS_REF}/scripts/ci/docker/Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/substrate_injected.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://wiki.parity.io/Parity-Substrate" diff --git a/docker/dockerfiles/test-parachain-collator.dockerfile b/docker/dockerfiles/test-parachain-collator.Dockerfile similarity index 96% rename from docker/dockerfiles/test-parachain-collator.dockerfile rename to docker/dockerfiles/test-parachain-collator.Dockerfile index 0d56949152e2cf69538baf89fd3601e5ec73b53c..116520284dd34b1488f218c7c5ba34035260202c 100644 --- a/docker/dockerfiles/test-parachain-collator.dockerfile +++ b/docker/dockerfiles/test-parachain-collator.Dockerfile @@ -1,4 +1,4 @@ -# This file is sourced from https://github.com/paritytech/polkadot/blob/master/docker/dockerfiles/polkadot/polkadot_builder.Dockerfile +# This file is sourced from https://github.com/paritytech/polkadot-sdk/blob/master/docker/dockerfiles/test-parachain-collator.Dockerfile FROM docker.io/paritytech/ci-linux:production as builder WORKDIR /cumulus diff --git a/docker/dockerfiles/test-parachain_injected.Dockerfile b/docker/dockerfiles/test-parachain_injected.Dockerfile index e5d0df7aad673b48135ecb73928c53cf5c1a0c8a..317312a18bf14e37fd726914db9bb227577dc2ec 100644 --- a/docker/dockerfiles/test-parachain_injected.Dockerfile +++ b/docker/dockerfiles/test-parachain_injected.Dockerfile @@ -9,10 +9,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="${IMAGE_NAME}" \ io.parity.image.description="Test parachain for Zombienet" \ - io.parity.image.source="https://github.com/paritytech/cumulus/blob/${VCS_REF}/docker/dockerfiles/test-parachain_injected.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/test-parachain_injected.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/cumulus/" + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/tree/master/cumulus" # show backtraces ENV RUST_BACKTRACE 1 diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index d134188e25dfd30e6725d705fcb7e2cb9226d9ca..1e05755a9b8338c5769a48c5e8f477670eb92e25 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -43,7 +43,7 @@ The set of labels and their description can be found [here](https://paritytech.g 2. Please tag each PR with minimum one `T*` label. The respective `T*` labels should signal the component that was changed, they are also used by downstream users to track changes and to include these changes properly into their own releases. -3. If your’re still working on your PR, please submit as “Draft”. Once a PR is ready for review change +3. If you’re still working on your PR, please submit as “Draft”. Once a PR is ready for review change the status to “Open”, so that the maintainers get to review your PR. Generally PRs should sit for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. 4. If you’re introducing a major change, that might impact the documentation please add the label @@ -143,4 +143,18 @@ UI tests are used for macros to ensure that the output of a macro doesn’t chan These UI tests are sensible to any changes in the macro generated code or to switching the rust stable version. The tests are only run when the `RUN_UI_TESTS` environment variable is set. So, when the CI is for example complaining about failing UI tests and it is expected that they fail these tests need to be executed locally. -To simplify the updating of the UI test ouput there is the `.maintain/update-rust-stable +To simplify the updating of the UI test output there is a script +- `./scripts/update-ui-tests.sh` to update the tests for a current rust version locally +- `./scripts/update-ui-tests.sh 1.70` # to update the tests for a specific rust version locally + +Or if you have opened PR and you're member of `paritytech` - you can use command-bot to run the tests for you in CI: +- `bot update-ui` - will run the tests for the current rust version +- `bot update-ui latest --rust_version=1.70.0` - will run the tests for the specified rust version +- `bot update-ui latest -v CMD_IMAGE=paritytech/ci-unified:bullseye-1.70.0-2023-05-23 --rust_version=1.70.0` - +will run the tests for the specified rust version and specified image + +## Command Bot + +If you're member of **paritytech** org - you can use command-bot to run various of common commands in CI: + +Start with comment in PR: `bot help` to see the list of available commands. diff --git a/docs/DOCUMENTATION_GUIDELINE.md b/docs/DOCUMENTATION_GUIDELINES.md similarity index 98% rename from docs/DOCUMENTATION_GUIDELINE.md rename to docs/DOCUMENTATION_GUIDELINES.md index dbb4298d50fe7fa3435eff53be368fe9b8ba5d61..5d1164e8ca89f8eefea71ad96318b9347ca29c89 100644 --- a/docs/DOCUMENTATION_GUIDELINE.md +++ b/docs/DOCUMENTATION_GUIDELINES.md @@ -210,7 +210,7 @@ The guidelines so far have been general in nature, and are applicable to crates pallets. The following is relevant to how to document parts of a crate that is a pallet. See -[`pallet-fast-unstake`](../frame/fast-unstake/src/lib.rs) as one example of adhering these guidelines. +[`pallet-fast-unstake`](../substrate/frame/fast-unstake/src/lib.rs) as one example of adhering these guidelines. --- @@ -291,7 +291,7 @@ Optionally, in order to demonstrate the relation between the two, you can start ``` //! > Made with *Substrate*, for *Polkadot*. //! -//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) - +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/fast-unstake) - //! [![polkadot]](https://polkadot.network) //! //! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 284ad15afc9e6c5b6ffe5f666d5a5bfa43da550b..c93ac90c7e32e1c6c33d4409920eaa85a1aea814 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -24,10 +24,6 @@ Fixes # (issue number, *if applicable*) Closes # (issue number, *if applicable*) -Polkadot companion: (*if applicable*) - -Cumulus companion: (*if applicable*) - # Checklist - [ ] My PR includes a detailed description as outlined in the "Description" section above @@ -35,8 +31,6 @@ Cumulus companion: (*if applicable*) required) - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) -- [ ] If this PR alters any external APIs or interfaces used by Polkadot, the corresponding Polkadot PR is ready as well - as the corresponding Cumulus PR (optional) You can remove the "Checklist" section once all have been checked. Thank you for your contribution! diff --git a/docs/container.md b/docs/container.md index afd3b27957c259501a85df76f978ba9f3af2db2b..dd44b31bfe96994ed54e3eca8610e7d8778f5261 100644 --- a/docs/container.md +++ b/docs/container.md @@ -22,10 +22,10 @@ The command below allows building a Linux binary without having to even install ```bash docker run --rm -it \ - -w /shellhere/cumulus \ - -v $(pwd):/shellhere/cumulus \ - paritytech/ci-linux:production - cargo build --release --locked --bin polkadot-parachain + -w /polkadot-sdk \ + -v $(pwd):/polkadot-sdk \ + paritytech/ci-linux:production \ + cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain sudo chown -R $(id -u):$(id -g) target/ ``` @@ -37,11 +37,11 @@ If you want to reproduce other steps of CI process you can use the following Injecting a binary inside a base image is the quickest option to get a working container image. This only works if you were able to build a Linux binary, either locally, or using a container as described above. -After building a Linux binary ()`polkadot-parachain`) with cargo or with Parity CI image as documented above, the +After building a Linux binary (`polkadot-parachain`) with cargo or with Parity CI image as documented above, the following command allows producing a new container image where the compiled binary is injected: ```bash -./docker/scripts/build-injected-image.sh +ARTIFACTS_FOLDER=./target/release /docker/scripts/build-injected.sh ``` ## Container build @@ -52,7 +52,7 @@ anyone to get a working container image without requiring any of the Rust toolch ```bash docker build \ --tag $OWNER/$IMAGE_NAME \ - --file ./docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Containerfile . + --file ./docker/dockerfiles/polkadot-parachain/polkadot-parachain_builder.Dockerfile . ``` You may then run your new container: @@ -62,5 +62,5 @@ docker run --rm -it \ $OWNER/$IMAGE_NAME \ --collator --tmp \ --execution wasm \ - --chain /specs/westmint.json + --chain /specs/asset-hub-westend.json ``` diff --git a/polkadot/.gitattributes b/polkadot/.gitattributes deleted file mode 100644 index 2ea1ab2d6b9cff5f075666eb5a780575870c221e..0000000000000000000000000000000000000000 --- a/polkadot/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -/.gitlab-ci.yml filter=ci-prettier -/scripts/ci/gitlab/pipeline/*.yml filter=ci-prettier diff --git a/polkadot/.github/dependabot.yml b/polkadot/.github/dependabot.yml deleted file mode 100644 index a1fa925970bbb088349d610bd81284f1129cb154..0000000000000000000000000000000000000000 --- a/polkadot/.github/dependabot.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "cargo" - directory: "/" - labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] - # Handle updates for crates from github.com/paritytech/substrate manually. - ignore: - - dependency-name: "substrate-*" - - dependency-name: "sc-*" - - dependency-name: "sp-*" - - dependency-name: "frame-*" - - dependency-name: "fork-tree" - - dependency-name: "frame-remote-externalities" - - dependency-name: "pallet-*" - - dependency-name: "beefy-*" - - dependency-name: "try-runtime-*" - - dependency-name: "test-runner" - - dependency-name: "generate-bags" - - dependency-name: "sub-tokens" - schedule: - interval: "daily" - - package-ecosystem: github-actions - directory: '/' - labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] - schedule: - interval: daily diff --git a/polkadot/.github/pr-custom-review.yml b/polkadot/.github/pr-custom-review.yml deleted file mode 100644 index 136c9e75ff2deca5a031e41f065aec74a264ab1f..0000000000000000000000000000000000000000 --- a/polkadot/.github/pr-custom-review.yml +++ /dev/null @@ -1,42 +0,0 @@ -# 🔒 PROTECTED: Changes to locks-review-team should be approved by the current locks-review-team -locks-review-team: locks-review -team-leads-team: polkadot-review -action-review-team: ci - -rules: - - name: Runtime files - check_type: changed_files - condition: - include: ^runtime\/(kusama|polkadot)\/src\/.+\.rs$ - exclude: ^runtime\/(kusama|polkadot)\/src\/weights\/.+\.rs$ - all_distinct: - - min_approvals: 1 - teams: - - locks-review - - min_approvals: 1 - teams: - - polkadot-review - - - name: Core developers - check_type: changed_files - condition: - include: .* - # excluding files from 'Runtime files' and 'CI files' rules - exclude: ^runtime/(kusama|polkadot)/src/[^/]+\.rs$|^\.gitlab-ci\.yml|^(?!.*\.dic$|.*spellcheck\.toml$)scripts/ci/.*|^\.github/.* - min_approvals: 3 - teams: - - core-devs - - - name: CI files - check_type: changed_files - condition: - # dictionary files are excluded - include: ^\.gitlab-ci\.yml|^(?!.*\.dic$|.*spellcheck\.toml$)scripts/ci/.*|^\.github/.* - min_approvals: 2 - teams: - - ci - - release-engineering - -prevent-review-request: - teams: - - core-devs diff --git a/polkadot/.github/workflows/burnin-label-notification.yml b/polkadot/.github/workflows/burnin-label-notification.yml deleted file mode 100644 index 536f8fa2a3f6571a3643db62ee41e08bf3fec5da..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/burnin-label-notification.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Notify devops when burn-in label applied -on: - pull_request: - types: [labeled] - -jobs: - notify-devops: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - - steps: - - name: Send Matrix message to ${{ matrix.channel.name }} - if: startsWith(github.event.label.name, 'A1-') - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: m.parity.io - message: | - @room Burn-in request received for the following PR: ${{ github.event.pull_request.html_url }} diff --git a/polkadot/.github/workflows/check-D-labels.yml b/polkadot/.github/workflows/check-D-labels.yml deleted file mode 100644 index 9abefaa6fa10034c56432709ede371309a77df2b..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-D-labels.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Check D labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - paths: - - runtime/polkadot/** - - runtime/kusama/** - - runtime/common/** - - primitives/src/** - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - env: - IMAGE: paritytech/ruled_labels:0.4.0 - run: docker pull $IMAGE - - - name: Check labels - env: - IMAGE: paritytech/ruled_labels:0.4.0 - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_polkadot.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags audit --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags audit diff --git a/polkadot/.github/workflows/check-bootnodes.yml b/polkadot/.github/workflows/check-bootnodes.yml deleted file mode 100644 index 897a90d3ae928336688d6fdcbc2a6f80036e11a3..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-bootnodes.yml +++ /dev/null @@ -1,31 +0,0 @@ -# checks all networks we care about (kusama, polkadot, westend) and ensures -# the bootnodes in their respective chainspecs are contactable - -name: Check all bootnodes -on: - push: - branches: - # Catches v1.2.3 and v1.2.3-rc1 - - release-v[0-9]+.[0-9]+.[0-9]+* - -jobs: - check_bootnodes: - strategy: - fail-fast: false - matrix: - runtime: [westend, kusama, polkadot] - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Install polkadot - shell: bash - run: | - curl -L "$(curl -s https://api.github.com/repos/paritytech/polkadot/releases/latest \ - | jq -r '.assets | .[] | select(.name == "polkadot").browser_download_url')" \ - | sudo tee /usr/local/bin/polkadot > /dev/null - sudo chmod +x /usr/local/bin/polkadot - polkadot --version - - name: Check ${{ matrix.runtime }} bootnodes - shell: bash - run: scripts/ci/github/check_bootnodes.sh node/service/chain-specs/${{ matrix.runtime }}.json diff --git a/polkadot/.github/workflows/check-labels.yml b/polkadot/.github/workflows/check-labels.yml deleted file mode 100644 index df0a0e9cf02dd182492f7ecbf5a8bf9c4ebbf254..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-labels.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Check labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - env: - IMAGE: paritytech/ruled_labels:0.4.0 - run: docker pull $IMAGE - - - name: Check labels - env: - IMAGE: paritytech/ruled_labels:0.4.0 - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_polkadot.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags PR --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags PR diff --git a/polkadot/.github/workflows/check-licenses.yml b/polkadot/.github/workflows/check-licenses.yml deleted file mode 100644 index 1e654f7b30705751b3877ccdf93c76ac12723682..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-licenses.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Check licenses - -on: - pull_request: - -jobs: - check-licenses: - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - uses: actions/setup-node@v3.8.1 - with: - node-version: '18.x' - registry-url: 'https://npm.pkg.github.com' - scope: '@paritytech' - - name: Check the licenses - run: | - shopt -s globstar - - npx @paritytech/license-scanner@0.0.5 scan \ - --ensure-licenses=Apache-2.0 \ - --ensure-licenses=GPL-3.0-only \ - ./**/*.rs - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/polkadot/.github/workflows/check-new-bootnodes.yml b/polkadot/.github/workflows/check-new-bootnodes.yml deleted file mode 100644 index 25b2a0a56fe5f8f93854e38ea4b20416a35064a9..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-new-bootnodes.yml +++ /dev/null @@ -1,28 +0,0 @@ -# If a chainspec file is updated with new bootnodes, we check to make sure those bootnodes are contactable - -name: Check new bootnodes -on: - pull_request: - paths: - - 'node/service/chain-specs/*.json' - -jobs: - check_bootnodes: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Install polkadot - shell: bash - run: | - curl -L "$(curl -s https://api.github.com/repos/paritytech/polkadot/releases/latest \ - | jq -r '.assets | .[] | select(.name == "polkadot").browser_download_url')" \ - | sudo tee /usr/local/bin/polkadot > /dev/null - sudo chmod +x /usr/local/bin/polkadot - polkadot --version - - name: Check new bootnodes - shell: bash - run: | - scripts/ci/github/check_new_bootnodes.sh diff --git a/polkadot/.github/workflows/check-weights.yml b/polkadot/.github/workflows/check-weights.yml deleted file mode 100644 index e6a6c43e0a6a9b76448d448685d63672d8288a3f..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/check-weights.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Check updated weights - -on: - pull_request: - paths: -  - 'runtime/*/src/weights/**' - -jobs: - check_weights_files: - strategy: - fail-fast: false - matrix: - runtime: [westend, kusama, polkadot, rococo] - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Check weights files - shell: bash - run: | - scripts/ci/github/verify_updated_weights.sh ${{ matrix.runtime }} - - # This job uses https://github.com/ggwpez/substrate-weight-compare to compare the weights of the current - # release with the last release, then adds them as a comment to the PR. - check_weight_changes: - strategy: - fail-fast: false - matrix: - runtime: [westend, kusama, polkadot, rococo] - runs-on: ubuntu-latest - steps: - - name: Get latest release - run: | - LAST_RELEASE=$(curl -s https://api.github.com/repos/paritytech/polkadot/releases/latest | jq -r .tag_name) - echo "LAST_RELEASE=$LAST_RELEASE" >> $GITHUB_ENV - - name: Checkout current sources - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Check weight changes - shell: bash - run: | - cargo install --git https://github.com/ggwpez/substrate-weight-compare swc - ./scripts/ci/github/check_weights_swc.sh ${{ matrix.runtime }} "$LAST_RELEASE" | tee swc_output_${{ matrix.runtime }}.md - - name: Add comment - uses: thollander/actions-comment-pull-request@v2 - with: - filePath: ./swc_output_${{ matrix.runtime }}.md - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/polkadot/.github/workflows/honggfuzz.yml b/polkadot/.github/workflows/honggfuzz.yml deleted file mode 100644 index 27fa0d9967f3b062e75266364092ec9e2cb7c306..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/honggfuzz.yml +++ /dev/null @@ -1,137 +0,0 @@ -name: Run nightly fuzzer jobs - -on: - schedule: - - cron: '0 0 * * *' - -jobs: - xcm-fuzzer: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - - name: Install minimal stable Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Install minimal nightly Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - target: wasm32-unknown-unknown - - - name: Install honggfuzz deps - run: sudo apt-get install --no-install-recommends binutils-dev libunwind8-dev - - - name: Install honggfuzz - uses: actions-rs/cargo@v1 - with: - command: install - args: honggfuzz --version "0.5.54" - - - name: Build fuzzer binaries - working-directory: xcm/xcm-simulator/fuzzer/ - run: cargo hfuzz build - - - name: Run fuzzer - working-directory: xcm/xcm-simulator/fuzzer/ - run: bash $GITHUB_WORKSPACE/scripts/ci/github/run_fuzzer.sh xcm-fuzzer - - erasure-coding-round-trip: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - - name: Cache Seed - id: cache-seed-round-trip - uses: actions/cache@v3 - with: - path: erasure-coding/fuzzer/hfuzz_workspace - key: ${{ runner.os }}-erasure-coding - - - name: Install minimal stable Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Install minimal nightly Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - target: wasm32-unknown-unknown - - - name: Install honggfuzz deps - run: sudo apt-get install --no-install-recommends binutils-dev libunwind8-dev - - - name: Install honggfuzz - uses: actions-rs/cargo@v1 - with: - command: install - args: honggfuzz --version "0.5.54" - - - name: Build fuzzer binaries - working-directory: erasure-coding/fuzzer - run: cargo hfuzz build - - - name: Run fuzzer - working-directory: erasure-coding/fuzzer - run: bash $GITHUB_WORKSPACE/scripts/ci/github/run_fuzzer.sh round_trip - - erasure-coding-reconstruct: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - - name: Cache Seed - id: cache-seed-reconstruct - uses: actions/cache@v3 - with: - path: erasure-coding/fuzzer/hfuzz_workspace - key: ${{ runner.os }}-erasure-coding - - - name: Install minimal stable Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Install minimal nightly Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - target: wasm32-unknown-unknown - - - name: Install honggfuzz deps - run: sudo apt-get install --no-install-recommends binutils-dev libunwind8-dev - - - name: Install honggfuzz - uses: actions-rs/cargo@v1 - with: - command: install - args: honggfuzz --version "0.5.54" - - - name: Build fuzzer binaries - working-directory: erasure-coding/fuzzer - run: cargo hfuzz build - - - name: Run fuzzer - working-directory: erasure-coding/fuzzer - run: bash $GITHUB_WORKSPACE/scripts/ci/github/run_fuzzer.sh reconstruct diff --git a/polkadot/.github/workflows/pr-custom-review.yml b/polkadot/.github/workflows/pr-custom-review.yml deleted file mode 100644 index 8e40c9ee72989d9ef244247456aa578d3836f8c6..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/pr-custom-review.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Assign reviewers - -on: - pull_request: - branches: - - master - - main - types: - - opened - - reopened - - synchronize - - review_requested - - review_request_removed - - ready_for_review - - converted_to_draft - pull_request_review: - -jobs: - pr-custom-review: - runs-on: ubuntu-latest - steps: - - name: Skip if pull request is in Draft - # `if: github.event.pull_request.draft == true` should be kept here, at - # the step level, rather than at the job level. The latter is not - # recommended because when the PR is moved from "Draft" to "Ready to - # review" the workflow will immediately be passing (since it was skipped), - # even though it hasn't actually ran, since it takes a few seconds for - # the workflow to start. This is also disclosed in: - # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17 - # That scenario would open an opportunity for the check to be bypassed: - # 1. Get your PR approved - # 2. Move it to Draft - # 3. Push whatever commits you want - # 4. Move it to "Ready for review"; now the workflow is passing (it was - # skipped) and "Check reviews" is also passing (it won't be updated - # until the workflow is finished) - if: github.event.pull_request.draft == true - run: exit 1 - - name: pr-custom-review - uses: paritytech/pr-custom-review@action-v3 - with: - checks-reviews-api: http://pcr.parity-prod.parity.io/api/v1/check_reviews diff --git a/polkadot/.github/workflows/release-01_branch-check.yml b/polkadot/.github/workflows/release-01_branch-check.yml deleted file mode 100644 index f2b559b7c176bb52b5668e1ce9a3ac217a388f69..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-01_branch-check.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Release - Branch check -on: - push: - branches: - # Catches v1.2.3 and v1.2.3-rc1 - - release-v[0-9]+.[0-9]+.[0-9]+* - - workflow_dispatch: - -jobs: - check_branch: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Run check - shell: bash - run: ./scripts/ci/github/check-rel-br diff --git a/polkadot/.github/workflows/release-10_candidate.yml b/polkadot/.github/workflows/release-10_candidate.yml deleted file mode 100644 index 54a937a7819a155346aca1405399bdcacaf5f0e3..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-10_candidate.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Release - RC automation -on: - push: - branches: - # Catches v1.2.3 and v1.2.3-rc1 - - release-v[0-9]+.[0-9]+.[0-9]+* -jobs: - tag_rc: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: "RelEng: Polkadot Release Coordination" - room: '!cqAmzdIcbOFwrdrubV:parity.io' - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - id: compute_tag - name: Compute next rc tag - shell: bash - run: | - # Get last rc tag if exists, else set it to {version}-rc1 - version=${GITHUB_REF#refs/heads/release-} - echo "$version" - echo "version=$version" >> $GITHUB_OUTPUT - git tag -l - last_rc=$(git tag -l "$version-rc*" | sort -V | tail -n 1) - if [ -n "$last_rc" ]; then - suffix=$(echo "$last_rc" | grep -Eo '[0-9]+$') - echo $suffix - ((suffix++)) - echo $suffix - echo "new_tag=$version-rc$suffix" >> $GITHUB_OUTPUT - echo "first_rc=false" >> $GITHUB_OUTPUT - else - echo "new_tag=$version-rc1" >> $GITHUB_OUTPUT - echo "first_rc=true" >> $GITHUB_OUTPUT - fi - - - name: Apply new tag - uses: tvdias/github-tagger@ed7350546e3e503b5e942dffd65bc8751a95e49d # v0.0.2 - with: - # We can't use the normal GITHUB_TOKEN for the following reason: - # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token - # RELEASE_BRANCH_TOKEN requires public_repo OAuth scope - repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}" - tag: ${{ steps.compute_tag.outputs.new_tag }} - - - id: create-issue - uses: JasonEtco/create-an-issue@e27dddc79c92bc6e4562f268fffa5ed752639abd # v2.9.1 - # Only create the issue if it's the first release candidate - if: steps.compute_tag.outputs.first_rc == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.compute_tag.outputs.version }} - with: - filename: .github/ISSUE_TEMPLATE/release.md - - - name: Send Matrix message to ${{ matrix.channel.name }} - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - if: steps.create-issue.outputs.url != '' - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: m.parity.io - message: | - Release process for polkadot ${{ steps.compute_tag.outputs.version }} has been started.
- Tracking issue: ${{ steps.create-issue.outputs.url }} diff --git a/polkadot/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml b/polkadot/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml deleted file mode 100644 index 0613ed04d35a93f16b0e0f7be3557216a665d0fc..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml +++ /dev/null @@ -1,81 +0,0 @@ -# This workflow performs the Extrinsic Ordering Check on demand using a binary - -name: Release - Extrinsic Ordering Check -on: - workflow_dispatch: - inputs: - reference_url: - description: The WebSocket url of the reference node - default: wss://kusama-rpc.polkadot.io - required: true - binary_url: - description: A url to a Linux binary for the node containing the runtime to test - default: https://releases.parity.io/polkadot/x86_64-debian:stretch/v0.9.10/polkadot - required: true - chain: - description: The name of the chain under test. Usually, you would pass a local chain - default: kusama-local - required: true - -jobs: - check: - name: Run check - runs-on: ubuntu-latest - env: - CHAIN: ${{github.event.inputs.chain}} - BIN_URL: ${{github.event.inputs.binary_url}} - REF_URL: ${{github.event.inputs.reference_url}} - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Fetch binary - run: | - echo Fetching $BIN_URL - wget $BIN_URL - chmod a+x polkadot - ./polkadot --version - - - name: Start local node - run: | - echo Running on $CHAIN - ./polkadot --chain=$CHAIN & - - - name: Prepare output - run: | - VERSION=$(./polkadot --version) - echo "Metadata comparison:" >> output.txt - echo "Date: $(date)" >> output.txt - echo "Reference: $REF_URL" >> output.txt - echo "Target version: $VERSION" >> output.txt - echo "Chain: $CHAIN" >> output.txt - echo "----------------------------------------------------------------------" >> output.txt - - - name: Pull polkadot-js-tools image - run: docker pull jacogr/polkadot-js-tools - - - name: Compare the metadata - run: | - CMD="docker run --pull always --network host jacogr/polkadot-js-tools metadata $REF_URL ws://localhost:9944" - echo -e "Running:\n$CMD" - $CMD >> output.txt - sed -z -i 's/\n\n/\n/g' output.txt - cat output.txt | egrep -n -i '' - SUMMARY=$(./scripts/ci/github/extrinsic-ordering-filter.sh output.txt) - echo -e $SUMMARY - echo -e $SUMMARY >> output.txt - - - name: Show result - run: | - cat output.txt - - - name: Stop our local node - run: pkill polkadot - - - name: Save output as artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ env.CHAIN }} - path: | - output.txt diff --git a/polkadot/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml b/polkadot/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml deleted file mode 100644 index 6513897f4a13451a1ea8ffa4ea68d51f722c9513..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml +++ /dev/null @@ -1,97 +0,0 @@ -# This workflow performs the Extrinsic Ordering Check on demand using two reference binaries - -name: Release - Extrinsic API Check with reference bins -on: - workflow_dispatch: - inputs: - reference_binary_url: - description: A url to a Linux binary for the node containing the reference runtime to test against - default: https://releases.parity.io/polkadot/x86_64-debian:stretch/v0.9.26/polkadot - required: true - binary_url: - description: A url to a Linux binary for the node containing the runtime to test - default: https://releases.parity.io/polkadot/x86_64-debian:stretch/v0.9.27-rc1/polkadot - required: true - -jobs: - check: - name: Run check - runs-on: ubuntu-latest - env: - BIN_URL: ${{github.event.inputs.binary_url}} - REF_URL: ${{github.event.inputs.reference_binary_url}} - strategy: - fail-fast: false - matrix: - chain: [polkadot, kusama, westend, rococo] - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Fetch reference binary - run: | - echo Fetching $REF_URL - curl $REF_URL -o polkadot-ref - chmod a+x polkadot-ref - ./polkadot-ref --version - - - name: Fetch test binary - run: | - echo Fetching $BIN_URL - curl $BIN_URL -o polkadot - chmod a+x polkadot - ./polkadot --version - - - name: Start local reference node - run: | - echo Running reference on ${{ matrix.chain }}-local - ./polkadot-ref --chain=${{ matrix.chain }}-local --rpc-port=9934 --ws-port=9945 --base-path=polkadot-ref-base/ & - - - name: Start local test node - run: | - echo Running test on ${{ matrix.chain }}-local - ./polkadot --chain=${{ matrix.chain }}-local & - - - name: Prepare output - run: | - REF_VERSION=$(./polkadot-ref --version) - BIN_VERSION=$(./polkadot --version) - echo "Metadata comparison:" >> output.txt - echo "Date: $(date)" >> output.txt - echo "Ref. binary: $REF_URL" >> output.txt - echo "Test binary: $BIN_URL" >> output.txt - echo "Ref. version: $REF_VERSION" >> output.txt - echo "Test version: $BIN_VERSION" >> output.txt - echo "Chain: ${{ matrix.chain }}-local" >> output.txt - echo "----------------------------------------------------------------------" >> output.txt - - - name: Pull polkadot-js-tools image - run: docker pull jacogr/polkadot-js-tools - - - name: Compare the metadata - run: | - CMD="docker run --pull always --network host jacogr/polkadot-js-tools metadata ws://localhost:9945 ws://localhost:9944" - echo -e "Running:\n$CMD" - $CMD >> output.txt - sed -z -i 's/\n\n/\n/g' output.txt - cat output.txt | egrep -n -i '' - SUMMARY=$(./scripts/ci/github/extrinsic-ordering-filter.sh output.txt) - echo -e $SUMMARY - echo -e $SUMMARY >> output.txt - - - name: Show result - run: | - cat output.txt - - - name: Save output as artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.chain }} - path: | - output.txt - - - name: Stop our local nodes - run: | - pkill polkadot-ref - pkill polkadot diff --git a/polkadot/.github/workflows/release-30_publish-draft-release.yml b/polkadot/.github/workflows/release-30_publish-draft-release.yml deleted file mode 100644 index 206b1871d80a48672ab89434f90b33b99492dd74..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-30_publish-draft-release.yml +++ /dev/null @@ -1,199 +0,0 @@ -name: Release - Publish draft - -on: - push: - tags: - # Catches v1.2.3 and v1.2.3-rc1 - - v[0-9]+.[0-9]+.[0-9]+* - -jobs: - get-rust-versions: - runs-on: ubuntu-latest - container: - image: paritytech/ci-linux:production - outputs: - rustc-stable: ${{ steps.get-rust-versions.outputs.stable }} - rustc-nightly: ${{ steps.get-rust-versions.outputs.nightly }} - steps: - - id: get-rust-versions - run: | - echo "stable=$(rustc +stable --version)" >> $GITHUB_OUTPUT - echo "nightly=$(rustc +nightly --version)" >> $GITHUB_OUTPUT - - build-runtimes: - runs-on: ubuntu-latest - strategy: - matrix: - runtime: ["polkadot", "kusama", "westend", "rococo"] - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Cache target dir - uses: actions/cache@v3 - with: - path: "${{ github.workspace }}/runtime/${{ matrix.runtime }}/target" - key: srtool-target-${{ matrix.runtime }}-${{ github.sha }} - restore-keys: | - srtool-target-${{ matrix.runtime }}- - srtool-target- - - - name: Build ${{ matrix.runtime }} runtime - id: srtool_build - uses: chevdor/srtool-actions@v0.8.0 - with: - image: paritytech/srtool - chain: ${{ matrix.runtime }} - - - name: Store srtool digest to disk - run: | - echo '${{ steps.srtool_build.outputs.json }}' | jq > ${{ matrix.runtime }}_srtool_output.json - - - name: Upload ${{ matrix.runtime }} srtool json - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.runtime }}-srtool-json - path: ${{ matrix.runtime }}_srtool_output.json - - - name: Upload ${{ matrix.runtime }} runtime - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.runtime }}-runtime - path: | - ${{ steps.srtool_build.outputs.wasm_compressed }} - - publish-draft-release: - runs-on: ubuntu-latest - needs: ["get-rust-versions", "build-runtimes"] - outputs: - release_url: ${{ steps.create-release.outputs.html_url }} - asset_upload_url: ${{ steps.create-release.outputs.upload_url }} - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 0 - path: polkadot - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.0.0 - - - name: Download srtool json output - uses: actions/download-artifact@v3 - - - name: Prepare tooling - run: | - cd polkadot/scripts/ci/changelog - gem install bundler changelogerator:0.9.1 - bundle install - changelogerator --help - - URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.1/tera-cli_linux_amd64.deb - wget $URL -O tera.deb - sudo dpkg -i tera.deb - tera --version - - - name: Generate release notes - env: - RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }} - RUSTC_NIGHTLY: ${{ needs.get-rust-versions.outputs.rustc-nightly }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NO_CACHE: 1 - DEBUG: 1 - ROCOCO_DIGEST: ${{ github.workspace}}/rococo-srtool-json/rococo_srtool_output.json - WESTEND_DIGEST: ${{ github.workspace}}/westend-srtool-json/westend_srtool_output.json - KUSAMA_DIGEST: ${{ github.workspace}}/kusama-srtool-json/kusama_srtool_output.json - POLKADOT_DIGEST: ${{ github.workspace}}/polkadot-srtool-json/polkadot_srtool_output.json - PRE_RELEASE: ${{ github.event.inputs.pre_release }} - run: | - find ${{env.GITHUB_WORKSPACE}} -type f -name "*_srtool_output.json" - ls -al $ROCOCO_DIGEST - ls -al $WESTEND_DIGEST - ls -al $KUSAMA_DIGEST - ls -al $POLKADOT_DIGEST - - cd polkadot/scripts/ci/changelog - - ./bin/changelog ${GITHUB_REF} - ls -al release-notes.md - ls -al context.json - - - name: Archive artifact context.json - uses: actions/upload-artifact@v3 - with: - name: release-notes-context - path: | - polkadot/scripts/ci/changelog/context.json - **/*_srtool_output.json - - - name: Create draft release - id: create-release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Polkadot ${{ github.ref }} - body_path: ./polkadot/scripts/ci/changelog/release-notes.md - draft: true - - publish-runtimes: - runs-on: ubuntu-latest - needs: ["publish-draft-release"] - env: - RUNTIME_DIR: runtime - strategy: - matrix: - runtime: ["polkadot", "kusama", "westend", "rococo"] - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Download artifacts - uses: actions/download-artifact@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.0.0 - - name: Get runtime version - id: get-runtime-ver - run: | - echo "require './scripts/ci/github/lib.rb'" > script.rb - echo "puts get_runtime(runtime: \"${{ matrix.runtime }}\", runtime_dir: \"$RUNTIME_DIR\")" >> script.rb - - echo "Current folder: $PWD" - ls "$RUNTIME_DIR/${{ matrix.runtime }}" - runtime_ver=$(ruby script.rb) - echo "Found version: >$runtime_ver<" - echo "runtime_ver=$runtime_ver" >> $GITHUB_OUTPUT - - - name: Upload compressed ${{ matrix.runtime }} wasm - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.publish-draft-release.outputs.asset_upload_url }} - asset_path: "${{ matrix.runtime }}-runtime/${{ matrix.runtime }}_runtime.compact.compressed.wasm" - asset_name: ${{ matrix.runtime }}_runtime-v${{ steps.get-runtime-ver.outputs.runtime_ver }}.compact.compressed.wasm - asset_content_type: application/wasm - - post_to_matrix: - runs-on: ubuntu-latest - needs: publish-draft-release - strategy: - matrix: - channel: - - name: "RelEng: Polkadot Release Coordination" - room: '!cqAmzdIcbOFwrdrubV:parity.io' - - steps: - - name: Send Matrix message to ${{ matrix.channel.name }} - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: m.parity.io - message: | - **New version of polkadot tagged**: ${{ github.ref }}
- Draft release created: ${{ needs.publish-draft-release.outputs.release_url }} diff --git a/polkadot/.github/workflows/release-99_bot.yml b/polkadot/.github/workflows/release-99_bot.yml deleted file mode 100644 index 5d45c0d44eda3d43e77ce6cc2272b79cc35f5c7e..0000000000000000000000000000000000000000 --- a/polkadot/.github/workflows/release-99_bot.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Release - Send new release notification to matrix channels -on: - release: - types: - - published - -jobs: - ping_matrix: - strategy: - matrix: - channel: - - name: '#KusamaValidatorLounge:polkadot.builders' - room: '!LhjZccBOqFNYKLdmbb:polkadot.builders' - pre-releases: false - - name: '#kusama-announcements:matrix.parity.io' - room: '!FMwxpQnYhRCNDRsYGI:matrix.parity.io' - pre-release: false - - name: '#polkadotvalidatorlounge:web3.foundation' - room: '!NZrbtteFeqYKCUGQtr:matrix.parity.io' - pre-release: false - - name: '#polkadot-announcements:matrix.parity.io' - room: '!UqHPWiCBGZWxrmYBkF:matrix.parity.io' - pre-release: false - - name: "RelEng: Polkadot Release Coordination" - room: '!cqAmzdIcbOFwrdrubV:parity.io' - pre-release: true - - name: 'Ledger <> Polkadot Coordination' - room: '!EoIhaKfGPmFOBrNSHT:web3.foundation' - pre-release: true - - name: 'General: Rust, Polkadot, Substrate' - room: '!aJymqQYtCjjqImFLSb:parity.io' - pre-release: false - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - pre-release: true - - runs-on: ubuntu-latest - steps: - - name: Send Matrix message to ${{ matrix.channel.name }} - if: github.event.release.prerelease == false || matrix.channel.pre-release - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: m.parity.io - message: | - ***Polkadot ${{github.event.release.tag_name}} has been released!***
- ${{github.event.release.html_url}}

- ${{github.event.release.body}}
diff --git a/polkadot/.gitlab-ci.yml b/polkadot/.gitlab-ci.yml deleted file mode 100644 index b2d91e61da94a53a791cd1085357eb986ef67c12..0000000000000000000000000000000000000000 --- a/polkadot/.gitlab-ci.yml +++ /dev/null @@ -1,287 +0,0 @@ -# .gitlab-ci.yml -# -# polkadot -# -# Pipelines can be triggered manually in the web. -# -# Please do not add new jobs without "rules:" and "*-env". There are &test-refs for everything, -# "docker-env" is used for Rust jobs. -# And "kubernetes-env" for everything else. Please mention "image:" container name to be used -# with it, as there's no default one. - -# All jobs are sorted according to their duration using DAG mechanism -# Currently, test-linux-stable job is the longest one and other jobs are -# sorted in order to complete during this job and occupy less runners in one -# moment of time. - -stages: - - .pre - - weights - - check - - test - - build - - publish - - zombienet - - short-benchmarks - -workflow: - rules: - - if: $CI_COMMIT_TAG - - if: $CI_COMMIT_BRANCH - -variables: - GIT_STRATEGY: fetch - GIT_DEPTH: 100 - CI_SERVER_NAME: "GitLab CI" - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] - BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" - BUILDAH_COMMAND: "buildah --storage-driver overlay2" - DOCKER_OS: "debian:stretch" - ARCH: "x86_64" - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.65" - -default: - cache: {} - retry: - max: 2 - when: - - runner_system_failure - - unknown_failure - - api_failure - interruptible: true - -.common-before-script: - before_script: - - !reference [.job-switcher, before_script] - - !reference [.timestamp, before_script] - -.collect-artifacts: - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 7 days - paths: - - ./artifacts/ - -.collect-artifacts-short: - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 1 days - paths: - - ./artifacts/ - -# collecting vars for pipeline stopper -# they will be used if the job fails -.pipeline-stopper-vars: - before_script: - - echo "FAILED_JOB_URL=${CI_JOB_URL}" > pipeline-stopper.env - - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env - - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env - - echo "PR_NUM=${CI_COMMIT_REF_NAME}" >> pipeline-stopper.env - -.pipeline-stopper-artifacts: - artifacts: - reports: - dotenv: pipeline-stopper.env - -.job-switcher: - before_script: - - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi - -.kubernetes-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.common-before-script, before_script] - tags: - - kubernetes-parity-build - -.docker-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.common-before-script, before_script] - tags: - - linux-docker-vm-c2 - -.compiler-info: - before_script: - - !reference [.common-before-script, before_script] - - rustup show - - cargo --version - -.test-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.common-refs: - # these jobs run always* - rules: - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^release-v[0-9]+\.[0-9]+.*$/ # i.e. release-v0.9.27 - -.test-pr-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.zombienet-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "schedule" - when: never - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.deploy-testnet-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - -.publish-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_PIPELINE_SOURCE == "web" && - $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - -.build-push-image: - variables: - CI_IMAGE: "${BUILDAH_IMAGE}" - - REGISTRY: "docker.io" - DOCKER_OWNER: "paritypr" - DOCKER_USER: "${PARITYPR_USER}" - DOCKER_PASS: "${PARITYPR_PASS}" - IMAGE: "${REGISTRY}/${DOCKER_OWNER}/${IMAGE_NAME}" - - ENGINE: "${BUILDAH_COMMAND}" - BUILDAH_FORMAT: "docker" - SKIP_IMAGE_VALIDATION: 1 - - PROJECT_ROOT: "." - BIN_FOLDER: "./artifacts" - VCS_REF: "${CI_COMMIT_SHA}" - - before_script: - - !reference [.common-before-script, before_script] - - test -s ./artifacts/VERSION || exit 1 - - test -s ./artifacts/EXTRATAG || exit 1 - - export VERSION="$(cat ./artifacts/VERSION)" - - EXTRATAG="$(cat ./artifacts/EXTRATAG)" - - echo "Polkadot version = ${VERSION} (EXTRATAG = ${EXTRATAG})" - script: - - test "$DOCKER_USER" -a "$DOCKER_PASS" || - ( echo "no docker credentials provided"; exit 1 ) - - TAGS="${VERSION},${EXTRATAG}" scripts/ci/dockerfiles/build-injected.sh - - echo "$DOCKER_PASS" | - buildah login --username "$DOCKER_USER" --password-stdin "${REGISTRY}" - - $BUILDAH_COMMAND info - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE:$VERSION" - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE:$EXTRATAG" - after_script: - - buildah logout --all - -#### stage: .pre - -# By default our pipelines are interruptible, but some special pipelines shouldn't be interrupted: -# * multi-project pipelines such as the ones triggered by the scripts repo -# -# In those cases, we add an uninterruptible .pre job; once that one has started, -# the entire pipeline becomes uninterruptible. -uninterruptible-pipeline: - extends: .kubernetes-env - variables: - CI_IMAGE: "paritytech/tools:latest" - stage: .pre - interruptible: false - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - script: "true" - -include: - # weights jobs - - scripts/ci/gitlab/pipeline/weights.yml - # check jobs - - scripts/ci/gitlab/pipeline/check.yml - # test jobs - - scripts/ci/gitlab/pipeline/test.yml - # build jobs - - scripts/ci/gitlab/pipeline/build.yml - # short-benchmarks jobs - - scripts/ci/gitlab/pipeline/short-benchmarks.yml - # publish jobs - - scripts/ci/gitlab/pipeline/publish.yml - # zombienet jobs - - scripts/ci/gitlab/pipeline/zombienet.yml - # timestamp handler - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/timestamp.yml - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/ci-unified.yml - - -#### stage: .post - -deploy-parity-testnet: - stage: .post - extends: - - .deploy-testnet-refs - variables: - POLKADOT_CI_COMMIT_NAME: "${CI_COMMIT_REF_NAME}" - POLKADOT_CI_COMMIT_REF: "${CI_COMMIT_SHORT_SHA}" - allow_failure: false - trigger: "parity/infrastructure/parity-testnet" - -# This job cancels the whole pipeline if any of provided jobs fail. -# In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests -# to fail the pipeline as soon as possible to shorten the feedback loop. -.cancel-pipeline-template: - stage: .post - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - when: on_failure - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "${FAILED_JOB_URL}" - FAILED_JOB_NAME: "${FAILED_JOB_NAME}" - PR_NUM: "${PR_NUM}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" - branch: "as-improve" - -remove-cancel-pipeline-message: - stage: .post - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "https://gitlab.com" - FAILED_JOB_NAME: "nope" - PR_NUM: "${CI_COMMIT_REF_NAME}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" - -cancel-pipeline-test-linux-stable: - extends: .cancel-pipeline-template - needs: - - job: test-linux-stable diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index e4494b1abb200fe06f6182b90ae2030882a03abe..6e82cb69f6ecd6c4db535c9797a4ea7fde9d67c1 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -26,11 +26,7 @@ color-eyre = { version = "0.6.1", default-features = false } tikv-jemallocator = { version = "0.5.0", optional = true } # Crates in our workspace, defined as dependencies so we can pass them feature flags. -polkadot-cli = { path = "cli", features = [ - "kusama-native", - "westend-native", - "rococo-native", -] } +polkadot-cli = { path = "cli", features = [ "westend-native", "rococo-native" ] } polkadot-node-core-pvf = { path = "node/core/pvf" } polkadot-node-core-pvf-prepare-worker = { path = "node/core/pvf/prepare-worker" } polkadot-overseer = { path = "node/overseer" } @@ -72,7 +68,6 @@ jemalloc-allocator = [ # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky # when run locally depending on system load ci-only-tests = [ "polkadot-node-core-pvf/ci-only-tests" ] -network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] # Configuration for building a .deb package - for use with `cargo-deb` [package.metadata.deb] diff --git a/polkadot/README.md b/polkadot/README.md index 93e93cfba0ee54aac2b5b61d8bb0685ee10f7bb0..3c234bb8e3f4d3bed19331047f42c9afa2658053 100644 --- a/polkadot/README.md +++ b/polkadot/README.md @@ -2,29 +2,17 @@ Implementation of a node in Rust based on the Substrate framework. -> **NOTE:** In 2018, we split our implementation of "Polkadot" from its development framework > -"Substrate". See the [Substrate][substrate-repo] repo for git history prior to 2018. - -[substrate-repo]: https://github.com/paritytech/substrate - -This repo contains runtimes for the Polkadot, Kusama, and Westend networks. The README provides -information about installing the `polkadot` binary and developing on the codebase. For more specific -guides, like how to be a validator, see the [Polkadot -Wiki](https://wiki.polkadot.network/docs/getting-started). +The README provides information about installing the `polkadot` binary and developing on the codebase. For more specific +guides, like how to run a validator node, see the [Polkadot Wiki](https://wiki.polkadot.network/docs/getting-started). ## Installation +### Using a pre-compiled binary + If you just wish to run a Polkadot node without compiling it yourself, you may either run the latest binary from our [releases](https://github.com/paritytech/polkadot-sdk/releases) page, or install Polkadot from one of our package repositories. -Installation from the Debian repository will create a `systemd` service that can be used to run a -Polkadot node. This is disabled by default, and can be started by running `systemctl start polkadot` -on demand (use `systemctl enable polkadot` to make it auto-start after reboot). By default, it will -run as the `polkadot` user. Command-line flags passed to the binary can be customized by editing -`/etc/default/polkadot`. This file will not be overwritten on updating Polkadot. You may also just -run the node directly from the command-line. - ### Debian-based (Debian, Ubuntu) Currently supports Debian 10 (Buster) and Ubuntu 20.04 (Focal), and derivatives. Run the following @@ -45,8 +33,18 @@ apt install polkadot ``` +Installation from the Debian repository will create a `systemd` service that can be used to run a +Polkadot node. This is disabled by default, and can be started by running `systemctl start polkadot` +on demand (use `systemctl enable polkadot` to make it auto-start after reboot). By default, it will +run as the `polkadot` user. Command-line flags passed to the binary can be customized by editing +`/etc/default/polkadot`. This file will not be overwritten on updating Polkadot. You may also just +run the node directly from the command-line. + ## Building +Since the Polkadot node is based on Substrate, first set up your build environment according to the +[Substrate installation instructions](https://docs.substrate.io/install/). + ### Install via Cargo Make sure you have the support software installed from the **Build from Source** section below this @@ -60,25 +58,6 @@ cargo install --git https://github.com/paritytech/polkadot-sdk --tag p ### Build from Source -If you'd like to build from source, first install Rust. You may need to add Cargo's bin directory to -your PATH environment variable. Restarting your computer will do this for you automatically. - -```bash -curl https://sh.rustup.rs -sSf | sh -``` - -If you already have Rust installed, make sure you're using the latest version by running: - -```bash -rustup update -``` - -Once done, finish installing the support software: - -```bash -sudo apt install build-essential git clang libclang-dev pkg-config libssl-dev protobuf-compiler -``` - Build the client by cloning this repository and running the following commands from the root directory of the repo: @@ -88,9 +67,6 @@ git checkout cargo build --release ``` -**Note:** compilation is a memory intensive process. We recommend having 4 GiB of physical RAM or -swap available (keep in mind that if a build hits swap it tends to be very slow). - **Note:** if you want to move the built `polkadot` binary somewhere (e.g. into $PATH) you will also need to move `polkadot-execute-worker` and `polkadot-prepare-worker`. You can let cargo do all this for you by running: @@ -123,7 +99,7 @@ This repo supports runtimes for Polkadot, Kusama, and Westend. Connect to the global Polkadot Mainnet network by running: ```bash -./target/release/polkadot --chain=polkadot +../target/release/polkadot --chain=polkadot ``` You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). @@ -135,7 +111,7 @@ You can see your node on [telemetry] (set a custom name with `--name "my custom Connect to the global Kusama canary network by running: ```bash -./target/release/polkadot --chain=kusama +../target/release/polkadot --chain=kusama ``` You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). @@ -147,7 +123,7 @@ You can see your node on [telemetry] (set a custom name with `--name "my custom Connect to the global Westend testnet by running: ```bash -./target/release/polkadot --chain=westend +../target/release/polkadot --chain=westend ``` You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). @@ -157,20 +133,14 @@ You can see your node on [telemetry] (set a custom name with `--name "my custom ### Obtaining DOTs If you want to do anything on Polkadot, Kusama, or Westend, then you'll need to get an account and -some DOT, KSM, or WND tokens, respectively. See the [claims -instructions](https://claims.polkadot.network/) for Polkadot if you have DOTs to claim. For -Westend's WND tokens, see the faucet -[instructions](https://wiki.polkadot.network/docs/learn-DOT#getting-westies) on the Wiki. +some DOT, KSM, or WND tokens, respectively. Follow the +[instructions](https://wiki.polkadot.network/docs/learn-DOT#obtaining-testnet-tokens) on the Wiki to obtain tokens for +your testnet of choice. ## Hacking on Polkadot If you'd actually like to hack on Polkadot, you can grab the source code and build it. Ensure you -have Rust and the support software installed. This script will install or update Rust and install -the required dependencies (this may take up to 30 minutes on Mac machines): - -```bash -curl https://getsubstrate.io -sSf | bash -s -- --fast -``` +have Rust and the support software installed. Then, grab the Polkadot source code: @@ -183,14 +153,15 @@ Then build the code. You will need to build in release mode (`--release`) to sta use debug mode for development (faster compile times for development and testing). ```bash -./scripts/init.sh # Install WebAssembly. Update Rust -cargo build # Builds all native code +cargo build ``` You can run the tests if you like: ```bash -cargo test --workspace --release +cargo test --workspace --profile testnet +# Or run only the tests for specified crated +cargo test -p --profile testnet ``` You can start a development chain with: @@ -202,7 +173,7 @@ cargo run --bin polkadot -- --dev Detailed logs may be shown by running the node with the following environment variables set: ```bash -RUST_LOG=debug RUST_BACKTRACE=1 cargo run --bin polkadot -- --dev +RUST_LOG=debug RUST_BACKTRACE=1 cargo run --bin polkadot -- --dev ``` ### Development @@ -222,13 +193,13 @@ If you want to see the multi-node consensus algorithm in action locally, then yo testnet. You'll need two terminals open. In one, run: ```bash -polkadot --chain=polkadot-local --alice -d /tmp/alice +polkadot --dev --alice -d /tmp/alice ``` And in the other, run: ```bash -polkadot --chain=polkadot-local --bob -d /tmp/bob --port 30334 --bootnodes '/ip4/127.0.0.1/tcp/30333/p2p/ALICE_BOOTNODE_ID_HERE' +polkadot --dev --bob -d /tmp/bob --bootnodes '/ip4/127.0.0.1/tcp/30333/p2p/ALICE_BOOTNODE_ID_HERE' ``` Ensure you replace `ALICE_BOOTNODE_ID_HERE` with the node ID from the output of the first terminal. @@ -242,7 +213,7 @@ that we currently maintain. ### Using Docker -[Using Docker](doc/docker.md) +[Using Docker](../docs/docker.md) ### Shell Completion diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index a9631fb9a7da1fa730a5f4035fc6a42e69cc0595..9cad7e88dfe92fd5587b71ffc030ffa56c5cf007 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -15,7 +15,7 @@ wasm-opt = false crate-type = ["cdylib", "rlib"] [dependencies] -clap = { version = "4.4.3", features = ["derive"], optional = true } +clap = { version = "4.4.6", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.48" futures = "0.3.21" @@ -23,7 +23,6 @@ pyro = { package = "pyroscope", version = "0.5.3", optional = true } pyroscope_pprofrs = { version = "0.2", optional = true } service = { package = "polkadot-service", path = "../node/service", default-features = false, optional = true } -polkadot-performance-test = { path = "../node/test/performance-test", optional = true } sp-core = { path = "../../substrate/primitives/core" } sp-io = { path = "../../substrate/primitives/io" } @@ -34,6 +33,7 @@ try-runtime-cli = { path = "../../substrate/utils/frame/try-runtime/cli", option sc-cli = { path = "../../substrate/client/cli", optional = true } sc-service = { path = "../../substrate/client/service", optional = true } polkadot-node-metrics = { path = "../node/metrics" } +polkadot-node-primitives = { path = "../node/primitives" } sc-tracing = { path = "../../substrate/client/tracing", optional = true } sc-sysinfo = { path = "../../substrate/client/sysinfo" } sc-executor = { path = "../../substrate/client/executor" } @@ -57,7 +57,6 @@ cli = [ runtime-benchmarks = [ "frame-benchmarking-cli?/runtime-benchmarks", "polkadot-node-metrics/runtime-benchmarks", - "polkadot-performance-test?/runtime-benchmarks", "sc-service?/runtime-benchmarks", "service/runtime-benchmarks", ] @@ -65,13 +64,8 @@ full-node = [ "service/full-node" ] try-runtime = [ "service/try-runtime", "try-runtime-cli/try-runtime" ] fast-runtime = [ "service/fast-runtime" ] pyroscope = [ "pyro", "pyroscope_pprofrs" ] -hostperfcheck = [ "polkadot-performance-test" ] -# Configure the native runtimes to use. Polkadot is enabled by default. -# -# Validators require the native runtime currently -polkadot-native = [ "service/polkadot-native" ] -kusama-native = [ "service/kusama-native" ] +# Configure the native runtimes to use. westend-native = [ "service/westend-native" ] rococo-native = [ "service/rococo-native" ] @@ -80,4 +74,3 @@ runtime-metrics = [ "polkadot-node-metrics/runtime-metrics", "service/runtime-metrics", ] -network-protocol-staging = [ "service/network-protocol-staging" ] diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index aaf8f170576075414a00aba17f39c042d9463a98..bc060c21fba70b55e0652bb853b8e40d50f15a52 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -16,19 +16,11 @@ //! Polkadot CLI library. +pub use polkadot_node_primitives::NODE_VERSION; + use clap::Parser; use std::path::PathBuf; -/// The version of the node. -/// -/// This is the version that is used for versioning this node binary. -/// By default the `minor` version is bumped in every release. `Major` or `patch` releases are only -/// expected in very rare cases. -/// -/// The worker binaries associated to the node binary should ensure that they are using the same -/// version as the main node that started them. -pub const NODE_VERSION: &'static str = "1.1.0"; - #[allow(missing_docs)] #[derive(Debug, Parser)] pub enum Subcommand { @@ -58,10 +50,6 @@ pub enum Subcommand { #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), - /// Runs performance checks such as PVF compilation in order to measure machine - /// capabilities of running a validator. - HostPerfCheck, - /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and /// deprecation notice. It will be removed entirely some time after Janurary 2024. diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index a081e1b5181bf978484425541b5dd74dbd21da10..3da6e54b812b2ab31c0d34bd46ee32b2f2f7b937 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -34,12 +34,6 @@ pub use polkadot_performance_test::PerfCheckError; #[cfg(feature = "pyroscope")] use pyroscope_pprofrs::{pprof_backend, PprofConfig}; -impl From for Error { - fn from(s: String) -> Self { - Self::Other(s) - } -} - type Result = std::result::Result; fn get_exec_name() -> Option { @@ -68,7 +62,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/polkadot/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -92,29 +86,20 @@ impl SubstrateCli for Cli { }; Ok(match id { "kusama" => Box::new(service::chain_spec::kusama_config()?), - #[cfg(feature = "kusama-native")] - "kusama-dev" => Box::new(service::chain_spec::kusama_development_config()?), - #[cfg(feature = "kusama-native")] - "kusama-local" => Box::new(service::chain_spec::kusama_local_testnet_config()?), - #[cfg(feature = "kusama-native")] - "kusama-staging" => Box::new(service::chain_spec::kusama_staging_testnet_config()?), - #[cfg(not(feature = "kusama-native"))] name if name.starts_with("kusama-") && !name.ends_with(".json") => - Err(format!("`{}` only supported with `kusama-native` feature enabled.", name))?, + Err(format!("`{name}` is not supported anymore as the kusama native runtime no longer part of the node."))?, "polkadot" => Box::new(service::chain_spec::polkadot_config()?), - #[cfg(feature = "polkadot-native")] - "polkadot-dev" | "dev" => Box::new(service::chain_spec::polkadot_development_config()?), - #[cfg(feature = "polkadot-native")] - "polkadot-local" => Box::new(service::chain_spec::polkadot_local_testnet_config()?), + name if name.starts_with("polkadot-") && !name.ends_with(".json") => + Err(format!("`{name}` is not supported anymore as the polkadot native runtime no longer part of the node."))?, "rococo" => Box::new(service::chain_spec::rococo_config()?), #[cfg(feature = "rococo-native")] - "rococo-dev" => Box::new(service::chain_spec::rococo_development_config()?), + "dev" | "rococo-dev" => Box::new(service::chain_spec::rococo_development_config()?), #[cfg(feature = "rococo-native")] "rococo-local" => Box::new(service::chain_spec::rococo_local_testnet_config()?), #[cfg(feature = "rococo-native")] "rococo-staging" => Box::new(service::chain_spec::rococo_staging_testnet_config()?), #[cfg(not(feature = "rococo-native"))] - name if name.starts_with("rococo-") && !name.ends_with(".json") => + name if name.starts_with("rococo-") && !name.ends_with(".json") || name == "dev" => Err(format!("`{}` only supported with `rococo-native` feature enabled.", name))?, "westend" => Box::new(service::chain_spec::westend_config()?), #[cfg(feature = "westend-native")] @@ -146,7 +131,7 @@ impl SubstrateCli for Cli { path => { let path = std::path::PathBuf::from(path); - let chain_spec = Box::new(service::PolkadotChainSpec::from_json_file(path.clone())?) + let chain_spec = Box::new(service::GenericChainSpec::from_json_file(path.clone())?) as Box; // When `force_*` is given or the file name starts with the name of one of the known @@ -158,7 +143,7 @@ impl SubstrateCli for Cli { { Box::new(service::RococoChainSpec::from_json_file(path)?) } else if self.run.force_kusama || chain_spec.is_kusama() { - Box::new(service::KusamaChainSpec::from_json_file(path)?) + Box::new(service::GenericChainSpec::from_json_file(path)?) } else if self.run.force_westend || chain_spec.is_westend() { Box::new(service::WestendChainSpec::from_json_file(path)?) } else { @@ -182,37 +167,6 @@ fn set_default_ss58_version(spec: &Box) { sp_core::crypto::set_default_ss58_version(ss58_version); } -const DEV_ONLY_ERROR_PATTERN: &'static str = - "can only use subcommand with --chain [polkadot-dev, kusama-dev, westend-dev, rococo-dev, wococo-dev], got "; - -fn ensure_dev(spec: &Box) -> std::result::Result<(), String> { - if spec.is_dev() { - Ok(()) - } else { - Err(format!("{}{}", DEV_ONLY_ERROR_PATTERN, spec.id())) - } -} - -/// Runs performance checks. -/// Should only be used in release build since the check would take too much time otherwise. -fn host_perf_check() -> Result<()> { - #[cfg(not(feature = "hostperfcheck"))] - { - return Err(Error::FeatureNotEnabled { feature: "hostperfcheck" }.into()) - } - - #[cfg(all(not(build_type = "release"), feature = "hostperfcheck"))] - { - return Err(PerfCheckError::WrongBuildType.into()) - } - - #[cfg(all(feature = "hostperfcheck", build_type = "release"))] - { - crate::host_perf_check::host_perf_check()?; - return Ok(()) - } -} - /// Launch a node, accepting arguments just like a regular node, /// accepts an alternative overseer generator, to adjust behavior /// for integration tests as needed. @@ -241,9 +195,8 @@ where .map_err(Error::from)?; let chain_spec = &runner.config().chain_spec; - // By default, enable BEEFY on all networks except Polkadot (for now), unless - // explicitly disabled through CLI. - let mut enable_beefy = !chain_spec.is_polkadot() && !cli.run.no_beefy; + // By default, enable BEEFY on all networks, unless explicitly disabled through CLI. + let mut enable_beefy = !cli.run.no_beefy; // BEEFY doesn't (yet) support warp sync: // Until we implement https://github.com/paritytech/substrate/issues/14756 // - disallow warp sync for validators, @@ -471,8 +424,7 @@ pub fn run() -> Result<()> { cmd.run(client.clone()).map_err(Error::SubstrateCli) }), // These commands are very similar and can be handled in nearly the same way. - BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => { - ensure_dev(chain_spec).map_err(Error::Other)?; + BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => runner.sync_run(|mut config| { let (client, _, _, _) = service::new_chain_ops(&mut config, None)?; let header = client.header(client.info().genesis_hash).unwrap().unwrap(); @@ -508,11 +460,9 @@ pub fn run() -> Result<()> { .map_err(Error::SubstrateCli), _ => unreachable!("Ensured by the outside match; qed"), } - }) - }, + }), BenchmarkCmd::Pallet(cmd) => { set_default_ss58_version(chain_spec); - ensure_dev(chain_spec).map_err(Error::Other)?; if cfg!(feature = "runtime-benchmarks") { runner.sync_run(|config| { @@ -538,13 +488,6 @@ pub fn run() -> Result<()> { _ => Err(Error::CommandNotImplemented), } }, - Some(Subcommand::HostPerfCheck) => { - let mut builder = sc_cli::LoggerBuilder::new(""); - builder.with_colors(true); - builder.init()?; - - host_perf_check() - }, Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime) => Err(try_runtime_cli::DEPRECATION_NOTICE.to_owned().into()), diff --git a/polkadot/cli/src/error.rs b/polkadot/cli/src/error.rs index a4591e2508c9796764d09296405bdb05fb834a3c..219289796522e495db1b7170a8efcec9b95a3530 100644 --- a/polkadot/cli/src/error.rs +++ b/polkadot/cli/src/error.rs @@ -28,10 +28,6 @@ pub enum Error { #[error(transparent)] SubstrateTracing(#[from] sc_tracing::logging::Error), - #[error(transparent)] - #[cfg(feature = "hostperfcheck")] - PerfCheck(#[from] polkadot_performance_test::PerfCheckError), - #[cfg(not(feature = "pyroscope"))] #[error("Binary was not compiled with `--feature=pyroscope`")] PyroscopeNotCompiledIn, @@ -58,3 +54,9 @@ pub enum Error { #[error("This subcommand is only available when compiled with `{feature}`")] FeatureNotEnabled { feature: &'static str }, } + +impl From for Error { + fn from(s: String) -> Self { + Self::Other(s) + } +} diff --git a/polkadot/cli/src/host_perf_check.rs b/polkadot/cli/src/host_perf_check.rs deleted file mode 100644 index adfdebce6779bd2d0cd18ad09141bcfa514d2631..0000000000000000000000000000000000000000 --- a/polkadot/cli/src/host_perf_check.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -use log::info; -use polkadot_performance_test::{ - measure_erasure_coding, measure_pvf_prepare, PerfCheckError, ERASURE_CODING_N_VALIDATORS, - ERASURE_CODING_TIME_LIMIT, PVF_PREPARE_TIME_LIMIT, VALIDATION_CODE_BOMB_LIMIT, -}; -use std::time::Duration; - -pub fn host_perf_check() -> Result<(), PerfCheckError> { - let pvf_prepare_time_limit = time_limit_from_baseline(PVF_PREPARE_TIME_LIMIT); - let erasure_coding_time_limit = time_limit_from_baseline(ERASURE_CODING_TIME_LIMIT); - let wasm_code = - polkadot_performance_test::WASM_BINARY.ok_or(PerfCheckError::WasmBinaryMissing)?; - - // Decompress the code before running checks. - let code = sp_maybe_compressed_blob::decompress(wasm_code, VALIDATION_CODE_BOMB_LIMIT) - .or(Err(PerfCheckError::CodeDecompressionFailed))?; - - info!("Running the performance checks..."); - - perf_check("PVF-prepare", pvf_prepare_time_limit, || measure_pvf_prepare(code.as_ref()))?; - - perf_check("Erasure-coding", erasure_coding_time_limit, || { - measure_erasure_coding(ERASURE_CODING_N_VALIDATORS, code.as_ref()) - })?; - - Ok(()) -} - -/// Returns a no-warning threshold for the given time limit. -fn green_threshold(duration: Duration) -> Duration { - duration * 4 / 5 -} - -/// Returns an extended time limit to be used for the actual check. -fn time_limit_from_baseline(duration: Duration) -> Duration { - duration * 3 / 2 -} - -fn perf_check( - test_name: &str, - time_limit: Duration, - test: impl Fn() -> Result, -) -> Result<(), PerfCheckError> { - let elapsed = test()?; - - if elapsed < green_threshold(time_limit) { - info!("🟢 {} performance check passed, elapsed: {:?}", test_name, elapsed); - Ok(()) - } else if elapsed <= time_limit { - info!( - "🟡 {} performance check passed, {:?} limit almost exceeded, elapsed: {:?}", - test_name, time_limit, elapsed - ); - Ok(()) - } else { - Err(PerfCheckError::TimeOut { elapsed, limit: time_limit }) - } -} diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs index 057592fa8a10ea79939b66bad8f6adc2e7476059..35a467146b428e60462ef36f86d65651b03c40ed 100644 --- a/polkadot/cli/src/lib.rs +++ b/polkadot/cli/src/lib.rs @@ -24,8 +24,6 @@ mod cli; mod command; #[cfg(feature = "cli")] mod error; -#[cfg(all(feature = "hostperfcheck", build_type = "release"))] -mod host_perf_check; #[cfg(feature = "service")] pub use service::{self, Block, CoreApi, IdentifyVariant, ProvideRuntimeApi, TFullClient}; diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 27779f3d1acbb8bd05a1b3f63f1d7ebdc92bd895..b8c9c1a36e46b9f4b2e7fcc7d40e2ea68ce8cc7e 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -43,9 +43,8 @@ use polkadot_node_subsystem::{ SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ - request_availability_cores, request_persisted_validation_data, - request_staging_async_backing_params, request_validation_code, request_validation_code_hash, - request_validators, + request_async_backing_params, request_availability_cores, request_persisted_validation_data, + request_validation_code, request_validation_code_hash, request_validators, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, @@ -194,7 +193,7 @@ async fn handle_new_activations( metrics: Metrics, ) -> crate::error::Result<()> { // follow the procedure from the guide: - // https://paritytech.github.io/polkadot/book/node/collators/collation-generation.html + // https://paritytech.github.io/polkadot-sdk/book/node/collators/collation-generation.html if config.collator.is_none() { return Ok(()) @@ -208,7 +207,7 @@ async fn handle_new_activations( let (availability_cores, validators, async_backing_params) = join!( request_availability_cores(relay_parent, ctx.sender()).await, request_validators(relay_parent, ctx.sender()).await, - request_staging_async_backing_params(relay_parent, ctx.sender()).await, + request_async_backing_params(relay_parent, ctx.sender()).await, ); let availability_cores = availability_cores??; diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index da6b343e6aee4715e9bf45eb1a7b25aa056fca3a..9094f40cca8419b608d451c1dc6f09854f53f07c 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -153,7 +153,7 @@ fn requests_availability_per_relay_parent() { } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, - RuntimeApiRequest::StagingAsyncBackingParams( + RuntimeApiRequest::AsyncBackingParams( tx, ), ))) => { @@ -235,7 +235,7 @@ fn requests_validation_data_for_scheduled_matches() { }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, - RuntimeApiRequest::StagingAsyncBackingParams(tx), + RuntimeApiRequest::AsyncBackingParams(tx), ))) => { tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter", @@ -332,7 +332,7 @@ fn sends_distribute_collation_message() { }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, - RuntimeApiRequest::StagingAsyncBackingParams(tx), + RuntimeApiRequest::AsyncBackingParams(tx), ))) => { tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter", @@ -494,7 +494,7 @@ fn fallback_when_no_validation_code_hash_api() { }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, - RuntimeApiRequest::StagingAsyncBackingParams(tx), + RuntimeApiRequest::AsyncBackingParams(tx), ))) => { tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter", diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 4c2fd6becb424033a13d1d1f5b1653cf811c48ad..35d17f3d905e4f342d32cbf195a61cc6feb371fd 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -237,7 +237,7 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == test_state.relay_parent => { tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } @@ -1595,8 +1595,8 @@ fn retry_works() { }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, - RuntimeApiRequest::SessionExecutorParams(sess_idx, tx), - )) if sess_idx == 1 => { + RuntimeApiRequest::SessionExecutorParams(1, tx), + )) => { tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); }, msg => { diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 14f720b721f2612e668fecf295232d1a34a766f3..b79515ed37a6ef590680fb834402f6ed3bef73be 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -20,12 +20,12 @@ use polkadot_node_subsystem::{ messages::{ChainApiMessage, FragmentTreeMembership}, ActivatedLeaf, TimeoutExt, }; -use polkadot_primitives::{vstaging as vstaging_primitives, BlockNumber, Header, OccupiedCore}; +use polkadot_primitives::{AsyncBackingParams, BlockNumber, Header, OccupiedCore}; use super::*; -const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = - vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; +const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; struct TestLeaf { activated: ActivatedLeaf, @@ -56,7 +56,7 @@ async fn activate_leaf( assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == leaf_hash => { tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 3281fcc59a158cc49c07009d43e9de29d42b9d02..21a7121d47bd005b428a4b969f535e0c9f1c7c04 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -44,6 +44,10 @@ use polkadot_parachain_primitives::primitives::{ ValidationParams, ValidationResult as WasmValidationResult, }; use polkadot_primitives::{ + executor_params::{ + DEFAULT_APPROVAL_EXECUTION_TIMEOUT, DEFAULT_BACKING_EXECUTION_TIMEOUT, + DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT, + }, CandidateCommitments, CandidateDescriptor, CandidateReceipt, ExecutorParams, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfExecTimeoutKind, PvfPrepTimeoutKind, ValidationCode, ValidationCodeHash, @@ -83,13 +87,6 @@ const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_secs(3); #[cfg(test)] const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); -// Default PVF timeouts. Must never be changed! Use executor environment parameters in -// `session_info` pallet to adjust them. See also `PvfTimeoutKind` docs. -const DEFAULT_PRECHECK_PREPARATION_TIMEOUT: Duration = Duration::from_secs(60); -const DEFAULT_LENIENT_PREPARATION_TIMEOUT: Duration = Duration::from_secs(360); -const DEFAULT_BACKING_EXECUTION_TIMEOUT: Duration = Duration::from_secs(2); -const DEFAULT_APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12); - /// Configuration for the candidate validation subsystem #[derive(Clone)] pub struct Config { diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 9cd544a8c5362ea25c30d1ed1fc21c38bd24458e..e44530b3f1bbab0995f850af7e951984bd1dc55b 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -43,7 +43,7 @@ use polkadot_node_subsystem_util::runtime::{ self, key_ownership_proof, submit_report_dispute_lost, RuntimeInfo, }; use polkadot_primitives::{ - vstaging, BlockNumber, CandidateHash, CandidateReceipt, CompactStatement, DisputeStatement, + slashing, BlockNumber, CandidateHash, CandidateReceipt, CompactStatement, DisputeStatement, DisputeStatementSet, Hash, ScrapedOnChainVotes, SessionIndex, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, }; @@ -385,7 +385,7 @@ impl Initialized { &mut self, ctx: &mut Context, relay_parent: Hash, - unapplied_slashes: Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>, + unapplied_slashes: Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>, ) { for (session_index, candidate_hash, pending) in unapplied_slashes { gum::info!( @@ -422,11 +422,9 @@ impl Initialized { match res { Ok(Some(key_ownership_proof)) => { key_ownership_proofs.push(key_ownership_proof); - let time_slot = vstaging::slashing::DisputesTimeSlot::new( - session_index, - candidate_hash, - ); - let dispute_proof = vstaging::slashing::DisputeProof { + let time_slot = + slashing::DisputesTimeSlot::new(session_index, candidate_hash); + let dispute_proof = slashing::DisputeProof { time_slot, kind: pending.kind, validator_index: *validator_index, diff --git a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs index ed2988fcb39f2be0768b1d9c0cb927689223e955..292e4ebe5282b4344853ca5f3247caf1d9af6cc7 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs @@ -96,10 +96,10 @@ use std::{ use super::LOG_TARGET; use bitvec::prelude::*; -use polkadot_node_subsystem_util::inclusion_emulator::staging::{ +use polkadot_node_subsystem_util::inclusion_emulator::{ ConstraintModifications, Constraints, Fragment, ProspectiveCandidate, RelayChainBlockInfo, }; -use polkadot_primitives::vstaging::{ +use polkadot_primitives::{ BlockNumber, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, PersistedValidationData, }; @@ -981,10 +981,8 @@ impl FragmentNode { mod tests { use super::*; use assert_matches::assert_matches; - use polkadot_node_subsystem_util::inclusion_emulator::staging::InboundHrmpLimitations; - use polkadot_primitives::vstaging::{ - BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData, - }; + 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( diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index 6e5844a62a16b2387dc9bc7c3d515102fe0828e8..fcca0dd0b536ba69d27805ae1cf37b54d834fd02 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -22,7 +22,7 @@ //! backing phases of parachain consensus. //! //! This is primarily an implementation of "Fragment Trees", as described in -//! [`polkadot_node_subsystem_util::inclusion_emulator::staging`]. +//! [`polkadot_node_subsystem_util::inclusion_emulator`]. //! //! This subsystem also handles concerns such as the relay-chain being forkful and session changes. @@ -42,13 +42,14 @@ use polkadot_node_subsystem::{ overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ - inclusion_emulator::staging::{Constraints, RelayChainBlockInfo}, + inclusion_emulator::{Constraints, RelayChainBlockInfo}, request_session_index_for_child, runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, }; -use polkadot_primitives::vstaging::{ - BlockNumber, CandidateHash, CandidatePendingAvailability, CommittedCandidateReceipt, CoreState, - Hash, HeadData, Header, Id as ParaId, PersistedValidationData, +use polkadot_primitives::{ + async_backing::CandidatePendingAvailability, BlockNumber, CandidateHash, + CommittedCandidateReceipt, CoreState, Hash, HeadData, Header, Id as ParaId, + PersistedValidationData, }; use crate::{ @@ -792,7 +793,7 @@ async fn fetch_backing_state( let (tx, rx) = oneshot::channel(); ctx.send_message(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::StagingParaBackingState(para_id, tx), + RuntimeApiRequest::ParaBackingState(para_id, tx), )) .await; diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index eb12ea4537f745c2241865c3d3af7a1d4150105b..d2cd23fe95fc1d8638238c8e30b5227da7e883a0 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -25,7 +25,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - vstaging::{AsyncBackingParams, BackingState, Constraints, InboundHrmpLimitations}, + async_backing::{AsyncBackingParams, BackingState, Constraints, InboundHrmpLimitations}, CommittedCandidateReceipt, HeadData, Header, PersistedValidationData, ScheduledCore, ValidationCodeHash, }; @@ -219,7 +219,7 @@ async fn handle_leaf_activation( assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == *hash => { tx.send(Ok(async_backing_params)).unwrap(); } @@ -284,7 +284,7 @@ async fn handle_leaf_activation( let para_id = match message { AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, - RuntimeApiRequest::StagingParaBackingState(p_id, _), + RuntimeApiRequest::ParaBackingState(p_id, _), )) => p_id, _ => panic!("received unexpected message {:?}", message), }; @@ -303,7 +303,7 @@ async fn handle_leaf_activation( assert_matches!( message, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingParaBackingState(p_id, tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx)) ) if parent == *hash && p_id == para_id => { tx.send(Ok(Some(backing_state))).unwrap(); } @@ -499,7 +499,7 @@ fn should_do_no_work_if_async_backing_disabled_for_leaf() { assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == hash => { tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } @@ -1569,7 +1569,7 @@ fn uses_ancestry_only_within_session() { assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == hash => { tx.send(Ok(AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: ancestry_len })).unwrap(); } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 478d1952d9d9168080cdd14917b25cd051495a60..27f4df117e578ebb8f86dd5eb6570af0b247492b 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true [dependencies] always-assert = "0.1" +cfg-if = "1.0" futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 621f7e24f72bef8650337a05372b1075054d4964..4bdacca72f4208079bd4f810f71c2af15991cb3a 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -7,6 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] +cfg-if = "1.0" cpu-time = "1.0.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } @@ -28,7 +29,7 @@ sp-io = { path = "../../../../../substrate/primitives/io" } sp-tracing = { path = "../../../../../substrate/primitives/tracing" } [target.'cfg(target_os = "linux")'.dependencies] -landlock = "0.2.0" +landlock = "0.3.0" [dev-dependencies] assert_matches = "1.4.0" diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index 6eb0d9b7df42f7a25414d5d834a2b3e10d1bfa3a..6fdd06057c8b021cc89b29eb0265c78e316eed02 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -44,7 +44,17 @@ pub enum PrepareError { /// The response from the worker is received, but the file cannot be renamed (moved) to the /// final destination location. This state is reported by the validation host (not by the /// worker). - RenameTmpFileErr(String), + RenameTmpFileErr { + err: String, + // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible + // conversion to `Option`. + src: Option, + dest: Option, + }, + /// The response from the worker is received, but the worker cache could not be cleared. The + /// worker has to be killed to avoid jobs having access to data from other jobs. This state is + /// reported by the validation host (not by the worker). + ClearWorkerDir(String), } impl PrepareError { @@ -58,7 +68,11 @@ impl PrepareError { use PrepareError::*; match self { Prevalidation(_) | Preparation(_) | Panic(_) => true, - TimedOut | IoErr(_) | CreateTmpFileErr(_) | RenameTmpFileErr(_) => false, + TimedOut | + IoErr(_) | + CreateTmpFileErr(_) | + RenameTmpFileErr { .. } | + ClearWorkerDir(_) => false, // Can occur due to issues with the PVF, but also due to local errors. RuntimeConstruction(_) => false, } @@ -76,7 +90,9 @@ impl fmt::Display for PrepareError { TimedOut => write!(f, "prepare: timeout"), IoErr(err) => write!(f, "prepare: io error while receiving response: {}", err), CreateTmpFileErr(err) => write!(f, "prepare: error creating tmp file: {}", err), - RenameTmpFileErr(err) => write!(f, "prepare: error renaming tmp file: {}", err), + RenameTmpFileErr { err, src, dest } => + write!(f, "prepare: error renaming tmp file ({:?} -> {:?}): {}", src, dest, err), + ClearWorkerDir(err) => write!(f, "prepare: error clearing worker cache: {}", err), } } } @@ -89,8 +105,17 @@ impl fmt::Display for PrepareError { pub enum InternalValidationError { /// Some communication error occurred with the host. HostCommunication(String), + /// Host could not create a hard link to the artifact path. + CouldNotCreateLink(String), /// Could not find or open compiled artifact file. CouldNotOpenFile(String), + /// Host could not clear the worker cache after a job. + CouldNotClearWorkerDir { + err: String, + // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible + // conversion to `Option`. + path: Option, + }, /// An error occurred in the CPU time monitor thread. Should be totally unrelated to /// validation. CpuTimeMonitorThread(String), @@ -104,8 +129,18 @@ impl fmt::Display for InternalValidationError { match self { HostCommunication(err) => write!(f, "validation: some communication error occurred with the host: {}", err), + CouldNotCreateLink(err) => write!( + f, + "validation: host could not create a hard link to the artifact path: {}", + err + ), CouldNotOpenFile(err) => write!(f, "validation: could not find or open compiled artifact file: {}", err), + CouldNotClearWorkerDir { err, path } => write!( + f, + "validation: host could not clear the worker cache ({:?}) after a job: {}", + path, err + ), CpuTimeMonitorThread(err) => write!(f, "validation: an error occurred in the CPU time monitor thread: {}", err), NonDeterministicPrepareError(err) => write!(f, "validation: prepare: {}", err), diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index 399b847791a91e616c6ae6589dae9ce5fef2cdf9..b89ab089af1c02eba401517e8248c292dd7040f8 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -29,7 +29,7 @@ pub struct Handshake { } /// The response from an execution job on the worker. -#[derive(Encode, Decode)] +#[derive(Debug, Encode, Decode)] pub enum Response { /// The job completed successfully. Ok { diff --git a/polkadot/node/core/pvf/common/src/executor_intf.rs b/polkadot/node/core/pvf/common/src/executor_intf.rs index 79839149ebdf1c09b80b346d31ba0ebf9dc6e299..58d2a90371cf42508a98501d11be15453ba52db9 100644 --- a/polkadot/node/core/pvf/common/src/executor_intf.rs +++ b/polkadot/node/core/pvf/common/src/executor_intf.rs @@ -16,7 +16,10 @@ //! Interface to the Substrate Executor -use polkadot_primitives::{ExecutorParam, ExecutorParams}; +use polkadot_primitives::{ + executor_params::{DEFAULT_LOGICAL_STACK_MAX, DEFAULT_NATIVE_STACK_MAX}, + ExecutorParam, ExecutorParams, +}; use sc_executor_common::{ error::WasmError, runtime_blob::RuntimeBlob, @@ -42,9 +45,6 @@ use std::any::{Any, TypeId}; const DEFAULT_HEAP_PAGES_ESTIMATE: u32 = 32; const EXTRA_HEAP_PAGES: u32 = 2048; -/// The number of bytes devoted for the stack during wasm execution of a PVF. -pub const NATIVE_STACK_MAX: u32 = 256 * 1024 * 1024; - // VALUES OF THE DEFAULT CONFIGURATION SHOULD NEVER BE CHANGED // They are used as base values for the execution environment parametrization. // To overwrite them, add new ones to `EXECUTOR_PARAMS` in the `session_info` pallet and perform @@ -73,8 +73,8 @@ pub const DEFAULT_CONFIG: Config = Config { // also increase the native 256x. This hopefully should preclude wasm code from reaching // the stack limit set by the wasmtime. deterministic_stack_limit: Some(DeterministicStackLimit { - logical_max: 65536, - native_stack_max: NATIVE_STACK_MAX, + logical_max: DEFAULT_LOGICAL_STACK_MAX, + native_stack_max: DEFAULT_NATIVE_STACK_MAX, }), canonicalize_nans: true, // Rationale for turning the multi-threaded compilation off is to make the preparation time @@ -95,6 +95,60 @@ pub const DEFAULT_CONFIG: Config = Config { }, }; +/// Executes the given PVF in the form of a compiled artifact and returns the result of +/// execution upon success. +/// +/// # Safety +/// +/// The caller must ensure that the compiled artifact passed here was: +/// 1) produced by `prepare`, +/// 2) was not modified, +/// +/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. +pub unsafe fn execute_artifact( + compiled_artifact_blob: &[u8], + executor_params: &ExecutorParams, + params: &[u8], +) -> Result, String> { + let mut extensions = sp_externalities::Extensions::new(); + + extensions.register(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion)); + + let mut ext = ValidationExternalities(extensions); + + match sc_executor::with_externalities_safe(&mut ext, || { + let runtime = create_runtime_from_artifact_bytes(compiled_artifact_blob, executor_params)?; + runtime.new_instance()?.call(InvokeMethod::Export("validate_block"), params) + }) { + Ok(Ok(ok)) => Ok(ok), + Ok(Err(err)) | Err(err) => Err(err), + } + .map_err(|err| format!("execute error: {:?}", err)) +} + +/// Constructs the runtime for the given PVF, given the artifact bytes. +/// +/// # Safety +/// +/// The caller must ensure that the compiled artifact passed here was: +/// 1) produced by `prepare`, +/// 2) was not modified, +/// +/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. +pub unsafe fn create_runtime_from_artifact_bytes( + compiled_artifact_blob: &[u8], + executor_params: &ExecutorParams, +) -> Result { + let mut config = DEFAULT_CONFIG.clone(); + config.semantics = + params_to_wasmtime_semantics(executor_params).map_err(|err| WasmError::Other(err))?; + + sc_executor_wasmtime::create_runtime_from_artifact_bytes::( + compiled_artifact_blob, + config, + ) +} + pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result { let mut sem = DEFAULT_CONFIG.semantics.clone(); let mut stack_limit = if let Some(stack_limit) = sem.deterministic_stack_limit.clone() { @@ -106,8 +160,9 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result - sem.heap_alloc_strategy = - HeapAllocStrategy::Dynamic { maximum_pages: Some(*max_pages) }, + sem.heap_alloc_strategy = HeapAllocStrategy::Dynamic { + maximum_pages: Some((*max_pages).saturating_add(DEFAULT_HEAP_PAGES_ESTIMATE)), + }, ExecutorParam::StackLogicalMax(slm) => stack_limit.logical_max = *slm, ExecutorParam::StackNativeMax(snm) => stack_limit.native_stack_max = *snm, ExecutorParam::WasmExtBulkMemory => sem.wasm_bulk_memory = true, @@ -120,72 +175,6 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result Result { - let mut config = DEFAULT_CONFIG.clone(); - config.semantics = params_to_wasmtime_semantics(¶ms)?; - - Ok(Self { config }) - } - - /// Executes the given PVF in the form of a compiled artifact and returns the result of - /// execution upon success. - /// - /// # Safety - /// - /// The caller must ensure that the compiled artifact passed here was: - /// 1) produced by `prepare`, - /// 2) was not modified, - /// - /// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. - pub unsafe fn execute( - &self, - compiled_artifact_blob: &[u8], - params: &[u8], - ) -> Result, String> { - let mut extensions = sp_externalities::Extensions::new(); - - extensions.register(sp_core::traits::ReadRuntimeVersionExt::new(ReadRuntimeVersion)); - - let mut ext = ValidationExternalities(extensions); - - match sc_executor::with_externalities_safe(&mut ext, || { - let runtime = self.create_runtime_from_bytes(compiled_artifact_blob)?; - runtime.new_instance()?.call(InvokeMethod::Export("validate_block"), params) - }) { - Ok(Ok(ok)) => Ok(ok), - Ok(Err(err)) | Err(err) => Err(err), - } - .map_err(|err| format!("execute error: {:?}", err)) - } - - /// Constructs the runtime for the given PVF, given the artifact bytes. - /// - /// # Safety - /// - /// The caller must ensure that the compiled artifact passed here was: - /// 1) produced by `prepare`, - /// 2) was not modified, - /// - /// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. - pub unsafe fn create_runtime_from_bytes( - &self, - compiled_artifact_blob: &[u8], - ) -> Result { - sc_executor_wasmtime::create_runtime_from_artifact_bytes::( - compiled_artifact_blob, - self.config.clone(), - ) - } -} - /// Available host functions. We leave out: /// /// 1. storage related stuff (PVF doesn't have a notion of a persistent storage/trie) diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index c358ad6e134de50367bb2941b0b12d91e8dcb21f..53c287ea970907cb8884ec47c74bd4e03e38d7e7 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -22,6 +22,7 @@ pub mod executor_intf; pub mod prepare; pub mod pvf; pub mod worker; +pub mod worker_dir; pub use cpu_time::ProcessTime; @@ -30,8 +31,11 @@ pub use sp_tracing; const LOG_TARGET: &str = "parachain::pvf-common"; -use std::mem; -use tokio::io::{self, AsyncRead, AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _}; +use std::{ + io::{Read, Write}, + mem, +}; +use tokio::io; #[cfg(feature = "test-utils")] pub mod tests { @@ -41,20 +45,31 @@ pub mod tests { pub const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); } -/// Write some data prefixed by its length into `w`. -pub async fn framed_send(w: &mut (impl AsyncWrite + Unpin), buf: &[u8]) -> io::Result<()> { +/// Status of security features on the current system. +#[derive(Debug, Clone, Default)] +pub struct SecurityStatus { + /// Whether the landlock features we use are fully available on this system. + pub can_enable_landlock: bool, + // Whether we are able to unshare the user namespace and change the filesystem root. + pub can_unshare_user_namespace_and_change_root: bool, +} + +/// Write some data prefixed by its length into `w`. Sync version of `framed_send` to avoid +/// dependency on tokio. +pub fn framed_send_blocking(w: &mut (impl Write + Unpin), buf: &[u8]) -> io::Result<()> { let len_buf = buf.len().to_le_bytes(); - w.write_all(&len_buf).await?; - w.write_all(buf).await?; + w.write_all(&len_buf)?; + w.write_all(buf)?; Ok(()) } -/// Read some data prefixed by its length from `r`. -pub async fn framed_recv(r: &mut (impl AsyncRead + Unpin)) -> io::Result> { +/// Read some data prefixed by its length from `r`. Sync version of `framed_recv` to avoid +/// dependency on tokio. +pub fn framed_recv_blocking(r: &mut (impl Read + Unpin)) -> io::Result> { let mut len_buf = [0u8; mem::size_of::()]; - r.read_exact(&mut len_buf).await?; + r.read_exact(&mut len_buf)?; let len = usize::from_le_bytes(len_buf); let mut buf = vec![0; len]; - r.read_exact(&mut buf).await?; + r.read_exact(&mut buf)?; Ok(buf) } diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index bcdf882f300c09c14c54e6f5b3cbc131f600c3a4..d0bd5b6bd7c56495efa8fe64730e9fadba9c066b 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -18,16 +18,18 @@ pub mod security; -use crate::LOG_TARGET; +use crate::{SecurityStatus, LOG_TARGET}; use cpu_time::ProcessTime; use futures::never::Never; use std::{ any::Any, + fmt, + os::unix::net::UnixStream, path::PathBuf, sync::mpsc::{Receiver, RecvTimeoutError}, time::Duration, }; -use tokio::{io, net::UnixStream, runtime::Runtime}; +use tokio::{io, runtime::Runtime}; /// Use this macro to declare a `fn main() {}` that will create an executable that can be used for /// spawning the desired worker. @@ -41,10 +43,15 @@ macro_rules! decl_worker_main { } fn main() { + #[cfg(target_os = "linux")] + use $crate::worker::security; + // TODO: Remove this dependency, and `pub use sp_tracing` in `lib.rs`. // See . $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); @@ -60,10 +67,43 @@ macro_rules! decl_worker_main { println!("{}", $worker_version); return }, + + "--check-can-enable-landlock" => { + #[cfg(target_os = "linux")] + let status = if security::landlock::check_is_fully_enabled() { 0 } else { -1 }; + #[cfg(not(target_os = "linux"))] + let status = -1; + std::process::exit(status) + }, + "--check-can-unshare-user-namespace-and-change-root" => { + #[cfg(target_os = "linux")] + let status = if let Err(err) = security::unshare_user_namespace_and_change_root( + $crate::worker::WorkerKind::CheckPivotRoot, + worker_pid, + // We're not accessing any files, so we can try to pivot_root in the temp + // dir without conflicts with other processes. + &std::env::temp_dir(), + ) { + // Write the error to stderr, log it on the host-side. + eprintln!("{}", err); + -1 + } else { + 0 + }; + #[cfg(not(target_os = "linux"))] + let status = { + // Write the error to stderr, log it on the host-side. + eprintln!("not available on macos"); + -1 + }; + std::process::exit(status) + }, + "test-sleep" => { std::thread::sleep(std::time::Duration::from_secs(5)); return }, + subcommand => { // Must be passed for compatibility with the single-binary test workers. if subcommand != $expected_command { @@ -75,18 +115,52 @@ macro_rules! decl_worker_main { }, } + let mut socket_path = None; + let mut worker_dir_path = None; let mut node_version = None; - let mut socket_path: &str = ""; + let mut can_enable_landlock = false; + let mut can_unshare_user_namespace_and_change_root = false; - for i in (2..args.len()).step_by(2) { + let mut i = 2; + while i < args.len() { match args[i].as_ref() { - "--socket-path" => socket_path = args[i + 1].as_str(), - "--node-impl-version" => node_version = Some(args[i + 1].as_str()), + "--socket-path" => { + socket_path = Some(args[i + 1].as_str()); + i += 1 + }, + "--worker-dir-path" => { + worker_dir_path = Some(args[i + 1].as_str()); + i += 1 + }, + "--node-impl-version" => { + node_version = Some(args[i + 1].as_str()); + i += 1 + }, + "--can-enable-landlock" => can_enable_landlock = true, + "--can-unshare-user-namespace-and-change-root" => + can_unshare_user_namespace_and_change_root = true, arg => panic!("Unexpected argument found: {}", arg), } + i += 1; } - - $entrypoint(&socket_path, node_version, Some($worker_version)); + let socket_path = socket_path.expect("the --socket-path argument is required"); + let worker_dir_path = + worker_dir_path.expect("the --worker-dir-path argument is required"); + + let socket_path = std::path::Path::new(socket_path).to_owned(); + let worker_dir_path = std::path::Path::new(worker_dir_path).to_owned(); + let security_status = $crate::SecurityStatus { + can_enable_landlock, + can_unshare_user_namespace_and_change_root, + }; + + $entrypoint( + socket_path, + worker_dir_path, + node_version, + Some($worker_version), + security_status, + ); } }; } @@ -95,61 +169,180 @@ macro_rules! decl_worker_main { /// child process. pub const JOB_TIMEOUT_OVERHEAD: Duration = Duration::from_millis(50); -/// Interprets the given bytes as a path. Returns `None` if the given bytes do not constitute a -/// a proper utf-8 string. -pub fn bytes_to_path(bytes: &[u8]) -> Option { - std::str::from_utf8(bytes).ok().map(PathBuf::from) +#[derive(Debug, Clone, Copy)] +pub enum WorkerKind { + Prepare, + Execute, + CheckPivotRoot, +} + +impl fmt::Display for WorkerKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Prepare => write!(f, "prepare"), + Self::Execute => write!(f, "execute"), + Self::CheckPivotRoot => write!(f, "check pivot root"), + } + } } // The worker version must be passed in so that we accurately get the version of the worker, and not // the version that this crate was compiled with. pub fn worker_event_loop( - debug_id: &'static str, - socket_path: &str, + worker_kind: WorkerKind, + socket_path: PathBuf, + #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] mut worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] security_status: &SecurityStatus, mut event_loop: F, ) where - F: FnMut(UnixStream) -> Fut, + F: FnMut(UnixStream, PathBuf) -> Fut, Fut: futures::Future>, { let worker_pid = std::process::id(); - gum::debug!(target: LOG_TARGET, %worker_pid, "starting pvf worker ({})", debug_id); + gum::debug!( + target: LOG_TARGET, + %worker_pid, + ?socket_path, + ?worker_dir_path, + ?security_status, + "starting pvf worker ({})", + worker_kind + ); // Check for a mismatch between the node and worker versions. if let (Some(node_version), Some(worker_version)) = (node_version, worker_version) { if node_version != worker_version { gum::error!( target: LOG_TARGET, + %worker_kind, %worker_pid, %node_version, %worker_version, "Node and worker version mismatch, node needs restarting, forcing shutdown", ); kill_parent_node_in_emergency(); - let err = io::Error::new(io::ErrorKind::Unsupported, "Version mismatch"); - worker_shutdown_message(debug_id, worker_pid, err); + worker_shutdown_message(worker_kind, worker_pid, "Version mismatch"); return } } - remove_env_vars(debug_id); + // Make sure that we can read the worker dir path, and log its contents. + let entries = || -> Result, io::Error> { + std::fs::read_dir(&worker_dir_path)? + .map(|res| res.map(|e| e.file_name())) + .collect() + }(); + match entries { + Ok(entries) => + gum::trace!(target: LOG_TARGET, %worker_pid, ?worker_dir_path, "content of worker dir: {:?}", entries), + Err(err) => { + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "Could not read worker dir: {}", + err.to_string() + ); + worker_shutdown_message(worker_kind, worker_pid, &err.to_string()); + return + }, + } + + // Connect to the socket. + let stream = || -> std::io::Result { + let stream = UnixStream::connect(&socket_path)?; + let _ = std::fs::remove_file(&socket_path); + Ok(stream) + }(); + let stream = match stream { + Ok(s) => s, + Err(err) => { + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + "{}", + err + ); + worker_shutdown_message(worker_kind, worker_pid, &err.to_string()); + return + }, + }; + + // Enable some security features. + { + // Call based on whether we can change root. Error out if it should work but fails. + // + // NOTE: This should not be called in a multi-threaded context (i.e. inside the tokio + // runtime). `unshare(2)`: + // + // > CLONE_NEWUSER requires that the calling process is not threaded. + #[cfg(target_os = "linux")] + if security_status.can_unshare_user_namespace_and_change_root { + if let Err(err) = security::unshare_user_namespace_and_change_root( + worker_kind, + worker_pid, + &worker_dir_path, + ) { + // The filesystem may be in an inconsistent state, bail out. + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "Could not change root to be the worker cache path: {}", + err + ); + worker_shutdown_message(worker_kind, worker_pid, &err); + return + } + worker_dir_path = std::path::Path::new("/").to_owned(); + } + + #[cfg(target_os = "linux")] + if security_status.can_enable_landlock { + let landlock_status = + security::landlock::enable_for_worker(worker_kind, worker_pid, &worker_dir_path); + if !matches!(landlock_status, Ok(landlock::RulesetStatus::FullyEnforced)) { + // We previously were able to enable, so this should never happen. + // + // TODO: Make this a real error in secure-mode. See: + // + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + "could not fully enable landlock: {:?}. This should not happen, please report to the Polkadot devs", + landlock_status + ); + } + } + + if !security::check_env_vars_were_cleared(worker_kind, worker_pid) { + let err = "not all env vars were cleared when spawning the process"; + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + "{}", + err + ); + worker_shutdown_message(worker_kind, worker_pid, err); + return + } + } // Run the main worker loop. let rt = Runtime::new().expect("Creates tokio runtime. If this panics the worker will die and the host will detect that and deal with it."); let err = rt - .block_on(async move { - let stream = UnixStream::connect(socket_path).await?; - let _ = tokio::fs::remove_file(socket_path).await; - - let result = event_loop(stream).await; - - result - }) + .block_on(event_loop(stream, worker_dir_path)) // It's never `Ok` because it's `Ok(Never)`. .unwrap_err(); - worker_shutdown_message(debug_id, worker_pid, err); + worker_shutdown_message(worker_kind, worker_pid, &err.to_string()); // We don't want tokio to wait for the tasks to finish. We want to bring down the worker as fast // as possible and not wait for stalled validation to finish. This isn't strictly necessary now, @@ -157,51 +350,9 @@ pub fn worker_event_loop( rt.shutdown_background(); } -/// Delete all env vars to prevent malicious code from accessing them. -fn remove_env_vars(debug_id: &'static str) { - for (key, value) in std::env::vars_os() { - // TODO: *theoretically* the value (or mere presence) of `RUST_LOG` can be a source of - // randomness for malicious code. In the future we can remove it also and log in the host; - // see . - if key == "RUST_LOG" { - continue - } - - // In case of a key or value that would cause [`env::remove_var` to - // panic](https://doc.rust-lang.org/std/env/fn.remove_var.html#panics), we first log a - // warning and then proceed to attempt to remove the env var. - let mut err_reasons = vec![]; - let (key_str, value_str) = (key.to_str(), value.to_str()); - if key.is_empty() { - err_reasons.push("key is empty"); - } - if key_str.is_some_and(|s| s.contains('=')) { - err_reasons.push("key contains '='"); - } - if key_str.is_some_and(|s| s.contains('\0')) { - err_reasons.push("key contains null character"); - } - if value_str.is_some_and(|s| s.contains('\0')) { - err_reasons.push("value contains null character"); - } - if !err_reasons.is_empty() { - gum::warn!( - target: LOG_TARGET, - %debug_id, - ?key, - ?value, - "Attempting to remove badly-formatted env var, this may cause the PVF worker to crash. Please remove it yourself. Reasons: {:?}", - err_reasons - ); - } - - std::env::remove_var(key); - } -} - /// Provide a consistent message on worker shutdown. -fn worker_shutdown_message(debug_id: &'static str, worker_pid: u32, err: io::Error) { - gum::debug!(target: LOG_TARGET, %worker_pid, "quitting pvf worker ({}): {:?}", debug_id, err); +fn worker_shutdown_message(worker_kind: WorkerKind, worker_pid: u32, err: &str) { + gum::debug!(target: LOG_TARGET, %worker_pid, "quitting pvf worker ({}): {}", worker_kind, err); } /// Loop that runs in the CPU time monitor thread on prepare and execute jobs. Continuously wakes up @@ -305,7 +456,7 @@ pub mod thread { Arc::new((Mutex::new(WaitOutcome::Pending), Condvar::new())) } - /// Runs a worker thread. Will first enable security features, and afterwards notify the threads + /// Runs a worker thread. Will run the requested function, and afterwards notify the threads /// waiting on the condvar. Catches panics during execution and resumes the panics after /// triggering the condvar, so that the waiting thread is notified on panics. /// diff --git a/polkadot/node/core/pvf/common/src/worker/security.rs b/polkadot/node/core/pvf/common/src/worker/security.rs index 6c5f96e0b5dbb3289dc237c91cc003e3b2aa37c5..1b7614177448539f4263022c757d3eba4557ecac 100644 --- a/polkadot/node/core/pvf/common/src/worker/security.rs +++ b/polkadot/node/core/pvf/common/src/worker/security.rs @@ -17,30 +17,189 @@ //! Functionality for securing workers. //! //! This is needed because workers are used to compile and execute untrusted code (PVFs). +//! +//! We currently employ the following security measures: +//! +//! - Restrict filesystem +//! - Use Landlock to remove all unnecessary FS access rights. +//! - Unshare the user and mount namespaces. +//! - Change the root directory to a worker-specific temporary directory. +//! - Remove env vars + +use crate::{worker::WorkerKind, LOG_TARGET}; + +/// Unshare the user namespace and change root to be the artifact directory. +/// +/// NOTE: This should not be called in a multi-threaded context. `unshare(2)`: +/// "CLONE_NEWUSER requires that the calling process is not threaded." +#[cfg(target_os = "linux")] +pub fn unshare_user_namespace_and_change_root( + worker_kind: WorkerKind, + worker_pid: u32, + worker_dir_path: &std::path::Path, +) -> Result<(), String> { + use std::{env, ffi::CString, os::unix::ffi::OsStrExt, path::Path, ptr}; + + // The following was copied from the `cstr_core` crate. + // + // TODO: Remove this once this is stable: https://github.com/rust-lang/rust/issues/105723 + #[inline] + #[doc(hidden)] + const fn cstr_is_valid(bytes: &[u8]) -> bool { + if bytes.is_empty() || bytes[bytes.len() - 1] != 0 { + return false + } + + let mut index = 0; + while index < bytes.len() - 1 { + if bytes[index] == 0 { + return false + } + index += 1; + } + true + } + + macro_rules! cstr { + ($e:expr) => {{ + const STR: &[u8] = concat!($e, "\0").as_bytes(); + const STR_VALID: bool = cstr_is_valid(STR); + let _ = [(); 0 - (!(STR_VALID) as usize)]; + #[allow(unused_unsafe)] + unsafe { + core::ffi::CStr::from_bytes_with_nul_unchecked(STR) + } + }} + } + + gum::debug!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "unsharing the user namespace and calling pivot_root", + ); + + let worker_dir_path_c = CString::new(worker_dir_path.as_os_str().as_bytes()) + .expect("on unix; the path will never contain 0 bytes; qed"); + + // Wrapper around all the work to prevent repetitive error handling. + // + // # Errors + // + // It's the caller's responsibility to call `Error::last_os_error`. Note that that alone does + // not give the context of which call failed, so we return a &str error. + || -> Result<(), &'static str> { + // SAFETY: We pass null-terminated C strings and use the APIs as documented. In fact, steps + // (2) and (3) are adapted from the example in pivot_root(2), with the additional + // change described in the `pivot_root(".", ".")` section. + unsafe { + // 1. `unshare` the user and the mount namespaces. + if libc::unshare(libc::CLONE_NEWUSER | libc::CLONE_NEWNS) < 0 { + return Err("unshare user and mount namespaces") + } + + // 2. Setup mounts. + // + // Ensure that new root and its parent mount don't have shared propagation (which would + // cause pivot_root() to return an error), and prevent propagation of mount events to + // the initial mount namespace. + if libc::mount( + ptr::null(), + cstr!("/").as_ptr(), + ptr::null(), + libc::MS_REC | libc::MS_PRIVATE, + ptr::null(), + ) < 0 + { + return Err("mount MS_PRIVATE") + } + // Ensure that the new root is a mount point. + let additional_flags = + if let WorkerKind::Execute | WorkerKind::CheckPivotRoot = worker_kind { + libc::MS_RDONLY + } else { + 0 + }; + if libc::mount( + worker_dir_path_c.as_ptr(), + worker_dir_path_c.as_ptr(), + ptr::null(), // ignored when MS_BIND is used + libc::MS_BIND | + libc::MS_REC | libc::MS_NOEXEC | + libc::MS_NODEV | libc::MS_NOSUID | + libc::MS_NOATIME | additional_flags, + ptr::null(), // ignored when MS_BIND is used + ) < 0 + { + return Err("mount MS_BIND") + } -/// To what degree landlock is enabled. It's a separate struct from `RulesetStatus` because that is -/// only available on Linux, plus this has a nicer name. -pub enum LandlockStatus { - FullyEnforced, - PartiallyEnforced, - NotEnforced, - /// Thread panicked, we don't know what the status is. - Unavailable, + // 3. `pivot_root` to the artifact directory. + if libc::chdir(worker_dir_path_c.as_ptr()) < 0 { + return Err("chdir to worker dir path") + } + if libc::syscall(libc::SYS_pivot_root, cstr!(".").as_ptr(), cstr!(".").as_ptr()) < 0 { + return Err("pivot_root") + } + if libc::umount2(cstr!(".").as_ptr(), libc::MNT_DETACH) < 0 { + return Err("umount the old root mount point") + } + } + + Ok(()) + }() + .map_err(|err_ctx| { + let err = std::io::Error::last_os_error(); + format!("{}: {}", err_ctx, err) + })?; + + // Do some assertions. + if env::current_dir().map_err(|err| err.to_string())? != Path::new("/") { + return Err("expected current dir after pivot_root to be `/`".into()) + } + env::set_current_dir("..").map_err(|err| err.to_string())?; + if env::current_dir().map_err(|err| err.to_string())? != Path::new("/") { + return Err("expected not to be able to break out of new root by doing `..`".into()) + } + + Ok(()) } -impl LandlockStatus { - #[cfg(target_os = "linux")] - pub fn from_ruleset_status(ruleset_status: ::landlock::RulesetStatus) -> Self { - use ::landlock::RulesetStatus::*; - match ruleset_status { - FullyEnforced => LandlockStatus::FullyEnforced, - PartiallyEnforced => LandlockStatus::PartiallyEnforced, - NotEnforced => LandlockStatus::NotEnforced, +/// Require env vars to have been removed when spawning the process, to prevent malicious code from +/// accessing them. +pub fn check_env_vars_were_cleared(worker_kind: WorkerKind, worker_pid: u32) -> bool { + let mut ok = true; + + for (key, value) in std::env::vars_os() { + // TODO: *theoretically* the value (or mere presence) of `RUST_LOG` can be a source of + // randomness for malicious code. In the future we can remove it also and log in the host; + // see . + if key == "RUST_LOG" { + continue + } + // An exception for MacOS. This is not a secure platform anyway, so we let it slide. + #[cfg(target_os = "macos")] + if key == "__CF_USER_TEXT_ENCODING" { + continue } + + gum::error!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?key, + ?value, + "env var was present that should have been removed", + ); + + ok = false; } + + ok } -/// The [landlock] docs say it best: +/// The [landlock] docs say it best: /// /// > "Landlock is a security feature available since Linux 5.13. The goal is to enable to restrict /// ambient rights (e.g., global filesystem access) for a set of processes by creating safe security @@ -52,18 +211,34 @@ impl LandlockStatus { /// [landlock]: https://docs.rs/landlock/latest/landlock/index.html #[cfg(target_os = "linux")] pub mod landlock { - use landlock::{Access, AccessFs, Ruleset, RulesetAttr, RulesetError, RulesetStatus, ABI}; + pub use landlock::RulesetStatus; + + use crate::{worker::WorkerKind, LOG_TARGET}; + use landlock::*; + use std::{ + fmt, + path::{Path, PathBuf}, + }; /// Landlock ABI version. We use ABI V1 because: /// /// 1. It is supported by our reference kernel version. - /// 2. Later versions do not (yet) provide additional security. + /// 2. Later versions do not (yet) provide additional security that would benefit us. /// - /// # Versions (June 2023) + /// # Versions (as of October 2023) /// /// - Polkadot reference kernel version: 5.16+ - /// - ABI V1: 5.13 - introduces landlock, including full restrictions on file reads - /// - ABI V2: 5.19 - adds ability to configure file renaming (not used by us) + /// + /// - ABI V1: kernel 5.13 - Introduces landlock, including full restrictions on file reads. + /// + /// - ABI V2: kernel 5.19 - Adds ability to prevent file renaming. Does not help us. During + /// execution an attacker can only affect the name of a symlinked artifact and not the + /// original one. + /// + /// - ABI V3: kernel 6.2 - Adds ability to prevent file truncation. During execution, can + /// prevent attackers from affecting a symlinked artifact. We don't strictly need this as we + /// plan to check for file integrity anyway; see + /// . /// /// # Determinism /// @@ -83,46 +258,103 @@ pub mod landlock { /// supports it or if it introduces some new feature that is beneficial to security. pub const LANDLOCK_ABI: ABI = ABI::V1; - // TODO: - /// Returns to what degree landlock is enabled with the given ABI on the current Linux - /// environment. - pub fn get_status() -> Result> { - match std::thread::spawn(|| try_restrict_thread()).join() { - Ok(Ok(status)) => Ok(status), - Ok(Err(ruleset_err)) => Err(ruleset_err.into()), - Err(_err) => Err("a panic occurred in try_restrict_thread".into()), + #[derive(Debug)] + pub enum TryRestrictError { + InvalidExceptionPath(PathBuf), + RulesetError(RulesetError), + } + + impl From for TryRestrictError { + fn from(err: RulesetError) -> Self { + Self::RulesetError(err) } } - /// Based on the given `status`, returns a single bool indicating whether the given landlock - /// ABI is fully enabled on the current Linux environment. - pub fn status_is_fully_enabled( - status: &Result>, - ) -> bool { - matches!(status, Ok(RulesetStatus::FullyEnforced)) + impl fmt::Display for TryRestrictError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidExceptionPath(path) => write!(f, "invalid exception path: {:?}", path), + Self::RulesetError(err) => write!(f, "ruleset error: {}", err.to_string()), + } + } } + impl std::error::Error for TryRestrictError {} + + /// Try to enable landlock for the given kind of worker. + pub fn enable_for_worker( + worker_kind: WorkerKind, + worker_pid: u32, + worker_dir_path: &Path, + ) -> Result> { + let exceptions: Vec<(PathBuf, BitFlags)> = match worker_kind { + WorkerKind::Prepare => { + vec![(worker_dir_path.to_owned(), AccessFs::WriteFile.into())] + }, + WorkerKind::Execute => { + vec![(worker_dir_path.to_owned(), AccessFs::ReadFile.into())] + }, + WorkerKind::CheckPivotRoot => + panic!("this should only be passed for checking pivot_root; qed"), + }; + + gum::debug!( + target: LOG_TARGET, + %worker_kind, + %worker_pid, + ?worker_dir_path, + "enabling landlock with exceptions: {:?}", + exceptions, + ); + + Ok(try_restrict(exceptions)?) + } + + // TODO: /// Runs a check for landlock and returns a single bool indicating whether the given landlock /// ABI is fully enabled on the current Linux environment. pub fn check_is_fully_enabled() -> bool { - status_is_fully_enabled(&get_status()) + let status_from_thread: Result> = + match std::thread::spawn(|| try_restrict(std::iter::empty::<(PathBuf, AccessFs)>())) + .join() + { + Ok(Ok(status)) => Ok(status), + Ok(Err(ruleset_err)) => Err(ruleset_err.into()), + Err(_err) => Err("a panic occurred in try_restrict".into()), + }; + + matches!(status_from_thread, Ok(RulesetStatus::FullyEnforced)) } - /// Tries to restrict the current thread with the following landlock access controls: + /// Tries to restrict the current thread (should only be called in a process' main thread) with + /// the following landlock access controls: /// - /// 1. all global filesystem access - /// 2. ... more may be supported in the future. + /// 1. all global filesystem access restricted, with optional exceptions + /// 2. ... more sandbox types (e.g. networking) may be supported in the future. /// /// If landlock is not supported in the current environment this is simply a noop. /// /// # Returns /// /// The status of the restriction (whether it was fully, partially, or not-at-all enforced). - pub fn try_restrict_thread() -> Result { - let status = Ruleset::new() - .handle_access(AccessFs::from_all(LANDLOCK_ABI))? - .create()? - .restrict_self()?; + fn try_restrict(fs_exceptions: I) -> Result + where + I: IntoIterator, + P: AsRef, + A: Into>, + { + let mut ruleset = + Ruleset::default().handle_access(AccessFs::from_all(LANDLOCK_ABI))?.create()?; + for (fs_path, access_bits) in fs_exceptions { + let paths = &[fs_path.as_ref().to_owned()]; + let mut rules = path_beneath_rules(paths, access_bits).peekable(); + if rules.peek().is_none() { + // `path_beneath_rules` silently ignores missing paths, so check for it manually. + return Err(TryRestrictError::InvalidExceptionPath(fs_path.as_ref().to_owned())) + } + ruleset = ruleset.add_rules(rules)?; + } + let status = ruleset.restrict_self()?; Ok(status.ruleset) } @@ -132,55 +364,147 @@ pub mod landlock { use std::{fs, io::ErrorKind, thread}; #[test] - fn restricted_thread_cannot_access_fs() { + fn restricted_thread_cannot_read_file() { // TODO: This would be nice: . if !check_is_fully_enabled() { return } // Restricted thread cannot read from FS. - let handle = thread::spawn(|| { - // Write to a tmp file, this should succeed before landlock is applied. - let text = "foo"; - let tmpfile = tempfile::NamedTempFile::new().unwrap(); - let path = tmpfile.path(); - fs::write(path, text).unwrap(); - let s = fs::read_to_string(path).unwrap(); - assert_eq!(s, text); - - let status = try_restrict_thread().unwrap(); - if !matches!(status, RulesetStatus::FullyEnforced) { - panic!("Ruleset should be enforced since we checked if landlock is enabled"); - } - - // Try to read from the tmp file after landlock. - let result = fs::read_to_string(path); - assert!(matches!( - result, - Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) - )); - }); + let handle = + thread::spawn(|| { + // Create, write, and read two tmp files. This should succeed before any + // landlock restrictions are applied. + const TEXT: &str = "foo"; + let tmpfile1 = tempfile::NamedTempFile::new().unwrap(); + let path1 = tmpfile1.path(); + let tmpfile2 = tempfile::NamedTempFile::new().unwrap(); + let path2 = tmpfile2.path(); + + fs::write(path1, TEXT).unwrap(); + let s = fs::read_to_string(path1).unwrap(); + assert_eq!(s, TEXT); + fs::write(path2, TEXT).unwrap(); + let s = fs::read_to_string(path2).unwrap(); + assert_eq!(s, TEXT); + + // Apply Landlock with a read exception for only one of the files. + let status = try_restrict(vec![(path1, AccessFs::ReadFile)]); + if !matches!(status, Ok(RulesetStatus::FullyEnforced)) { + panic!("Ruleset should be enforced since we checked if landlock is enabled: {:?}", status); + } + + // Try to read from both files, only tmpfile1 should succeed. + let result = fs::read_to_string(path1); + assert!(matches!( + result, + Ok(s) if s == TEXT + )); + let result = fs::read_to_string(path2); + assert!(matches!( + result, + Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) + )); + + // Apply Landlock for all files. + let status = try_restrict(std::iter::empty::<(PathBuf, AccessFs)>()); + if !matches!(status, Ok(RulesetStatus::FullyEnforced)) { + panic!("Ruleset should be enforced since we checked if landlock is enabled: {:?}", status); + } + + // Try to read from tmpfile1 after landlock, it should fail. + let result = fs::read_to_string(path1); + assert!(matches!( + result, + Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) + )); + }); assert!(handle.join().is_ok()); + } + + #[test] + fn restricted_thread_cannot_write_file() { + // TODO: This would be nice: . + if !check_is_fully_enabled() { + return + } // Restricted thread cannot write to FS. - let handle = thread::spawn(|| { - let text = "foo"; - let tmpfile = tempfile::NamedTempFile::new().unwrap(); - let path = tmpfile.path(); - - let status = try_restrict_thread().unwrap(); - if !matches!(status, RulesetStatus::FullyEnforced) { - panic!("Ruleset should be enforced since we checked if landlock is enabled"); - } - - // Try to write to the tmp file after landlock. - let result = fs::write(path, text); - assert!(matches!( - result, - Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) - )); - }); + let handle = + thread::spawn(|| { + // Create and write two tmp files. This should succeed before any landlock + // restrictions are applied. + const TEXT: &str = "foo"; + let tmpfile1 = tempfile::NamedTempFile::new().unwrap(); + let path1 = tmpfile1.path(); + let tmpfile2 = tempfile::NamedTempFile::new().unwrap(); + let path2 = tmpfile2.path(); + + fs::write(path1, TEXT).unwrap(); + fs::write(path2, TEXT).unwrap(); + + // Apply Landlock with a write exception for only one of the files. + let status = try_restrict(vec![(path1, AccessFs::WriteFile)]); + if !matches!(status, Ok(RulesetStatus::FullyEnforced)) { + panic!("Ruleset should be enforced since we checked if landlock is enabled: {:?}", status); + } + + // Try to write to both files, only tmpfile1 should succeed. + let result = fs::write(path1, TEXT); + assert!(matches!(result, Ok(_))); + let result = fs::write(path2, TEXT); + assert!(matches!( + result, + Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) + )); + + // Apply Landlock for all files. + let status = try_restrict(std::iter::empty::<(PathBuf, AccessFs)>()); + if !matches!(status, Ok(RulesetStatus::FullyEnforced)) { + panic!("Ruleset should be enforced since we checked if landlock is enabled: {:?}", status); + } + + // Try to write to tmpfile1 after landlock, it should fail. + let result = fs::write(path1, TEXT); + assert!(matches!( + result, + Err(err) if matches!(err.kind(), ErrorKind::PermissionDenied) + )); + }); + + assert!(handle.join().is_ok()); + } + + // Test that checks whether landlock under our ABI version is able to truncate files. + #[test] + fn restricted_thread_can_truncate_file() { + // TODO: This would be nice: . + if !check_is_fully_enabled() { + return + } + + // Restricted thread can truncate file. + let handle = + thread::spawn(|| { + // Create and write a file. This should succeed before any landlock + // restrictions are applied. + const TEXT: &str = "foo"; + let tmpfile = tempfile::NamedTempFile::new().unwrap(); + let path = tmpfile.path(); + + fs::write(path, TEXT).unwrap(); + + // Apply Landlock with all exceptions under the current ABI. + let status = try_restrict(vec![(path, AccessFs::from_all(LANDLOCK_ABI))]); + if !matches!(status, Ok(RulesetStatus::FullyEnforced)) { + panic!("Ruleset should be enforced since we checked if landlock is enabled: {:?}", status); + } + + // Try to truncate the file. + let result = tmpfile.as_file().set_len(0); + assert!(result.is_ok()); + }); assert!(handle.join().is_ok()); } diff --git a/polkadot/runtime/kusama/build.rs b/polkadot/node/core/pvf/common/src/worker_dir.rs similarity index 61% rename from polkadot/runtime/kusama/build.rs rename to polkadot/node/core/pvf/common/src/worker_dir.rs index 404ba3f2fdbdfdc68d35d0dd08958448f30d90c6..1cdf43a61e48bafbd3423a13cc8adcc46b3c96c7 100644 --- a/polkadot/runtime/kusama/build.rs +++ b/polkadot/node/core/pvf/common/src/worker_dir.rs @@ -14,12 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use substrate_wasm_builder::WasmBuilder; - -fn main() { - WasmBuilder::new() - .with_current_project() - .import_memory() - .export_heap_base() - .build() +//! Shared functions for getting the known worker files. + +use std::path::{Path, PathBuf}; + +const WORKER_EXECUTE_ARTIFACT_NAME: &str = "artifact"; +const WORKER_PREPARE_TMP_ARTIFACT_NAME: &str = "tmp-artifact"; + +pub fn execute_artifact(worker_dir_path: &Path) -> PathBuf { + worker_dir_path.join(WORKER_EXECUTE_ARTIFACT_NAME) +} + +pub fn prepare_tmp_artifact(worker_dir_path: &Path) -> PathBuf { + worker_dir_path.join(WORKER_PREPARE_TMP_ARTIFACT_NAME) } diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index 36793a5c71eca169c09da8565006dfbc133518ef..af73eb16e685a153330ab81353959ecf07a4a2e8 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -16,7 +16,9 @@ //! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary. -pub use polkadot_node_core_pvf_common::executor_intf::Executor; +pub use polkadot_node_core_pvf_common::{ + executor_intf::execute_artifact, worker_dir, SecurityStatus, +}; // NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are // separate spawned processes. Run with e.g. `RUST_LOG=parachain::pvf-execute-worker=trace`. @@ -27,23 +29,22 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, execute::{Handshake, Response}, - executor_intf::NATIVE_STACK_MAX, - framed_recv, framed_send, + framed_recv_blocking, framed_send_blocking, worker::{ - bytes_to_path, cpu_time_monitor_loop, - security::LandlockStatus, - stringify_panic_payload, + cpu_time_monitor_loop, stringify_panic_payload, thread::{self, WaitOutcome}, - worker_event_loop, + worker_event_loop, WorkerKind, }, }; use polkadot_parachain_primitives::primitives::ValidationResult; +use polkadot_primitives::{executor_params::DEFAULT_NATIVE_STACK_MAX, ExecutorParams}; use std::{ + os::unix::net::UnixStream, path::PathBuf, sync::{mpsc::channel, Arc}, time::Duration, }; -use tokio::{io, net::UnixStream}; +use tokio::io; // Wasmtime powers the Substrate Executor. It compiles the wasm bytecode into native code. // That native code does not create any stacks and just reuses the stack of the thread that @@ -70,7 +71,7 @@ use tokio::{io, net::UnixStream}; // // Typically on Linux the main thread gets the stack size specified by the `ulimit` and // typically it's configured to 8 MiB. Rust's spawned threads are 2 MiB. OTOH, the -// NATIVE_STACK_MAX is set to 256 MiB. Not nearly enough. +// DEFAULT_NATIVE_STACK_MAX is set to 256 MiB. Not nearly enough. // // Hence we need to increase it. The simplest way to fix that is to spawn a thread with the desired // stack limit. @@ -79,10 +80,10 @@ use tokio::{io, net::UnixStream}; // // The default Rust thread stack limit 2 MiB + 256 MiB wasm stack. /// The stack size for the execute thread. -pub const EXECUTE_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024 + NATIVE_STACK_MAX as usize; +pub const EXECUTE_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024 + DEFAULT_NATIVE_STACK_MAX as usize; -async fn recv_handshake(stream: &mut UnixStream) -> io::Result { - let handshake_enc = framed_recv(stream).await?; +fn recv_handshake(stream: &mut UnixStream) -> io::Result { + let handshake_enc = framed_recv_blocking(stream)?; let handshake = Handshake::decode(&mut &handshake_enc[..]).map_err(|_| { io::Error::new( io::ErrorKind::Other, @@ -92,57 +93,59 @@ async fn recv_handshake(stream: &mut UnixStream) -> io::Result { Ok(handshake) } -async fn recv_request(stream: &mut UnixStream) -> io::Result<(PathBuf, Vec, Duration)> { - let artifact_path = framed_recv(stream).await?; - let artifact_path = bytes_to_path(&artifact_path).ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - "execute pvf recv_request: non utf-8 artifact path".to_string(), - ) - })?; - let params = framed_recv(stream).await?; - let execution_timeout = framed_recv(stream).await?; +fn recv_request(stream: &mut UnixStream) -> io::Result<(Vec, Duration)> { + let params = framed_recv_blocking(stream)?; + let execution_timeout = framed_recv_blocking(stream)?; let execution_timeout = Duration::decode(&mut &execution_timeout[..]).map_err(|_| { io::Error::new( io::ErrorKind::Other, "execute pvf recv_request: failed to decode duration".to_string(), ) })?; - Ok((artifact_path, params, execution_timeout)) + Ok((params, execution_timeout)) } -async fn send_response(stream: &mut UnixStream, response: Response) -> io::Result<()> { - framed_send(stream, &response.encode()).await +fn send_response(stream: &mut UnixStream, response: Response) -> io::Result<()> { + framed_send_blocking(stream, &response.encode()) } /// The entrypoint that the spawned execute worker should start with. /// /// # Parameters /// -/// The `socket_path` specifies the path to the socket used to communicate with the host. The -/// `node_version`, if `Some`, is checked against the worker version. A mismatch results in -/// immediate worker termination. `None` is used for tests and in other situations when version -/// check is not necessary. +/// - `socket_path`: specifies the path to the socket used to communicate with the host. +/// +/// - `worker_dir_path`: specifies the path to the worker-specific temporary directory. +/// +/// - `node_version`: if `Some`, is checked against the `worker_version`. A mismatch results in +/// immediate worker termination. `None` is used for tests and in other situations when version +/// check is not necessary. +/// +/// - `worker_version`: see above +/// +/// - `security_status`: contains the detected status of security features. pub fn worker_entrypoint( - socket_path: &str, + socket_path: PathBuf, + worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, + security_status: SecurityStatus, ) { worker_event_loop( - "execute", + WorkerKind::Execute, socket_path, + worker_dir_path, node_version, worker_version, - |mut stream| async move { + &security_status, + |mut stream, worker_dir_path| async move { let worker_pid = std::process::id(); + let artifact_path = worker_dir::execute_artifact(&worker_dir_path); - let handshake = recv_handshake(&mut stream).await?; - let executor = Executor::new(handshake.executor_params).map_err(|e| { - io::Error::new(io::ErrorKind::Other, format!("cannot create executor: {}", e)) - })?; + let Handshake { executor_params } = recv_handshake(&mut stream)?; loop { - let (artifact_path, params, execution_timeout) = recv_request(&mut stream).await?; + let (params, execution_timeout) = recv_request(&mut stream)?; gum::debug!( target: LOG_TARGET, %worker_pid, @@ -151,15 +154,13 @@ pub fn worker_entrypoint( ); // Get the artifact bytes. - // - // We do this outside the thread so that we can lock down filesystem access there. - let compiled_artifact_blob = match std::fs::read(artifact_path) { + let compiled_artifact_blob = match std::fs::read(&artifact_path) { Ok(bytes) => bytes, Err(err) => { let response = Response::InternalError( InternalValidationError::CouldNotOpenFile(err.to_string()), ); - send_response(&mut stream, response).await?; + send_response(&mut stream, response)?; continue }, }; @@ -183,26 +184,16 @@ pub fn worker_entrypoint( Arc::clone(&condvar), WaitOutcome::TimedOut, )?; - let executor_2 = executor.clone(); + + let executor_params_2 = executor_params.clone(); let execute_thread = thread::spawn_worker_thread_with_stack_size( "execute thread", move || { - // Try to enable landlock. - #[cfg(target_os = "linux")] - let landlock_status = polkadot_node_core_pvf_common::worker::security::landlock::try_restrict_thread() - .map(LandlockStatus::from_ruleset_status) - .map_err(|e| e.to_string()); - #[cfg(not(target_os = "linux"))] - let landlock_status: Result = Ok(LandlockStatus::NotEnforced); - - ( - validate_using_artifact( - &compiled_artifact_blob, - ¶ms, - executor_2, - cpu_time_start, - ), - landlock_status, + validate_using_artifact( + &compiled_artifact_blob, + &executor_params_2, + ¶ms, + cpu_time_start, ) }, Arc::clone(&condvar), @@ -215,24 +206,9 @@ pub fn worker_entrypoint( let response = match outcome { WaitOutcome::Finished => { let _ = cpu_time_monitor_tx.send(()); - let (result, landlock_status) = execute_thread.join().unwrap_or_else(|e| { - ( - Response::Panic(stringify_panic_payload(e)), - Ok(LandlockStatus::Unavailable), - ) - }); - - // Log if landlock threw an error. - if let Err(err) = landlock_status { - gum::warn!( - target: LOG_TARGET, - %worker_pid, - "error enabling landlock: {}", - err - ); - } - - result + execute_thread + .join() + .unwrap_or_else(|e| Response::Panic(stringify_panic_payload(e))) }, // If the CPU thread is not selected, we signal it to end, the join handle is // dropped and the thread will finish in the background. @@ -267,7 +243,13 @@ pub fn worker_entrypoint( ), }; - send_response(&mut stream, response).await?; + gum::trace!( + target: LOG_TARGET, + %worker_pid, + "worker: sending response to host: {:?}", + response + ); + send_response(&mut stream, response)?; } }, ); @@ -275,15 +257,15 @@ pub fn worker_entrypoint( fn validate_using_artifact( compiled_artifact_blob: &[u8], + executor_params: &ExecutorParams, params: &[u8], - executor: Executor, cpu_time_start: ProcessTime, ) -> Response { let descriptor_bytes = match unsafe { // SAFETY: this should be safe since the compiled artifact passed here comes from the // file created by the prepare workers. These files are obtained by calling // [`executor_intf::prepare`]. - executor.execute(compiled_artifact_blob, params) + execute_artifact(compiled_artifact_blob, executor_params, params) } { Err(err) => return Response::format_invalid("execute", &err), Ok(d) => d, diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index e7a12cd9a809c5ef2fafa32df9b3cf4588dc1b52..886209b78c329f062e674a96992509d0390a4220 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -7,6 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] +cfg-if = "1.0" futures = "0.3.21" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.139" diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index caa7d33df12adfc67440caf3a9d68a65257edf99..fa5d3656a35e69fb0d738db82ed8f5ca54a75a9e 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -32,26 +32,25 @@ use crate::memory_stats::memory_tracker::{get_memory_tracker_loop_stats, memory_ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, - executor_intf::Executor, - framed_recv, framed_send, + executor_intf::create_runtime_from_artifact_bytes, + framed_recv_blocking, framed_send_blocking, prepare::{MemoryStats, PrepareJobKind, PrepareStats}, pvf::PvfPrepData, worker::{ - bytes_to_path, cpu_time_monitor_loop, - security::LandlockStatus, - stringify_panic_payload, + cpu_time_monitor_loop, stringify_panic_payload, thread::{self, WaitOutcome}, - worker_event_loop, + worker_event_loop, WorkerKind, }, - ProcessTime, + worker_dir, ProcessTime, SecurityStatus, }; use polkadot_primitives::ExecutorParams; use std::{ + os::unix::net::UnixStream, path::PathBuf, sync::{mpsc::channel, Arc}, time::Duration, }; -use tokio::{io, net::UnixStream}; +use tokio::io; /// Contains the bytes for a successfully compiled artifact. pub struct CompiledArtifact(Vec); @@ -69,36 +68,36 @@ impl AsRef<[u8]> for CompiledArtifact { } } -async fn recv_request(stream: &mut UnixStream) -> io::Result<(PvfPrepData, PathBuf)> { - let pvf = framed_recv(stream).await?; +fn recv_request(stream: &mut UnixStream) -> io::Result { + let pvf = framed_recv_blocking(stream)?; let pvf = PvfPrepData::decode(&mut &pvf[..]).map_err(|e| { io::Error::new( io::ErrorKind::Other, format!("prepare pvf recv_request: failed to decode PvfPrepData: {}", e), ) })?; - let tmp_file = framed_recv(stream).await?; - let tmp_file = bytes_to_path(&tmp_file).ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - "prepare pvf recv_request: non utf-8 artifact path".to_string(), - ) - })?; - Ok((pvf, tmp_file)) + Ok(pvf) } -async fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<()> { - framed_send(stream, &result.encode()).await +fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Result<()> { + framed_send_blocking(stream, &result.encode()) } /// The entrypoint that the spawned prepare worker should start with. /// /// # Parameters /// -/// The `socket_path` specifies the path to the socket used to communicate with the host. The -/// `node_version`, if `Some`, is checked against the worker version. A mismatch results in -/// immediate worker termination. `None` is used for tests and in other situations when version -/// check is not necessary. +/// - `socket_path`: specifies the path to the socket used to communicate with the host. +/// +/// - `worker_dir_path`: specifies the path to the worker-specific temporary directory. +/// +/// - `node_version`: if `Some`, is checked against the `worker_version`. A mismatch results in +/// immediate worker termination. `None` is used for tests and in other situations when version +/// check is not necessary. +/// +/// - `worker_version`: see above +/// +/// - `security_status`: contains the detected status of security features. /// /// # Flow /// @@ -119,20 +118,25 @@ async fn send_response(stream: &mut UnixStream, result: PrepareResult) -> io::Re /// 7. Send the result of preparation back to the host. If any error occurred in the above steps, we /// send that in the `PrepareResult`. pub fn worker_entrypoint( - socket_path: &str, + socket_path: PathBuf, + worker_dir_path: PathBuf, node_version: Option<&str>, worker_version: Option<&str>, + security_status: SecurityStatus, ) { worker_event_loop( - "prepare", + WorkerKind::Prepare, socket_path, + worker_dir_path, node_version, worker_version, - |mut stream| async move { + &security_status, + |mut stream, worker_dir_path| async move { let worker_pid = std::process::id(); + let temp_artifact_dest = worker_dir::prepare_tmp_artifact(&worker_dir_path); loop { - let (pvf, temp_artifact_dest) = recv_request(&mut stream).await?; + let pvf = recv_request(&mut stream)?; gum::debug!( target: LOG_TARGET, %worker_pid, @@ -141,7 +145,7 @@ pub fn worker_entrypoint( let preparation_timeout = pvf.prep_timeout(); let prepare_job_kind = pvf.prep_kind(); - let executor_params = (*pvf.executor_params()).clone(); + let executor_params = pvf.executor_params(); // Conditional variable to notify us when a thread is done. let condvar = thread::get_condvar(); @@ -172,14 +176,6 @@ pub fn worker_entrypoint( let prepare_thread = thread::spawn_worker_thread( "prepare thread", move || { - // Try to enable landlock. - #[cfg(target_os = "linux")] - let landlock_status = polkadot_node_core_pvf_common::worker::security::landlock::try_restrict_thread() - .map(LandlockStatus::from_ruleset_status) - .map_err(|e| e.to_string()); - #[cfg(not(target_os = "linux"))] - let landlock_status: Result = Ok(LandlockStatus::NotEnforced); - #[allow(unused_mut)] let mut result = prepare_artifact(pvf, cpu_time_start); @@ -195,12 +191,15 @@ pub fn worker_entrypoint( // anyway. if let PrepareJobKind::Prechecking = prepare_job_kind { result = result.and_then(|output| { - runtime_construction_check(output.0.as_ref(), executor_params)?; + runtime_construction_check( + output.0.as_ref(), + executor_params.as_ref(), + )?; Ok(output) }); } - (result, landlock_status) + result }, Arc::clone(&condvar), WaitOutcome::Finished, @@ -213,20 +212,20 @@ pub fn worker_entrypoint( let _ = cpu_time_monitor_tx.send(()); match prepare_thread.join().unwrap_or_else(|err| { - ( - Err(PrepareError::Panic(stringify_panic_payload(err))), - Ok(LandlockStatus::Unavailable), - ) + Err(PrepareError::Panic(stringify_panic_payload(err))) }) { - (Err(err), _) => { + Err(err) => { // Serialized error will be written into the socket. Err(err) }, - (Ok(ok), landlock_status) => { - #[cfg(not(target_os = "linux"))] - let (artifact, cpu_time_elapsed) = ok; - #[cfg(target_os = "linux")] - let (artifact, cpu_time_elapsed, max_rss) = ok; + Ok(ok) => { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + let (artifact, cpu_time_elapsed, max_rss) = ok; + } else { + let (artifact, cpu_time_elapsed) = ok; + } + } // Stop the memory stats worker and get its observed memory stats. #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] @@ -242,16 +241,6 @@ pub fn worker_entrypoint( max_rss: extract_max_rss_stat(max_rss, worker_pid), }; - // Log if landlock threw an error. - if let Err(err) = landlock_status { - gum::warn!( - target: LOG_TARGET, - %worker_pid, - "error enabling landlock: {}", - err - ); - } - // Write the serialized artifact into a temp file. // // PVF host only keeps artifacts statuses in its memory, @@ -300,7 +289,13 @@ pub fn worker_entrypoint( ), }; - send_response(&mut stream, result).await?; + gum::trace!( + target: LOG_TARGET, + %worker_pid, + "worker: sending response to host: {:?}", + result + ); + send_response(&mut stream, result)?; } }, ); @@ -325,13 +320,10 @@ fn prepare_artifact( /// Try constructing the runtime to catch any instantiation errors during pre-checking. fn runtime_construction_check( artifact_bytes: &[u8], - executor_params: ExecutorParams, + executor_params: &ExecutorParams, ) -> Result<(), PrepareError> { - let executor = Executor::new(executor_params) - .map_err(|e| PrepareError::RuntimeConstruction(format!("cannot create executor: {}", e)))?; - // SAFETY: We just compiled this artifact. - let result = unsafe { executor.create_runtime_from_bytes(&artifact_bytes) }; + let result = unsafe { create_runtime_from_artifact_bytes(artifact_bytes, executor_params) }; result .map(|_runtime| ()) .map_err(|err| PrepareError::RuntimeConstruction(format!("{:?}", err))) diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index dc5921df96884dd8ce0bbb10b8de3c6eca90b1f6..d7b15ece7b29457bde9c862f6720a7ad505b6dbe 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -58,6 +58,7 @@ use crate::host::PrepareResultSender; use always_assert::always; use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; +use polkadot_node_primitives::NODE_VERSION; use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParamsHash; use std::{ @@ -75,6 +76,7 @@ pub struct ArtifactId { impl ArtifactId { const PREFIX: &'static str = "wasmtime_"; + const NODE_VERSION_PREFIX: &'static str = "polkadot_v"; /// Creates a new artifact ID with the given hash. pub fn new(code_hash: ValidationCodeHash, executor_params_hash: ExecutorParamsHash) -> Self { @@ -92,8 +94,13 @@ impl ArtifactId { use polkadot_core_primitives::Hash; use std::str::FromStr as _; - let file_name = file_name.strip_prefix(Self::PREFIX)?; - let (code_hash_str, executor_params_hash_str) = file_name.split_once('_')?; + let file_name = + file_name.strip_prefix(Self::PREFIX)?.strip_prefix(Self::NODE_VERSION_PREFIX)?; + + // [ node version | code hash | param hash ] + let parts: Vec<&str> = file_name.split('_').collect(); + let (_node_ver, code_hash_str, executor_params_hash_str) = (parts[0], parts[1], parts[2]); + let code_hash = Hash::from_str(code_hash_str).ok()?.into(); let executor_params_hash = ExecutorParamsHash::from_hash(Hash::from_str(executor_params_hash_str).ok()?); @@ -103,8 +110,14 @@ impl ArtifactId { /// Returns the expected path to this artifact given the root of the cache. pub fn path(&self, cache_path: &Path) -> PathBuf { - let file_name = - format!("{}{:#x}_{:#x}", Self::PREFIX, self.code_hash, self.executor_params_hash); + let file_name = format!( + "{}{}{}_{:#x}_{:#x}", + Self::PREFIX, + Self::NODE_VERSION_PREFIX, + NODE_VERSION, + self.code_hash, + self.executor_params_hash + ); cache_path.join(file_name) } } @@ -172,9 +185,10 @@ impl Artifacts { /// /// The recognized artifacts will be filled in the table and unrecognized will be removed. pub async fn new(cache_path: &Path) -> Self { - // Make sure that the cache path directory and all its parents are created. - // First delete the entire cache. Nodes are long-running so this should populate shortly. + // First delete the entire cache. This includes artifacts and any leftover worker dirs (see + // [`WorkerDir`]). Nodes are long-running so this should populate shortly. let _ = tokio::fs::remove_dir_all(cache_path).await; + // Make sure that the cache path directory and all its parents are created. let _ = tokio::fs::create_dir_all(cache_path).await; Self { artifacts: HashMap::new() } @@ -252,20 +266,27 @@ impl Artifacts { #[cfg(test)] mod tests { - use super::{ArtifactId, Artifacts}; + use super::{ArtifactId, Artifacts, NODE_VERSION}; use polkadot_primitives::ExecutorParamsHash; use sp_core::H256; use std::{path::Path, str::FromStr}; + fn file_name(code_hash: &str, param_hash: &str) -> String { + format!("wasmtime_polkadot_v{}_0x{}_0x{}", NODE_VERSION, code_hash, param_hash) + } + #[test] fn from_file_name() { assert!(ArtifactId::from_file_name("").is_none()); assert!(ArtifactId::from_file_name("junk").is_none()); + let file_name = file_name( + "0022800000000000000000000000000000000000000000000000000000000000", + "0033900000000000000000000000000000000000000000000000000000000000", + ); + assert_eq!( - ArtifactId::from_file_name( - "wasmtime_0x0022800000000000000000000000000000000000000000000000000000000000_0x0033900000000000000000000000000000000000000000000000000000000000" - ), + ArtifactId::from_file_name(&file_name), Some(ArtifactId::new( hex_literal::hex![ "0022800000000000000000000000000000000000000000000000000000000000" @@ -280,22 +301,25 @@ mod tests { #[test] fn path() { - let path = Path::new("/test"); - let hash = - H256::from_str("1234567890123456789012345678901234567890123456789012345678901234") - .unwrap(); + let dir = Path::new("/test"); + let code_hash = "1234567890123456789012345678901234567890123456789012345678901234"; + let params_hash = "4321098765432109876543210987654321098765432109876543210987654321"; + let file_name = file_name(code_hash, params_hash); + + let code_hash = H256::from_str(code_hash).unwrap(); + let params_hash = H256::from_str(params_hash).unwrap(); assert_eq!( - ArtifactId::new(hash.into(), ExecutorParamsHash::from_hash(hash)).path(path).to_str(), - Some( - "/test/wasmtime_0x1234567890123456789012345678901234567890123456789012345678901234_0x1234567890123456789012345678901234567890123456789012345678901234" - ), + ArtifactId::new(code_hash.into(), ExecutorParamsHash::from_hash(params_hash)) + .path(dir) + .to_str(), + Some(format!("/test/{}", file_name).as_str()), ); } #[tokio::test] async fn artifacts_removes_cache_on_startup() { - let fake_cache_path = crate::worker_intf::tmpfile("test-cache").await.unwrap(); + let fake_cache_path = crate::worker_intf::tmppath("test-cache").await.unwrap(); let fake_artifact_path = { let mut p = fake_cache_path.clone(); p.push("wasmtime_0x1234567890123456789012345678901234567890123456789012345678901234"); diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index acb260e256931686c15dadb64341e2155b56ee2e..aca604f0de21dd805e10c68c1a8d80c202010e9b 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -30,6 +30,7 @@ use futures::{ stream::{FuturesUnordered, StreamExt as _}, Future, FutureExt, }; +use polkadot_node_core_pvf_common::SecurityStatus; use polkadot_primitives::{ExecutorParams, ExecutorParamsHash}; use slotmap::HopSlotMap; use std::{ @@ -139,8 +140,10 @@ struct Queue { // Some variables related to the current session. program_path: PathBuf, + cache_path: PathBuf, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, /// The queue of jobs that are waiting for a worker to pick up. queue: VecDeque, @@ -152,16 +155,20 @@ impl Queue { fn new( metrics: Metrics, program_path: PathBuf, + cache_path: PathBuf, worker_capacity: usize, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, to_queue_rx: mpsc::Receiver, ) -> Self { Self { metrics, program_path, + cache_path, spawn_timeout, node_version, + security_status, to_queue_rx, queue: VecDeque::new(), mux: Mux::new(), @@ -405,9 +412,11 @@ fn spawn_extra_worker(queue: &mut Queue, job: ExecuteJob) { queue.mux.push( spawn_worker_task( queue.program_path.clone(), + queue.cache_path.clone(), job, queue.spawn_timeout, queue.node_version.clone(), + queue.security_status.clone(), ) .boxed(), ); @@ -423,18 +432,22 @@ fn spawn_extra_worker(queue: &mut Queue, job: ExecuteJob) { /// execute other jobs with a compatible execution environment. async fn spawn_worker_task( program_path: PathBuf, + cache_path: PathBuf, job: ExecuteJob, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, ) -> QueueEvent { use futures_timer::Delay; loop { match super::worker_intf::spawn( &program_path, + &cache_path, job.executor_params.clone(), spawn_timeout, node_version.as_deref(), + security_status.clone(), ) .await { @@ -496,17 +509,21 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) { pub fn start( metrics: Metrics, program_path: PathBuf, + cache_path: PathBuf, worker_capacity: usize, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, ) -> (mpsc::Sender, impl Future) { let (to_queue_tx, to_queue_rx) = mpsc::channel(20); let run = Queue::new( metrics, program_path, + cache_path, worker_capacity, spawn_timeout, node_version, + security_status, to_queue_rx, ) .run(); diff --git a/polkadot/node/core/pvf/src/execute/worker_intf.rs b/polkadot/node/core/pvf/src/execute/worker_intf.rs index d66444a8102d9124188a48e98e5fa8f321a0bb97..783c7c7abbc8c7526819d85e3e06bd1ae6e9209c 100644 --- a/polkadot/node/core/pvf/src/execute/worker_intf.rs +++ b/polkadot/node/core/pvf/src/execute/worker_intf.rs @@ -19,8 +19,8 @@ use crate::{ artifacts::ArtifactPathId, worker_intf::{ - path_to_bytes, spawn_with_program_path, IdleWorker, SpawnErr, WorkerHandle, - JOB_TIMEOUT_WALL_CLOCK_FACTOR, + clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, + SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }, LOG_TARGET, }; @@ -30,7 +30,7 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, execute::{Handshake, Response}, - framed_recv, framed_send, + worker_dir, SecurityStatus, }; use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::ExecutorParams; @@ -38,21 +38,30 @@ use std::{path::Path, time::Duration}; use tokio::{io, net::UnixStream}; /// Spawns a new worker with the given program path that acts as the worker and the spawn timeout. -/// Sends a handshake message to the worker as soon as it is spawned. /// -/// The program should be able to handle ` execute-worker ` invocation. +/// Sends a handshake message to the worker as soon as it is spawned. pub async fn spawn( program_path: &Path, + cache_path: &Path, executor_params: ExecutorParams, spawn_timeout: Duration, node_version: Option<&str>, + security_status: SecurityStatus, ) -> Result<(IdleWorker, WorkerHandle), SpawnErr> { let mut extra_args = vec!["execute-worker"]; if let Some(node_version) = node_version { extra_args.extend_from_slice(&["--node-impl-version", node_version]); } - let (mut idle_worker, worker_handle) = - spawn_with_program_path("execute", program_path, &extra_args, spawn_timeout).await?; + + let (mut idle_worker, worker_handle) = spawn_with_program_path( + "execute", + program_path, + cache_path, + &extra_args, + spawn_timeout, + security_status, + ) + .await?; send_handshake(&mut idle_worker.stream, Handshake { executor_params }) .await .map_err(|error| { @@ -104,89 +113,151 @@ pub async fn start_work( execution_timeout: Duration, validation_params: Vec, ) -> Outcome { - let IdleWorker { mut stream, pid } = worker; + let IdleWorker { mut stream, pid, worker_dir } = worker; gum::debug!( target: LOG_TARGET, worker_pid = %pid, + ?worker_dir, validation_code_hash = ?artifact.id.code_hash, "starting execute for {}", artifact.path.display(), ); - if let Err(error) = - send_request(&mut stream, &artifact.path, &validation_params, execution_timeout).await - { + 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::IoErr + } + + // 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 + // in the child. We want to use CPU time because it varies less than wall clock time under + // 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 { + Err(error) => { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + validation_code_hash = ?artifact.id.code_hash, + ?error, + "failed to recv an execute response", + ); + return Outcome::IoErr + }, + Ok(response) => { + if let Response::Ok{duration, ..} = response { + if duration > execution_timeout { + // The job didn't complete within the timeout. + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + "execute job took {}ms cpu time, exceeded execution timeout {}ms.", + duration.as_millis(), + execution_timeout.as_millis(), + ); + + // Return a timeout error. + return Outcome::HardTimeout; + } + } + + response + }, + } + }, + _ = Delay::new(timeout).fuse() => { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + validation_code_hash = ?artifact.id.code_hash, + "execution worker exceeded lenient timeout for execution, child worker likely stalled", + ); + Response::TimedOut + }, + }; + + match response { + Response::Ok { result_descriptor, duration } => Outcome::Ok { + result_descriptor, + duration, + idle_worker: IdleWorker { stream, pid, worker_dir }, + }, + Response::InvalidCandidate(err) => Outcome::InvalidCandidate { + err, + idle_worker: IdleWorker { stream, pid, worker_dir }, + }, + Response::TimedOut => Outcome::HardTimeout, + Response::Panic(err) => Outcome::Panic { err }, + Response::InternalError(err) => Outcome::InternalError { err }, + } + }) + .await +} + +/// Create a temporary file for an artifact in the worker cache, execute the given future/closure +/// passing the file path in, and clean up the worker cache. +/// +/// Failure to clean up the worker cache results in an error - leaving any files here could be a +/// security issue, and we should shut down the worker. This should be very rare. +async fn with_worker_dir_setup( + worker_dir: WorkerDir, + pid: u32, + artifact_path: &Path, + f: F, +) -> Outcome +where + 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 + // worker cache, and the child can't access any other artifacts or gain any information from the + // original filename. + let link_path = worker_dir::execute_artifact(&worker_dir.path); + if let Err(err) = tokio::fs::hard_link(artifact_path, link_path).await { gum::warn!( target: LOG_TARGET, worker_pid = %pid, - validation_code_hash = ?artifact.id.code_hash, - ?error, - "failed to send an execute request", + ?worker_dir, + "failed to clear worker cache after the job: {:?}", + err, ); - return Outcome::IoErr + return Outcome::InternalError { + err: InternalValidationError::CouldNotCreateLink(format!("{:?}", err)), + } } - // 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 - // in the child. We want to use CPU time because it varies less than wall clock time under - // 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 { - Err(error) => { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - validation_code_hash = ?artifact.id.code_hash, - ?error, - "failed to recv an execute response", - ); - return Outcome::IoErr - }, - Ok(response) => { - if let Response::Ok{duration, ..} = response { - if duration > execution_timeout { - // The job didn't complete within the timeout. - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - "execute job took {}ms cpu time, exceeded execution timeout {}ms.", - duration.as_millis(), - execution_timeout.as_millis(), - ); - - // Return a timeout error. - return Outcome::HardTimeout; - } - } + let worker_dir_path = worker_dir.path.clone(); + let outcome = f(worker_dir).await; - response - }, - } - }, - _ = Delay::new(timeout).fuse() => { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - validation_code_hash = ?artifact.id.code_hash, - "execution worker exceeded lenient timeout for execution, child worker likely stalled", - ); - Response::TimedOut - }, - }; - - match response { - Response::Ok { result_descriptor, duration } => - Outcome::Ok { result_descriptor, duration, idle_worker: IdleWorker { stream, pid } }, - Response::InvalidCandidate(err) => - Outcome::InvalidCandidate { err, idle_worker: IdleWorker { stream, pid } }, - Response::TimedOut => Outcome::HardTimeout, - Response::Panic(err) => Outcome::Panic { err }, - Response::InternalError(err) => Outcome::InternalError { err }, + // Try to clear the worker dir. + if let Err(err) = clear_worker_dir_path(&worker_dir_path) { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + ?worker_dir_path, + "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), + }, + } } + + outcome } async fn send_handshake(stream: &mut UnixStream, handshake: Handshake) -> io::Result<()> { @@ -195,11 +266,9 @@ async fn send_handshake(stream: &mut UnixStream, handshake: Handshake) -> io::Re async fn send_request( stream: &mut UnixStream, - artifact_path: &Path, validation_params: &[u8], execution_timeout: Duration, ) -> io::Result<()> { - framed_send(stream, path_to_bytes(artifact_path)).await?; framed_send(stream, validation_params).await?; framed_send(stream, &execution_timeout.encode()).await } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 5290b2760f423403d9fa9cf334f735e253952e19..81695829122b9d3ba03307f1c597ac5877dc7023 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -34,6 +34,7 @@ use futures::{ use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, pvf::PvfPrepData, + SecurityStatus, }; use polkadot_parachain_primitives::primitives::ValidationResult; use std::{ @@ -202,8 +203,13 @@ impl Config { pub fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Future) { gum::debug!(target: LOG_TARGET, ?config, "starting PVF validation host"); - // Run checks for supported security features once per host startup. - warn_if_no_landlock(); + // Run checks for supported security features once per host startup. Warn here if not enabled. + let security_status = { + let can_enable_landlock = check_landlock(&config.prepare_worker_program_path); + let can_unshare_user_namespace_and_change_root = + check_can_unshare_user_namespace_and_change_root(&config.prepare_worker_program_path); + SecurityStatus { can_enable_landlock, can_unshare_user_namespace_and_change_root } + }; let (to_host_tx, to_host_rx) = mpsc::channel(10); @@ -215,6 +221,7 @@ pub fn start(config: Config, metrics: Metrics) -> (ValidationHost, impl Future (ValidationHost, impl Future impl futures::Stream .map(|_| ()) } -/// Check if landlock is supported and emit a warning if not. -fn warn_if_no_landlock() { - #[cfg(target_os = "linux")] - { - use polkadot_node_core_pvf_common::worker::security::landlock; - let status = landlock::get_status(); - if !landlock::status_is_fully_enabled(&status) { - let abi = landlock::LANDLOCK_ABI as u8; +/// Check if we can sandbox the root and emit a warning if not. +/// +/// We do this check by spawning a new process and trying to sandbox it. To get as close as possible +/// to running the check in a worker, we try it... in a worker. The expected return status is 0 on +/// success and -1 on failure. +fn check_can_unshare_user_namespace_and_change_root( + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] + prepare_worker_program_path: &Path, +) -> bool { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + let output = std::process::Command::new(prepare_worker_program_path) + .arg("--check-can-unshare-user-namespace-and-change-root") + .output(); + + match output { + Ok(output) if output.status.success() => true, + Ok(output) => { + let stderr = std::str::from_utf8(&output.stderr) + .expect("child process writes a UTF-8 string to stderr; qed") + .trim(); + gum::warn!( + target: LOG_TARGET, + ?prepare_worker_program_path, + // Docs say to always print status using `Display` implementation. + status = %output.status, + %stderr, + "Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running with support for unsharing user namespaces for maximum security." + ); + false + }, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?prepare_worker_program_path, + "Could not start child process: {}", + err + ); + false + }, + } + } else { gum::warn!( target: LOG_TARGET, - ?status, - %abi, - "Cannot fully enable landlock, a Linux kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security." + "Cannot unshare user namespace and change root, which are Linux-specific kernel security features. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with support for unsharing user namespaces for maximum security." ); + false } } +} - #[cfg(not(target_os = "linux"))] - gum::warn!( - target: LOG_TARGET, - "Cannot enable landlock, a Linux kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with landlock support for maximum security." - ); +/// Check if landlock is supported and emit a warning if not. +/// +/// We do this check by spawning a new process and trying to sandbox it. To get as close as possible +/// to running the check in a worker, we try it... in a worker. The expected return status is 0 on +/// success and -1 on failure. +fn check_landlock( + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] + prepare_worker_program_path: &Path, +) -> bool { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + match std::process::Command::new(prepare_worker_program_path) + .arg("--check-can-enable-landlock") + .status() + { + Ok(status) if status.success() => true, + Ok(status) => { + let abi = + polkadot_node_core_pvf_common::worker::security::landlock::LANDLOCK_ABI as u8; + gum::warn!( + target: LOG_TARGET, + ?prepare_worker_program_path, + ?status, + %abi, + "Cannot fully enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security." + ); + false + }, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?prepare_worker_program_path, + "Could not start child process: {}", + err + ); + false + }, + } + } else { + gum::warn!( + target: LOG_TARGET, + "Cannot enable landlock, a Linux-specific kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider running on Linux with landlock support for maximum security." + ); + false + } + } } #[cfg(test)] diff --git a/polkadot/node/core/pvf/src/lib.rs b/polkadot/node/core/pvf/src/lib.rs index 0e4f2444adf72ce01c4444024f589e79653d0e86..e3c6da9c4c6ba80ee94658921e975610d3b2d58f 100644 --- a/polkadot/node/core/pvf/src/lib.rs +++ b/polkadot/node/core/pvf/src/lib.rs @@ -19,8 +19,10 @@ //! The PVF validation host. Responsible for coordinating preparation and execution of PVFs. //! //! For more background, refer to the Implementer's Guide: [PVF -//! Pre-checking](https://paritytech.github.io/polkadot/book/pvf-prechecking.html) and [Candidate -//! Validation](https://paritytech.github.io/polkadot/book/node/utility/candidate-validation.html#pvf-host). +//! Pre-checking](https://paritytech.github.io/polkadot-sdk/book/pvf-prechecking.html), [Candidate +//! Validation](https://paritytech.github.io/polkadot-sdk/book/node/utility/candidate-validation.html) +//! and [PVF Host and Workers](https://paritytech.github.io/polkadot-sdk/book/node/utility/pvf-host-and-workers.html). +//! //! //! # Entrypoint //! @@ -111,6 +113,7 @@ pub use polkadot_node_core_pvf_common::{ error::{InternalValidationError, PrepareError}, prepare::{PrepareJobKind, PrepareStats}, pvf::PvfPrepData, + SecurityStatus, }; /// The log target for this crate. diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 92aa4896c263ce5c4e6aac507ed2eee61a3cdd3b..7933b0319a6f9fcd9fe83cad9f47950827a6ecc9 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -27,6 +27,7 @@ use futures::{ use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, pvf::PvfPrepData, + SecurityStatus, }; use slotmap::HopSlotMap; use std::{ @@ -110,10 +111,12 @@ enum PoolEvent { type Mux = FuturesUnordered>; struct Pool { + // Some variables related to the current session. program_path: PathBuf, cache_path: PathBuf, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, to_pool: mpsc::Receiver, from_pool: mpsc::UnboundedSender, @@ -132,6 +135,7 @@ async fn run( cache_path, spawn_timeout, node_version, + security_status, to_pool, mut from_pool, mut spawned, @@ -160,6 +164,7 @@ async fn run( &cache_path, spawn_timeout, node_version.clone(), + security_status.clone(), &mut spawned, &mut mux, to_pool, @@ -207,6 +212,7 @@ fn handle_to_pool( cache_path: &Path, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, spawned: &mut HopSlotMap, mux: &mut Mux, to_pool: ToPool, @@ -216,7 +222,14 @@ fn handle_to_pool( gum::debug!(target: LOG_TARGET, "spawning a new prepare worker"); metrics.prepare_worker().on_begin_spawn(); mux.push( - spawn_worker_task(program_path.to_owned(), spawn_timeout, node_version).boxed(), + spawn_worker_task( + program_path.to_owned(), + cache_path.to_owned(), + spawn_timeout, + node_version, + security_status, + ) + .boxed(), ); }, ToPool::StartWork { worker, pvf, artifact_path } => { @@ -229,7 +242,6 @@ fn handle_to_pool( worker, idle, pvf, - cache_path.to_owned(), artifact_path, preparation_timer, ) @@ -258,13 +270,23 @@ fn handle_to_pool( async fn spawn_worker_task( program_path: PathBuf, + cache_path: PathBuf, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, ) -> PoolEvent { use futures_timer::Delay; loop { - match worker_intf::spawn(&program_path, spawn_timeout, node_version.as_deref()).await { + match worker_intf::spawn( + &program_path, + &cache_path, + spawn_timeout, + node_version.as_deref(), + security_status.clone(), + ) + .await + { Ok((idle, handle)) => break PoolEvent::Spawn(idle, handle), Err(err) => { gum::warn!(target: LOG_TARGET, "failed to spawn a prepare worker: {:?}", err); @@ -281,11 +303,10 @@ async fn start_work_task( worker: Worker, idle: IdleWorker, pvf: PvfPrepData, - cache_path: PathBuf, artifact_path: PathBuf, _preparation_timer: Option, ) -> PoolEvent { - let outcome = worker_intf::start_work(&metrics, idle, pvf, &cache_path, artifact_path).await; + let outcome = worker_intf::start_work(&metrics, idle, pvf, artifact_path).await; PoolEvent::StartWork(worker, outcome) } @@ -322,14 +343,29 @@ fn handle_mux( ), // Return `Concluded`, but do not kill the worker since the error was on the host // side. - Outcome::RenameTmpFileErr { worker: idle, result: _, err } => + Outcome::RenameTmpFileErr { worker: idle, result: _, err, src, dest } => handle_concluded_no_rip( from_pool, spawned, worker, idle, - Err(PrepareError::RenameTmpFileErr(err)), + Err(PrepareError::RenameTmpFileErr { err, src, dest }), ), + // Could not clear worker cache. Kill the worker so other jobs can't see the data. + Outcome::ClearWorkerDir { err } => { + if attempt_retire(metrics, spawned, worker) { + reply( + from_pool, + FromPool::Concluded { + worker, + rip: true, + result: Err(PrepareError::ClearWorkerDir(err)), + }, + )?; + } + + Ok(()) + }, Outcome::Unreachable => { if attempt_retire(metrics, spawned, worker) { reply(from_pool, FromPool::Rip(worker))?; @@ -434,6 +470,7 @@ pub fn start( cache_path: PathBuf, spawn_timeout: Duration, node_version: Option, + security_status: SecurityStatus, ) -> (mpsc::Sender, mpsc::UnboundedReceiver, impl Future) { let (to_pool_tx, to_pool_rx) = mpsc::channel(10); let (from_pool_tx, from_pool_rx) = mpsc::unbounded(); @@ -444,6 +481,7 @@ pub fn start( cache_path, spawn_timeout, node_version, + security_status, to_pool: to_pool_rx, from_pool: from_pool_tx, spawned: HopSlotMap::with_capacity_and_key(20), diff --git a/polkadot/node/core/pvf/src/prepare/worker_intf.rs b/polkadot/node/core/pvf/src/prepare/worker_intf.rs index 5280ab6b42a235b441fe9d9e25bc415b46ecfa2f..b66c3604434363cdffefaaddf9091397c25b49a0 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_intf.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_intf.rs @@ -19,17 +19,17 @@ use crate::{ metrics::Metrics, worker_intf::{ - path_to_bytes, spawn_with_program_path, tmpfile_in, IdleWorker, SpawnErr, WorkerHandle, - JOB_TIMEOUT_WALL_CLOCK_FACTOR, + clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker, + SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }, LOG_TARGET, }; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::{PrepareError, PrepareResult}, - framed_recv, framed_send, prepare::PrepareStats, pvf::PvfPrepData, + worker_dir, SecurityStatus, }; use sp_core::hexdisplay::HexDisplay; @@ -41,19 +41,33 @@ use tokio::{io, net::UnixStream}; /// Spawns a new worker with the given program path that acts as the worker and the spawn timeout. /// -/// The program should be able to handle ` prepare-worker ` invocation. +/// Sends a handshake message to the worker as soon as it is spawned. pub async fn spawn( program_path: &Path, + cache_path: &Path, spawn_timeout: Duration, node_version: Option<&str>, + security_status: SecurityStatus, ) -> Result<(IdleWorker, WorkerHandle), SpawnErr> { let mut extra_args = vec!["prepare-worker"]; if let Some(node_version) = node_version { extra_args.extend_from_slice(&["--node-impl-version", node_version]); } - spawn_with_program_path("prepare", program_path, &extra_args, spawn_timeout).await + + spawn_with_program_path( + "prepare", + program_path, + cache_path, + &extra_args, + spawn_timeout, + security_status, + ) + .await } +/// Outcome of PVF preparation. +/// +/// If the idle worker token is not returned, it means the worker must be terminated. pub enum Outcome { /// The worker has finished the work assigned to it. Concluded { worker: IdleWorker, result: PrepareResult }, @@ -62,9 +76,19 @@ pub enum Outcome { Unreachable, /// The temporary file for the artifact could not be created at the given cache path. CreateTmpFileErr { worker: IdleWorker, err: String }, - /// The response from the worker is received, but the file cannot be renamed (moved) to the + /// The response from the worker is received, but the tmp file cannot be renamed (moved) to the /// final destination location. - RenameTmpFileErr { worker: IdleWorker, result: PrepareResult, err: String }, + RenameTmpFileErr { + worker: IdleWorker, + result: PrepareResult, + err: String, + // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible + // conversion to `Option`. + src: Option, + dest: Option, + }, + /// The worker cache could not be cleared for the given reason. + ClearWorkerDir { err: String }, /// The worker failed to finish the job until the given deadline. /// /// The worker is no longer usable and should be killed. @@ -84,83 +108,88 @@ pub async fn start_work( metrics: &Metrics, worker: IdleWorker, pvf: PvfPrepData, - cache_path: &Path, artifact_path: PathBuf, ) -> Outcome { - let IdleWorker { stream, pid } = worker; + let IdleWorker { stream, pid, worker_dir } = worker; gum::debug!( target: LOG_TARGET, worker_pid = %pid, + ?worker_dir, "starting prepare for {}", artifact_path.display(), ); - with_tmp_file(stream, pid, cache_path, |tmp_file, mut stream| async move { - let preparation_timeout = pvf.prep_timeout(); - if let Err(err) = send_request(&mut stream, pvf, &tmp_file).await { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - "failed to send a prepare request: {:?}", - err, - ); - return Outcome::Unreachable - } - - // Wait for the result from the worker, keeping in mind that there may be a timeout, the - // worker may get killed, or something along these lines. In that case we should propagate - // the error to the pool. - // - // 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 - // in the child. We want to use CPU time because it varies less than wall clock time under - // load, but the CPU resources of the child can only be measured from the parent after the - // child process terminates. - let timeout = preparation_timeout * JOB_TIMEOUT_WALL_CLOCK_FACTOR; - let result = tokio::time::timeout(timeout, recv_response(&mut stream, pid)).await; - - match result { - // Received bytes from worker within the time limit. - Ok(Ok(prepare_result)) => - handle_response( - metrics, - IdleWorker { stream, pid }, - prepare_result, - pid, - tmp_file, - artifact_path, - preparation_timeout, - ) - .await, - Ok(Err(err)) => { - // Communication error within the time limit. + with_worker_dir_setup( + worker_dir, + stream, + pid, + |tmp_artifact_file, mut stream, worker_dir| async move { + let preparation_timeout = pvf.prep_timeout(); + if let Err(err) = send_request(&mut stream, pvf).await { gum::warn!( target: LOG_TARGET, worker_pid = %pid, - "failed to recv a prepare response: {:?}", + "failed to send a prepare request: {:?}", err, ); - Outcome::IoErr(err.to_string()) - }, - Err(_) => { - // Timed out here on the host. - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - "did not recv a prepare response within the time limit", - ); - Outcome::TimedOut - }, - } - }) + return Outcome::Unreachable + } + + // Wait for the result from the worker, keeping in mind that there may be a timeout, the + // worker may get killed, or something along these lines. In that case we should + // propagate the error to the pool. + // + // 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 in the child. We want to use CPU time because it varies less than wall clock + // time under load, but the CPU resources of the child can only be measured from the + // parent after the child process terminates. + let timeout = preparation_timeout * JOB_TIMEOUT_WALL_CLOCK_FACTOR; + let result = tokio::time::timeout(timeout, recv_response(&mut stream, pid)).await; + + match result { + // Received bytes from worker within the time limit. + Ok(Ok(prepare_result)) => + handle_response( + metrics, + IdleWorker { stream, pid, worker_dir }, + prepare_result, + pid, + tmp_artifact_file, + artifact_path, + preparation_timeout, + ) + .await, + Ok(Err(err)) => { + // Communication error within the time limit. + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + "failed to recv a prepare response: {:?}", + err, + ); + Outcome::IoErr(err.to_string()) + }, + Err(_) => { + // Timed out here on the host. + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + "did not recv a prepare response within the time limit", + ); + Outcome::TimedOut + }, + } + }, + ) .await } /// Handles the case where we successfully received response bytes on the host from the child. /// -/// NOTE: Here we know the artifact exists, but is still located in a temporary file which will be -/// cleared by `with_tmp_file`. +/// 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( metrics: &Metrics, worker: IdleWorker, @@ -209,7 +238,13 @@ async fn handle_response( artifact_path.display(), err, ); - Outcome::RenameTmpFileErr { worker, result, err: format!("{:?}", err) } + Outcome::RenameTmpFileErr { + worker, + result, + err: format!("{:?}", err), + src: tmp_file.to_str().map(String::from), + dest: artifact_path.to_str().map(String::from), + } }, }; @@ -220,61 +255,58 @@ async fn handle_response( outcome } -/// Create a temporary file for an artifact at the given cache path and execute the given -/// future/closure passing the file path in. +/// Create a temporary file for an artifact in the worker cache, execute the given future/closure +/// passing the file path in, and clean up the worker cache. /// -/// The function will try best effort to not leave behind the temporary file. -async fn with_tmp_file(stream: UnixStream, pid: u32, cache_path: &Path, f: F) -> Outcome +/// Failure to clean up the worker cache results in an error - leaving any files here could be a +/// security issue, and we should shut down the worker. This should be very rare. +async fn with_worker_dir_setup( + worker_dir: WorkerDir, + stream: UnixStream, + pid: u32, + f: F, +) -> Outcome where Fut: futures::Future, - F: FnOnce(PathBuf, UnixStream) -> Fut, + F: FnOnce(PathBuf, UnixStream, WorkerDir) -> Fut, { - let tmp_file = match tmpfile_in("prepare-artifact-", cache_path).await { - Ok(f) => f, - Err(err) => { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - "failed to create a temp file for the artifact: {:?}", - err, - ); - return Outcome::CreateTmpFileErr { - worker: IdleWorker { stream, pid }, - err: format!("{:?}", err), - } - }, + // Create the tmp file here so that the child doesn't need any file creation rights. This will + // be cleared at the end of this function. + let tmp_file = worker_dir::prepare_tmp_artifact(&worker_dir.path); + if let Err(err) = tokio::fs::File::create(&tmp_file).await { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + ?worker_dir, + "failed to create a temp file for the artifact: {:?}", + err, + ); + return Outcome::CreateTmpFileErr { + worker: IdleWorker { stream, pid, worker_dir }, + err: format!("{:?}", err), + } }; - let outcome = f(tmp_file.clone(), stream).await; + let worker_dir_path = worker_dir.path.clone(); + let outcome = f(tmp_file, stream, worker_dir).await; - // The function called above is expected to move `tmp_file` to a new location upon success. - // However, the function may as well fail and in that case we should remove the tmp file here. - // - // In any case, we try to remove the file here so that there are no leftovers. We only report - // errors that are different from the `NotFound`. - match tokio::fs::remove_file(tmp_file).await { - Ok(()) => (), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => (), - Err(err) => { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - "failed to remove the tmp file: {:?}", - err, - ); - }, + // Try to clear the worker dir. + if let Err(err) = clear_worker_dir_path(&worker_dir_path) { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + ?worker_dir_path, + "failed to clear worker cache after the job: {:?}", + err, + ); + return Outcome::ClearWorkerDir { err: format!("{:?}", err) } } outcome } -async fn send_request( - stream: &mut UnixStream, - pvf: PvfPrepData, - tmp_file: &Path, -) -> io::Result<()> { +async fn send_request(stream: &mut UnixStream, pvf: PvfPrepData) -> io::Result<()> { framed_send(stream, &pvf.encode()).await?; - framed_send(stream, path_to_bytes(tmp_file)).await?; Ok(()) } diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 4301afc3cc7ea6e736a351470b39019b74f5f16b..ca69ef9e4d047d61590c3a0ff362ab43d8e4de6f 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -29,20 +29,20 @@ pub fn validate_candidate( code: &[u8], params: &[u8], ) -> Result, Box> { - use polkadot_node_core_pvf_execute_worker::Executor; + use polkadot_node_core_pvf_execute_worker::execute_artifact; use polkadot_node_core_pvf_prepare_worker::{prepare, prevalidate}; let code = sp_maybe_compressed_blob::decompress(code, 10 * 1024 * 1024) .expect("Decompressing code failed"); let blob = prevalidate(&code)?; - let compiled_artifact_blob = prepare(blob, &ExecutorParams::default())?; + let executor_params = ExecutorParams::default(); + let compiled_artifact_blob = prepare(blob, &executor_params)?; - let executor = Executor::new(ExecutorParams::default())?; let result = unsafe { // SAFETY: This is trivially safe since the artifact is obtained by calling `prepare` // and is written into a temporary directory in an unmodified state. - executor.execute(&compiled_artifact_blob, params)? + execute_artifact(&compiled_artifact_blob, &executor_params, params)? }; Ok(result) diff --git a/polkadot/node/core/pvf/src/worker_intf.rs b/polkadot/node/core/pvf/src/worker_intf.rs index 795ad4524443bcf1032a40d5931520c110219055..bd85d84055ce5e6136a97fac329ee20a39744137 100644 --- a/polkadot/node/core/pvf/src/worker_intf.rs +++ b/polkadot/node/core/pvf/src/worker_intf.rs @@ -20,6 +20,7 @@ use crate::LOG_TARGET; use futures::FutureExt as _; use futures_timer::Delay; use pin_project::pin_project; +use polkadot_node_core_pvf_common::SecurityStatus; use rand::Rng; use std::{ fmt, mem, @@ -39,17 +40,37 @@ use tokio::{ pub const JOB_TIMEOUT_WALL_CLOCK_FACTOR: u32 = 4; /// This is publicly exposed only for integration tests. +/// +/// # Parameters +/// +/// - `debug_id`: An identifier for the process (e.g. "execute" or "prepare"). +/// +/// - `program_path`: The path to the program. +/// +/// - `cache_path`: The path to the artifact cache. +/// +/// - `extra_args`: Optional extra CLI arguments to the program. NOTE: Should only contain data +/// required before the handshake, like node/worker versions for the version check. Other data +/// should go through the handshake. +/// +/// - `spawn_timeout`: The amount of time to wait for the child process to spawn. +/// +/// - `security_status`: contains the detected status of security features. #[doc(hidden)] pub async fn spawn_with_program_path( debug_id: &'static str, program_path: impl Into, + cache_path: &Path, extra_args: &[&str], spawn_timeout: Duration, + security_status: SecurityStatus, ) -> Result<(IdleWorker, WorkerHandle), SpawnErr> { let program_path = program_path.into(); + let worker_dir = WorkerDir::new(debug_id, cache_path).await?; + let extra_args: Vec = extra_args.iter().map(|arg| arg.to_string()).collect(); + with_transient_socket_path(debug_id, |socket_path| { let socket_path = socket_path.to_owned(); - let extra_args: Vec = extra_args.iter().map(|arg| arg.to_string()).collect(); async move { let listener = UnixListener::bind(&socket_path).map_err(|err| { @@ -58,25 +79,36 @@ pub async fn spawn_with_program_path( %debug_id, ?program_path, ?extra_args, + ?worker_dir, + ?socket_path, "cannot bind unix socket: {:?}", err, ); SpawnErr::Bind })?; - let handle = - WorkerHandle::spawn(&program_path, &extra_args, socket_path).map_err(|err| { - gum::warn!( - target: LOG_TARGET, - %debug_id, - ?program_path, - ?extra_args, - "cannot spawn a worker: {:?}", - err, - ); - SpawnErr::ProcessSpawn - })?; + let handle = WorkerHandle::spawn( + &program_path, + &extra_args, + &socket_path, + &worker_dir.path, + security_status, + ) + .map_err(|err| { + gum::warn!( + target: LOG_TARGET, + %debug_id, + ?program_path, + ?extra_args, + ?worker_dir.path, + ?socket_path, + "cannot spawn a worker: {:?}", + err, + ); + SpawnErr::ProcessSpawn + })?; + let worker_dir_path = worker_dir.path.clone(); futures::select! { accept_result = listener.accept().fuse() => { let (stream, _) = accept_result.map_err(|err| { @@ -85,12 +117,14 @@ pub async fn spawn_with_program_path( %debug_id, ?program_path, ?extra_args, + ?worker_dir_path, + ?socket_path, "cannot accept a worker: {:?}", err, ); SpawnErr::Accept })?; - Ok((IdleWorker { stream, pid: handle.id() }, handle)) + Ok((IdleWorker { stream, pid: handle.id(), worker_dir }, handle)) } _ = Delay::new(spawn_timeout).fuse() => { gum::warn!( @@ -98,6 +132,8 @@ pub async fn spawn_with_program_path( %debug_id, ?program_path, ?extra_args, + ?worker_dir_path, + ?socket_path, ?spawn_timeout, "spawning and connecting to socket timed out", ); @@ -114,9 +150,9 @@ where F: FnOnce(&Path) -> Fut, Fut: futures::Future> + 'static, { - let socket_path = tmpfile(&format!("pvf-host-{}", debug_id)) + let socket_path = tmppath(&format!("pvf-host-{}", debug_id)) .await - .map_err(|_| SpawnErr::TmpFile)?; + .map_err(|_| SpawnErr::TmpPath)?; let result = f(&socket_path).await; // Best effort to remove the socket file. Under normal circumstances the socket will be removed @@ -126,12 +162,12 @@ where result } -/// Returns a path under the given `dir`. The file name will start with the given prefix. +/// Returns a path under the given `dir`. The path name will start with the given prefix. /// /// There is only a certain number of retries. If exceeded this function will give up and return an /// error. -pub async fn tmpfile_in(prefix: &str, dir: &Path) -> io::Result { - fn tmppath(prefix: &str, dir: &Path) -> PathBuf { +pub async fn tmppath_in(prefix: &str, dir: &Path) -> io::Result { + fn make_tmppath(prefix: &str, dir: &Path) -> PathBuf { use rand::distributions::Alphanumeric; const DESCRIMINATOR_LEN: usize = 10; @@ -143,27 +179,27 @@ pub async fn tmpfile_in(prefix: &str, dir: &Path) -> io::Result { let s = std::str::from_utf8(&buf) .expect("the string is collected from a valid utf-8 sequence; qed"); - let mut file = dir.to_owned(); - file.push(s); - file + let mut path = dir.to_owned(); + path.push(s); + path } const NUM_RETRIES: usize = 50; for _ in 0..NUM_RETRIES { - let candidate_path = tmppath(prefix, dir); - if !candidate_path.exists() { - return Ok(candidate_path) + let tmp_path = make_tmppath(prefix, dir); + if !tmp_path.exists() { + return Ok(tmp_path) } } - Err(io::Error::new(io::ErrorKind::Other, "failed to create a temporary file")) + Err(io::Error::new(io::ErrorKind::Other, "failed to create a temporary path")) } -/// The same as [`tmpfile_in`], but uses [`std::env::temp_dir`] as the directory. -pub async fn tmpfile(prefix: &str) -> io::Result { +/// The same as [`tmppath_in`], but uses [`std::env::temp_dir`] as the directory. +pub async fn tmppath(prefix: &str) -> io::Result { let temp_dir = PathBuf::from(std::env::temp_dir()); - tmpfile_in(prefix, &temp_dir).await + tmppath_in(prefix, &temp_dir).await } /// A struct that represents an idle worker. @@ -177,13 +213,19 @@ pub struct IdleWorker { /// The identifier of this process. Used to reset the niceness. pub pid: u32, + + /// The temporary per-worker path. We clean up the worker dir between jobs and delete it when + /// the worker dies. + pub worker_dir: WorkerDir, } /// An error happened during spawning a worker process. #[derive(Clone, Debug)] pub enum SpawnErr { - /// Cannot obtain a temporary file location. - TmpFile, + /// Cannot obtain a temporary path location. + TmpPath, + /// An FS error occurred. + Fs(String), /// Cannot bind the socket to the given path. Bind, /// An error happened during accepting a connection to the socket. @@ -220,11 +262,34 @@ impl WorkerHandle { program: impl AsRef, extra_args: &[String], socket_path: impl AsRef, + worker_dir_path: impl AsRef, + security_status: SecurityStatus, ) -> io::Result { - let mut child = process::Command::new(program.as_ref()) + let security_args = { + let mut args = vec![]; + if security_status.can_enable_landlock { + args.push("--can-enable-landlock".to_string()); + } + if security_status.can_unshare_user_namespace_and_change_root { + args.push("--can-unshare-user-namespace-and-change-root".to_string()); + } + args + }; + + // Clear all env vars from the spawned process. + let mut command = process::Command::new(program.as_ref()); + command.env_clear(); + // Add back any env vars we want to keep. + if let Ok(value) = std::env::var("RUST_LOG") { + command.env("RUST_LOG", value); + } + let mut child = command .args(extra_args) .arg("--socket-path") .arg(socket_path.as_ref().as_os_str()) + .arg("--worker-dir-path") + .arg(worker_dir_path.as_ref().as_os_str()) + .args(&security_args) .stdout(std::process::Stdio::piped()) .kill_on_drop(true) .spawn()?; @@ -306,16 +371,6 @@ impl fmt::Debug for WorkerHandle { } } -/// Convert the given path into a byte buffer. -pub fn path_to_bytes(path: &Path) -> &[u8] { - // Ideally, we take the `OsStr` of the path, send that and reconstruct this on the other side. - // However, libstd doesn't provide us with such an option. There are crates out there that - // allow for extraction of a path, but TBH it doesn't seem to be a real issue. - // - // However, should be there reports we can incorporate such a crate here. - path.to_str().expect("non-UTF-8 path").as_bytes() -} - /// Write some data prefixed by its length into `w`. pub async fn framed_send(w: &mut (impl AsyncWrite + Unpin), buf: &[u8]) -> io::Result<()> { let len_buf = buf.len().to_le_bytes(); @@ -333,3 +388,84 @@ pub async fn framed_recv(r: &mut (impl AsyncRead + Unpin)) -> io::Result r.read_exact(&mut buf).await?; Ok(buf) } + +/// A temporary worker dir that contains only files needed by the worker. The worker will change its +/// root (the `/` directory) to this directory; it should have access to no other paths on its +/// filesystem. +/// +/// NOTE: This struct cleans up its associated directory when it is dropped. Therefore it should not +/// implement `Clone`. +/// +/// # File structure +/// +/// The overall file structure for the PVF system is as follows. The `worker-dir-X`s are managed by +/// this struct. +/// +/// ```nocompile +/// + // +/// - artifact-1 +/// - artifact-2 +/// - [...] +/// - worker-dir-1/ (new `/` for worker-1) +/// + socket (created by host) +/// + tmp-artifact (created by host) (prepare-only) +/// + artifact (link -> artifact-1) (created by host) (execute-only) +/// - worker-dir-2/ (new `/` for worker-2) +/// + [...] +/// ``` +#[derive(Debug)] +pub struct WorkerDir { + pub path: PathBuf, +} + +impl WorkerDir { + /// Creates a new, empty worker dir with a random name in the given cache dir. + pub async fn new(debug_id: &'static str, cache_dir: &Path) -> Result { + let prefix = format!("worker-dir-{}-", debug_id); + let path = tmppath_in(&prefix, cache_dir).await.map_err(|_| SpawnErr::TmpPath)?; + tokio::fs::create_dir(&path) + .await + .map_err(|err| SpawnErr::Fs(err.to_string()))?; + Ok(Self { path }) + } +} + +// Try to clean up the temporary worker dir at the end of the worker's lifetime. It should be wiped +// on startup, but we make a best effort not to leave it around. +impl Drop for WorkerDir { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.path); + } +} + +// Not async since Rust has trouble with async recursion. There should be few files here anyway. +// +// TODO: A lingering malicious job can still access future files in this dir. See +// for how to fully secure this. +/// Clear the temporary worker dir without deleting it. Not deleting is important because the worker +/// has mounted its own separate filesystem here. +/// +/// Should be called right after a job has finished. We don't want jobs to have access to +/// artifacts from previous jobs. +pub fn clear_worker_dir_path(worker_dir_path: &Path) -> io::Result<()> { + fn remove_dir_contents(path: &Path) -> io::Result<()> { + for entry in std::fs::read_dir(&path)? { + let entry = entry?; + let path = entry.path(); + + if entry.file_type()?.is_dir() { + remove_dir_contents(&path)?; + std::fs::remove_dir(path)?; + } else { + std::fs::remove_file(path)?; + } + } + Ok(()) + } + + // Note the worker dir may not exist anymore because of the worker dying and being cleaned up. + match remove_dir_contents(worker_dir_path) { + Err(err) if matches!(err.kind(), io::ErrorKind::NotFound) => Ok(()), + result => result, + } +} diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index bad7a66054c9e885c6693f2652e1d6235b7324f4..8bdd09db208a92f5510f0c60856bab6a1c3103e0 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -100,7 +100,7 @@ async fn execute_bad_block_on_parent() { let host = TestHost::new(); - let _ret = host + let _err = host .validate_candidate( adder::wasm_binary_unwrap(), ValidationParams { @@ -145,3 +145,37 @@ async fn stress_spawn() { futures::future::join_all((0..100).map(|_| execute(host.clone()))).await; } + +// With one worker, run multiple execution jobs serially. They should not conflict. +#[tokio::test] +async fn execute_can_run_serially() { + let host = std::sync::Arc::new(TestHost::new_with_config(|cfg| { + cfg.execute_workers_max_num = 1; + })); + + async fn execute(host: std::sync::Arc) { + let parent_head = HeadData { number: 0, parent_hash: [0; 32], post_state: hash_state(0) }; + let block_data = BlockData { state: 0, add: 512 }; + let ret = host + .validate_candidate( + adder::wasm_binary_unwrap(), + ValidationParams { + parent_head: GenericHeadData(parent_head.encode()), + block_data: GenericBlockData(block_data.encode()), + relay_parent_number: 1, + relay_parent_storage_root: Default::default(), + }, + Default::default(), + ) + .await + .unwrap(); + + let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); + + assert_eq!(new_head.number, 1); + assert_eq!(new_head.parent_hash, parent_head.hash()); + assert_eq!(new_head.post_state, hash_state(512)); + } + + futures::future::join_all((0..5).map(|_| execute(host.clone()))).await; +} diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index dc8f00098ec5ebe55fa319116d23b308c094ffd9..f699b5840d8faa7e0a51e859b735caed02f3e621 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -18,8 +18,8 @@ use assert_matches::assert_matches; use parity_scale_codec::Encode as _; use polkadot_node_core_pvf::{ - start, Config, InvalidCandidate, Metrics, PrepareJobKind, PvfPrepData, ValidationError, - ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, + start, Config, InvalidCandidate, Metrics, PrepareError, PrepareJobKind, PrepareStats, + PvfPrepData, ValidationError, ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; use polkadot_primitives::ExecutorParams; @@ -70,6 +70,33 @@ impl TestHost { Self { cache_dir, host: Mutex::new(host) } } + async fn precheck_pvf( + &self, + code: &[u8], + executor_params: ExecutorParams, + ) -> Result { + let (result_tx, result_rx) = futures::channel::oneshot::channel(); + + let code = sp_maybe_compressed_blob::decompress(code, 16 * 1024 * 1024) + .expect("Compression works"); + + self.host + .lock() + .await + .precheck_pvf( + PvfPrepData::from_code( + code.into(), + executor_params, + TEST_PREPARATION_TIMEOUT, + PrepareJobKind::Prechecking, + ), + result_tx, + ) + .await + .unwrap(); + result_rx.await.unwrap() + } + async fn validate_candidate( &self, code: &[u8], @@ -291,8 +318,12 @@ async fn deleting_prepared_artifact_does_not_dispute() { { // Get the artifact path (asserting it exists). let mut cache_dir: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); - assert_eq!(cache_dir.len(), 1); - let artifact_path = cache_dir.pop().unwrap().unwrap(); + // Should contain the artifact and the worker dir. + assert_eq!(cache_dir.len(), 2); + let mut artifact_path = cache_dir.pop().unwrap().unwrap(); + if artifact_path.path().is_dir() { + artifact_path = cache_dir.pop().unwrap().unwrap(); + } // Delete the artifact. std::fs::remove_file(artifact_path.path()).unwrap(); @@ -317,3 +348,19 @@ async fn deleting_prepared_artifact_does_not_dispute() { r => panic!("{:?}", r), } } + +// With one worker, run multiple preparation jobs serially. They should not conflict. +#[tokio::test] +async fn prepare_can_run_serially() { + let host = TestHost::new_with_config(|cfg| { + cfg.prepare_workers_hard_max_num = 1; + }); + + let _stats = host + .precheck_pvf(::adder::wasm_binary_unwrap(), Default::default()) + .await + .unwrap(); + + // Prepare a different wasm blob to prevent skipping work. + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), Default::default()).await.unwrap(); +} diff --git a/polkadot/node/core/pvf/tests/it/worker_common.rs b/polkadot/node/core/pvf/tests/it/worker_common.rs index 875ae79af09732fd14ebabbc1c711549c43f46fa..5379d29556c76aff3a489d7d0a967d4b6a503637 100644 --- a/polkadot/node/core/pvf/tests/it/worker_common.rs +++ b/polkadot/node/core/pvf/tests/it/worker_common.rs @@ -14,8 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use polkadot_node_core_pvf::testing::{spawn_with_program_path, SpawnErr}; -use std::time::Duration; +use polkadot_node_core_pvf::{ + testing::{spawn_with_program_path, SpawnErr}, + SecurityStatus, +}; +use std::{env, time::Duration}; fn worker_path(name: &str) -> std::path::PathBuf { let mut worker_path = std::env::current_exe().unwrap(); @@ -33,8 +36,10 @@ async fn spawn_immediate_exit() { let result = spawn_with_program_path( "integration-test", worker_path("polkadot-prepare-worker"), + &env::temp_dir(), &["exit"], Duration::from_secs(2), + SecurityStatus::default(), ) .await; assert!(matches!(result, Err(SpawnErr::AcceptTimeout))); @@ -45,8 +50,10 @@ async fn spawn_timeout() { let result = spawn_with_program_path( "integration-test", worker_path("polkadot-execute-worker"), + &env::temp_dir(), &["test-sleep"], Duration::from_secs(2), + SecurityStatus::default(), ) .await; assert!(matches!(result, Err(SpawnErr::AcceptTimeout))); @@ -57,8 +64,10 @@ async fn should_connect() { let _ = spawn_with_program_path( "integration-test", worker_path("polkadot-prepare-worker"), + &env::temp_dir(), &["prepare-worker"], Duration::from_secs(2), + SecurityStatus::default(), ) .await .unwrap(); diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 7f41d74e616c6152038f6ac58d8189c5d722fab3..69eea22b23bda4d8c67543c535c5f80afd81703d 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,12 +20,12 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, + CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -61,14 +61,12 @@ pub(crate) struct RequestResultCache { LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option>, version: LruMap, disputes: LruMap)>>, - unapplied_slashes: - LruMap>, - key_ownership_proof: - LruMap<(Hash, ValidatorId), Option>, + unapplied_slashes: LruMap>, + key_ownership_proof: LruMap<(Hash, ValidatorId), Option>, minimum_backing_votes: LruMap, - - staging_para_backing_state: LruMap<(Hash, ParaId), Option>, - staging_async_backing_params: LruMap, + disabled_validators: LruMap>, + para_backing_state: LruMap<(Hash, ParaId), Option>, + async_backing_params: LruMap, } impl Default for RequestResultCache { @@ -99,9 +97,9 @@ impl Default for RequestResultCache { unapplied_slashes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), key_ownership_proof: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), minimum_backing_votes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), - - staging_para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), - staging_async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + disabled_validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } } } @@ -401,14 +399,14 @@ impl RequestResultCache { pub(crate) fn unapplied_slashes( &mut self, relay_parent: &Hash, - ) -> Option<&Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>> { + ) -> Option<&Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>> { self.unapplied_slashes.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_unapplied_slashes( &mut self, relay_parent: Hash, - value: Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>, + value: Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>, ) { self.unapplied_slashes.insert(relay_parent, value); } @@ -416,14 +414,14 @@ impl RequestResultCache { pub(crate) fn key_ownership_proof( &mut self, key: (Hash, ValidatorId), - ) -> Option<&Option> { + ) -> Option<&Option> { self.key_ownership_proof.get(&key).map(|v| &*v) } pub(crate) fn cache_key_ownership_proof( &mut self, key: (Hash, ValidatorId), - value: Option, + value: Option, ) { self.key_ownership_proof.insert(key, value); } @@ -431,7 +429,7 @@ impl RequestResultCache { // This request is never cached, hence always returns `None`. pub(crate) fn submit_report_dispute_lost( &mut self, - _key: (Hash, vstaging::slashing::DisputeProof, vstaging::slashing::OpaqueKeyOwnershipProof), + _key: (Hash, slashing::DisputeProof, slashing::OpaqueKeyOwnershipProof), ) -> Option<&Option<()>> { None } @@ -448,34 +446,49 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } - pub(crate) fn staging_para_backing_state( + pub(crate) fn disabled_validators( + &mut self, + relay_parent: &Hash, + ) -> Option<&Vec> { + self.disabled_validators.get(relay_parent).map(|v| &*v) + } + + pub(crate) fn cache_disabled_validators( + &mut self, + relay_parent: Hash, + disabled_validators: Vec, + ) { + self.disabled_validators.insert(relay_parent, disabled_validators); + } + + pub(crate) fn para_backing_state( &mut self, key: (Hash, ParaId), - ) -> Option<&Option> { - self.staging_para_backing_state.get(&key).map(|v| &*v) + ) -> Option<&Option> { + self.para_backing_state.get(&key).map(|v| &*v) } - pub(crate) fn cache_staging_para_backing_state( + pub(crate) fn cache_para_backing_state( &mut self, key: (Hash, ParaId), - value: Option, + value: Option, ) { - self.staging_para_backing_state.insert(key, value); + self.para_backing_state.insert(key, value); } - pub(crate) fn staging_async_backing_params( + pub(crate) fn async_backing_params( &mut self, key: &Hash, - ) -> Option<&vstaging::AsyncBackingParams> { - self.staging_async_backing_params.get(key).map(|v| &*v) + ) -> Option<&async_backing::AsyncBackingParams> { + self.async_backing_params.get(key).map(|v| &*v) } - pub(crate) fn cache_staging_async_backing_params( + pub(crate) fn cache_async_backing_params( &mut self, key: Hash, - value: vstaging::AsyncBackingParams, + value: async_backing::AsyncBackingParams, ) { - self.staging_async_backing_params.insert(key, value); + self.async_backing_params.insert(key, value); } } @@ -515,16 +528,16 @@ pub(crate) enum RequestResult { ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option), Version(Hash, u32), Disputes(Hash, Vec<(SessionIndex, CandidateHash, DisputeState)>), - UnappliedSlashes(Hash, Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>), - KeyOwnershipProof(Hash, ValidatorId, Option), + UnappliedSlashes(Hash, Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>), + KeyOwnershipProof(Hash, ValidatorId, Option), // This is a request with side-effects. SubmitReportDisputeLost( Hash, - vstaging::slashing::DisputeProof, - vstaging::slashing::OpaqueKeyOwnershipProof, + slashing::DisputeProof, + slashing::OpaqueKeyOwnershipProof, Option<()>, ), - - StagingParaBackingState(Hash, ParaId, Option), - StagingAsyncBackingParams(Hash, vstaging::AsyncBackingParams), + DisabledValidators(Hash, Vec), + ParaBackingState(Hash, ParaId, Option), + AsyncBackingParams(Hash, async_backing::AsyncBackingParams), } diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index ec9bf10fa6e3add92ca37a274966a1e84277f07e..bdcca08b10dda6fed122e482e5ac015beb2a29bb 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -166,12 +166,13 @@ where .requests_cache .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), SubmitReportDisputeLost(_, _, _, _) => {}, - - StagingParaBackingState(relay_parent, para_id, constraints) => self + DisabledValidators(relay_parent, disabled_validators) => + self.requests_cache.cache_disabled_validators(relay_parent, disabled_validators), + ParaBackingState(relay_parent, para_id, constraints) => self .requests_cache - .cache_staging_para_backing_state((relay_parent, para_id), constraints), - StagingAsyncBackingParams(relay_parent, params) => - self.requests_cache.cache_staging_async_backing_params(relay_parent, params), + .cache_para_backing_state((relay_parent, para_id), constraints), + AsyncBackingParams(relay_parent, params) => + self.requests_cache.cache_async_backing_params(relay_parent, params), } } @@ -297,13 +298,12 @@ where Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) }, ), - - Request::StagingParaBackingState(para, sender) => - query!(staging_para_backing_state(para), sender) - .map(|sender| Request::StagingParaBackingState(para, sender)), - Request::StagingAsyncBackingParams(sender) => - query!(staging_async_backing_params(), sender) - .map(|sender| Request::StagingAsyncBackingParams(sender)), + Request::DisabledValidators(sender) => query!(disabled_validators(), sender) + .map(|sender| Request::DisabledValidators(sender)), + Request::ParaBackingState(para, sender) => query!(para_backing_state(para), sender) + .map(|sender| Request::ParaBackingState(para, sender)), + Request::AsyncBackingParams(sender) => query!(async_backing_params(), sender) + .map(|sender| Request::AsyncBackingParams(sender)), Request::MinimumBackingVotes(index, sender) => { if let Some(value) = self.requests_cache.minimum_backing_votes(index) { self.metrics.on_cached_request(); @@ -569,20 +569,25 @@ where ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT, sender ), - - Request::StagingParaBackingState(para, sender) => { + Request::DisabledValidators(sender) => query!( + DisabledValidators, + disabled_validators(), + ver = Request::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT, + sender + ), + Request::ParaBackingState(para, sender) => { query!( - StagingParaBackingState, - staging_para_backing_state(para), - ver = Request::STAGING_BACKING_STATE, + ParaBackingState, + para_backing_state(para), + ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT, sender ) }, - Request::StagingAsyncBackingParams(sender) => { + Request::AsyncBackingParams(sender) => { query!( - StagingAsyncBackingParams, - staging_async_backing_params(), - ver = Request::STAGING_BACKING_STATE, + AsyncBackingParams, + async_backing_params(), + ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT, sender ) }, diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index bb7c2968961171151e5690503b61d0950bd6a56a..979b3587d2692149d0d5927e80fea79f2618b0a0 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,9 +20,9 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + async_backing, slashing, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, + CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, @@ -213,7 +213,7 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { async fn unapplied_slashes( &self, _: Hash, - ) -> Result, ApiError> { + ) -> Result, ApiError> { todo!("Not required for tests") } @@ -221,15 +221,15 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { &self, _: Hash, _: ValidatorId, - ) -> Result, ApiError> { + ) -> Result, ApiError> { todo!("Not required for tests") } async fn submit_report_dispute_lost( &self, _: Hash, - _: vstaging::slashing::DisputeProof, - _: vstaging::slashing::OpaqueKeyOwnershipProof, + _: slashing::DisputeProof, + _: slashing::OpaqueKeyOwnershipProof, ) -> Result, ApiError> { todo!("Not required for tests") } @@ -250,24 +250,28 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { Ok(self.authorities.clone()) } - async fn staging_async_backing_params( + async fn async_backing_params( &self, _: Hash, - ) -> Result { + ) -> Result { todo!("Not required for tests") } - async fn staging_para_backing_state( + async fn para_backing_state( &self, _: Hash, _: ParaId, - ) -> Result, ApiError> { + ) -> Result, ApiError> { todo!("Not required for tests") } async fn minimum_backing_votes(&self, _: Hash, _: SessionIndex) -> Result { todo!("Not required for tests") } + + async fn disabled_validators(&self, _: Hash) -> Result, ApiError> { + todo!("Not required for tests") + } } #[test] diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index be302e46ad902241557d7fe46602dd199a8f5767..1ffaf6160ba2be444ab3ac6e2094c2b690fcde12 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.36", features = ["full", "extra-traits"] } +syn = { version = "2.0.38", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 08d203281cff467f7690728d6a73ef396ee1a025..9ce725f1682211d9b98166e50438e643c942d336 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -26,7 +26,7 @@ path = "../../src/bin/prepare-worker.rs" doc = false [dependencies] -polkadot-cli = { path = "../../cli", features = [ "malus", "rococo-native", "kusama-native", "westend-native", "polkadot-native" ] } +polkadot-cli = { path = "../../cli", features = [ "malus", "rococo-native", "westend-native" ] } polkadot-node-subsystem = { path = "../subsystem" } polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-node-subsystem-types = { path = "../subsystem-types" } @@ -40,7 +40,7 @@ assert_matches = "1.5" async-trait = "0.1.57" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 70c20437d125d234b47b0953fbf019931c72c33d..d8949b1c1123c25c00d85e2e9cf9392a6710f552 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -16,7 +16,10 @@ //! [`ApprovalDistribution`] implementation. //! -//! +//! See the documentation on [approval distribution][approval-distribution-page] in the +//! implementers' guide. +//! +//! [approval-distribution-page]: https://paritytech.github.io/polkadot-sdk/book/node/approval/approval-distribution.html #![warn(missing_docs)] @@ -26,8 +29,8 @@ use polkadot_node_network_protocol::{ self as net_protocol, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, peer_set::{ValidationVersion, MAX_NOTIFICATION_SIZE}, - v1 as protocol_v1, vstaging as protocol_vstaging, PeerId, UnifiedReputationChange as Rep, - Versioned, VersionedValidationProtocol, View, + v1 as protocol_v1, v2 as protocol_v2, PeerId, UnifiedReputationChange as Rep, Versioned, + VersionedValidationProtocol, View, }; use polkadot_node_primitives::approval::{ AssignmentCert, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, @@ -602,9 +605,7 @@ impl State { { match msg { Versioned::V1(protocol_v1::ApprovalDistributionMessage::Assignments(assignments)) | - Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Assignments( - assignments, - )) => { + Versioned::V2(protocol_v2::ApprovalDistributionMessage::Assignments(assignments)) => { gum::trace!( target: LOG_TARGET, peer_id = %peer_id, @@ -644,9 +645,7 @@ impl State { } }, Versioned::V1(protocol_v1::ApprovalDistributionMessage::Approvals(approvals)) | - Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Approvals( - approvals, - )) => { + Versioned::V2(protocol_v2::ApprovalDistributionMessage::Approvals(approvals)) => { gum::trace!( target: LOG_TARGET, peer_id = %peer_id, @@ -1060,7 +1059,7 @@ impl State { route_random }; - let (v1_peers, vstaging_peers) = { + let (v1_peers, v2_peers) = { let peer_data = &self.peer_data; let peers = entry .known_by @@ -1090,9 +1089,9 @@ impl State { } let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); - let vstaging_peers = filter_peers_by_version(&peers, ValidationVersion::VStaging); + let v2_peers = filter_peers_by_version(&peers, ValidationVersion::V2); - (v1_peers, vstaging_peers) + (v1_peers, v2_peers) }; if !v1_peers.is_empty() { @@ -1103,10 +1102,10 @@ impl State { .await; } - if !vstaging_peers.is_empty() { + if !v2_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_peers, - versioned_assignments_packet(ValidationVersion::VStaging, assignments.clone()), + v2_peers, + versioned_assignments_packet(ValidationVersion::V2, assignments.clone()), )) .await; } @@ -1395,7 +1394,7 @@ impl State { in_topology || knowledge.sent.contains(message_subject, MessageKind::Assignment) }; - let (v1_peers, vstaging_peers) = { + let (v1_peers, v2_peers) = { let peer_data = &self.peer_data; let peers = entry .known_by @@ -1425,9 +1424,9 @@ impl State { } let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); - let vstaging_peers = filter_peers_by_version(&peers, ValidationVersion::VStaging); + let v2_peers = filter_peers_by_version(&peers, ValidationVersion::V2); - (v1_peers, vstaging_peers) + (v1_peers, v2_peers) }; let approvals = vec![vote]; @@ -1440,10 +1439,10 @@ impl State { .await; } - if !vstaging_peers.is_empty() { + if !v2_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_peers, - versioned_approvals_packet(ValidationVersion::VStaging, approvals), + v2_peers, + versioned_approvals_packet(ValidationVersion::V2, approvals), )) .await; } @@ -2017,9 +2016,9 @@ fn versioned_approvals_packet( Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( protocol_v1::ApprovalDistributionMessage::Approvals(approvals), )), - ValidationVersion::VStaging => - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Approvals(approvals), + ValidationVersion::V2 => + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Approvals(approvals), )), } } @@ -2033,9 +2032,9 @@ fn versioned_assignments_packet( Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( protocol_v1::ApprovalDistributionMessage::Assignments(assignments), )), - ValidationVersion::VStaging => - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments), + ValidationVersion::V2 => + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Assignments(assignments), )), } } diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 1e9ae7b620072939b81a13949fbc7299333210ad..29c7d8aa45daa1f88ec6737c448e9e2d8a493bb5 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -2388,9 +2388,9 @@ fn import_versioned_approval() { let _ = test_harness(state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // All peers are aware of relay parent. - setup_peer_with_view(overseer, &peer_a, ValidationVersion::VStaging, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, ValidationVersion::V2, view![hash]).await; setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, ValidationVersion::VStaging, view![hash]).await; + setup_peer_with_view(overseer, &peer_c, ValidationVersion::V2, view![hash]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -2431,8 +2431,8 @@ fn import_versioned_approval() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Assignments(assignments) )) )) => { assert_eq!(peers.len(), 2); @@ -2450,8 +2450,8 @@ fn import_versioned_approval() { validator: validator_index, signature: dummy_signature(), }; - let msg = protocol_vstaging::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_a, Versioned::VStaging(msg)).await; + let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer(overseer, &peer_a, Versioned::V2(msg)).await; assert_matches!( overseer_recv(overseer).await, @@ -2483,8 +2483,8 @@ fn import_versioned_approval() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Approvals(approvals) + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Approvals(approvals) )) )) => { assert_eq!(peers, vec![peer_c]); diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 07ff09c7e70e0c48bf144703b571acc21e9b1fb9..42c3abef547b93e4187ed92764a91b4415602f06 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -11,6 +11,7 @@ schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" thiserror = "1.0.48" +async-trait = "0.1.73" gum = { package = "tracing-gum", path = "../../gum" } polkadot-erasure-coding = { path = "../../../erasure-coding" } diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index 99f42f4bf9fe668132cb020dd3e74d4faca34c46..e2146981da926d2c7027c902ba5be4716382f4da 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -23,11 +23,10 @@ use std::{ iter::Iterator, num::NonZeroUsize, pin::Pin, - time::Duration, }; use futures::{ - channel::oneshot::{self, channel}, + channel::oneshot, future::{Future, FutureExt, RemoteHandle}, pin_mut, prelude::*, @@ -35,77 +34,55 @@ use futures::{ stream::{FuturesUnordered, StreamExt}, task::{Context, Poll}, }; -use rand::seq::SliceRandom; use schnellru::{ByLength, LruMap}; +use task::{FetchChunks, FetchChunksParams, FetchFull, FetchFullParams}; use fatality::Nested; use polkadot_erasure_coding::{ branch_hash, branches, obtain_chunks_v1, recovery_threshold, Error as ErasureEncodingError, }; -#[cfg(not(test))] -use polkadot_node_network_protocol::request_response::CHUNK_REQUEST_TIMEOUT; +use task::{RecoveryParams, RecoveryStrategy, RecoveryTask}; + use polkadot_node_network_protocol::{ - request_response::{ - self as req_res, outgoing::RequestError, v1 as request_v1, IncomingRequestReceiver, - OutgoingRequest, Recipient, Requests, - }, - IfDisconnected, UnifiedReputationChange as Rep, + request_response::{v1 as request_v1, IncomingRequestReceiver}, + UnifiedReputationChange as Rep, }; use polkadot_node_primitives::{AvailableData, ErasureChunk}; use polkadot_node_subsystem::{ errors::RecoveryError, jaeger, - messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage, NetworkBridgeTxMessage}, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, - SubsystemResult, + messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage}, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, + SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::request_session_info; use polkadot_primitives::{ - AuthorityDiscoveryId, BlakeTwo256, BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, - Hash, HashT, IndexedVec, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + BlakeTwo256, BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, Hash, HashT, + SessionIndex, SessionInfo, ValidatorIndex, }; mod error; mod futures_undead; mod metrics; +mod task; use metrics::Metrics; -use futures_undead::FuturesUndead; -use sc_network::{OutboundFailure, RequestFailure}; - #[cfg(test)] mod tests; const LOG_TARGET: &str = "parachain::availability-recovery"; -// How many parallel recovery tasks should be running at once. -const N_PARALLEL: usize = 50; - // Size of the LRU cache where we keep recovered data. const LRU_SIZE: u32 = 16; const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Peer sent unparsable request"); -/// Time after which we consider a request to have failed -/// -/// and we should try more peers. Note in theory the request times out at the network level, -/// measurements have shown, that in practice requests might actually take longer to fail in -/// certain occasions. (The very least, authority discovery is not part of the timeout.) -/// -/// For the time being this value is the same as the timeout on the networking layer, but as this -/// timeout is more soft than the networking one, it might make sense to pick different values as -/// well. -#[cfg(not(test))] -const TIMEOUT_START_NEW_REQUESTS: Duration = CHUNK_REQUEST_TIMEOUT; -#[cfg(test)] -const TIMEOUT_START_NEW_REQUESTS: Duration = Duration::from_millis(100); - /// PoV size limit in bytes for which prefer fetching from backers. const SMALL_POV_LIMIT: usize = 128 * 1024; #[derive(Clone, PartialEq)] /// The strategy we use to recover the PoV. -pub enum RecoveryStrategy { +pub enum RecoveryStrategyKind { /// We always try the backing group first, then fallback to validator chunks. BackersFirstAlways, /// We try the backing group first if PoV size is lower than specified, then fallback to @@ -113,101 +90,25 @@ pub enum RecoveryStrategy { BackersFirstIfSizeLower(usize), /// We always recover using validator chunks. ChunksAlways, - /// Do not request data from the availability store. - /// This is the useful for nodes where the - /// availability-store subsystem is not expected to run, - /// such as collators. - BypassAvailabilityStore, } -impl RecoveryStrategy { - /// Returns true if the strategy needs backing group index. - pub fn needs_backing_group(&self) -> bool { - match self { - RecoveryStrategy::BackersFirstAlways | RecoveryStrategy::BackersFirstIfSizeLower(_) => - true, - _ => false, - } - } - - /// Returns the PoV size limit in bytes for `BackersFirstIfSizeLower` strategy, otherwise - /// `None`. - pub fn pov_size_limit(&self) -> Option { - match *self { - RecoveryStrategy::BackersFirstIfSizeLower(limit) => Some(limit), - _ => None, - } - } -} /// The Availability Recovery Subsystem. pub struct AvailabilityRecoverySubsystem { /// PoV recovery strategy to use. - recovery_strategy: RecoveryStrategy, + recovery_strategy_kind: RecoveryStrategyKind, + // If this is true, do not request data from the availability store. + /// This is the useful for nodes where the + /// availability-store subsystem is not expected to run, + /// such as collators. + bypass_availability_store: bool, /// Receiver for available data requests. req_receiver: IncomingRequestReceiver, /// Metrics for this subsystem. metrics: Metrics, } -struct RequestFromBackers { - // a random shuffling of the validators from the backing group which indicates the order - // in which we connect to them and request the chunk. - shuffled_backers: Vec, - // channel to the erasure task handler. - erasure_task_tx: futures::channel::mpsc::Sender, -} - -struct RequestChunksFromValidators { - /// How many request have been unsuccessful so far. - error_count: usize, - /// Total number of responses that have been received. - /// - /// including failed ones. - total_received_responses: usize, - /// a random shuffling of the validators which indicates the order in which we connect to the - /// validators and request the chunk from them. - shuffling: VecDeque, - /// Chunks received so far. - received_chunks: HashMap, - /// Pending chunk requests with soft timeout. - requesting_chunks: FuturesUndead, (ValidatorIndex, RequestError)>>, - // channel to the erasure task handler. - erasure_task_tx: futures::channel::mpsc::Sender, -} - -struct RecoveryParams { - /// Discovery ids of `validators`. - validator_authority_keys: Vec, - - /// Validators relevant to this `RecoveryTask`. - validators: IndexedVec, - - /// The number of pieces needed. - threshold: usize, - - /// A hash of the relevant candidate. - candidate_hash: CandidateHash, - - /// The root of the erasure encoding of the para block. - erasure_root: Hash, - - /// Metrics to report - metrics: Metrics, - - /// Do not request data from availability-store - bypass_availability_store: bool, -} - -/// Source the availability data either by means -/// of direct request response protocol to -/// backers (a.k.a. fast-path), or recover from chunks. -enum Source { - RequestFromBackers(RequestFromBackers), - RequestChunks(RequestChunksFromValidators), -} - /// Expensive erasure coding computations that we want to run on a blocking thread. -enum ErasureTask { +pub enum ErasureTask { /// Reconstructs `AvailableData` from chunks given `n_validators`. Reconstruct( usize, @@ -219,486 +120,6 @@ enum ErasureTask { Reencode(usize, Hash, AvailableData, oneshot::Sender>), } -/// A stateful reconstruction of availability data in reference to -/// a candidate hash. -struct RecoveryTask { - sender: Sender, - - /// The parameters of the recovery process. - params: RecoveryParams, - - /// The source to obtain the availability data from. - source: Source, - - // channel to the erasure task handler. - erasure_task_tx: futures::channel::mpsc::Sender, -} - -impl RequestFromBackers { - fn new( - mut backers: Vec, - erasure_task_tx: futures::channel::mpsc::Sender, - ) -> Self { - backers.shuffle(&mut rand::thread_rng()); - - RequestFromBackers { shuffled_backers: backers, erasure_task_tx } - } - - // Run this phase to completion. - async fn run( - &mut self, - params: &RecoveryParams, - sender: &mut impl overseer::AvailabilityRecoverySenderTrait, - ) -> Result { - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - erasure_root = ?params.erasure_root, - "Requesting from backers", - ); - loop { - // Pop the next backer, and proceed to next phase if we're out. - let validator_index = - self.shuffled_backers.pop().ok_or_else(|| RecoveryError::Unavailable)?; - - // Request data. - let (req, response) = OutgoingRequest::new( - Recipient::Authority( - params.validator_authority_keys[validator_index.0 as usize].clone(), - ), - req_res::v1::AvailableDataFetchingRequest { candidate_hash: params.candidate_hash }, - ); - - sender - .send_message(NetworkBridgeTxMessage::SendRequests( - vec![Requests::AvailableDataFetchingV1(req)], - IfDisconnected::ImmediateError, - )) - .await; - - match response.await { - Ok(req_res::v1::AvailableDataFetchingResponse::AvailableData(data)) => { - let (reencode_tx, reencode_rx) = channel(); - self.erasure_task_tx - .send(ErasureTask::Reencode( - params.validators.len(), - params.erasure_root, - data, - reencode_tx, - )) - .await - .map_err(|_| RecoveryError::ChannelClosed)?; - - let reencode_response = - reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; - - if let Some(data) = reencode_response { - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - "Received full data", - ); - - return Ok(data) - } else { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - ?validator_index, - "Invalid data response", - ); - - // it doesn't help to report the peer with req/res. - } - }, - Ok(req_res::v1::AvailableDataFetchingResponse::NoSuchData) => {}, - Err(e) => gum::debug!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - ?validator_index, - err = ?e, - "Error fetching full available data." - ), - } - } - } -} - -impl RequestChunksFromValidators { - fn new( - n_validators: u32, - erasure_task_tx: futures::channel::mpsc::Sender, - ) -> Self { - let mut shuffling: Vec<_> = (0..n_validators).map(ValidatorIndex).collect(); - shuffling.shuffle(&mut rand::thread_rng()); - - RequestChunksFromValidators { - error_count: 0, - total_received_responses: 0, - shuffling: shuffling.into(), - received_chunks: HashMap::new(), - requesting_chunks: FuturesUndead::new(), - erasure_task_tx, - } - } - - fn is_unavailable(&self, params: &RecoveryParams) -> bool { - is_unavailable( - self.chunk_count(), - self.requesting_chunks.total_len(), - self.shuffling.len(), - params.threshold, - ) - } - - fn chunk_count(&self) -> usize { - self.received_chunks.len() - } - - fn insert_chunk(&mut self, validator_index: ValidatorIndex, chunk: ErasureChunk) { - self.received_chunks.insert(validator_index, chunk); - } - - fn can_conclude(&self, params: &RecoveryParams) -> bool { - self.chunk_count() >= params.threshold || self.is_unavailable(params) - } - - /// Desired number of parallel requests. - /// - /// For the given threshold (total required number of chunks) get the desired number of - /// requests we want to have running in parallel at this time. - fn get_desired_request_count(&self, threshold: usize) -> usize { - // Upper bound for parallel requests. - // We want to limit this, so requests can be processed within the timeout and we limit the - // following feedback loop: - // 1. Requests fail due to timeout - // 2. We request more chunks to make up for it - // 3. Bandwidth is spread out even more, so we get even more timeouts - // 4. We request more chunks to make up for it ... - let max_requests_boundary = std::cmp::min(N_PARALLEL, threshold); - // How many chunks are still needed? - let remaining_chunks = threshold.saturating_sub(self.chunk_count()); - // What is the current error rate, so we can make up for it? - let inv_error_rate = - self.total_received_responses.checked_div(self.error_count).unwrap_or(0); - // Actual number of requests we want to have in flight in parallel: - std::cmp::min( - max_requests_boundary, - remaining_chunks + remaining_chunks.checked_div(inv_error_rate).unwrap_or(0), - ) - } - - async fn launch_parallel_requests( - &mut self, - params: &RecoveryParams, - sender: &mut Sender, - ) where - Sender: overseer::AvailabilityRecoverySenderTrait, - { - let num_requests = self.get_desired_request_count(params.threshold); - let candidate_hash = ¶ms.candidate_hash; - let already_requesting_count = self.requesting_chunks.len(); - - gum::debug!( - target: LOG_TARGET, - ?candidate_hash, - ?num_requests, - error_count= ?self.error_count, - total_received = ?self.total_received_responses, - threshold = ?params.threshold, - ?already_requesting_count, - "Requesting availability chunks for a candidate", - ); - let mut requests = Vec::with_capacity(num_requests - already_requesting_count); - - while self.requesting_chunks.len() < num_requests { - if let Some(validator_index) = self.shuffling.pop_back() { - let validator = params.validator_authority_keys[validator_index.0 as usize].clone(); - gum::trace!( - target: LOG_TARGET, - ?validator, - ?validator_index, - ?candidate_hash, - "Requesting chunk", - ); - - // Request data. - let raw_request = req_res::v1::ChunkFetchingRequest { - candidate_hash: params.candidate_hash, - index: validator_index, - }; - - let (req, res) = OutgoingRequest::new(Recipient::Authority(validator), raw_request); - requests.push(Requests::ChunkFetchingV1(req)); - - params.metrics.on_chunk_request_issued(); - let timer = params.metrics.time_chunk_request(); - - self.requesting_chunks.push(Box::pin(async move { - let _timer = timer; - match res.await { - Ok(req_res::v1::ChunkFetchingResponse::Chunk(chunk)) => - Ok(Some(chunk.recombine_into_chunk(&raw_request))), - Ok(req_res::v1::ChunkFetchingResponse::NoSuchChunk) => Ok(None), - Err(e) => Err((validator_index, e)), - } - })); - } else { - break - } - } - - sender - .send_message(NetworkBridgeTxMessage::SendRequests( - requests, - IfDisconnected::TryConnect, - )) - .await; - } - - /// Wait for a sufficient amount of chunks to reconstruct according to the provided `params`. - async fn wait_for_chunks(&mut self, params: &RecoveryParams) { - let metrics = ¶ms.metrics; - - // Wait for all current requests to conclude or time-out, or until we reach enough chunks. - // We also declare requests undead, once `TIMEOUT_START_NEW_REQUESTS` is reached and will - // return in that case for `launch_parallel_requests` to fill up slots again. - while let Some(request_result) = - self.requesting_chunks.next_with_timeout(TIMEOUT_START_NEW_REQUESTS).await - { - self.total_received_responses += 1; - - match request_result { - Ok(Some(chunk)) => - if is_chunk_valid(params, &chunk) { - metrics.on_chunk_request_succeeded(); - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - validator_index = ?chunk.index, - "Received valid chunk", - ); - self.insert_chunk(chunk.index, chunk); - } else { - metrics.on_chunk_request_invalid(); - self.error_count += 1; - }, - Ok(None) => { - metrics.on_chunk_request_no_such_chunk(); - self.error_count += 1; - }, - Err((validator_index, e)) => { - self.error_count += 1; - - gum::trace!( - target: LOG_TARGET, - candidate_hash= ?params.candidate_hash, - err = ?e, - ?validator_index, - "Failure requesting chunk", - ); - - match e { - RequestError::InvalidResponse(_) => { - metrics.on_chunk_request_invalid(); - - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - err = ?e, - ?validator_index, - "Chunk fetching response was invalid", - ); - }, - RequestError::NetworkError(err) => { - // No debug logs on general network errors - that became very spammy - // occasionally. - if let RequestFailure::Network(OutboundFailure::Timeout) = err { - metrics.on_chunk_request_timeout(); - } else { - metrics.on_chunk_request_error(); - } - - self.shuffling.push_front(validator_index); - }, - RequestError::Canceled(_) => { - metrics.on_chunk_request_error(); - - self.shuffling.push_front(validator_index); - }, - } - }, - } - - // Stop waiting for requests when we either can already recover the data - // or have gotten firm 'No' responses from enough validators. - if self.can_conclude(params) { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - received_chunks_count = ?self.chunk_count(), - requested_chunks_count = ?self.requesting_chunks.len(), - threshold = ?params.threshold, - "Can conclude availability for a candidate", - ); - break - } - } - } - - async fn run( - &mut self, - params: &RecoveryParams, - sender: &mut Sender, - ) -> Result - where - Sender: overseer::AvailabilityRecoverySenderTrait, - { - let metrics = ¶ms.metrics; - - // First query the store for any chunks we've got. - if !params.bypass_availability_store { - let (tx, rx) = oneshot::channel(); - sender - .send_message(AvailabilityStoreMessage::QueryAllChunks(params.candidate_hash, tx)) - .await; - - match rx.await { - Ok(chunks) => { - // This should either be length 1 or 0. If we had the whole data, - // we wouldn't have reached this stage. - let chunk_indices: Vec<_> = chunks.iter().map(|c| c.index).collect(); - self.shuffling.retain(|i| !chunk_indices.contains(i)); - - for chunk in chunks { - if is_chunk_valid(params, &chunk) { - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - validator_index = ?chunk.index, - "Found valid chunk on disk" - ); - self.insert_chunk(chunk.index, chunk); - } else { - gum::error!( - target: LOG_TARGET, - "Loaded invalid chunk from disk! Disk/Db corruption _very_ likely - please fix ASAP!" - ); - }; - } - }, - Err(oneshot::Canceled) => { - gum::warn!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - "Failed to reach the availability store" - ); - }, - } - } - - let _recovery_timer = metrics.time_full_recovery(); - - loop { - if self.is_unavailable(¶ms) { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - erasure_root = ?params.erasure_root, - received = %self.chunk_count(), - requesting = %self.requesting_chunks.len(), - total_requesting = %self.requesting_chunks.total_len(), - n_validators = %params.validators.len(), - "Data recovery is not possible", - ); - - metrics.on_recovery_failed(); - - return Err(RecoveryError::Unavailable) - } - - self.launch_parallel_requests(params, sender).await; - self.wait_for_chunks(params).await; - - // If received_chunks has more than threshold entries, attempt to recover the data. - // If that fails, or a re-encoding of it doesn't match the expected erasure root, - // return Err(RecoveryError::Invalid) - if self.chunk_count() >= params.threshold { - let recovery_duration = metrics.time_erasure_recovery(); - - // Send request to reconstruct available data from chunks. - let (avilable_data_tx, available_data_rx) = channel(); - self.erasure_task_tx - .send(ErasureTask::Reconstruct( - params.validators.len(), - std::mem::take(&mut self.received_chunks), - avilable_data_tx, - )) - .await - .map_err(|_| RecoveryError::ChannelClosed)?; - - let available_data_response = - available_data_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; - - return match available_data_response { - Ok(data) => { - // Send request to re-encode the chunks and check merkle root. - let (reencode_tx, reencode_rx) = channel(); - self.erasure_task_tx - .send(ErasureTask::Reencode( - params.validators.len(), - params.erasure_root, - data, - reencode_tx, - )) - .await - .map_err(|_| RecoveryError::ChannelClosed)?; - - let reencode_response = - reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; - - if let Some(data) = reencode_response { - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - erasure_root = ?params.erasure_root, - "Data recovery complete", - ); - metrics.on_recovery_succeeded(); - - Ok(data) - } else { - recovery_duration.map(|rd| rd.stop_and_discard()); - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - erasure_root = ?params.erasure_root, - "Data recovery - root mismatch", - ); - metrics.on_recovery_invalid(); - - Err(RecoveryError::Invalid) - } - }, - Err(err) => { - recovery_duration.map(|rd| rd.stop_and_discard()); - gum::trace!( - target: LOG_TARGET, - candidate_hash = ?params.candidate_hash, - erasure_root = ?params.erasure_root, - ?err, - "Data recovery error ", - ); - metrics.on_recovery_invalid(); - - Err(RecoveryError::Invalid) - }, - } - } - } - } -} - const fn is_unavailable( received_chunks: usize, requesting_chunks: usize, @@ -777,60 +198,6 @@ fn reconstructed_data_matches_root( branches.root() == *expected_root } -impl RecoveryTask -where - Sender: overseer::AvailabilityRecoverySenderTrait, -{ - async fn run(mut self) -> Result { - // First just see if we have the data available locally. - if !self.params.bypass_availability_store { - let (tx, rx) = oneshot::channel(); - self.sender - .send_message(AvailabilityStoreMessage::QueryAvailableData( - self.params.candidate_hash, - tx, - )) - .await; - - match rx.await { - Ok(Some(data)) => return Ok(data), - Ok(None) => {}, - Err(oneshot::Canceled) => { - gum::warn!( - target: LOG_TARGET, - candidate_hash = ?self.params.candidate_hash, - "Failed to reach the availability store", - ) - }, - } - } - - self.params.metrics.on_recovery_started(); - - loop { - // These only fail if we cannot reach the underlying subsystem, which case there is - // nothing meaningful we can do. - match self.source { - Source::RequestFromBackers(ref mut from_backers) => { - match from_backers.run(&self.params, &mut self.sender).await { - Ok(data) => break Ok(data), - Err(RecoveryError::Invalid) => break Err(RecoveryError::Invalid), - Err(RecoveryError::ChannelClosed) => - break Err(RecoveryError::ChannelClosed), - Err(RecoveryError::Unavailable) => - self.source = Source::RequestChunks(RequestChunksFromValidators::new( - self.params.validators.len() as _, - self.erasure_task_tx.clone(), - )), - } - }, - Source::RequestChunks(ref mut from_all) => - break from_all.run(&self.params, &mut self.sender).await, - } - } - } -} - /// Accumulate all awaiting sides for some particular `AvailableData`. struct RecoveryHandle { candidate_hash: CandidateHash, @@ -973,65 +340,23 @@ async fn launch_recovery_task( ctx: &mut Context, session_info: SessionInfo, receipt: CandidateReceipt, - mut backing_group: Option, response_sender: oneshot::Sender>, metrics: &Metrics, - recovery_strategy: &RecoveryStrategy, - erasure_task_tx: futures::channel::mpsc::Sender, + recovery_strategies: VecDeque::Sender>>>, + bypass_availability_store: bool, ) -> error::Result<()> { let candidate_hash = receipt.hash(); let params = RecoveryParams { validator_authority_keys: session_info.discovery_keys.clone(), - validators: session_info.validators.clone(), + n_validators: session_info.validators.len(), threshold: recovery_threshold(session_info.validators.len())?, candidate_hash, erasure_root: receipt.descriptor.erasure_root, metrics: metrics.clone(), - bypass_availability_store: recovery_strategy == &RecoveryStrategy::BypassAvailabilityStore, + bypass_availability_store, }; - if let Some(small_pov_limit) = recovery_strategy.pov_size_limit() { - // Get our own chunk size to get an estimate of the PoV size. - let chunk_size: Result, error::Error> = - query_chunk_size(ctx, candidate_hash).await; - if let Ok(Some(chunk_size)) = chunk_size { - let pov_size_estimate = chunk_size.saturating_mul(session_info.validators.len()) / 3; - let prefer_backing_group = pov_size_estimate < small_pov_limit; - - gum::trace!( - target: LOG_TARGET, - ?candidate_hash, - pov_size_estimate, - small_pov_limit, - enabled = prefer_backing_group, - "Prefer fetch from backing group", - ); - - backing_group = backing_group.filter(|_| { - // We keep the backing group only if `1/3` of chunks sum up to less than - // `small_pov_limit`. - prefer_backing_group - }); - } - } - - let phase = backing_group - .and_then(|g| session_info.validator_groups.get(g)) - .map(|group| { - Source::RequestFromBackers(RequestFromBackers::new( - group.clone(), - erasure_task_tx.clone(), - )) - }) - .unwrap_or_else(|| { - Source::RequestChunks(RequestChunksFromValidators::new( - params.validators.len() as _, - erasure_task_tx.clone(), - )) - }); - - let recovery_task = - RecoveryTask { sender: ctx.sender().clone(), params, source: phase, erasure_task_tx }; + let recovery_task = RecoveryTask::new(ctx.sender().clone(), params, recovery_strategies); let (remote, remote_handle) = recovery_task.run().remote_handle(); @@ -1062,8 +387,9 @@ async fn handle_recover( backing_group: Option, response_sender: oneshot::Sender>, metrics: &Metrics, - recovery_strategy: &RecoveryStrategy, erasure_task_tx: futures::channel::mpsc::Sender, + recovery_strategy_kind: RecoveryStrategyKind, + bypass_availability_store: bool, ) -> error::Result<()> { let candidate_hash = receipt.hash(); @@ -1098,19 +424,71 @@ async fn handle_recover( let _span = span.child("session-info-ctx-received"); match session_info { - Some(session_info) => + Some(session_info) => { + let mut recovery_strategies: VecDeque< + Box::Sender>>, + > = VecDeque::with_capacity(2); + + if let Some(backing_group) = backing_group { + if let Some(backing_validators) = session_info.validator_groups.get(backing_group) { + let mut small_pov_size = true; + + if let RecoveryStrategyKind::BackersFirstIfSizeLower(small_pov_limit) = + recovery_strategy_kind + { + // Get our own chunk size to get an estimate of the PoV size. + let chunk_size: Result, error::Error> = + query_chunk_size(ctx, candidate_hash).await; + if let Ok(Some(chunk_size)) = chunk_size { + let pov_size_estimate = + chunk_size.saturating_mul(session_info.validators.len()) / 3; + small_pov_size = pov_size_estimate < small_pov_limit; + + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + pov_size_estimate, + small_pov_limit, + enabled = small_pov_size, + "Prefer fetch from backing group", + ); + } else { + // we have a POV limit but were not able to query the chunk size, so + // don't use the backing group. + small_pov_size = false; + } + }; + + match (&recovery_strategy_kind, small_pov_size) { + (RecoveryStrategyKind::BackersFirstAlways, _) | + (RecoveryStrategyKind::BackersFirstIfSizeLower(_), true) => recovery_strategies.push_back( + Box::new(FetchFull::new(FetchFullParams { + validators: backing_validators.to_vec(), + erasure_task_tx: erasure_task_tx.clone(), + })), + ), + _ => {}, + }; + } + } + + recovery_strategies.push_back(Box::new(FetchChunks::new(FetchChunksParams { + n_validators: session_info.validators.len(), + erasure_task_tx, + }))); + launch_recovery_task( state, ctx, session_info, receipt, - backing_group, response_sender, metrics, - recovery_strategy, - erasure_task_tx, + recovery_strategies, + bypass_availability_store, ) - .await, + .await + }, None => { gum::warn!(target: LOG_TARGET, "SessionInfo is `None` at {:?}", state.live_block); response_sender @@ -1155,7 +533,12 @@ impl AvailabilityRecoverySubsystem { req_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> Self { - Self { recovery_strategy: RecoveryStrategy::BypassAvailabilityStore, req_receiver, metrics } + Self { + recovery_strategy_kind: RecoveryStrategyKind::BackersFirstIfSizeLower(SMALL_POV_LIMIT), + bypass_availability_store: true, + req_receiver, + metrics, + } } /// Create a new instance of `AvailabilityRecoverySubsystem` which starts with a fast path to @@ -1164,7 +547,12 @@ impl AvailabilityRecoverySubsystem { req_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> Self { - Self { recovery_strategy: RecoveryStrategy::BackersFirstAlways, req_receiver, metrics } + Self { + recovery_strategy_kind: RecoveryStrategyKind::BackersFirstAlways, + bypass_availability_store: false, + req_receiver, + metrics, + } } /// Create a new instance of `AvailabilityRecoverySubsystem` which requests only chunks @@ -1172,7 +560,12 @@ impl AvailabilityRecoverySubsystem { req_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> Self { - Self { recovery_strategy: RecoveryStrategy::ChunksAlways, req_receiver, metrics } + Self { + recovery_strategy_kind: RecoveryStrategyKind::ChunksAlways, + bypass_availability_store: false, + req_receiver, + metrics, + } } /// Create a new instance of `AvailabilityRecoverySubsystem` which requests chunks if PoV is @@ -1182,7 +575,8 @@ impl AvailabilityRecoverySubsystem { metrics: Metrics, ) -> Self { Self { - recovery_strategy: RecoveryStrategy::BackersFirstIfSizeLower(SMALL_POV_LIMIT), + recovery_strategy_kind: RecoveryStrategyKind::BackersFirstIfSizeLower(SMALL_POV_LIMIT), + bypass_availability_store: false, req_receiver, metrics, } @@ -1190,7 +584,8 @@ impl AvailabilityRecoverySubsystem { async fn run(self, mut ctx: Context) -> SubsystemResult<()> { let mut state = State::default(); - let Self { recovery_strategy, mut req_receiver, metrics } = self; + let Self { mut req_receiver, metrics, recovery_strategy_kind, bypass_availability_store } = + self; let (erasure_task_tx, erasure_task_rx) = futures::channel::mpsc::channel(16); let mut erasure_task_rx = erasure_task_rx.fuse(); @@ -1275,11 +670,12 @@ impl AvailabilityRecoverySubsystem { &mut ctx, receipt, session_index, - maybe_backing_group.filter(|_| recovery_strategy.needs_backing_group()), + maybe_backing_group, response_sender, &metrics, - &recovery_strategy, erasure_task_tx.clone(), + recovery_strategy_kind.clone(), + bypass_availability_store ).await { gum::warn!( target: LOG_TARGET, @@ -1295,7 +691,7 @@ impl AvailabilityRecoverySubsystem { in_req = recv_req => { match in_req.into_nested().map_err(|fatal| SubsystemError::with_origin("availability-recovery", fatal))? { Ok(req) => { - if recovery_strategy == RecoveryStrategy::BypassAvailabilityStore { + if bypass_availability_store { gum::debug!( target: LOG_TARGET, "Skipping request to availability-store.", diff --git a/polkadot/node/network/availability-recovery/src/task.rs b/polkadot/node/network/availability-recovery/src/task.rs new file mode 100644 index 0000000000000000000000000000000000000000..d5bc2da84944a3403f9d4a3bf9d5a11b0e772f40 --- /dev/null +++ b/polkadot/node/network/availability-recovery/src/task.rs @@ -0,0 +1,830 @@ +// 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 . + +//! Recovery task and associated strategies. + +#![warn(missing_docs)] + +use crate::{ + futures_undead::FuturesUndead, is_chunk_valid, is_unavailable, metrics::Metrics, ErasureTask, + LOG_TARGET, +}; +use futures::{channel::oneshot, SinkExt}; +#[cfg(not(test))] +use polkadot_node_network_protocol::request_response::CHUNK_REQUEST_TIMEOUT; +use polkadot_node_network_protocol::request_response::{ + self as req_res, outgoing::RequestError, OutgoingRequest, Recipient, Requests, +}; +use polkadot_node_primitives::{AvailableData, ErasureChunk}; +use polkadot_node_subsystem::{ + messages::{AvailabilityStoreMessage, NetworkBridgeTxMessage}, + overseer, RecoveryError, +}; +use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash, ValidatorIndex}; +use rand::seq::SliceRandom; +use sc_network::{IfDisconnected, OutboundFailure, RequestFailure}; +use std::{ + collections::{HashMap, VecDeque}, + time::Duration, +}; + +// How many parallel recovery tasks should be running at once. +const N_PARALLEL: usize = 50; + +/// Time after which we consider a request to have failed +/// +/// and we should try more peers. Note in theory the request times out at the network level, +/// measurements have shown, that in practice requests might actually take longer to fail in +/// certain occasions. (The very least, authority discovery is not part of the timeout.) +/// +/// For the time being this value is the same as the timeout on the networking layer, but as this +/// timeout is more soft than the networking one, it might make sense to pick different values as +/// well. +#[cfg(not(test))] +const TIMEOUT_START_NEW_REQUESTS: Duration = CHUNK_REQUEST_TIMEOUT; +#[cfg(test)] +const TIMEOUT_START_NEW_REQUESTS: Duration = Duration::from_millis(100); + +#[async_trait::async_trait] +/// Common trait for runnable recovery strategies. +pub trait RecoveryStrategy: Send { + /// Main entry point of the strategy. + async fn run( + &mut self, + state: &mut State, + sender: &mut Sender, + common_params: &RecoveryParams, + ) -> Result; + + /// Return the name of the strategy for logging purposes. + fn display_name(&self) -> &'static str; +} + +/// Recovery parameters common to all strategies in a `RecoveryTask`. +pub struct RecoveryParams { + /// Discovery ids of `validators`. + pub validator_authority_keys: Vec, + + /// Number of validators. + pub n_validators: usize, + + /// The number of chunks needed. + pub threshold: usize, + + /// A hash of the relevant candidate. + pub candidate_hash: CandidateHash, + + /// The root of the erasure encoding of the candidate. + pub erasure_root: Hash, + + /// Metrics to report. + pub metrics: Metrics, + + /// Do not request data from availability-store. Useful for collators. + pub bypass_availability_store: bool, +} + +/// Intermediate/common data that must be passed between `RecoveryStrategy`s belonging to the +/// same `RecoveryTask`. +pub struct State { + /// Chunks received so far. + received_chunks: HashMap, +} + +impl State { + fn new() -> Self { + Self { received_chunks: HashMap::new() } + } + + fn insert_chunk(&mut self, validator: ValidatorIndex, chunk: ErasureChunk) { + self.received_chunks.insert(validator, chunk); + } + + fn chunk_count(&self) -> usize { + self.received_chunks.len() + } + + /// Retrieve the local chunks held in the av-store (either 0 or 1). + async fn populate_from_av_store( + &mut self, + params: &RecoveryParams, + sender: &mut Sender, + ) -> Vec { + let (tx, rx) = oneshot::channel(); + sender + .send_message(AvailabilityStoreMessage::QueryAllChunks(params.candidate_hash, tx)) + .await; + + match rx.await { + Ok(chunks) => { + // This should either be length 1 or 0. If we had the whole data, + // we wouldn't have reached this stage. + let chunk_indices: Vec<_> = chunks.iter().map(|c| c.index).collect(); + + for chunk in chunks { + if is_chunk_valid(params, &chunk) { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?params.candidate_hash, + validator_index = ?chunk.index, + "Found valid chunk on disk" + ); + self.insert_chunk(chunk.index, chunk); + } else { + gum::error!( + target: LOG_TARGET, + "Loaded invalid chunk from disk! Disk/Db corruption _very_ likely - please fix ASAP!" + ); + }; + } + + chunk_indices + }, + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + candidate_hash = ?params.candidate_hash, + "Failed to reach the availability store" + ); + + vec![] + }, + } + } + + /// Launch chunk requests in parallel, according to the parameters. + async fn launch_parallel_chunk_requests( + &mut self, + params: &RecoveryParams, + sender: &mut Sender, + desired_requests_count: usize, + validators: &mut VecDeque, + requesting_chunks: &mut FuturesUndead< + Result, (ValidatorIndex, RequestError)>, + >, + ) where + Sender: overseer::AvailabilityRecoverySenderTrait, + { + let candidate_hash = ¶ms.candidate_hash; + let already_requesting_count = requesting_chunks.len(); + + let mut requests = Vec::with_capacity(desired_requests_count - already_requesting_count); + + while requesting_chunks.len() < desired_requests_count { + if let Some(validator_index) = validators.pop_back() { + let validator = params.validator_authority_keys[validator_index.0 as usize].clone(); + gum::trace!( + target: LOG_TARGET, + ?validator, + ?validator_index, + ?candidate_hash, + "Requesting chunk", + ); + + // Request data. + let raw_request = req_res::v1::ChunkFetchingRequest { + candidate_hash: params.candidate_hash, + index: validator_index, + }; + + let (req, res) = OutgoingRequest::new(Recipient::Authority(validator), raw_request); + requests.push(Requests::ChunkFetchingV1(req)); + + params.metrics.on_chunk_request_issued(); + let timer = params.metrics.time_chunk_request(); + + requesting_chunks.push(Box::pin(async move { + let _timer = timer; + match res.await { + Ok(req_res::v1::ChunkFetchingResponse::Chunk(chunk)) => + Ok(Some(chunk.recombine_into_chunk(&raw_request))), + Ok(req_res::v1::ChunkFetchingResponse::NoSuchChunk) => Ok(None), + Err(e) => Err((validator_index, e)), + } + })); + } else { + break + } + } + + sender + .send_message(NetworkBridgeTxMessage::SendRequests( + requests, + IfDisconnected::TryConnect, + )) + .await; + } + + /// Wait for a sufficient amount of chunks to reconstruct according to the provided `params`. + async fn wait_for_chunks( + &mut self, + params: &RecoveryParams, + validators: &mut VecDeque, + requesting_chunks: &mut FuturesUndead< + Result, (ValidatorIndex, RequestError)>, + >, + can_conclude: impl Fn(usize, usize, usize, &RecoveryParams, usize) -> bool, + ) -> (usize, usize) { + let metrics = ¶ms.metrics; + + let mut total_received_responses = 0; + let mut error_count = 0; + + // Wait for all current requests to conclude or time-out, or until we reach enough chunks. + // We also declare requests undead, once `TIMEOUT_START_NEW_REQUESTS` is reached and will + // return in that case for `launch_parallel_requests` to fill up slots again. + while let Some(request_result) = + requesting_chunks.next_with_timeout(TIMEOUT_START_NEW_REQUESTS).await + { + total_received_responses += 1; + + match request_result { + Ok(Some(chunk)) => + if is_chunk_valid(params, &chunk) { + metrics.on_chunk_request_succeeded(); + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?params.candidate_hash, + validator_index = ?chunk.index, + "Received valid chunk", + ); + self.insert_chunk(chunk.index, chunk); + } else { + metrics.on_chunk_request_invalid(); + error_count += 1; + }, + Ok(None) => { + metrics.on_chunk_request_no_such_chunk(); + error_count += 1; + }, + Err((validator_index, e)) => { + error_count += 1; + + gum::trace!( + target: LOG_TARGET, + candidate_hash= ?params.candidate_hash, + err = ?e, + ?validator_index, + "Failure requesting chunk", + ); + + match e { + RequestError::InvalidResponse(_) => { + metrics.on_chunk_request_invalid(); + + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?params.candidate_hash, + err = ?e, + ?validator_index, + "Chunk fetching response was invalid", + ); + }, + RequestError::NetworkError(err) => { + // No debug logs on general network errors - that became very spammy + // occasionally. + if let RequestFailure::Network(OutboundFailure::Timeout) = err { + metrics.on_chunk_request_timeout(); + } else { + metrics.on_chunk_request_error(); + } + + validators.push_front(validator_index); + }, + RequestError::Canceled(_) => { + metrics.on_chunk_request_error(); + + validators.push_front(validator_index); + }, + } + }, + } + + // Stop waiting for requests when we either can already recover the data + // or have gotten firm 'No' responses from enough validators. + if can_conclude( + validators.len(), + requesting_chunks.total_len(), + self.chunk_count(), + params, + error_count, + ) { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?params.candidate_hash, + received_chunks_count = ?self.chunk_count(), + requested_chunks_count = ?requesting_chunks.len(), + threshold = ?params.threshold, + "Can conclude availability for a candidate", + ); + break + } + } + + (total_received_responses, error_count) + } +} + +/// A stateful reconstruction of availability data in reference to +/// a candidate hash. +pub struct RecoveryTask { + sender: Sender, + params: RecoveryParams, + strategies: VecDeque>>, + state: State, +} + +impl RecoveryTask +where + Sender: overseer::AvailabilityRecoverySenderTrait, +{ + /// Instantiate a new recovery task. + pub fn new( + sender: Sender, + params: RecoveryParams, + strategies: VecDeque>>, + ) -> Self { + Self { sender, params, strategies, state: State::new() } + } + + async fn in_availability_store(&mut self) -> Option { + if !self.params.bypass_availability_store { + let (tx, rx) = oneshot::channel(); + self.sender + .send_message(AvailabilityStoreMessage::QueryAvailableData( + self.params.candidate_hash, + tx, + )) + .await; + + match rx.await { + Ok(Some(data)) => return Some(data), + Ok(None) => {}, + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + candidate_hash = ?self.params.candidate_hash, + "Failed to reach the availability store", + ) + }, + } + } + + None + } + + /// Run this recovery task to completion. It will loop through the configured strategies + /// in-order and return whenever the first one recovers the full `AvailableData`. + pub async fn run(mut self) -> Result { + if let Some(data) = self.in_availability_store().await { + return Ok(data) + } + + self.params.metrics.on_recovery_started(); + + let _timer = self.params.metrics.time_full_recovery(); + + while let Some(mut current_strategy) = self.strategies.pop_front() { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?self.params.candidate_hash, + "Starting `{}` strategy", + current_strategy.display_name(), + ); + + let res = current_strategy.run(&mut self.state, &mut self.sender, &self.params).await; + + match res { + Err(RecoveryError::Unavailable) => + if self.strategies.front().is_some() { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?self.params.candidate_hash, + "Recovery strategy `{}` did not conclude. Trying the next one.", + current_strategy.display_name(), + ); + continue + }, + Err(err) => { + match &err { + RecoveryError::Invalid => self.params.metrics.on_recovery_invalid(), + _ => self.params.metrics.on_recovery_failed(), + } + return Err(err) + }, + Ok(data) => { + self.params.metrics.on_recovery_succeeded(); + return Ok(data) + }, + } + } + + // We have no other strategies to try. + gum::warn!( + target: LOG_TARGET, + candidate_hash = ?self.params.candidate_hash, + "Recovery of available data failed.", + ); + self.params.metrics.on_recovery_failed(); + + Err(RecoveryError::Unavailable) + } +} + +/// `RecoveryStrategy` that sequentially tries to fetch the full `AvailableData` from +/// already-connected validators in the configured validator set. +pub struct FetchFull { + params: FetchFullParams, +} + +pub struct FetchFullParams { + /// Validators that will be used for fetching the data. + pub validators: Vec, + /// Channel to the erasure task handler. + pub erasure_task_tx: futures::channel::mpsc::Sender, +} + +impl FetchFull { + /// Create a new `FetchFull` recovery strategy. + pub fn new(mut params: FetchFullParams) -> Self { + params.validators.shuffle(&mut rand::thread_rng()); + Self { params } + } +} + +#[async_trait::async_trait] +impl RecoveryStrategy for FetchFull { + fn display_name(&self) -> &'static str { + "Full recovery from backers" + } + + async fn run( + &mut self, + _: &mut State, + sender: &mut Sender, + common_params: &RecoveryParams, + ) -> Result { + loop { + // Pop the next validator, and proceed to next fetch_chunks_task if we're out. + let validator_index = + self.params.validators.pop().ok_or_else(|| RecoveryError::Unavailable)?; + + // Request data. + let (req, response) = OutgoingRequest::new( + Recipient::Authority( + common_params.validator_authority_keys[validator_index.0 as usize].clone(), + ), + req_res::v1::AvailableDataFetchingRequest { + candidate_hash: common_params.candidate_hash, + }, + ); + + sender + .send_message(NetworkBridgeTxMessage::SendRequests( + vec![Requests::AvailableDataFetchingV1(req)], + IfDisconnected::ImmediateError, + )) + .await; + + match response.await { + Ok(req_res::v1::AvailableDataFetchingResponse::AvailableData(data)) => { + let (reencode_tx, reencode_rx) = oneshot::channel(); + self.params + .erasure_task_tx + .send(ErasureTask::Reencode( + common_params.n_validators, + common_params.erasure_root, + data, + reencode_tx, + )) + .await + .map_err(|_| RecoveryError::ChannelClosed)?; + + let reencode_response = + reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; + + if let Some(data) = reencode_response { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + "Received full data", + ); + + return Ok(data) + } else { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + ?validator_index, + "Invalid data response", + ); + + // it doesn't help to report the peer with req/res. + } + }, + Ok(req_res::v1::AvailableDataFetchingResponse::NoSuchData) => {}, + Err(e) => gum::debug!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + ?validator_index, + err = ?e, + "Error fetching full available data." + ), + } + } + } +} + +/// `RecoveryStrategy` that requests chunks from validators, in parallel. +pub struct FetchChunks { + /// How many requests have been unsuccessful so far. + error_count: usize, + /// Total number of responses that have been received, including failed ones. + total_received_responses: usize, + /// Collection of in-flight requests. + requesting_chunks: FuturesUndead, (ValidatorIndex, RequestError)>>, + /// A random shuffling of the validators which indicates the order in which we connect to the + /// validators and request the chunk from them. + validators: VecDeque, + /// Channel to the erasure task handler. + erasure_task_tx: futures::channel::mpsc::Sender, +} + +/// Parameters specific to the `FetchChunks` strategy. +pub struct FetchChunksParams { + /// Total number of validators. + pub n_validators: usize, + /// Channel to the erasure task handler. + pub erasure_task_tx: futures::channel::mpsc::Sender, +} + +impl FetchChunks { + /// Instantiate a new strategy. + pub fn new(params: FetchChunksParams) -> Self { + let mut shuffling: Vec<_> = (0..params.n_validators) + .map(|i| ValidatorIndex(i.try_into().expect("number of validators must fit in a u32"))) + .collect(); + shuffling.shuffle(&mut rand::thread_rng()); + + Self { + error_count: 0, + total_received_responses: 0, + requesting_chunks: FuturesUndead::new(), + validators: shuffling.into(), + erasure_task_tx: params.erasure_task_tx, + } + } + + fn is_unavailable( + unrequested_validators: usize, + in_flight_requests: usize, + chunk_count: usize, + threshold: usize, + ) -> bool { + is_unavailable(chunk_count, in_flight_requests, unrequested_validators, threshold) + } + + /// Desired number of parallel requests. + /// + /// For the given threshold (total required number of chunks) get the desired number of + /// requests we want to have running in parallel at this time. + fn get_desired_request_count(&self, chunk_count: usize, threshold: usize) -> usize { + // Upper bound for parallel requests. + // We want to limit this, so requests can be processed within the timeout and we limit the + // following feedback loop: + // 1. Requests fail due to timeout + // 2. We request more chunks to make up for it + // 3. Bandwidth is spread out even more, so we get even more timeouts + // 4. We request more chunks to make up for it ... + let max_requests_boundary = std::cmp::min(N_PARALLEL, threshold); + // How many chunks are still needed? + let remaining_chunks = threshold.saturating_sub(chunk_count); + // What is the current error rate, so we can make up for it? + let inv_error_rate = + self.total_received_responses.checked_div(self.error_count).unwrap_or(0); + // Actual number of requests we want to have in flight in parallel: + std::cmp::min( + max_requests_boundary, + remaining_chunks + remaining_chunks.checked_div(inv_error_rate).unwrap_or(0), + ) + } + + async fn attempt_recovery( + &mut self, + state: &mut State, + common_params: &RecoveryParams, + ) -> Result { + let recovery_duration = common_params.metrics.time_erasure_recovery(); + + // Send request to reconstruct available data from chunks. + let (avilable_data_tx, available_data_rx) = oneshot::channel(); + self.erasure_task_tx + .send(ErasureTask::Reconstruct( + common_params.n_validators, + // Safe to leave an empty vec in place, as we're stopping the recovery process if + // this reconstruct fails. + std::mem::take(&mut state.received_chunks), + avilable_data_tx, + )) + .await + .map_err(|_| RecoveryError::ChannelClosed)?; + + let available_data_response = + available_data_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; + + match available_data_response { + Ok(data) => { + // Send request to re-encode the chunks and check merkle root. + let (reencode_tx, reencode_rx) = oneshot::channel(); + self.erasure_task_tx + .send(ErasureTask::Reencode( + common_params.n_validators, + common_params.erasure_root, + data, + reencode_tx, + )) + .await + .map_err(|_| RecoveryError::ChannelClosed)?; + + let reencode_response = + reencode_rx.await.map_err(|_| RecoveryError::ChannelClosed)?; + + if let Some(data) = reencode_response { + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + erasure_root = ?common_params.erasure_root, + "Data recovery from chunks complete", + ); + + Ok(data) + } else { + recovery_duration.map(|rd| rd.stop_and_discard()); + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + erasure_root = ?common_params.erasure_root, + "Data recovery error - root mismatch", + ); + + Err(RecoveryError::Invalid) + } + }, + Err(err) => { + recovery_duration.map(|rd| rd.stop_and_discard()); + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + erasure_root = ?common_params.erasure_root, + ?err, + "Data recovery error ", + ); + + Err(RecoveryError::Invalid) + }, + } + } +} + +#[async_trait::async_trait] +impl RecoveryStrategy for FetchChunks { + fn display_name(&self) -> &'static str { + "Fetch chunks" + } + + async fn run( + &mut self, + state: &mut State, + sender: &mut Sender, + common_params: &RecoveryParams, + ) -> Result { + // First query the store for any chunks we've got. + if !common_params.bypass_availability_store { + let local_chunk_indices = state.populate_from_av_store(common_params, sender).await; + self.validators.retain(|i| !local_chunk_indices.contains(i)); + } + + // No need to query the validators that have the chunks we already received. + self.validators.retain(|i| !state.received_chunks.contains_key(i)); + + loop { + // If received_chunks has more than threshold entries, attempt to recover the data. + // If that fails, or a re-encoding of it doesn't match the expected erasure root, + // return Err(RecoveryError::Invalid). + // Do this before requesting any chunks because we may have enough of them coming from + // past RecoveryStrategies. + if state.chunk_count() >= common_params.threshold { + return self.attempt_recovery(state, common_params).await + } + + if Self::is_unavailable( + self.validators.len(), + self.requesting_chunks.total_len(), + state.chunk_count(), + common_params.threshold, + ) { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?common_params.candidate_hash, + erasure_root = ?common_params.erasure_root, + received = %state.chunk_count(), + requesting = %self.requesting_chunks.len(), + total_requesting = %self.requesting_chunks.total_len(), + n_validators = %common_params.n_validators, + "Data recovery from chunks is not possible", + ); + + return Err(RecoveryError::Unavailable) + } + + let desired_requests_count = + self.get_desired_request_count(state.chunk_count(), common_params.threshold); + let already_requesting_count = self.requesting_chunks.len(); + gum::debug!( + target: LOG_TARGET, + ?common_params.candidate_hash, + ?desired_requests_count, + error_count= ?self.error_count, + total_received = ?self.total_received_responses, + threshold = ?common_params.threshold, + ?already_requesting_count, + "Requesting availability chunks for a candidate", + ); + state + .launch_parallel_chunk_requests( + common_params, + sender, + desired_requests_count, + &mut self.validators, + &mut self.requesting_chunks, + ) + .await; + + let (total_responses, error_count) = state + .wait_for_chunks( + common_params, + &mut self.validators, + &mut self.requesting_chunks, + |unrequested_validators, reqs, chunk_count, params, _error_count| { + chunk_count >= params.threshold || + Self::is_unavailable( + unrequested_validators, + reqs, + chunk_count, + params.threshold, + ) + }, + ) + .await; + + self.total_received_responses += total_responses; + self.error_count += error_count; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_erasure_coding::recovery_threshold; + + #[test] + fn parallel_request_calculation_works_as_expected() { + let num_validators = 100; + let threshold = recovery_threshold(num_validators).unwrap(); + let (erasure_task_tx, _erasure_task_rx) = futures::channel::mpsc::channel(16); + + let mut fetch_chunks_task = + FetchChunks::new(FetchChunksParams { n_validators: 100, erasure_task_tx }); + assert_eq!(fetch_chunks_task.get_desired_request_count(0, threshold), threshold); + fetch_chunks_task.error_count = 1; + fetch_chunks_task.total_received_responses = 1; + // We saturate at threshold (34): + assert_eq!(fetch_chunks_task.get_desired_request_count(0, threshold), threshold); + + fetch_chunks_task.total_received_responses = 2; + // With given error rate - still saturating: + assert_eq!(fetch_chunks_task.get_desired_request_count(1, threshold), threshold); + fetch_chunks_task.total_received_responses += 8; + // error rate: 1/10 + // remaining chunks needed: threshold (34) - 9 + // expected: 24 * (1+ 1/10) = (next greater integer) = 27 + assert_eq!(fetch_chunks_task.get_desired_request_count(9, threshold), 27); + fetch_chunks_task.error_count = 0; + // With error count zero - we should fetch exactly as needed: + assert_eq!(fetch_chunks_task.get_desired_request_count(10, threshold), threshold - 10); + } +} diff --git a/polkadot/node/network/availability-recovery/src/tests.rs b/polkadot/node/network/availability-recovery/src/tests.rs index 60c2d38ab31ba57eef9590af7b80591b24dfae48..63ccf0e94f91ebad2a8cba3158d6db24159683c0 100644 --- a/polkadot/node/network/availability-recovery/src/tests.rs +++ b/polkadot/node/network/availability-recovery/src/tests.rs @@ -21,15 +21,19 @@ use futures::{executor, future}; use futures_timer::Delay; use parity_scale_codec::Encode; -use polkadot_node_network_protocol::request_response::{IncomingRequest, ReqProtocolNames}; +use polkadot_node_network_protocol::request_response::{ + self as req_res, IncomingRequest, Recipient, ReqProtocolNames, Requests, +}; use super::*; -use sc_network::config::RequestResponseConfig; +use sc_network::{config::RequestResponseConfig, IfDisconnected, OutboundFailure, RequestFailure}; use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks}; use polkadot_node_primitives::{BlockData, PoV, Proof}; -use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; +use polkadot_node_subsystem::messages::{ + AllMessages, NetworkBridgeTxMessage, RuntimeApiMessage, RuntimeApiRequest, +}; use polkadot_node_subsystem_test_helpers::{ make_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; @@ -204,7 +208,7 @@ use sp_keyring::Sr25519Keyring; enum Has { No, Yes, - NetworkError(sc_network::RequestFailure), + NetworkError(RequestFailure), /// Make request not return at all, instead the sender is returned from the function. /// /// Note, if you use `DoesNotReturn` you have to keep the returned senders alive, otherwise the @@ -214,7 +218,7 @@ enum Has { impl Has { fn timeout() -> Self { - Has::NetworkError(sc_network::RequestFailure::Network(sc_network::OutboundFailure::Timeout)) + Has::NetworkError(RequestFailure::Network(OutboundFailure::Timeout)) } } @@ -393,7 +397,7 @@ impl TestState { candidate_hash: CandidateHash, virtual_overseer: &mut VirtualOverseer, who_has: impl Fn(usize) -> Has, - ) -> Vec, sc_network::RequestFailure>>> { + ) -> Vec, RequestFailure>>> { let mut senders = Vec::new(); for _ in 0..self.validators.len() { // Receive a request for a chunk. @@ -1010,7 +1014,7 @@ fn recovers_from_only_chunks_if_pov_large() { AvailabilityRecoveryMessage::RecoverAvailableData( new_candidate.clone(), test_state.session_index, - None, + Some(GroupIndex(0)), tx, ), ) @@ -1546,36 +1550,3 @@ fn invalid_local_chunk_is_ignored() { (virtual_overseer, req_cfg) }); } - -#[test] -fn parallel_request_calculation_works_as_expected() { - let num_validators = 100; - let threshold = recovery_threshold(num_validators).unwrap(); - let (erasure_task_tx, _erasure_task_rx) = futures::channel::mpsc::channel(16); - - let mut phase = RequestChunksFromValidators::new(100, erasure_task_tx); - assert_eq!(phase.get_desired_request_count(threshold), threshold); - phase.error_count = 1; - phase.total_received_responses = 1; - // We saturate at threshold (34): - assert_eq!(phase.get_desired_request_count(threshold), threshold); - - let dummy_chunk = - ErasureChunk { chunk: Vec::new(), index: ValidatorIndex(0), proof: Proof::dummy_proof() }; - phase.insert_chunk(ValidatorIndex(0), dummy_chunk.clone()); - phase.total_received_responses = 2; - // With given error rate - still saturating: - assert_eq!(phase.get_desired_request_count(threshold), threshold); - for i in 1..9 { - phase.insert_chunk(ValidatorIndex(i), dummy_chunk.clone()); - } - phase.total_received_responses += 8; - // error rate: 1/10 - // remaining chunks needed: threshold (34) - 9 - // expected: 24 * (1+ 1/10) = (next greater integer) = 27 - assert_eq!(phase.get_desired_request_count(threshold), 27); - phase.insert_chunk(ValidatorIndex(9), dummy_chunk.clone()); - phase.error_count = 0; - // With error count zero - we should fetch exactly as needed: - assert_eq!(phase.get_desired_request_count(threshold), threshold - phase.chunk_count()); -} diff --git a/polkadot/node/network/bitfield-distribution/src/lib.rs b/polkadot/node/network/bitfield-distribution/src/lib.rs index c85d874bc4db6edad95d15cdfcdd01820948b0bc..68e381ab6be51d65e4ed0a45eb971b84089cb62e 100644 --- a/polkadot/node/network/bitfield-distribution/src/lib.rs +++ b/polkadot/node/network/bitfield-distribution/src/lib.rs @@ -31,8 +31,8 @@ use polkadot_node_network_protocol::{ GridNeighbors, RandomRouting, RequiredRouting, SessionBoundGridTopologyStorage, }, peer_set::{ProtocolVersion, ValidationVersion}, - v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, - UnifiedReputationChange as Rep, Versioned, View, + v1 as protocol_v1, v2 as protocol_v2, OurView, PeerId, UnifiedReputationChange as Rep, + Versioned, View, }; use polkadot_node_subsystem::{ jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, @@ -96,8 +96,8 @@ impl BitfieldGossipMessage { self.relay_parent, self.signed_availability.into(), )), - Some(ValidationVersion::VStaging) => - Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + Some(ValidationVersion::V2) => + Versioned::V2(protocol_v2::BitfieldDistributionMessage::Bitfield( self.relay_parent, self.signed_availability.into(), )), @@ -502,8 +502,7 @@ async fn relay_message( }; let v1_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V1); - let vstaging_interested_peers = - filter_by_version(&interested_peers, ValidationVersion::VStaging); + let v2_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V2); if !v1_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( @@ -513,10 +512,10 @@ async fn relay_message( .await; } - if !vstaging_interested_peers.is_empty() { + if !v2_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_interested_peers, - message.into_validation_protocol(ValidationVersion::VStaging.into()), + v2_interested_peers, + message.into_validation_protocol(ValidationVersion::V2.into()), )) .await } @@ -538,7 +537,7 @@ async fn process_incoming_peer_message( relay_parent, bitfield, )) => (relay_parent, bitfield), - Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + Versioned::V2(protocol_v2::BitfieldDistributionMessage::Bitfield( relay_parent, bitfield, )) => (relay_parent, bitfield), diff --git a/polkadot/node/network/bitfield-distribution/src/tests.rs b/polkadot/node/network/bitfield-distribution/src/tests.rs index d6795247e7866f4bb160d941161f114316c3633d..ba2434ea47d69469e812d6274b17b43c3b6b5ee3 100644 --- a/polkadot/node/network/bitfield-distribution/src/tests.rs +++ b/polkadot/node/network/bitfield-distribution/src/tests.rs @@ -1111,9 +1111,9 @@ fn network_protocol_versioning() { let peer_c = PeerId::random(); let peers = [ - (peer_a, ValidationVersion::VStaging), + (peer_a, ValidationVersion::V2), (peer_b, ValidationVersion::V1), - (peer_c, ValidationVersion::VStaging), + (peer_c, ValidationVersion::V2), ]; // validator 0 key pair @@ -1173,7 +1173,7 @@ fn network_protocol_versioning() { &Default::default(), NetworkBridgeEvent::PeerMessage( peer_a, - msg.clone().into_network_message(ValidationVersion::VStaging.into()), + msg.clone().into_network_message(ValidationVersion::V2.into()), ), &mut rng, )); @@ -1201,14 +1201,14 @@ fn network_protocol_versioning() { } ); - // vstaging gossip + // v2 gossip assert_matches!( handle.recv().await, AllMessages::NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg), ) => { assert_eq!(peers, vec![peer_c]); - assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::VStaging.into())); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V2.into())); } ); diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 82c67061d9a5053e6c531c82c560f0c124470647..7e86b46a7e0397ed78e5796afd9a9979688350fa 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -33,7 +33,7 @@ use polkadot_node_network_protocol::{ CollationVersion, PeerSet, PeerSetProtocolNames, PerPeerSet, ProtocolVersion, ValidationVersion, }, - v1 as protocol_v1, vstaging as protocol_vstaging, ObservedRole, OurView, PeerId, + v1 as protocol_v1, v2 as protocol_v2, ObservedRole, OurView, PeerId, UnifiedReputationChange as Rep, View, }; @@ -262,13 +262,13 @@ where ), &metrics, ), - ValidationVersion::VStaging => send_message( + ValidationVersion::V2 => send_message( &mut network_service, vec![peer], PeerSet::Validation, version, &peerset_protocol_names, - WireMessage::::ViewUpdate( + WireMessage::::ViewUpdate( local_view, ), &metrics, @@ -304,13 +304,13 @@ where ), &metrics, ), - CollationVersion::VStaging => send_message( + CollationVersion::V2 => send_message( &mut network_service, vec![peer], PeerSet::Collation, version, &peerset_protocol_names, - WireMessage::::ViewUpdate( + WireMessage::::ViewUpdate( local_view, ), &metrics, @@ -465,9 +465,9 @@ where &metrics, ) } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::VStaging.into()) + Some(ValidationVersion::V2.into()) { - handle_peer_messages::( + handle_peer_messages::( remote, PeerSet::Validation, &mut shared.0.lock().validation_peers, @@ -507,9 +507,9 @@ where &metrics, ) } else if expected_versions[PeerSet::Collation] == - Some(CollationVersion::VStaging.into()) + Some(CollationVersion::V2.into()) { - handle_peer_messages::( + handle_peer_messages::( remote, PeerSet::Collation, &mut shared.0.lock().collation_peers, @@ -813,10 +813,8 @@ fn update_our_view( let v1_validation_peers = filter_by_version(&validation_peers, ValidationVersion::V1.into()); let v1_collation_peers = filter_by_version(&collation_peers, CollationVersion::V1.into()); - let vstaging_validation_peers = - filter_by_version(&validation_peers, ValidationVersion::VStaging.into()); - let vstaging_collation_peers = - filter_by_version(&collation_peers, ValidationVersion::VStaging.into()); + let v2_validation_peers = filter_by_version(&validation_peers, ValidationVersion::V2.into()); + let v2_collation_peers = filter_by_version(&collation_peers, ValidationVersion::V2.into()); send_validation_message_v1( net, @@ -834,17 +832,17 @@ fn update_our_view( metrics, ); - send_validation_message_vstaging( + send_validation_message_v2( net, - vstaging_validation_peers, + v2_validation_peers, peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, ); - send_collation_message_vstaging( + send_collation_message_v2( net, - vstaging_collation_peers, + v2_collation_peers, peerset_protocol_names, WireMessage::ViewUpdate(new_view), metrics, @@ -955,36 +953,36 @@ fn send_collation_message_v1( ); } -fn send_validation_message_vstaging( +fn send_validation_message_v2( net: &mut impl Network, peers: Vec, protocol_names: &PeerSetProtocolNames, - message: WireMessage, + message: WireMessage, metrics: &Metrics, ) { send_message( net, peers, PeerSet::Validation, - ValidationVersion::VStaging.into(), + ValidationVersion::V2.into(), protocol_names, message, metrics, ); } -fn send_collation_message_vstaging( +fn send_collation_message_v2( net: &mut impl Network, peers: Vec, protocol_names: &PeerSetProtocolNames, - message: WireMessage, + message: WireMessage, metrics: &Metrics, ) { send_message( net, peers, PeerSet::Collation, - CollationVersion::VStaging.into(), + CollationVersion::V2.into(), protocol_names, message, metrics, diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 127f46e0fa37390a440125f8d567c6ff47e53aef..7c69cce48391b65294970232b1a277d7c261ba05 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -1216,10 +1216,10 @@ fn network_protocol_versioning_view_update() { let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); let peers = [ - (peer_ids[0], PeerSet::Validation, ValidationVersion::VStaging), + (peer_ids[0], PeerSet::Validation, ValidationVersion::V2), (peer_ids[1], PeerSet::Collation, ValidationVersion::V1), (peer_ids[2], PeerSet::Validation, ValidationVersion::V1), - (peer_ids[3], PeerSet::Collation, ValidationVersion::VStaging), + (peer_ids[3], PeerSet::Collation, ValidationVersion::V2), ]; let head = Hash::repeat_byte(1); @@ -1245,8 +1245,8 @@ fn network_protocol_versioning_view_update() { ValidationVersion::V1 => WireMessage::::ViewUpdate(view.clone()) .encode(), - ValidationVersion::VStaging => - WireMessage::::ViewUpdate(view.clone()) + ValidationVersion::V2 => + WireMessage::::ViewUpdate(view.clone()) .encode(), }; assert_network_actions_contains( @@ -1268,12 +1268,7 @@ fn network_protocol_versioning_subsystem_msg() { let peer = PeerId::random(); network_handle - .connect_peer( - peer, - ValidationVersion::VStaging, - PeerSet::Validation, - ObservedRole::Full, - ) + .connect_peer(peer, ValidationVersion::V2, PeerSet::Validation, ObservedRole::Full) .await; // bridge will inform about all connected peers. @@ -1282,7 +1277,7 @@ fn network_protocol_versioning_subsystem_msg() { NetworkBridgeEvent::PeerConnected( peer, ObservedRole::Full, - ValidationVersion::VStaging.into(), + ValidationVersion::V2.into(), None, ), &mut virtual_overseer, @@ -1297,9 +1292,9 @@ fn network_protocol_versioning_subsystem_msg() { } let approval_distribution_message = - protocol_vstaging::ApprovalDistributionMessage::Approvals(Vec::new()); + protocol_v2::ApprovalDistributionMessage::Approvals(Vec::new()); - let msg = protocol_vstaging::ValidationProtocol::ApprovalDistribution( + let msg = protocol_v2::ValidationProtocol::ApprovalDistribution( approval_distribution_message.clone(), ); @@ -1315,7 +1310,7 @@ fn network_protocol_versioning_subsystem_msg() { virtual_overseer.recv().await, AllMessages::ApprovalDistribution( ApprovalDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(p, Versioned::VStaging(m)) + NetworkBridgeEvent::PeerMessage(p, Versioned::V2(m)) ) ) => { assert_eq!(p, peer); @@ -1330,10 +1325,10 @@ fn network_protocol_versioning_subsystem_msg() { signature: sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]), }; let statement_distribution_message = - protocol_vstaging::StatementDistributionMessage::V1Compatibility( + protocol_v2::StatementDistributionMessage::V1Compatibility( protocol_v1::StatementDistributionMessage::LargeStatement(metadata), ); - let msg = protocol_vstaging::ValidationProtocol::StatementDistribution( + let msg = protocol_v2::ValidationProtocol::StatementDistribution( statement_distribution_message.clone(), ); @@ -1349,7 +1344,7 @@ fn network_protocol_versioning_subsystem_msg() { virtual_overseer.recv().await, AllMessages::StatementDistribution( StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(p, Versioned::VStaging(m)) + NetworkBridgeEvent::PeerMessage(p, Versioned::V2(m)) ) ) => { assert_eq!(p, peer); diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 7fa1149593cab977edbb321a96a5e8268859476c..f15635f1f41c528f6b15a07870f1f348a6b777a3 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -20,7 +20,7 @@ use super::*; use polkadot_node_network_protocol::{ peer_set::{CollationVersion, PeerSet, PeerSetProtocolNames, ValidationVersion}, request_response::ReqProtocolNames, - v1 as protocol_v1, vstaging as protocol_vstaging, PeerId, Versioned, + v1 as protocol_v1, v2 as protocol_v2, PeerId, Versioned, }; use polkadot_node_subsystem::{ @@ -198,7 +198,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::VStaging(msg) => send_validation_message_vstaging( + Versioned::V2(msg) => send_validation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -223,7 +223,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::VStaging(msg) => send_validation_message_vstaging( + Versioned::V2(msg) => send_validation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -248,7 +248,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::VStaging(msg) => send_collation_message_vstaging( + Versioned::V2(msg) => send_collation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -273,7 +273,7 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), - Versioned::VStaging(msg) => send_collation_message_vstaging( + Versioned::V2(msg) => send_collation_message_v2( &mut network_service, peers, peerset_protocol_names, @@ -296,13 +296,11 @@ where Requests::AvailableDataFetchingV1(_) => metrics.on_message("available_data_fetching_v1"), Requests::CollationFetchingV1(_) => metrics.on_message("collation_fetching_v1"), - Requests::CollationFetchingVStaging(_) => - metrics.on_message("collation_fetching_vstaging"), + Requests::CollationFetchingV2(_) => metrics.on_message("collation_fetching_v2"), Requests::PoVFetchingV1(_) => metrics.on_message("pov_fetching_v1"), Requests::DisputeSendingV1(_) => metrics.on_message("dispute_sending_v1"), Requests::StatementFetchingV1(_) => metrics.on_message("statement_fetching_v1"), - Requests::AttestedCandidateVStaging(_) => - metrics.on_message("attested_candidate_vstaging"), + Requests::AttestedCandidateV2(_) => metrics.on_message("attested_candidate_v2"), } network_service @@ -425,36 +423,36 @@ fn send_collation_message_v1( ); } -fn send_validation_message_vstaging( +fn send_validation_message_v2( net: &mut impl Network, peers: Vec, protocol_names: &PeerSetProtocolNames, - message: WireMessage, + message: WireMessage, metrics: &Metrics, ) { send_message( net, peers, PeerSet::Validation, - ValidationVersion::VStaging.into(), + ValidationVersion::V2.into(), protocol_names, message, metrics, ); } -fn send_collation_message_vstaging( +fn send_collation_message_v2( net: &mut impl Network, peers: Vec, protocol_names: &PeerSetProtocolNames, - message: WireMessage, + message: WireMessage, metrics: &Metrics, ) { send_message( net, peers, PeerSet::Collation, - CollationVersion::VStaging.into(), + CollationVersion::V2.into(), protocol_names, message, metrics, diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 21cd134c54f2141af111c5dd41ed5cf6038b58fe..48287f8b74c91a526263fed1d176f916753ce985 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -341,10 +341,10 @@ fn network_protocol_versioning_send() { let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); let peers = [ - (peer_ids[0], PeerSet::Validation, ValidationVersion::VStaging), + (peer_ids[0], PeerSet::Validation, ValidationVersion::V2), (peer_ids[1], PeerSet::Collation, ValidationVersion::V1), (peer_ids[2], PeerSet::Validation, ValidationVersion::V1), - (peer_ids[3], PeerSet::Collation, ValidationVersion::VStaging), + (peer_ids[3], PeerSet::Collation, ValidationVersion::V2), ]; for &(peer_id, peer_set, version) in &peers { @@ -359,9 +359,9 @@ fn network_protocol_versioning_send() { { let approval_distribution_message = - protocol_vstaging::ApprovalDistributionMessage::Approvals(Vec::new()); + protocol_v2::ApprovalDistributionMessage::Approvals(Vec::new()); - let msg = protocol_vstaging::ValidationProtocol::ApprovalDistribution( + let msg = protocol_v2::ValidationProtocol::ApprovalDistribution( approval_distribution_message.clone(), ); @@ -372,7 +372,7 @@ fn network_protocol_versioning_send() { .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendValidationMessage( receivers.clone(), - Versioned::VStaging(msg.clone()), + Versioned::V2(msg.clone()), ), }) .timeout(TIMEOUT) @@ -398,15 +398,14 @@ fn network_protocol_versioning_send() { // send a collation protocol message. { - let collator_protocol_message = protocol_vstaging::CollatorProtocolMessage::Declare( + let collator_protocol_message = protocol_v2::CollatorProtocolMessage::Declare( Sr25519Keyring::Alice.public().into(), 0_u32.into(), dummy_collator_signature(), ); - let msg = protocol_vstaging::CollationProtocol::CollatorProtocol( - collator_protocol_message.clone(), - ); + let msg = + protocol_v2::CollationProtocol::CollatorProtocol(collator_protocol_message.clone()); let receivers = vec![peer_ids[1], peer_ids[2]]; @@ -414,7 +413,7 @@ fn network_protocol_versioning_send() { .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendCollationMessages(vec![( receivers.clone(), - Versioned::VStaging(msg.clone()), + Versioned::V2(msg.clone()), )]), }) .await; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs index 627c38b776f7c6cffd4ba5ebd848d55ab02f32b4..53f947142d10d615496b184b22ce7d69d815c977 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs @@ -22,8 +22,7 @@ use futures::{future::BoxFuture, stream::FuturesUnordered}; use polkadot_node_network_protocol::{ request_response::{ - incoming::OutgoingResponse, v1 as protocol_v1, vstaging as protocol_vstaging, - IncomingRequest, + incoming::OutgoingResponse, v1 as protocol_v1, v2 as protocol_v2, IncomingRequest, }, PeerId, }; @@ -89,7 +88,7 @@ pub struct WaitingCollationFetches { /// Backwards-compatible wrapper for incoming collations requests. pub enum VersionedCollationRequest { V1(IncomingRequest), - VStaging(IncomingRequest), + V2(IncomingRequest), } impl From> for VersionedCollationRequest { @@ -98,11 +97,9 @@ impl From> for VersionedC } } -impl From> - for VersionedCollationRequest -{ - fn from(req: IncomingRequest) -> Self { - Self::VStaging(req) +impl From> for VersionedCollationRequest { + fn from(req: IncomingRequest) -> Self { + Self::V2(req) } } @@ -111,7 +108,7 @@ impl VersionedCollationRequest { pub fn para_id(&self) -> ParaId { match self { VersionedCollationRequest::V1(req) => req.payload.para_id, - VersionedCollationRequest::VStaging(req) => req.payload.para_id, + VersionedCollationRequest::V2(req) => req.payload.para_id, } } @@ -119,7 +116,7 @@ impl VersionedCollationRequest { pub fn relay_parent(&self) -> Hash { match self { VersionedCollationRequest::V1(req) => req.payload.relay_parent, - VersionedCollationRequest::VStaging(req) => req.payload.relay_parent, + VersionedCollationRequest::V2(req) => req.payload.relay_parent, } } @@ -127,7 +124,7 @@ impl VersionedCollationRequest { pub fn peer_id(&self) -> PeerId { match self { VersionedCollationRequest::V1(req) => req.peer, - VersionedCollationRequest::VStaging(req) => req.peer, + VersionedCollationRequest::V2(req) => req.peer, } } @@ -138,7 +135,7 @@ impl VersionedCollationRequest { ) -> Result<(), ()> { match self { VersionedCollationRequest::V1(req) => req.send_outgoing_response(response), - VersionedCollationRequest::VStaging(req) => req.send_outgoing_response(response), + VersionedCollationRequest::V2(req) => req.send_outgoing_response(response), } } } 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 ad2ab99568c8cdc3676984ae3fad43e87ccf4374..304cabbaac80c1a540a352da9ed74faa5f4dbf32 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -31,10 +31,10 @@ use polkadot_node_network_protocol::{ peer_set::{CollationVersion, PeerSet}, request_response::{ incoming::{self, OutgoingResponse}, - v1 as request_v1, vstaging as request_vstaging, IncomingRequestReceiver, + v1 as request_v1, v2 as request_v2, IncomingRequestReceiver, }, - v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, - UnifiedReputationChange as Rep, Versioned, View, + v1 as protocol_v1, v2 as protocol_v2, OurView, PeerId, UnifiedReputationChange as Rep, + Versioned, View, }; use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement}; use polkadot_node_subsystem::{ @@ -577,7 +577,7 @@ async fn determine_our_validators( fn declare_message( state: &mut State, version: CollationVersion, -) -> Option> { +) -> Option> { let para_id = state.collating_on?; Some(match version { CollationVersion::V1 => { @@ -590,17 +590,15 @@ fn declare_message( ); Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)) }, - CollationVersion::VStaging => { + CollationVersion::V2 => { let declare_signature_payload = - protocol_vstaging::declare_signature_payload(&state.local_peer_id); - let wire_message = protocol_vstaging::CollatorProtocolMessage::Declare( + protocol_v2::declare_signature_payload(&state.local_peer_id); + let wire_message = protocol_v2::CollatorProtocolMessage::Declare( state.collator_pair.public(), para_id, state.collator_pair.sign(&declare_signature_payload), ); - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( - wire_message, - )) + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol(wire_message)) }, }) } @@ -706,15 +704,13 @@ async fn advertise_collation( collation.status.advance_to_advertised(); let collation_message = match protocol_version { - CollationVersion::VStaging => { - let wire_message = protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + CollationVersion::V2 => { + let wire_message = protocol_v2::CollatorProtocolMessage::AdvertiseCollation { relay_parent, candidate_hash: *candidate_hash, parent_head_data_hash: collation.parent_head_data_hash, }; - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( - wire_message, - )) + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol(wire_message)) }, CollationVersion::V1 => { let wire_message = @@ -837,7 +833,7 @@ async fn send_collation( let candidate_hash = receipt.hash(); // The response payload is the same for both versions of protocol - // and doesn't have vstaging alias for simplicity. + // and doesn't have v2 alias for simplicity. let response = OutgoingResponse { result: Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)), reputation_changes: Vec::new(), @@ -868,16 +864,13 @@ async fn handle_incoming_peer_message( runtime: &mut RuntimeInfo, state: &mut State, origin: PeerId, - msg: Versioned< - protocol_v1::CollatorProtocolMessage, - protocol_vstaging::CollatorProtocolMessage, - >, + msg: Versioned, ) -> Result<()> { use protocol_v1::CollatorProtocolMessage as V1; - use protocol_vstaging::CollatorProtocolMessage as VStaging; + use protocol_v2::CollatorProtocolMessage as V2; match msg { - Versioned::V1(V1::Declare(..)) | Versioned::VStaging(VStaging::Declare(..)) => { + Versioned::V1(V1::Declare(..)) | Versioned::V2(V2::Declare(..)) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -888,8 +881,7 @@ async fn handle_incoming_peer_message( ctx.send_message(NetworkBridgeTxMessage::DisconnectPeer(origin, PeerSet::Collation)) .await; }, - Versioned::V1(V1::AdvertiseCollation(_)) | - Versioned::VStaging(VStaging::AdvertiseCollation { .. }) => { + Versioned::V1(V1::AdvertiseCollation(_)) | Versioned::V2(V2::AdvertiseCollation { .. }) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -904,7 +896,7 @@ async fn handle_incoming_peer_message( .await; }, Versioned::V1(V1::CollationSeconded(relay_parent, statement)) | - Versioned::VStaging(VStaging::CollationSeconded(relay_parent, statement)) => { + Versioned::V2(V2::CollationSeconded(relay_parent, statement)) => { if !matches!(statement.unchecked_payload(), Statement::Seconded(_)) { gum::warn!( target: LOG_TARGET, @@ -1006,7 +998,7 @@ async fn handle_incoming_request( let collation = match &req { VersionedCollationRequest::V1(_) if !mode.is_enabled() => per_relay_parent.collations.values_mut().next(), - VersionedCollationRequest::VStaging(req) => + VersionedCollationRequest::V2(req) => per_relay_parent.collations.get_mut(&req.payload.candidate_hash), _ => { gum::warn!( @@ -1322,7 +1314,7 @@ pub(crate) async fn run( local_peer_id: PeerId, collator_pair: CollatorPair, req_v1_receiver: IncomingRequestReceiver, - req_v2_receiver: IncomingRequestReceiver, + req_v2_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> std::result::Result<(), FatalError> { run_inner( @@ -1344,7 +1336,7 @@ async fn run_inner( local_peer_id: PeerId, collator_pair: CollatorPair, mut req_v1_receiver: IncomingRequestReceiver, - mut req_v2_receiver: IncomingRequestReceiver, + mut req_v2_receiver: IncomingRequestReceiver, metrics: Metrics, reputation: ReputationAggregator, reputation_interval: Duration, @@ -1425,7 +1417,7 @@ async fn run_inner( (ProspectiveParachainsMode::Disabled, VersionedCollationRequest::V1(_)) => { per_relay_parent.collations.values().next() }, - (ProspectiveParachainsMode::Enabled { .. }, VersionedCollationRequest::VStaging(req)) => { + (ProspectiveParachainsMode::Enabled { .. }, VersionedCollationRequest::V2(req)) => { per_relay_parent.collations.get(&req.payload.candidate_hash) }, _ => { @@ -1476,7 +1468,7 @@ async fn run_inner( log_error( handle_incoming_request(&mut ctx, &mut state, request).await, - "Handling incoming collation fetch request VStaging" + "Handling incoming collation fetch request V2" )?; } } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index b452c84c2cd8f1091a3c5f0e2c34f3e40f4b2a0b..7dd2287dab684debb39f68f94098c1b225024285 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -198,7 +198,7 @@ impl TestState { overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::StagingAsyncBackingParams(tx) + RuntimeApiRequest::AsyncBackingParams(tx) )) => { assert_eq!(relay_parent, self.relay_parent); tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); @@ -212,7 +212,7 @@ type VirtualOverseer = test_helpers::TestSubsystemContextHandle>( @@ -236,7 +236,7 @@ fn test_harness>( let (collation_req_receiver, req_v1_cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); - let (collation_req_vstaging_receiver, req_vstaging_cfg) = + let (collation_req_v2_receiver, req_v2_cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); let subsystem = async { run_inner( @@ -244,7 +244,7 @@ fn test_harness>( local_peer_id, collator_pair, collation_req_receiver, - collation_req_vstaging_receiver, + collation_req_v2_receiver, Default::default(), reputation, REPUTATION_CHANGE_TEST_INTERVAL, @@ -253,7 +253,7 @@ fn test_harness>( .unwrap(); }; - let test_fut = test(TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg }); + let test_fut = test(TestHarness { virtual_overseer, req_v1_cfg, req_v2_cfg }); futures::pin_mut!(test_fut); futures::pin_mut!(subsystem); @@ -330,7 +330,7 @@ async fn setup_system(virtual_overseer: &mut VirtualOverseer, test_state: &TestS overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::StagingAsyncBackingParams(tx) + RuntimeApiRequest::AsyncBackingParams(tx) )) => { assert_eq!(relay_parent, test_state.relay_parent); tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); @@ -545,7 +545,7 @@ async fn expect_declare_msg( /// Check that the next received message is a collation advertisement message. /// -/// Expects vstaging message if `expected_candidate_hashes` is `Some`, v1 otherwise. +/// Expects v2 message if `expected_candidate_hashes` is `Some`, v1 otherwise. async fn expect_advertise_collation_msg( virtual_overseer: &mut VirtualOverseer, peer: &PeerId, @@ -579,13 +579,13 @@ async fn expect_advertise_collation_msg( }, ( Some(candidate_hashes), - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( wire_message, )), ) => { assert_matches!( wire_message, - protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + protocol_v2::CollatorProtocolMessage::AdvertiseCollation { relay_parent, candidate_hash, .. @@ -634,7 +634,7 @@ fn advertise_and_send_collation() { |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; let mut req_v1_cfg = test_harness.req_v1_cfg; - let req_vstaging_cfg = test_harness.req_vstaging_cfg; + let req_v2_cfg = test_harness.req_v2_cfg; setup_system(&mut virtual_overseer, &test_state).await; @@ -789,7 +789,7 @@ fn advertise_and_send_collation() { None, ) .await; - TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } + TestHarness { virtual_overseer, req_v1_cfg, req_v2_cfg } }, ); } @@ -807,7 +807,7 @@ fn delay_reputation_change() { |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; let mut req_v1_cfg = test_harness.req_v1_cfg; - let req_vstaging_cfg = test_harness.req_vstaging_cfg; + let req_v2_cfg = test_harness.req_v2_cfg; setup_system(&mut virtual_overseer, &test_state).await; @@ -903,15 +903,15 @@ fn delay_reputation_change() { ); } - TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } + TestHarness { virtual_overseer, req_v1_cfg, req_v2_cfg } }, ); } -/// Tests that collator side works with vstaging network protocol +/// Tests that collator side works with v2 network protocol /// before async backing is enabled. #[test] -fn advertise_collation_vstaging_protocol() { +fn advertise_collation_v2_protocol() { let test_state = TestState::default(); let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); @@ -941,21 +941,16 @@ fn advertise_collation_vstaging_protocol() { Some(validators[0].clone()), ) .await; - // The rest with vstaging. + // The rest with v2. for (val, peer) in validators.iter().zip(peer_ids.iter()).skip(1) { - connect_peer( - virtual_overseer, - *peer, - CollationVersion::VStaging, - Some(val.clone()), - ) - .await; + connect_peer(virtual_overseer, *peer, CollationVersion::V2, Some(val.clone())) + .await; } // Declare messages. expect_declare_msg(virtual_overseer, &test_state, &peer_ids[0]).await; for peer_id in peer_ids.iter().skip(1) { - prospective_parachains::expect_declare_msg_vstaging( + prospective_parachains::expect_declare_msg_v2( virtual_overseer, &test_state, &peer_id, @@ -981,7 +976,7 @@ fn advertise_collation_vstaging_protocol() { virtual_overseer, peer_id, test_state.relay_parent, - Some(vec![candidate.hash()]), // This is `Some`, advertisement is vstaging. + Some(vec![candidate.hash()]), // This is `Some`, advertisement is v2. ) .await; } @@ -1405,7 +1400,7 @@ fn connect_to_buffered_groups() { |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; let mut req_cfg = test_harness.req_v1_cfg; - let req_vstaging_cfg = test_harness.req_vstaging_cfg; + let req_v2_cfg = test_harness.req_v2_cfg; setup_system(&mut virtual_overseer, &test_state).await; @@ -1510,7 +1505,7 @@ fn connect_to_buffered_groups() { } ); - TestHarness { virtual_overseer, req_v1_cfg: req_cfg, req_vstaging_cfg } + TestHarness { virtual_overseer, req_v1_cfg: req_cfg, req_v2_cfg } }, ); } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index bd55c35852fa96bf7a8f5747f2cb904bdf038fba..fd9d7a746ebe49623ff0feebd48793e8e603807b 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -19,10 +19,10 @@ use super::*; use polkadot_node_subsystem::messages::{ChainApiMessage, ProspectiveParachainsMessage}; -use polkadot_primitives::{vstaging as vstaging_primitives, Header, OccupiedCore}; +use polkadot_primitives::{AsyncBackingParams, Header, OccupiedCore}; -const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = - vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; +const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; fn get_parent_hash(hash: Hash) -> Hash { Hash::from_low_u64_be(hash.to_low_u64_be() + 1) @@ -52,7 +52,7 @@ async fn update_view( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, - RuntimeApiRequest::StagingAsyncBackingParams(tx), + RuntimeApiRequest::AsyncBackingParams(tx), )) => { tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) @@ -124,7 +124,7 @@ async fn update_view( } /// Check that the next received message is a `Declare` message. -pub(super) async fn expect_declare_msg_vstaging( +pub(super) async fn expect_declare_msg_v2( virtual_overseer: &mut VirtualOverseer, test_state: &TestState, peer: &PeerId, @@ -133,20 +133,20 @@ pub(super) async fn expect_declare_msg_vstaging( overseer_recv(virtual_overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( to, - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( wire_message, )), )) => { assert_eq!(to[0], *peer); assert_matches!( wire_message, - protocol_vstaging::CollatorProtocolMessage::Declare( + protocol_v2::CollatorProtocolMessage::Declare( collator_id, para_id, signature, ) => { assert!(signature.verify( - &*protocol_vstaging::declare_signature_payload(&test_state.local_peer_id), + &*protocol_v2::declare_signature_payload(&test_state.local_peer_id), &collator_id), ); assert_eq!(collator_id, test_state.collator_pair.public()); @@ -203,13 +203,12 @@ fn distribute_collation_from_implicit_view() { .into_iter() .zip(validator_peer_ids.clone()) { - connect_peer(virtual_overseer, peer, CollationVersion::VStaging, Some(val.clone())) - .await; + connect_peer(virtual_overseer, peer, CollationVersion::V2, Some(val.clone())).await; } // Collator declared itself to each peer. for peer_id in &validator_peer_ids { - expect_declare_msg_vstaging(virtual_overseer, &test_state, peer_id).await; + expect_declare_msg_v2(virtual_overseer, &test_state, peer_id).await; } let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; @@ -386,7 +385,7 @@ fn advertise_and_send_collation_by_hash() { |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; let req_v1_cfg = test_harness.req_v1_cfg; - let mut req_vstaging_cfg = test_harness.req_vstaging_cfg; + let mut req_v2_cfg = test_harness.req_v2_cfg; let head_a = Hash::from_low_u64_be(128); let head_a_num: u32 = 64; @@ -435,11 +434,11 @@ fn advertise_and_send_collation_by_hash() { connect_peer( &mut virtual_overseer, peer, - CollationVersion::VStaging, + CollationVersion::V2, Some(validator_id.clone()), ) .await; - expect_declare_msg_vstaging(&mut virtual_overseer, &test_state, &peer).await; + expect_declare_msg_v2(&mut virtual_overseer, &test_state, &peer).await; // Head `b` is not a leaf, but both advertisements are still relevant. send_peer_view_change(&mut virtual_overseer, &peer, vec![head_b]).await; @@ -449,13 +448,13 @@ fn advertise_and_send_collation_by_hash() { for (candidate, pov_block) in candidates { let (pending_response, rx) = oneshot::channel(); - req_vstaging_cfg + req_v2_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: request_vstaging::CollationFetchingRequest { + payload: request_v2::CollationFetchingRequest { relay_parent: head_b, para_id: test_state.para_id, candidate_hash: candidate.hash(), @@ -469,7 +468,7 @@ fn advertise_and_send_collation_by_hash() { assert_matches!( rx.await, Ok(full_response) => { - // Response is the same for vstaging. + // Response is the same for v2. let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse = request_v1::CollationFetchingResponse::decode( &mut full_response.result @@ -482,7 +481,7 @@ fn advertise_and_send_collation_by_hash() { ); } - TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } + TestHarness { virtual_overseer, req_v1_cfg, req_v2_cfg } }, ) } @@ -552,11 +551,11 @@ fn advertise_core_occupied() { connect_peer( virtual_overseer, peer_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, Some(validators[0].clone()), ) .await; - expect_declare_msg_vstaging(virtual_overseer, &test_state, &peer_ids[0]).await; + expect_declare_msg_v2(virtual_overseer, &test_state, &peer_ids[0]).await; // Peer is aware of the leaf. send_peer_view_change(virtual_overseer, &peer_ids[0], vec![head_a]).await; diff --git a/polkadot/node/network/collator-protocol/src/lib.rs b/polkadot/node/network/collator-protocol/src/lib.rs index 62c033954f75a00fb2c1b50a3afb0b858b977c5f..1edc67664172400503158f8a451756ca3674a3d9 100644 --- a/polkadot/node/network/collator-protocol/src/lib.rs +++ b/polkadot/node/network/collator-protocol/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_node_subsystem_util::reputation::ReputationAggregator; use sp_keystore::KeystorePtr; use polkadot_node_network_protocol::{ - request_response::{v1 as request_v1, vstaging as protocol_vstaging, IncomingRequestReceiver}, + request_response::{v1 as request_v1, v2 as protocol_v2, IncomingRequestReceiver}, PeerId, UnifiedReputationChange as Rep, }; use polkadot_primitives::CollatorPair; @@ -83,9 +83,8 @@ pub enum ProtocolSide { collator_pair: CollatorPair, /// Receiver for v1 collation fetching requests. request_receiver_v1: IncomingRequestReceiver, - /// Receiver for vstaging collation fetching requests. - request_receiver_vstaging: - IncomingRequestReceiver, + /// Receiver for v2 collation fetching requests. + request_receiver_v2: IncomingRequestReceiver, /// Metrics. metrics: collator_side::Metrics, }, @@ -121,14 +120,14 @@ impl CollatorProtocolSubsystem { peer_id, collator_pair, request_receiver_v1, - request_receiver_vstaging, + request_receiver_v2, metrics, } => collator_side::run( ctx, peer_id, collator_pair, request_receiver_v1, - request_receiver_vstaging, + request_receiver_v2, metrics, ) .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) 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 4c92780f2da9448f3b3a0992a3cc16c9b3676c30..a53e0028b9e70455f3dd918bad58fc5ec472c173 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -119,7 +119,7 @@ impl PendingCollation { } } -/// vstaging advertisement that was rejected by the backing +/// v2 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)] 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 e8cf769d2e5f336f17053cc6471366ae18d694a9..fcb408d54b1b72b856b2439bd2eb1823020fb513 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -34,10 +34,10 @@ use polkadot_node_network_protocol::{ peer_set::{CollationVersion, PeerSet}, request_response::{ outgoing::{Recipient, RequestError}, - v1 as request_v1, vstaging as request_vstaging, OutgoingRequest, Requests, + v1 as request_v1, v2 as request_v2, OutgoingRequest, Requests, }, - v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, - UnifiedReputationChange as Rep, Versioned, View, + v1 as protocol_v1, v2 as protocol_v2, OurView, PeerId, UnifiedReputationChange as Rep, + Versioned, View, }; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_node_subsystem::{ @@ -624,13 +624,9 @@ async fn notify_collation_seconded( CollationVersion::V1 => Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol( protocol_v1::CollatorProtocolMessage::CollationSeconded(relay_parent, statement), )), - CollationVersion::VStaging => - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( - protocol_vstaging::CollatorProtocolMessage::CollationSeconded( - relay_parent, - statement, - ), - )), + CollationVersion::V2 => Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( + protocol_v2::CollatorProtocolMessage::CollationSeconded(relay_parent, statement), + )), }; sender .send_message(NetworkBridgeTxMessage::SendCollationMessage(vec![peer_id], wire_message)) @@ -694,16 +690,12 @@ async fn request_collation( let requests = Requests::CollationFetchingV1(req); (requests, response_recv.boxed()) }, - (CollationVersion::VStaging, Some(ProspectiveCandidate { candidate_hash, .. })) => { + (CollationVersion::V2, Some(ProspectiveCandidate { candidate_hash, .. })) => { let (req, response_recv) = OutgoingRequest::new( Recipient::Peer(peer_id), - request_vstaging::CollationFetchingRequest { - relay_parent, - para_id, - candidate_hash, - }, + request_v2::CollationFetchingRequest { relay_parent, para_id, candidate_hash }, ); - let requests = Requests::CollationFetchingVStaging(req); + let requests = Requests::CollationFetchingV2(req); (requests, response_recv.boxed()) }, _ => return Err(FetchError::ProtocolMismatch), @@ -758,18 +750,15 @@ async fn process_incoming_peer_message( ctx: &mut Context, state: &mut State, origin: PeerId, - msg: Versioned< - protocol_v1::CollatorProtocolMessage, - protocol_vstaging::CollatorProtocolMessage, - >, + msg: Versioned, ) { use protocol_v1::CollatorProtocolMessage as V1; - use protocol_vstaging::CollatorProtocolMessage as VStaging; + use protocol_v2::CollatorProtocolMessage as V2; use sp_runtime::traits::AppVerify; match msg { Versioned::V1(V1::Declare(collator_id, para_id, signature)) | - Versioned::VStaging(VStaging::Declare(collator_id, para_id, signature)) => { + Versioned::V2(V2::Declare(collator_id, para_id, signature)) => { if collator_peer_id(&state.peer_data, &collator_id).is_some() { modify_reputation( &mut state.reputation, @@ -881,7 +870,7 @@ async fn process_incoming_peer_message( modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; } }, - Versioned::VStaging(VStaging::AdvertiseCollation { + Versioned::V2(V2::AdvertiseCollation { relay_parent, candidate_hash, parent_head_data_hash, @@ -901,15 +890,14 @@ async fn process_incoming_peer_message( ?relay_parent, ?candidate_hash, error = ?err, - "Rejected vstaging advertisement", + "Rejected v2 advertisement", ); if let Some(rep) = err.reputation_changes() { modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; } }, - Versioned::V1(V1::CollationSeconded(..)) | - Versioned::VStaging(VStaging::CollationSeconded(..)) => { + Versioned::V1(V1::CollationSeconded(..)) | Versioned::V2(V2::CollationSeconded(..)) => { gum::warn!( target: LOG_TARGET, peer_id = ?origin, @@ -1074,7 +1062,7 @@ where }; if relay_parent_mode.is_enabled() && prospective_candidate.is_none() { - // Expected vstaging advertisement. + // Expected v2 advertisement. return Err(AdvertisementError::ProtocolMismatch) } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs index 1cb656e325d325e6e824a3ea9ec5669f78d35424..9812998aab763cee54e1dac5232c1c9bddb4651b 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs @@ -357,7 +357,7 @@ async fn assert_fetch_collation_request( ), Some(candidate_hash) => assert_matches!( req, - Requests::CollationFetchingVStaging(req) => { + Requests::CollationFetchingV2(req) => { let payload = req.payload; assert_eq!(payload.relay_parent, relay_parent); assert_eq!(payload.para_id, para_id); @@ -394,12 +394,11 @@ async fn connect_and_declare_collator( para_id, collator.sign(&protocol_v1::declare_signature_payload(&peer)), )), - CollationVersion::VStaging => - Versioned::VStaging(protocol_vstaging::CollatorProtocolMessage::Declare( - collator.public(), - para_id, - collator.sign(&protocol_v1::declare_signature_payload(&peer)), - )), + CollationVersion::V2 => Versioned::V2(protocol_v2::CollatorProtocolMessage::Declare( + collator.public(), + para_id, + collator.sign(&protocol_v1::declare_signature_payload(&peer)), + )), }; overseer_send( @@ -421,7 +420,7 @@ async fn advertise_collation( ) { let wire_message = match candidate { Some((candidate_hash, parent_head_data_hash)) => - Versioned::VStaging(protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + Versioned::V2(protocol_v2::CollatorProtocolMessage::AdvertiseCollation { relay_parent, candidate_hash, parent_head_data_hash, @@ -444,7 +443,7 @@ async fn assert_async_backing_params_request(virtual_overseer: &mut VirtualOvers overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::StagingAsyncBackingParams(tx) + RuntimeApiRequest::AsyncBackingParams(tx) )) => { assert_eq!(relay_parent, hash); tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); @@ -499,10 +498,10 @@ fn act_on_advertisement() { }); } -/// Tests that validator side works with vstaging network protocol +/// Tests that validator side works with v2 network protocol /// before async backing is enabled. #[test] -fn act_on_advertisement_vstaging() { +fn act_on_advertisement_v2() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { @@ -529,13 +528,13 @@ fn act_on_advertisement_vstaging() { peer_b, pair.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; let candidate_hash = CandidateHash::default(); let parent_head_data_hash = Hash::zero(); - // vstaging advertisement. + // v2 advertisement. advertise_collation( &mut virtual_overseer, peer_b, 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 e2a007b308e54a9e65af18646f5353363e45ef3d..4da0f11da39002fe035c618608e44ffca2939e94 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -20,12 +20,12 @@ use super::*; use polkadot_node_subsystem::messages::ChainApiMessage; use polkadot_primitives::{ - vstaging as vstaging_primitives, BlockNumber, CandidateCommitments, CommittedCandidateReceipt, - Header, SigningContext, ValidatorId, + AsyncBackingParams, BlockNumber, CandidateCommitments, CommittedCandidateReceipt, Header, + SigningContext, ValidatorId, }; -const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = - vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; +const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; fn get_parent_hash(hash: Hash) -> Hash { Hash::from_low_u64_be(hash.to_low_u64_be() + 1) @@ -97,7 +97,7 @@ async fn update_view( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, - RuntimeApiRequest::StagingAsyncBackingParams(tx), + RuntimeApiRequest::AsyncBackingParams(tx), )) => { tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) @@ -226,8 +226,8 @@ async fn assert_collation_seconded( overseer_recv(virtual_overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( peers, - Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( - protocol_vstaging::CollatorProtocolMessage::CollationSeconded( + Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol( + protocol_v2::CollatorProtocolMessage::CollationSeconded( _relay_parent, .., ), @@ -306,7 +306,7 @@ fn accept_advertisements_from_implicit_view() { peer_a, pair_a.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; connect_and_declare_collator( @@ -314,7 +314,7 @@ fn accept_advertisements_from_implicit_view() { peer_b, pair_b.clone(), test_state.chain_ids[1], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -406,7 +406,7 @@ fn second_multiple_candidates_per_relay_parent() { peer_a, pair.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -457,7 +457,7 @@ fn second_multiple_candidates_per_relay_parent() { let pov = PoV { block_data: BlockData(vec![1]) }; response_channel - .send(Ok(request_vstaging::CollationFetchingResponse::Collation( + .send(Ok(request_v2::CollationFetchingResponse::Collation( candidate.clone(), pov.clone(), ) @@ -514,7 +514,7 @@ fn second_multiple_candidates_per_relay_parent() { peer_b, pair_b.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -562,7 +562,7 @@ fn fetched_collation_sanity_check() { peer_a, pair.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -611,7 +611,7 @@ fn fetched_collation_sanity_check() { let pov = PoV { block_data: BlockData(vec![1]) }; response_channel - .send(Ok(request_vstaging::CollationFetchingResponse::Collation( + .send(Ok(request_v2::CollationFetchingResponse::Collation( candidate.clone(), pov.clone(), ) @@ -668,7 +668,7 @@ fn advertisement_spam_protection() { peer_a, pair_a.clone(), test_state.chain_ids[1], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -748,7 +748,7 @@ fn backed_candidate_unblocks_advertisements() { peer_a, pair_a.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; connect_and_declare_collator( @@ -756,7 +756,7 @@ fn backed_candidate_unblocks_advertisements() { peer_b, pair_b.clone(), test_state.chain_ids[1], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; @@ -856,7 +856,7 @@ fn active_leave_unblocks_advertisements() { *peer_id, peer.clone(), test_state.chain_ids[0], - CollationVersion::VStaging, + CollationVersion::V2, ) .await; } diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index c5dc1ba14bd35b5127ff27c0c3d0732e0e56178c..4fa23507e86bd145782d068b0aa84d0cf2c98ba6 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -452,7 +452,7 @@ where // match void -> LLVM unreachable match message { Versioned::V1(m) => match m {}, - Versioned::VStaging(m) => match m {}, + Versioned::V2(m) => match m {}, } }, } diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index c33b9eae3252606e8d2fcbd954a0e180f4a47acb..379334ded24acde67100de5b61069d5cb5909ce4 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -27,6 +27,3 @@ bitvec = "1" [dev-dependencies] rand_chacha = "0.3.1" - -[features] -network-protocol-staging = [] diff --git a/polkadot/node/network/protocol/src/lib.rs b/polkadot/node/network/protocol/src/lib.rs index 1bed2c12fe202ce51ae07d50b0d07ca6282b669d..901ac99b66933a77b95ccb1c55fd22930fc5a34a 100644 --- a/polkadot/node/network/protocol/src/lib.rs +++ b/polkadot/node/network/protocol/src/lib.rs @@ -253,26 +253,25 @@ impl View { /// A protocol-versioned type. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Versioned { +pub enum Versioned { /// V1 type. V1(V1), - /// VStaging type. - VStaging(VStaging), + /// V2 type. + V2(V2), } -impl Versioned<&'_ V1, &'_ VStaging> { +impl Versioned<&'_ V1, &'_ V2> { /// Convert to a fully-owned version of the message. - pub fn clone_inner(&self) -> Versioned { + pub fn clone_inner(&self) -> Versioned { match *self { Versioned::V1(inner) => Versioned::V1(inner.clone()), - Versioned::VStaging(inner) => Versioned::VStaging(inner.clone()), + Versioned::V2(inner) => Versioned::V2(inner.clone()), } } } /// All supported versions of the validation protocol message. -pub type VersionedValidationProtocol = - Versioned; +pub type VersionedValidationProtocol = Versioned; impl From for VersionedValidationProtocol { fn from(v1: v1::ValidationProtocol) -> Self { @@ -280,14 +279,14 @@ impl From for VersionedValidationProtocol { } } -impl From for VersionedValidationProtocol { - fn from(vstaging: vstaging::ValidationProtocol) -> Self { - VersionedValidationProtocol::VStaging(vstaging) +impl From for VersionedValidationProtocol { + fn from(v2: v2::ValidationProtocol) -> Self { + VersionedValidationProtocol::V2(v2) } } /// All supported versions of the collation protocol message. -pub type VersionedCollationProtocol = Versioned; +pub type VersionedCollationProtocol = Versioned; impl From for VersionedCollationProtocol { fn from(v1: v1::CollationProtocol) -> Self { @@ -295,9 +294,9 @@ impl From for VersionedCollationProtocol { } } -impl From for VersionedCollationProtocol { - fn from(vstaging: vstaging::CollationProtocol) -> Self { - VersionedCollationProtocol::VStaging(vstaging) +impl From for VersionedCollationProtocol { + fn from(v2: v2::CollationProtocol) -> Self { + VersionedCollationProtocol::V2(v2) } } @@ -307,7 +306,7 @@ macro_rules! impl_versioned_full_protocol_from { fn from(versioned_from: $from) -> $out { match versioned_from { Versioned::V1(x) => Versioned::V1(x.into()), - Versioned::VStaging(x) => Versioned::VStaging(x.into()), + Versioned::V2(x) => Versioned::V2(x.into()), } } } @@ -321,7 +320,7 @@ macro_rules! impl_versioned_try_from { $from:ty, $out:ty, $v1_pat:pat => $v1_out:expr, - $vstaging_pat:pat => $vstaging_out:expr + $v2_pat:pat => $v2_out:expr ) => { impl TryFrom<$from> for $out { type Error = crate::WrongVariant; @@ -330,7 +329,7 @@ macro_rules! impl_versioned_try_from { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)), - Versioned::VStaging($vstaging_pat) => Ok(Versioned::VStaging($vstaging_out)), + Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)), _ => Err(crate::WrongVariant), } } @@ -343,8 +342,7 @@ macro_rules! impl_versioned_try_from { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())), - Versioned::VStaging($vstaging_pat) => - Ok(Versioned::VStaging($vstaging_out.clone())), + Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())), _ => Err(crate::WrongVariant), } } @@ -354,7 +352,7 @@ macro_rules! impl_versioned_try_from { /// Version-annotated messages used by the bitfield distribution subsystem. pub type BitfieldDistributionMessage = - Versioned; + Versioned; impl_versioned_full_protocol_from!( BitfieldDistributionMessage, VersionedValidationProtocol, @@ -364,12 +362,12 @@ impl_versioned_try_from!( VersionedValidationProtocol, BitfieldDistributionMessage, v1::ValidationProtocol::BitfieldDistribution(x) => x, - vstaging::ValidationProtocol::BitfieldDistribution(x) => x + v2::ValidationProtocol::BitfieldDistribution(x) => x ); /// Version-annotated messages used by the statement distribution subsystem. pub type StatementDistributionMessage = - Versioned; + Versioned; impl_versioned_full_protocol_from!( StatementDistributionMessage, VersionedValidationProtocol, @@ -379,12 +377,12 @@ impl_versioned_try_from!( VersionedValidationProtocol, StatementDistributionMessage, v1::ValidationProtocol::StatementDistribution(x) => x, - vstaging::ValidationProtocol::StatementDistribution(x) => x + v2::ValidationProtocol::StatementDistribution(x) => x ); /// Version-annotated messages used by the approval distribution subsystem. pub type ApprovalDistributionMessage = - Versioned; + Versioned; impl_versioned_full_protocol_from!( ApprovalDistributionMessage, VersionedValidationProtocol, @@ -394,13 +392,13 @@ impl_versioned_try_from!( VersionedValidationProtocol, ApprovalDistributionMessage, v1::ValidationProtocol::ApprovalDistribution(x) => x, - vstaging::ValidationProtocol::ApprovalDistribution(x) => x + v2::ValidationProtocol::ApprovalDistribution(x) => x ); /// Version-annotated messages used by the gossip-support subsystem (this is void). pub type GossipSupportNetworkMessage = - Versioned; + Versioned; // This is a void enum placeholder, so never gets sent over the wire. impl TryFrom for GossipSupportNetworkMessage { type Error = WrongVariant; @@ -418,7 +416,7 @@ impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessag /// Version-annotated messages used by the bitfield distribution subsystem. pub type CollatorProtocolMessage = - Versioned; + Versioned; impl_versioned_full_protocol_from!( CollatorProtocolMessage, VersionedCollationProtocol, @@ -428,7 +426,7 @@ impl_versioned_try_from!( VersionedCollationProtocol, CollatorProtocolMessage, v1::CollationProtocol::CollatorProtocol(x) => x, - vstaging::CollationProtocol::CollatorProtocol(x) => x + v2::CollationProtocol::CollatorProtocol(x) => x ); /// v1 notification protocol types. @@ -589,12 +587,12 @@ pub mod v1 { } } -/// vstaging network protocol types. -pub mod vstaging { +/// v2 network protocol types. +pub mod v2 { use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec}; use parity_scale_codec::{Decode, Encode}; - use polkadot_primitives::vstaging::{ + use polkadot_primitives::{ CandidateHash, CandidateIndex, CollatorId, CollatorSignature, GroupIndex, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield, UncheckedSignedStatement, }; diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index c2163783c2ce05d9eaac9b3718745107baaeeb08..8dd68b297e3000ec4fc0847b047a1323aae97353 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -118,16 +118,9 @@ impl PeerSet { /// Networking layer relies on `get_main_version()` being the version /// of the main protocol name reported by [`PeerSetProtocolNames::get_main_name()`]. pub fn get_main_version(self) -> ProtocolVersion { - #[cfg(not(feature = "network-protocol-staging"))] match self { - PeerSet::Validation => ValidationVersion::V1.into(), - PeerSet::Collation => CollationVersion::V1.into(), - } - - #[cfg(feature = "network-protocol-staging")] - match self { - PeerSet::Validation => ValidationVersion::VStaging.into(), - PeerSet::Collation => CollationVersion::VStaging.into(), + PeerSet::Validation => ValidationVersion::V2.into(), + PeerSet::Collation => CollationVersion::V2.into(), } } @@ -152,7 +145,7 @@ impl PeerSet { PeerSet::Validation => if version == ValidationVersion::V1.into() { Some("validation/1") - } else if version == ValidationVersion::VStaging.into() { + } else if version == ValidationVersion::V2.into() { Some("validation/2") } else { None @@ -160,7 +153,7 @@ impl PeerSet { PeerSet::Collation => if version == CollationVersion::V1.into() { Some("collation/1") - } else if version == CollationVersion::VStaging.into() { + } else if version == CollationVersion::V2.into() { Some("collation/2") } else { None @@ -223,8 +216,8 @@ impl From for u32 { pub enum ValidationVersion { /// The first version. V1 = 1, - /// The staging version. - VStaging = 2, + /// The second version. + V2 = 2, } /// Supported collation protocol versions. Only versions defined here must be used in the codebase. @@ -232,8 +225,8 @@ pub enum ValidationVersion { pub enum CollationVersion { /// The first version. V1 = 1, - /// The staging version. - VStaging = 2, + /// The second version. + V2 = 2, } /// Marker indicating the version is unknown. diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index baed4b8463160451231d3cbfc11e32337dbd9fec..96f7adeb29ba02987857fbac1eeed7b6770d9a35 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -55,7 +55,7 @@ pub use outgoing::{OutgoingRequest, OutgoingResult, Recipient, Requests, Respons pub mod v1; /// Actual versioned requests and responses that are sent over the wire. -pub mod vstaging; +pub mod v2; /// A protocol per subsystem seems to make the most sense, this way we don't need any dispatching /// within protocols. @@ -66,7 +66,7 @@ pub enum Protocol { /// Protocol for fetching collations from collators. CollationFetchingV1, /// Protocol for fetching collations from collators when async backing is enabled. - CollationFetchingVStaging, + CollationFetchingV2, /// Protocol for fetching seconded PoVs from validators of the same group. PoVFetchingV1, /// Protocol for fetching available data. @@ -78,7 +78,7 @@ pub enum Protocol { /// Protocol for requesting candidates with attestations in statement distribution /// when async backing is enabled. - AttestedCandidateVStaging, + AttestedCandidateV2, } /// Minimum bandwidth we expect for validators - 500Mbit/s is the recommendation, so approximately @@ -147,7 +147,7 @@ const POV_RESPONSE_SIZE: u64 = MAX_POV_SIZE as u64 + 10_000; /// This is `MAX_CODE_SIZE` plus some additional space for protocol overhead. const STATEMENT_RESPONSE_SIZE: u64 = MAX_CODE_SIZE as u64 + 10_000; -/// Maximum response sizes for `AttestedCandidateVStaging`. +/// Maximum response sizes for `AttestedCandidateV2`. /// /// This is `MAX_CODE_SIZE` plus some additional space for protocol overhead and /// additional backing statements. @@ -199,7 +199,7 @@ impl Protocol { request_timeout: CHUNK_REQUEST_TIMEOUT, inbound_queue: tx, }, - Protocol::CollationFetchingV1 | Protocol::CollationFetchingVStaging => + Protocol::CollationFetchingV1 | Protocol::CollationFetchingV2 => RequestResponseConfig { name, fallback_names, @@ -254,7 +254,7 @@ impl Protocol { request_timeout: DISPUTE_REQUEST_TIMEOUT, inbound_queue: tx, }, - Protocol::AttestedCandidateVStaging => RequestResponseConfig { + Protocol::AttestedCandidateV2 => RequestResponseConfig { name, fallback_names, max_request_size: 1_000, @@ -275,7 +275,7 @@ impl Protocol { // as well. Protocol::ChunkFetchingV1 => 100, // 10 seems reasonable, considering group sizes of max 10 validators. - Protocol::CollationFetchingV1 | Protocol::CollationFetchingVStaging => 10, + Protocol::CollationFetchingV1 | Protocol::CollationFetchingV2 => 10, // 10 seems reasonable, considering group sizes of max 10 validators. Protocol::PoVFetchingV1 => 10, // Validators are constantly self-selecting to request available data which may lead @@ -307,7 +307,7 @@ impl Protocol { // failure, so having a good value here is mostly about performance tuning. Protocol::DisputeSendingV1 => 100, - Protocol::AttestedCandidateVStaging => { + Protocol::AttestedCandidateV2 => { // We assume we can utilize up to 70% of the available bandwidth for statements. // This is just a guess/estimate, with the following considerations: If we are // faster than that, queue size will stay low anyway, even if not - requesters will @@ -344,8 +344,8 @@ impl Protocol { Protocol::DisputeSendingV1 => Some("/polkadot/send_dispute/1"), // Introduced after legacy names became legacy. - Protocol::AttestedCandidateVStaging => None, - Protocol::CollationFetchingVStaging => None, + Protocol::AttestedCandidateV2 => None, + Protocol::CollationFetchingV2 => None, } } } @@ -402,8 +402,8 @@ impl ReqProtocolNames { Protocol::StatementFetchingV1 => "/req_statement/1", Protocol::DisputeSendingV1 => "/send_dispute/1", - Protocol::CollationFetchingVStaging => "/req_collation/2", - Protocol::AttestedCandidateVStaging => "/req_attested_candidate/2", + Protocol::CollationFetchingV2 => "/req_collation/2", + Protocol::AttestedCandidateV2 => "/req_attested_candidate/2", }; format!("{}{}", prefix, short_name).into() diff --git a/polkadot/node/network/protocol/src/request_response/outgoing.rs b/polkadot/node/network/protocol/src/request_response/outgoing.rs index ddc6b85645bbb1dd457731a0b43f6628d4bf4c29..c613d5778f5eb5d21bbdaecfd8e4493ccac14117 100644 --- a/polkadot/node/network/protocol/src/request_response/outgoing.rs +++ b/polkadot/node/network/protocol/src/request_response/outgoing.rs @@ -23,7 +23,7 @@ use sc_network::PeerId; use polkadot_primitives::AuthorityDiscoveryId; -use super::{v1, vstaging, IsRequest, Protocol}; +use super::{v1, v2, IsRequest, Protocol}; /// All requests that can be sent to the network bridge via `NetworkBridgeTxMessage::SendRequest`. #[derive(Debug)] @@ -42,10 +42,10 @@ pub enum Requests { DisputeSendingV1(OutgoingRequest), /// Request a candidate and attestations. - AttestedCandidateVStaging(OutgoingRequest), + AttestedCandidateV2(OutgoingRequest), /// Fetch a collation from a collator which previously announced it. /// Compared to V1 it requires specifying which candidate is requested by its hash. - CollationFetchingVStaging(OutgoingRequest), + CollationFetchingV2(OutgoingRequest), } impl Requests { @@ -54,12 +54,12 @@ impl Requests { match self { Self::ChunkFetchingV1(_) => Protocol::ChunkFetchingV1, Self::CollationFetchingV1(_) => Protocol::CollationFetchingV1, - Self::CollationFetchingVStaging(_) => Protocol::CollationFetchingVStaging, + Self::CollationFetchingV2(_) => Protocol::CollationFetchingV2, Self::PoVFetchingV1(_) => Protocol::PoVFetchingV1, Self::AvailableDataFetchingV1(_) => Protocol::AvailableDataFetchingV1, Self::StatementFetchingV1(_) => Protocol::StatementFetchingV1, Self::DisputeSendingV1(_) => Protocol::DisputeSendingV1, - Self::AttestedCandidateVStaging(_) => Protocol::AttestedCandidateVStaging, + Self::AttestedCandidateV2(_) => Protocol::AttestedCandidateV2, } } @@ -74,12 +74,12 @@ impl Requests { match self { Self::ChunkFetchingV1(r) => r.encode_request(), Self::CollationFetchingV1(r) => r.encode_request(), - Self::CollationFetchingVStaging(r) => r.encode_request(), + Self::CollationFetchingV2(r) => r.encode_request(), Self::PoVFetchingV1(r) => r.encode_request(), Self::AvailableDataFetchingV1(r) => r.encode_request(), Self::StatementFetchingV1(r) => r.encode_request(), Self::DisputeSendingV1(r) => r.encode_request(), - Self::AttestedCandidateVStaging(r) => r.encode_request(), + Self::AttestedCandidateV2(r) => r.encode_request(), } } } diff --git a/polkadot/node/network/protocol/src/request_response/vstaging.rs b/polkadot/node/network/protocol/src/request_response/v2.rs similarity index 93% rename from polkadot/node/network/protocol/src/request_response/vstaging.rs rename to polkadot/node/network/protocol/src/request_response/v2.rs index 34a17b4baaa64ab6eda18382cfa4c9c3ccd36d3a..6b90c579237fbff95496035f461c5cc4c5202984 100644 --- a/polkadot/node/network/protocol/src/request_response/vstaging.rs +++ b/polkadot/node/network/protocol/src/request_response/v2.rs @@ -18,13 +18,13 @@ use parity_scale_codec::{Decode, Encode}; -use polkadot_primitives::vstaging::{ +use polkadot_primitives::{ CandidateHash, CommittedCandidateReceipt, Hash, Id as ParaId, PersistedValidationData, UncheckedSignedStatement, }; use super::{IsRequest, Protocol}; -use crate::vstaging::StatementFilter; +use crate::v2::StatementFilter; /// Request a candidate with statements. #[derive(Debug, Clone, Encode, Decode)] @@ -56,7 +56,7 @@ pub struct AttestedCandidateResponse { impl IsRequest for AttestedCandidateRequest { type Response = AttestedCandidateResponse; - const PROTOCOL: Protocol = Protocol::AttestedCandidateVStaging; + const PROTOCOL: Protocol = Protocol::AttestedCandidateV2; } /// Responses as sent by collators. @@ -76,5 +76,5 @@ pub struct CollationFetchingRequest { impl IsRequest for CollationFetchingRequest { // The response is the same as for V1. type Response = CollationFetchingResponse; - const PROTOCOL: Protocol = Protocol::CollationFetchingVStaging; + const PROTOCOL: Protocol = Protocol::CollationFetchingV2; } diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs index 9ae76047383cde679b4a9393ecdaef38fbcf8930..fc2aff0da305edbb7f6f39834ffd017e2701a550 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -21,8 +21,7 @@ use polkadot_node_network_protocol::{ grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage}, peer_set::{IsAuthority, PeerSet, ValidationVersion}, v1::{self as protocol_v1, StatementMetadata}, - vstaging as protocol_vstaging, IfDisconnected, PeerId, UnifiedReputationChange as Rep, - Versioned, View, + v2 as protocol_v2, IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::{ SignedFullStatement, Statement, StatementWithPVD, UncheckedSignedFullStatement, @@ -1062,7 +1061,7 @@ async fn circulate_statement<'a, Context>( "We filter out duplicates above. qed.", ); - let (v1_peers_to_send, vstaging_peers_to_send) = peers_to_send + let (v1_peers_to_send, v2_peers_to_send) = peers_to_send .into_iter() .map(|peer_id| { let peer_data = @@ -1074,7 +1073,7 @@ async fn circulate_statement<'a, Context>( }) .partition::, _>(|(_, _, version)| match version { ValidationVersion::V1 => true, - ValidationVersion::VStaging => false, + ValidationVersion::V2 => false, }); // partition is handy here but not if we add more protocol versions let payload = v1_statement_message(relay_parent, stored.statement.clone(), metrics); @@ -1094,24 +1093,24 @@ async fn circulate_statement<'a, Context>( )) .await; } - if !vstaging_peers_to_send.is_empty() { + if !v2_peers_to_send.is_empty() { gum::trace!( target: LOG_TARGET, - ?vstaging_peers_to_send, + ?v2_peers_to_send, ?relay_parent, statement = ?stored.statement, - "Sending statement to vstaging peers", + "Sending statement to v2 peers", ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_peers_to_send.iter().map(|(p, _, _)| *p).collect(), - compatible_v1_message(ValidationVersion::VStaging, payload.clone()).into(), + v2_peers_to_send.iter().map(|(p, _, _)| *p).collect(), + compatible_v1_message(ValidationVersion::V2, payload.clone()).into(), )) .await; } v1_peers_to_send .into_iter() - .chain(vstaging_peers_to_send) + .chain(v2_peers_to_send) .filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None }) .collect() } @@ -1443,10 +1442,8 @@ async fn handle_incoming_message<'a, Context>( let message = match message { Versioned::V1(m) => m, - Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::V1Compatibility( - m, - )) => m, - Versioned::VStaging(_) => { + Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) => m, + Versioned::V2(_) => { // The higher-level subsystem code is supposed to filter out // all non v1 messages. gum::debug!( @@ -2170,8 +2167,7 @@ fn compatible_v1_message( ) -> net_protocol::StatementDistributionMessage { match version { ValidationVersion::V1 => Versioned::V1(message), - ValidationVersion::VStaging => Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(message), - ), + ValidationVersion::V2 => + Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(message)), } } 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 17a66a9ff792ffddca4c5e8a750b5f7bdcf205f0..ca3038f9b3f3a4250b5337e70f9e009699afbc3b 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -793,7 +793,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == hash_a => { @@ -1033,7 +1033,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == hash_a => { @@ -1563,7 +1563,7 @@ fn delay_reputation_changes() { assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == hash_a => { @@ -2043,7 +2043,7 @@ fn share_prioritizes_backing_group() { assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == hash_a => { @@ -2365,7 +2365,7 @@ fn peer_cant_flood_with_large_statements() { assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == hash_a => { @@ -2590,7 +2590,7 @@ fn handle_multiple_seconded_statements() { assert_matches!( handle.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(r, RuntimeApiRequest::AsyncBackingParams(tx)) ) if r == relay_parent_hash => { diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index b2eb9cccced4de0b607d4a4dcd9142d98c80f7ab..eead7df5224d57ddf92bc90a3ba0b18e70a72c9e 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -26,10 +26,8 @@ use error::{log_error, FatalResult}; use std::time::Duration; use polkadot_node_network_protocol::{ - request_response::{ - v1 as request_v1, vstaging::AttestedCandidateRequest, IncomingRequestReceiver, - }, - vstaging as protocol_vstaging, Versioned, + request_response::{v1 as request_v1, v2::AttestedCandidateRequest, IncomingRequestReceiver}, + v2 as protocol_v2, Versioned, }; use polkadot_node_primitives::StatementWithPVD; use polkadot_node_subsystem::{ @@ -60,7 +58,7 @@ use legacy_v1::{ ResponderMessage as V1ResponderMessage, }; -mod vstaging; +mod v2; const LOG_TARGET: &str = "parachain::statement-distribution"; @@ -104,9 +102,9 @@ enum MuxedMessage { /// Messages from spawned v1 (legacy) responder background task. V1Responder(Option), /// Messages from candidate responder background task. - Responder(Option), + Responder(Option), /// Messages from answered requests. - Response(vstaging::UnhandledResponse), + Response(v2::UnhandledResponse), /// Message that a request is ready to be retried. This just acts as a signal that we should /// dispatch all pending requests again. RetryRequest(()), @@ -116,10 +114,10 @@ enum MuxedMessage { impl MuxedMessage { async fn receive( ctx: &mut Context, - state: &mut vstaging::State, + state: &mut v2::State, from_v1_requester: &mut mpsc::Receiver, from_v1_responder: &mut mpsc::Receiver, - from_responder: &mut mpsc::Receiver, + from_responder: &mut mpsc::Receiver, ) -> MuxedMessage { let (request_manager, response_manager) = state.request_and_response_managers(); // We are only fusing here to make `select` happy, in reality we will quit if one of those @@ -128,8 +126,8 @@ impl MuxedMessage { let from_v1_requester = from_v1_requester.next(); let from_v1_responder = from_v1_responder.next(); let from_responder = from_responder.next(); - let receive_response = vstaging::receive_response(response_manager).fuse(); - let retry_request = vstaging::next_retry(request_manager).fuse(); + let receive_response = v2::receive_response(response_manager).fuse(); + let retry_request = v2::next_retry(request_manager).fuse(); futures::pin_mut!( from_orchestra, from_v1_requester, @@ -182,7 +180,7 @@ impl StatementDistributionSubsystem { let mut reputation_delay = new_reputation_delay(); let mut legacy_v1_state = crate::legacy_v1::State::new(self.keystore.clone()); - let mut state = crate::vstaging::State::new(self.keystore.clone()); + let mut state = crate::v2::State::new(self.keystore.clone()); // Sender/Receiver for getting news from our statement fetching tasks. let (v1_req_sender, mut v1_req_receiver) = mpsc::channel(1); @@ -206,7 +204,7 @@ impl StatementDistributionSubsystem { ctx.spawn( "candidate-responder", - vstaging::respond_task( + v2::respond_task( self.req_receiver.take().expect("Mandatory argument to new. qed"), res_sender.clone(), ) @@ -280,14 +278,13 @@ impl StatementDistributionSubsystem { )?; }, MuxedMessage::Responder(result) => { - vstaging::answer_request( + v2::answer_request( &mut state, result.ok_or(FatalError::RequesterReceiverFinished)?, ); }, MuxedMessage::Response(result) => { - vstaging::handle_response(&mut ctx, &mut state, result, &mut self.reputation) - .await; + v2::handle_response(&mut ctx, &mut state, result, &mut self.reputation).await; }, MuxedMessage::RetryRequest(()) => { // A pending request is ready to retry. This is only a signal to call @@ -296,7 +293,7 @@ impl StatementDistributionSubsystem { }, }; - vstaging::dispatch_requests(&mut ctx, &mut state).await; + v2::dispatch_requests(&mut ctx, &mut state).await; } Ok(()) } @@ -304,7 +301,7 @@ impl StatementDistributionSubsystem { async fn handle_subsystem_message( &mut self, ctx: &mut Context, - state: &mut vstaging::State, + state: &mut v2::State, legacy_v1_state: &mut legacy_v1::State, v1_req_sender: &mpsc::Sender, message: FromOrchestra, @@ -318,11 +315,11 @@ impl StatementDistributionSubsystem { })) => { let _timer = metrics.time_active_leaves_update(); - // vstaging should handle activated first because of implicit view. + // v2 should handle activated first because of implicit view. if let Some(ref activated) = activated { let mode = prospective_parachains_mode(ctx.sender(), activated.hash).await?; if let ProspectiveParachainsMode::Enabled { .. } = mode { - vstaging::handle_active_leaves_update(ctx, state, activated, mode).await?; + v2::handle_active_leaves_update(ctx, state, activated, mode).await?; } else if let ProspectiveParachainsMode::Disabled = mode { for deactivated in &deactivated { crate::legacy_v1::handle_deactivate_leaf(legacy_v1_state, *deactivated); @@ -339,7 +336,7 @@ impl StatementDistributionSubsystem { for deactivated in &deactivated { crate::legacy_v1::handle_deactivate_leaf(legacy_v1_state, *deactivated); } - vstaging::handle_deactivate_leaves(state, &deactivated); + v2::handle_deactivate_leaves(state, &deactivated); } }, FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => { @@ -362,7 +359,7 @@ impl StatementDistributionSubsystem { ) .await?; } else { - vstaging::share_local_statement( + v2::share_local_statement( ctx, state, relay_parent, @@ -399,11 +396,11 @@ impl StatementDistributionSubsystem { let target = match &event { NetworkBridgeEvent::PeerMessage(_, message) => match message { - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + Versioned::V2( + protocol_v2::StatementDistributionMessage::V1Compatibility(_), ) => VersionTarget::Legacy, Versioned::V1(_) => VersionTarget::Legacy, - Versioned::VStaging(_) => VersionTarget::Current, + Versioned::V2(_) => VersionTarget::Current, }, _ => VersionTarget::Both, }; @@ -422,14 +419,12 @@ impl StatementDistributionSubsystem { } if target.targets_current() { - // pass to vstaging. - vstaging::handle_network_update(ctx, state, event, &mut self.reputation) - .await; + // pass to v2. + v2::handle_network_update(ctx, state, event, &mut self.reputation).await; } }, StatementDistributionMessage::Backed(candidate_hash) => { - crate::vstaging::handle_backed_candidate_message(ctx, state, candidate_hash) - .await; + crate::v2::handle_backed_candidate_message(ctx, state, candidate_hash).await; }, }, } diff --git a/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs b/polkadot/node/network/statement-distribution/src/v2/candidates.rs similarity index 99% rename from polkadot/node/network/statement-distribution/src/vstaging/candidates.rs rename to polkadot/node/network/statement-distribution/src/v2/candidates.rs index d6b68510f1c100e5dfd7c4ff7898399b2fd2eacc..e660df5da173e24dce8be7afdbe3ea55c17f94c9 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/candidates.rs +++ b/polkadot/node/network/statement-distribution/src/v2/candidates.rs @@ -27,7 +27,7 @@ use polkadot_node_network_protocol::PeerId; use polkadot_node_subsystem::messages::HypotheticalCandidate; -use polkadot_primitives::vstaging::{ +use polkadot_primitives::{ CandidateHash, CommittedCandidateReceipt, GroupIndex, Hash, Id as ParaId, PersistedValidationData, }; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/cluster.rs similarity index 99% rename from polkadot/node/network/statement-distribution/src/vstaging/cluster.rs rename to polkadot/node/network/statement-distribution/src/v2/cluster.rs index 55d847f831574eeef44d8214682c52c5370081b4..8adb8353ca929d75219252c2ea33e894dea41002 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/cluster.rs @@ -55,7 +55,7 @@ //! and to keep track of what we have sent to other validators in the group and what we may //! continue to send them. -use polkadot_primitives::vstaging::{CandidateHash, CompactStatement, ValidatorIndex}; +use polkadot_primitives::{CandidateHash, CompactStatement, ValidatorIndex}; use std::collections::{HashMap, HashSet}; @@ -459,7 +459,7 @@ pub enum RejectOutgoing { #[cfg(test)] mod tests { use super::*; - use polkadot_primitives::vstaging::Hash; + use polkadot_primitives::Hash; #[test] fn rejects_incoming_outside_of_group() { diff --git a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs b/polkadot/node/network/statement-distribution/src/v2/grid.rs similarity index 99% rename from polkadot/node/network/statement-distribution/src/vstaging/grid.rs rename to polkadot/node/network/statement-distribution/src/v2/grid.rs index 4fd77d0ced1cef3dcba81a088c1030c444a54d04..3d53ff6d321e2321c7b559aaaf7adc5504e18f49 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/grid.rs @@ -60,12 +60,8 @@ //! - which has sent a `BackedCandidateAcknowledgement` //! - 1st-hop nodes do the same thing -use polkadot_node_network_protocol::{ - grid_topology::SessionGridTopology, vstaging::StatementFilter, -}; -use polkadot_primitives::vstaging::{ - CandidateHash, CompactStatement, GroupIndex, Hash, ValidatorIndex, -}; +use polkadot_node_network_protocol::{grid_topology::SessionGridTopology, v2::StatementFilter}; +use polkadot_primitives::{CandidateHash, CompactStatement, GroupIndex, Hash, ValidatorIndex}; use std::collections::{ hash_map::{Entry, HashMap}, diff --git a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs b/polkadot/node/network/statement-distribution/src/v2/groups.rs similarity index 96% rename from polkadot/node/network/statement-distribution/src/vstaging/groups.rs rename to polkadot/node/network/statement-distribution/src/v2/groups.rs index b2daa1c0ac7caf3181c12dfc74fcff0f2f0cc6ed..d917b20905296eed7501c568d9bcd3057963f683 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/groups.rs +++ b/polkadot/node/network/statement-distribution/src/v2/groups.rs @@ -17,8 +17,7 @@ //! A utility for tracking groups and their members within a session. use polkadot_primitives::{ - effective_minimum_backing_votes, - vstaging::{GroupIndex, IndexedVec, ValidatorIndex}, + effective_minimum_backing_votes, GroupIndex, IndexedVec, ValidatorIndex, }; use std::collections::HashMap; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs similarity index 97% rename from polkadot/node/network/statement-distribution/src/vstaging/mod.rs rename to polkadot/node/network/statement-distribution/src/v2/mod.rs index 4639720b3221add0d61eb040f44844e07cd2a502..e11d66c41a04b62377008bb7c0e2b5f9f44cde5b 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -23,11 +23,11 @@ use polkadot_node_network_protocol::{ peer_set::ValidationVersion, request_response::{ incoming::OutgoingResponse, - vstaging::{AttestedCandidateRequest, AttestedCandidateResponse}, + v2::{AttestedCandidateRequest, AttestedCandidateResponse}, IncomingRequest, IncomingRequestReceiver, Requests, MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, }, - vstaging::{self as protocol_vstaging, StatementFilter}, + v2::{self as protocol_v2, StatementFilter}, IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::{ @@ -45,7 +45,7 @@ use polkadot_node_subsystem_util::{ reputation::ReputationAggregator, runtime::{request_min_backing_votes, ProspectiveParachainsMode}, }; -use polkadot_primitives::vstaging::{ +use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, IndexedVec, SessionIndex, SessionInfo, SignedStatement, SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, @@ -323,7 +323,7 @@ pub(crate) async fn handle_network_update( NetworkBridgeEvent::PeerConnected(peer_id, role, protocol_version, mut authority_ids) => { gum::trace!(target: LOG_TARGET, ?peer_id, ?role, ?protocol_version, "Peer connected"); - if protocol_version != ValidationVersion::VStaging.into() { + if protocol_version != ValidationVersion::V2.into() { return } @@ -381,19 +381,19 @@ pub(crate) async fn handle_network_update( }, NetworkBridgeEvent::PeerMessage(peer_id, message) => match message { net_protocol::StatementDistributionMessage::V1(_) => return, - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + net_protocol::StatementDistributionMessage::V2( + protocol_v2::StatementDistributionMessage::V1Compatibility(_), ) => return, - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + net_protocol::StatementDistributionMessage::V2( + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) => handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation) .await, - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(inner), + net_protocol::StatementDistributionMessage::V2( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(inner), ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await, - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(inner), + net_protocol::StatementDistributionMessage::V2( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(inner), ) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await, }, NetworkBridgeEvent::PeerViewChange(peer_id, view) => @@ -727,10 +727,8 @@ fn pending_statement_network_message( statement_store .validator_statement(originator, compact) .map(|s| s.as_unchecked().clone()) - .map(|signed| { - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, signed) - }) - .map(|msg| (vec![*peer], Versioned::VStaging(msg).into())) + .map(|signed| protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed)) + .map(|msg| (vec![*peer], Versioned::V2(msg).into())) } /// Send a peer all pending cluster statements for a relay parent. @@ -823,7 +821,7 @@ async fn send_pending_grid_messages( match kind { grid::ManifestKind::Full => { - let manifest = protocol_vstaging::BackedCandidateManifest { + let manifest = protocol_v2::BackedCandidateManifest { relay_parent, candidate_hash, group_index, @@ -847,8 +845,8 @@ async fn send_pending_grid_messages( messages.push(( vec![*peer_id], - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + Versioned::V2( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest, ), ) @@ -1192,7 +1190,7 @@ async fn circulate_statement( ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( statement_to, - Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::StatementDistributionMessage::Statement( relay_parent, statement.as_unchecked().clone(), )) @@ -1672,7 +1670,7 @@ async fn provide_candidate_to_grid( filter.clone(), ); - let manifest = protocol_vstaging::BackedCandidateManifest { + let manifest = protocol_v2::BackedCandidateManifest { relay_parent, candidate_hash, group_index, @@ -1680,16 +1678,15 @@ async fn provide_candidate_to_grid( parent_head_data_hash: confirmed_candidate.parent_head_data_hash(), statement_knowledge: filter.clone(), }; - let acknowledgement = protocol_vstaging::BackedCandidateAcknowledgement { + let acknowledgement = protocol_v2::BackedCandidateAcknowledgement { candidate_hash, statement_knowledge: filter.clone(), }; - let manifest_message = Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), - ); - let ack_message = Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(acknowledgement), + let manifest_message = + Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest)); + let ack_message = Versioned::V2( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(acknowledgement), ); let mut manifest_peers = Vec::new(); @@ -2062,8 +2059,8 @@ fn post_acknowledgement_statement_messages( statement.payload(), ); - messages.push(Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::Statement( + messages.push(Versioned::V2( + protocol_v2::StatementDistributionMessage::Statement( relay_parent, statement.as_unchecked().clone(), ) @@ -2079,7 +2076,7 @@ async fn handle_incoming_manifest( ctx: &mut Context, state: &mut State, peer: PeerId, - manifest: net_protocol::vstaging::BackedCandidateManifest, + manifest: net_protocol::v2::BackedCandidateManifest, reputation: &mut ReputationAggregator, ) { gum::debug!( @@ -2183,14 +2180,14 @@ fn acknowledgement_and_statement_messages( Some(l) => l, }; - let acknowledgement = protocol_vstaging::BackedCandidateAcknowledgement { + let acknowledgement = protocol_v2::BackedCandidateAcknowledgement { candidate_hash, statement_knowledge: local_knowledge.clone(), }; - let msg = Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(acknowledgement), - ); + let msg = Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement, + )); let mut messages = vec![(vec![peer], msg.into())]; @@ -2221,7 +2218,7 @@ async fn handle_incoming_acknowledgement( ctx: &mut Context, state: &mut State, peer: PeerId, - acknowledgement: net_protocol::vstaging::BackedCandidateAcknowledgement, + acknowledgement: net_protocol::v2::BackedCandidateAcknowledgement, reputation: &mut ReputationAggregator, ) { // The key difference between acknowledgments and full manifests is that only @@ -2521,7 +2518,7 @@ pub(crate) async fn dispatch_requests(ctx: &mut Context, state: &mut St ) { // Peer is supposedly connected. ctx.send_message(NetworkBridgeTxMessage::SendRequests( - vec![Requests::AttestedCandidateVStaging(request)], + vec![Requests::AttestedCandidateV2(request)], IfDisconnected::ImmediateError, )) .await; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs similarity index 99% rename from polkadot/node/network/statement-distribution/src/vstaging/requests.rs rename to polkadot/node/network/statement-distribution/src/v2/requests.rs index 79925f2115d430e61232e600b1db13a0886d3e88..f13496024fcfee52f48a3cdb2377c2e24eadda79 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -39,14 +39,14 @@ use crate::LOG_TARGET; use polkadot_node_network_protocol::{ request_response::{ outgoing::{Recipient as RequestRecipient, RequestError}, - vstaging::{AttestedCandidateRequest, AttestedCandidateResponse}, + v2::{AttestedCandidateRequest, AttestedCandidateResponse}, OutgoingRequest, OutgoingResult, MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, }, - vstaging::StatementFilter, + v2::StatementFilter, PeerId, UnifiedReputationChange as Rep, }; -use polkadot_primitives::vstaging::{ - CandidateHash, CommittedCandidateReceipt, CompactStatement, GroupIndex, Hash, ParaId, +use polkadot_primitives::{ + CandidateHash, CommittedCandidateReceipt, CompactStatement, GroupIndex, Hash, Id as ParaId, PersistedValidationData, SessionIndex, SignedStatement, SigningContext, ValidatorId, ValidatorIndex, }; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs similarity index 98% rename from polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs rename to polkadot/node/network/statement-distribution/src/v2/statement_store.rs index 9ea926f24aa833177230aa9bf1c8962517acd49a..74db431eda1d214e0031e98ab304cb0fd0fabd96 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs @@ -24,8 +24,8 @@ //! groups, and views based on the validators themselves. use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; -use polkadot_node_network_protocol::vstaging::StatementFilter; -use polkadot_primitives::vstaging::{ +use polkadot_node_network_protocol::v2::StatementFilter; +use polkadot_primitives::{ CandidateHash, CompactStatement, GroupIndex, SignedStatement, ValidatorIndex, }; use std::collections::hash_map::{Entry as HEntry, HashMap}; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs similarity index 95% rename from polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs rename to polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs index 50d0477eb5167cb2d8a179813452373061aedd9e..80dec1d75ab98be43b820bf7382b4436ef87c3b2 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -103,8 +103,8 @@ fn share_seconded_circulated_to_cluster() { overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -173,7 +173,7 @@ fn cluster_valid_statement_before_seconded_ignored() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( + protocol_v2::StatementDistributionMessage::Statement( relay_parent, signed_valid.as_unchecked().clone(), ), @@ -252,7 +252,7 @@ fn cluster_statement_bad_signature() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( + protocol_v2::StatementDistributionMessage::Statement( relay_parent, statement.clone(), ), @@ -327,7 +327,7 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -388,7 +388,7 @@ fn statement_from_non_cluster_originator_unexpected() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -465,7 +465,7 @@ fn seconded_statement_leads_to_request() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -593,8 +593,8 @@ fn cluster_statements_shared_seconded_first() { assert_matches!( &messages[0].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -604,8 +604,8 @@ fn cluster_statements_shared_seconded_first() { assert_matches!( &messages[1].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -699,8 +699,8 @@ fn cluster_accounts_for_implicit_view() { overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -749,8 +749,8 @@ fn cluster_accounts_for_implicit_view() { &messages[0], ( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -836,10 +836,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -971,10 +968,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -1191,7 +1185,7 @@ fn ensure_seconding_limit_is_respected() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1216,7 +1210,7 @@ fn ensure_seconding_limit_is_respected() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1241,7 +1235,7 @@ fn ensure_seconding_limit_is_respected() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs similarity index 95% rename from polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs rename to polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 0739f30194378e1ec7f5e6540e37f24d60130d89..a0af9579823597514383f57c9cbe691a7282bb20 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -17,9 +17,7 @@ use super::*; use bitvec::order::Lsb0; -use polkadot_node_network_protocol::vstaging::{ - BackedCandidateAcknowledgement, BackedCandidateManifest, -}; +use polkadot_node_network_protocol::v2::{BackedCandidateAcknowledgement, BackedCandidateManifest}; use polkadot_node_subsystem::messages::CandidateBackingMessage; use polkadot_primitives_test_helpers::make_candidate; @@ -156,7 +154,7 @@ fn backed_candidate_leads_to_advertisement() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -181,7 +179,7 @@ fn backed_candidate_leads_to_advertisement() { send_peer_message( &mut overseer, peer_b.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -210,9 +208,9 @@ fn backed_candidate_leads_to_advertisement() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ), ), ) @@ -349,7 +347,7 @@ fn received_advertisement_before_confirmation_leads_to_request() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ) .await; @@ -534,7 +532,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -603,9 +601,9 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(ack), ), ), ) @@ -629,7 +627,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { send_peer_message( &mut overseer, peer_d.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -654,8 +652,8 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { assert_matches!( &messages[0].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack) + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(ack) )) if *ack == expected_ack ); } @@ -782,7 +780,7 @@ fn received_advertisement_after_confirmation_before_backing() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -842,7 +840,7 @@ fn received_advertisement_after_confirmation_before_backing() { send_peer_message( &mut overseer, peer_d.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -951,7 +949,7 @@ fn additional_statements_are_shared_after_manifest_exchange() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -1066,9 +1064,9 @@ fn additional_statements_are_shared_after_manifest_exchange() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(ack), ), ), ) @@ -1104,7 +1102,7 @@ fn additional_statements_are_shared_after_manifest_exchange() { send_peer_message( &mut overseer, peer_d.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -1130,15 +1128,15 @@ fn additional_statements_are_shared_after_manifest_exchange() { assert_matches!( &messages[0].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack) + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateKnown(ack) )) if *ack == expected_ack ); assert_matches!( &messages[1].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement(r, s) + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement(r, s) )) if *r == relay_parent && s.unchecked_payload() == &CompactStatement::Seconded(candidate_hash) && s.unchecked_validator_index() == v_e ); } @@ -1281,7 +1279,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1306,7 +1304,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { send_peer_message( &mut overseer, peer_b.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1357,8 +1355,8 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { assert_matches!( &messages[0].1, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest) + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest) )) => { assert_eq!(*manifest, expected_manifest); } @@ -1504,7 +1502,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1529,7 +1527,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { send_peer_message( &mut overseer, peer_b.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1558,9 +1556,9 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ), ), ) @@ -1692,7 +1690,7 @@ fn grid_statements_imported_to_backing() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -1907,7 +1905,7 @@ fn advertisements_rejected_from_incorrect_peers() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -1925,7 +1923,7 @@ fn advertisements_rejected_from_incorrect_peers() { send_peer_message( &mut overseer, peer_b.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ) .await; @@ -2029,7 +2027,7 @@ fn manifest_rejected_with_unknown_relay_parent() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -2131,7 +2129,7 @@ fn manifest_rejected_when_not_a_validator() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -2238,7 +2236,7 @@ fn manifest_rejected_when_group_does_not_match_para() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -2370,7 +2368,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -2439,7 +2437,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ) .await; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs similarity index 98% rename from polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs rename to polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 48ceebb1949bfa2889986554b9583cbf33cd72aa..4150377a0c6c219832104024f6d6c046dccec709 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -31,7 +31,7 @@ use polkadot_node_subsystem::messages::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; -use polkadot_primitives::vstaging::{ +use polkadot_primitives::{ AssignmentPair, AsyncBackingParams, BlockNumber, CommittedCandidateReceipt, CoreState, GroupRotationInfo, HeadData, Header, IndexedVec, PersistedValidationData, ScheduledCore, SessionIndex, SessionInfo, ValidatorPair, @@ -380,7 +380,7 @@ async fn handle_leaf_activation( assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) ) if parent == *hash => { tx.send(Ok(test_state.config.async_backing_params.unwrap_or(DEFAULT_ASYNC_BACKING_PARAMETERS))).unwrap(); } @@ -479,7 +479,7 @@ async fn handle_sent_request( assert_eq!(requests.len(), 1); assert_matches!( requests.pop().unwrap(), - Requests::AttestedCandidateVStaging(outgoing) => { + Requests::AttestedCandidateV2(outgoing) => { assert_eq!(outgoing.peer, Recipient::Peer(peer)); assert_eq!(outgoing.payload.candidate_hash, candidate_hash); assert_eq!(outgoing.payload.mask, mask); @@ -537,7 +537,7 @@ async fn connect_peer( NetworkBridgeEvent::PeerConnected( peer, ObservedRole::Authority, - ValidationVersion::VStaging.into(), + ValidationVersion::V2.into(), authority_ids, ), ), @@ -570,12 +570,12 @@ async fn send_peer_view_change(virtual_overseer: &mut VirtualOverseer, peer: Pee async fn send_peer_message( virtual_overseer: &mut VirtualOverseer, peer: PeerId, - message: protocol_vstaging::StatementDistributionMessage, + message: protocol_v2::StatementDistributionMessage, ) { virtual_overseer .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(peer, Versioned::VStaging(message)), + NetworkBridgeEvent::PeerMessage(peer, Versioned::V2(message)), ), }) .await; diff --git a/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs similarity index 95% rename from polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs rename to polkadot/node/network/statement-distribution/src/v2/tests/requests.rs index 5eef5809b4d497e9334572ffa4e44f5d13ba48c5..0734b75c9712d50dc8be0f78bde52001ae26b8f0 100644 --- a/polkadot/node/network/statement-distribution/src/vstaging/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs @@ -19,7 +19,7 @@ use super::*; use bitvec::order::Lsb0; use parity_scale_codec::{Decode, Encode}; use polkadot_node_network_protocol::{ - request_response::vstaging as request_vstaging, vstaging::BackedCandidateManifest, + request_response::v2 as request_v2, v2::BackedCandidateManifest, }; use polkadot_primitives_test_helpers::make_candidate; use sc_network::config::{ @@ -109,10 +109,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -164,9 +161,9 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement(hash, statement), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement(hash, statement), ), ), ) @@ -304,7 +301,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -376,7 +373,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -453,7 +450,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -568,9 +565,7 @@ fn peer_reported_for_not_enough_statements() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( - manifest.clone(), - ), + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest.clone()), ) .await; @@ -752,10 +747,7 @@ fn peer_reported_for_duplicate_statements() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -812,9 +804,9 @@ fn peer_reported_for_duplicate_statements() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement(hash, statement), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement(hash, statement), ), ), ) @@ -916,10 +908,7 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -1058,10 +1047,7 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( - relay_parent, - a_seconded, - ), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), ) .await; @@ -1191,7 +1177,7 @@ fn local_node_sanity_checks_incoming_requests() { .send(RawIncomingRequest { // Request from peer that received manifest. peer: peer_c, - payload: request_vstaging::AttestedCandidateRequest { + payload: request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask: mask.clone(), } @@ -1225,8 +1211,8 @@ fn local_node_sanity_checks_incoming_requests() { overseer.recv().await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::Statement( + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( r, s, ) @@ -1250,7 +1236,7 @@ fn local_node_sanity_checks_incoming_requests() { .send(RawIncomingRequest { // Request from peer that received manifest. peer: peer_d, - payload: request_vstaging::AttestedCandidateRequest { + payload: request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask: mask.clone(), } @@ -1269,10 +1255,7 @@ fn local_node_sanity_checks_incoming_requests() { let response = state .send_request( peer_c, - request_vstaging::AttestedCandidateRequest { - candidate_hash: candidate.hash(), - mask, - }, + request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask }, ) .await .await; @@ -1296,7 +1279,7 @@ fn local_node_sanity_checks_incoming_requests() { let response = state .send_request( peer_c, - request_vstaging::AttestedCandidateRequest { + request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask: mask.clone(), }, @@ -1455,7 +1438,7 @@ fn local_node_respects_statement_mask() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) .await; @@ -1479,7 +1462,7 @@ fn local_node_respects_statement_mask() { send_peer_message( &mut overseer, peer_b.clone(), - protocol_vstaging::StatementDistributionMessage::Statement( + protocol_v2::StatementDistributionMessage::Statement( relay_parent, statement_b.clone(), ), @@ -1511,9 +1494,9 @@ fn local_node_respects_statement_mask() { AllMessages:: NetworkBridgeTx( NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::StatementDistribution( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + Versioned::V2( + protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest), ), ), ) @@ -1547,19 +1530,16 @@ fn local_node_respects_statement_mask() { let response = state .send_request( peer_c, - request_vstaging::AttestedCandidateRequest { - candidate_hash: candidate.hash(), - mask, - }, + request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask }, ) .await .await; let expected_statements = vec![statement_b]; assert_matches!(response, full_response => { - // Response is the same for vstaging. - let request_vstaging::AttestedCandidateResponse { candidate_receipt, persisted_validation_data, statements } = - request_vstaging::AttestedCandidateResponse::decode( + // Response is the same for v2. + let request_v2::AttestedCandidateResponse { candidate_receipt, persisted_validation_data, statements } = + request_v2::AttestedCandidateResponse::decode( &mut full_response.result.expect("We should have a proper answer").as_ref(), ).expect("Decoding should work"); assert_eq!(candidate_receipt, candidate); @@ -1683,7 +1663,7 @@ fn should_delay_before_retrying_dropped_requests() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) @@ -1696,7 +1676,7 @@ fn should_delay_before_retrying_dropped_requests() { assert_eq!(requests.len(), 1); assert_matches!( requests.pop().unwrap(), - Requests::AttestedCandidateVStaging(outgoing) => { + 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); @@ -1729,7 +1709,7 @@ fn should_delay_before_retrying_dropped_requests() { send_peer_message( &mut overseer, peer_c.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + protocol_v2::StatementDistributionMessage::BackedCandidateManifest( manifest.clone(), ), ) diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index e78941776d5ec1d79d3cd52096e3bb2e649c6e54..cffdfd9f8aa14851275ef3f41a4ddcb47ccb516f 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -163,7 +163,6 @@ fn main() { .unwrap(); let overseer_fut = overseer.run().fuse(); - let timer_stream = timer_stream; pin_mut!(timer_stream); pin_mut!(overseer_fut); diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 84d5d19c3b93c708110fc35d2f124b94984f8a86..673569ab946f0f98c06ca89523049bba5061df2b 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -17,7 +17,7 @@ //! # Overseer //! //! `overseer` implements the Overseer architecture described in the -//! [implementers-guide](https://w3f.github.io/parachain-implementers-guide/node/index.html). +//! [implementers' guide][overseer-page]. //! For the motivations behind implementing the overseer itself you should //! check out that guide, documentation in this crate will be mostly discussing //! technical stuff. @@ -53,6 +53,8 @@ //! . +--------------------+ +---------------------+ . //! .................................................................. //! ``` +//! +//! [overseer-page]: https://paritytech.github.io/polkadot-sdk/book/node/overseer.html // #![deny(unused_results)] // unused dependencies can not work for test and examples at the same time diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 463c7f960ba089c26bda8d3dad916cd1641f5ef5..dab72bb2a5ed80b1842d4ca341c609109dee8c75 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -53,6 +53,13 @@ pub use disputes::{ ValidDisputeVote, ACTIVE_DURATION_SECS, }; +/// The current node version, which takes the basic SemVer form `..`. +/// In general, minor should be bumped on every release while major or patch releases are +/// relatively rare. +/// +/// The associated worker binaries should use the same version as the node that spawns them. +pub const NODE_VERSION: &'static str = "1.1.0"; + // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: // header 1 + bitmap 2 + max partial_key 8 + children 16 * (32 + len 1) + value 32 + value len 1 diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 667f9b86d3e4b715e7b896284b4cca566ba06f87..ba5976fdceef89683150d68ec38e2d90ff803c6c 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -103,17 +103,12 @@ polkadot-node-subsystem-util = { path = "../subsystem-util" } polkadot-node-subsystem-types = { path = "../subsystem-types" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-node-network-protocol = { path = "../network/protocol" } -polkadot-runtime-common = { path = "../../runtime/common" } # Polkadot Runtime Constants -polkadot-runtime-constants = { path = "../../runtime/polkadot/constants", optional = true } -kusama-runtime-constants = { path = "../../runtime/kusama/constants", optional = true } rococo-runtime-constants = { path = "../../runtime/rococo/constants", optional = true } westend-runtime-constants = { path = "../../runtime/westend/constants", optional = true } # Polkadot Runtimes -polkadot-runtime = { path = "../../runtime/polkadot", optional = true } -kusama-runtime = { package = "staging-kusama-runtime", path = "../../runtime/kusama", optional = true } westend-runtime = { path = "../../runtime/westend", optional = true } rococo-runtime = { path = "../../runtime/rococo", optional = true } @@ -183,11 +178,7 @@ full-node = [ "polkadot-statement-distribution", ] -# Configure the native runtimes to use. Polkadot is enabled by default. -# -# Validators require the native runtime currently -polkadot-native = [ "polkadot-runtime", "polkadot-runtime-constants" ] -kusama-native = [ "kusama-runtime", "kusama-runtime-constants" ] +# Configure the native runtimes to use. westend-native = [ "westend-runtime", "westend-runtime-constants" ] rococo-native = [ "rococo-runtime", "rococo-runtime-constants" ] @@ -196,15 +187,12 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "kusama-runtime?/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", - "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", - "polkadot-runtime?/runtime-benchmarks", "polkadot-test-client/runtime-benchmarks", "rococo-runtime?/runtime-benchmarks", "sc-client-db/runtime-benchmarks", @@ -215,34 +203,23 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", - "kusama-runtime?/try-runtime", "pallet-babe/try-runtime", "pallet-im-online/try-runtime", "pallet-staking/try-runtime", "pallet-transaction-payment/try-runtime", - "polkadot-runtime-common/try-runtime", "polkadot-runtime-parachains/try-runtime", - "polkadot-runtime?/try-runtime", "rococo-runtime?/try-runtime", "sp-runtime/try-runtime", "westend-runtime?/try-runtime", ] fast-runtime = [ - "kusama-runtime?/fast-runtime", - "polkadot-runtime?/fast-runtime", "rococo-runtime?/fast-runtime", "westend-runtime?/fast-runtime", ] malus = [ "full-node" ] runtime-metrics = [ - "kusama-runtime?/runtime-metrics", "polkadot-runtime-parachains/runtime-metrics", - "polkadot-runtime?/runtime-metrics", "rococo-runtime?/runtime-metrics", "westend-runtime?/runtime-metrics", ] - -network-protocol-staging = [ - "polkadot-node-network-protocol/network-protocol-staging", -] diff --git a/polkadot/node/service/chain-specs/rococo.json b/polkadot/node/service/chain-specs/rococo.json index 43dc959b57677145629019e0b57924f5a251f280..2648063641c919108e4478f53ff8bd321ff7e64e 100644 --- a/polkadot/node/service/chain-specs/rococo.json +++ b/polkadot/node/service/chain-specs/rococo.json @@ -3,14 +3,22 @@ "id": "rococo_v2_2", "chainType": "Live", "bootNodes": [ - "/dns/rococo-bootnode-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWGikJMBmRiG5ofCqn8aijCijgfmZR5H9f53yUF3srm6Nm", - "/dns/rococo-bootnode-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWLDfH9mHRCidrd5NfQjp7rRMUcJSEUwSvEKyu7xU2cG3d", - "/dns/rococo-bootnode-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWSikgbrcWjVgSed7r1uXk4TeAieDnHKtrPDVZBu5XkQha", - "/dns/rococo-bootnode-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPeKuW1BBPv4pNr8xqEv7jqy7rQnS3oq9U7xTCvj9qt2k", - "/dns/rococo-bootnode-4.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWNy7K8TNaP2Whcp3tsjBVUg2HcKMUvAArsimjvd1g31w4", - "/dns/rococo-bootnode-5.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWAVV9DZfvJp2brvs5zcQDTBFxNmEFJKy2dsvezWL4Bmy8", - "/dns/rococo-bootnode-6.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWM3hvXvaShyp7drQCavFHuwobkYdnCp2uHU5iRRAQwsw2", - "/dns/rococo-bootnode-7.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWSbGtxfWCwn1tdmfZYESbmxzbTG2LKwKUrioDaZBcdMY4", + "/dns/rococo-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWGikJMBmRiG5ofCqn8aijCijgfmZR5H9f53yUF3srm6Nm", + "/dns/rococo-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWLDfH9mHRCidrd5NfQjp7rRMUcJSEUwSvEKyu7xU2cG3d", + "/dns/rococo-bootnode-2.polkadot.io/tcp/30333/p2p/12D3KooWSikgbrcWjVgSed7r1uXk4TeAieDnHKtrPDVZBu5XkQha", + "/dns/rococo-bootnode-3.polkadot.io/tcp/30333/p2p/12D3KooWPeKuW1BBPv4pNr8xqEv7jqy7rQnS3oq9U7xTCvj9qt2k", + "/dns/rococo-bootnode-4.polkadot.io/tcp/30333/p2p/12D3KooWNy7K8TNaP2Whcp3tsjBVUg2HcKMUvAArsimjvd1g31w4", + "/dns/rococo-bootnode-5.polkadot.io/tcp/30333/p2p/12D3KooWAVV9DZfvJp2brvs5zcQDTBFxNmEFJKy2dsvezWL4Bmy8", + "/dns/rococo-bootnode-6.polkadot.io/tcp/30333/p2p/12D3KooWM3hvXvaShyp7drQCavFHuwobkYdnCp2uHU5iRRAQwsw2", + "/dns/rococo-bootnode-7.polkadot.io/tcp/30333/p2p/12D3KooWSbGtxfWCwn1tdmfZYESbmxzbTG2LKwKUrioDaZBcdMY4", + "/dns/rococo-bootnode-0.polkadot.io/tcp/30334/ws/p2p/12D3KooWGikJMBmRiG5ofCqn8aijCijgfmZR5H9f53yUF3srm6Nm", + "/dns/rococo-bootnode-1.polkadot.io/tcp/30334/ws/p2p/12D3KooWLDfH9mHRCidrd5NfQjp7rRMUcJSEUwSvEKyu7xU2cG3d", + "/dns/rococo-bootnode-2.polkadot.io/tcp/30334/ws/p2p/12D3KooWSikgbrcWjVgSed7r1uXk4TeAieDnHKtrPDVZBu5XkQha", + "/dns/rococo-bootnode-3.polkadot.io/tcp/30334/ws/p2p/12D3KooWPeKuW1BBPv4pNr8xqEv7jqy7rQnS3oq9U7xTCvj9qt2k", + "/dns/rococo-bootnode-4.polkadot.io/tcp/30334/ws/p2p/12D3KooWNy7K8TNaP2Whcp3tsjBVUg2HcKMUvAArsimjvd1g31w4", + "/dns/rococo-bootnode-5.polkadot.io/tcp/30334/ws/p2p/12D3KooWAVV9DZfvJp2brvs5zcQDTBFxNmEFJKy2dsvezWL4Bmy8", + "/dns/rococo-bootnode-6.polkadot.io/tcp/30334/ws/p2p/12D3KooWM3hvXvaShyp7drQCavFHuwobkYdnCp2uHU5iRRAQwsw2", + "/dns/rococo-bootnode-7.polkadot.io/tcp/30334/ws/p2p/12D3KooWSbGtxfWCwn1tdmfZYESbmxzbTG2LKwKUrioDaZBcdMY4", "/dns/rococo-bootnode-0.polkadot.io/tcp/443/wss/p2p/12D3KooWGikJMBmRiG5ofCqn8aijCijgfmZR5H9f53yUF3srm6Nm", "/dns/rococo-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWLDfH9mHRCidrd5NfQjp7rRMUcJSEUwSvEKyu7xU2cG3d", "/dns/rococo-bootnode-2.polkadot.io/tcp/443/wss/p2p/12D3KooWSikgbrcWjVgSed7r1uXk4TeAieDnHKtrPDVZBu5XkQha", diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index e57786f78a6419748ab85f5c0a9f02f6e9a48029..fd1f4550127fc91e743d59e4430ad313713ed445 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -2,16 +2,18 @@ "name": "Westend", "id": "westend2", "bootNodes": [ - "/dns/0.westend.paritytech.net/tcp/30333/p2p/12D3KooWKer94o1REDPtAhjtYR4SdLehnSrN8PEhBnZm5NBoCrMC", - "/dns/0.westend.paritytech.net/tcp/30334/ws/p2p/12D3KooWKer94o1REDPtAhjtYR4SdLehnSrN8PEhBnZm5NBoCrMC", - "/dns/1.westend.paritytech.net/tcp/30333/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", - "/dns/1.westend.paritytech.net/tcp/30334/ws/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", - "/dns/2.westend.paritytech.net/tcp/30333/p2p/12D3KooWByVpK92hMi9CzTjyFg9cPHDU5ariTM3EPMq9vdh5S5Po", - "/dns/2.westend.paritytech.net/tcp/30334/ws/p2p/12D3KooWByVpK92hMi9CzTjyFg9cPHDU5ariTM3EPMq9vdh5S5Po", - "/dns/3.westend.paritytech.net/tcp/30333/p2p/12D3KooWGi1tCpKXLMYED9y28QXLnwgD4neYb1Arqq4QpeV1Sv3K", - "/dns/3.westend.paritytech.net/tcp/30334/ws/p2p/12D3KooWGi1tCpKXLMYED9y28QXLnwgD4neYb1Arqq4QpeV1Sv3K", - "/dns/westend-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWNg8iUqhux7X7voNU9Nty5pzehrFJwkQwg1CJnqN3CTzE", - "/dns/westend-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAq2A7UNFS6725XFatD5QW7iYBezTLdAUx1SmRkxN79Ne", + "/dns/westend-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWKer94o1REDPtAhjtYR4SdLehnSrN8PEhBnZm5NBoCrMC", + "/dns/westend-bootnode-0.polkadot.io/tcp/30334/ws/p2p/12D3KooWKer94o1REDPtAhjtYR4SdLehnSrN8PEhBnZm5NBoCrMC", + "/dns/westend-bootnode-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKer94o1REDPtAhjtYR4SdLehnSrN8PEhBnZm5NBoCrMC", + "/dns/westend-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", + "/dns/westend-bootnode-1.polkadot.io/tcp/30334/ws/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", + "/dns/westend-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPVPzs42GvRBShdUMtFsk4SvnByrSdWqb6aeAAHvLMSLS", + "/dns/westend-bootnode-2.polkadot.io/tcp/30333/p2p/12D3KooWByVpK92hMi9CzTjyFg9cPHDU5ariTM3EPMq9vdh5S5Po", + "/dns/westend-bootnode-2.polkadot.io/tcp/30334/ws/p2p/12D3KooWByVpK92hMi9CzTjyFg9cPHDU5ariTM3EPMq9vdh5S5Po", + "/dns/westend-bootnode-2.polkadot.io/tcp/443/wss/p2p/12D3KooWByVpK92hMi9CzTjyFg9cPHDU5ariTM3EPMq9vdh5S5Po", + "/dns/westend-bootnode-3.polkadot.io/tcp/30333/p2p/12D3KooWGi1tCpKXLMYED9y28QXLnwgD4neYb1Arqq4QpeV1Sv3K", + "/dns/westend-bootnode-3.polkadot.io/tcp/30334/ws/p2p/12D3KooWGi1tCpKXLMYED9y28QXLnwgD4neYb1Arqq4QpeV1Sv3K", + "/dns/westend-bootnode-3.polkadot.io/tcp/443/wss/p2p/12D3KooWGi1tCpKXLMYED9y28QXLnwgD4neYb1Arqq4QpeV1Sv3K", "/dns/boot.stake.plus/tcp/32333/p2p/12D3KooWK8fjVoSvMq5copQYMsdYreSGPGgcMbGMgbMDPfpf3sm7", "/dns/boot.stake.plus/tcp/32334/wss/p2p/12D3KooWK8fjVoSvMq5copQYMsdYreSGPGgcMbGMgbMDPfpf3sm7", "/dns/boot-node.helikon.io/tcp/7080/p2p/12D3KooWRFDPyT8vA8mLzh6dJoyujn4QNjeqi6Ch79eSMz9beKXC", diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index cfe1c873c0554b4a75d1cf6fefa389a5f56f22bd..400daf1aee3448f841f9030f24b78a0029fc0830 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -34,36 +34,8 @@ macro_rules! identify_chain { $generic_code:expr $(,)* ) => { match $chain { - Chain::Polkadot => { - #[cfg(feature = "polkadot-native")] - { - use polkadot_runtime as runtime; - - let call = $generic_code; - - Ok(polkadot_sign_call(call, $nonce, $current_block, $period, $genesis, $signer)) - } - - #[cfg(not(feature = "polkadot-native"))] - { - Err("`polkadot-native` feature not enabled") - } - }, - Chain::Kusama => { - #[cfg(feature = "kusama-native")] - { - use kusama_runtime as runtime; - - let call = $generic_code; - - Ok(kusama_sign_call(call, $nonce, $current_block, $period, $genesis, $signer)) - } - - #[cfg(not(feature = "kusama-native"))] - { - Err("`kusama-native` feature not enabled") - } - }, + Chain::Polkadot => Err("Polkadot runtimes are currently not supported"), + Chain::Kusama => Err("Kusama runtimes are currently not supported"), Chain::Rococo => { #[cfg(feature = "rococo-native")] { @@ -91,16 +63,18 @@ macro_rules! identify_chain { #[cfg(not(feature = "westend-native"))] { - let _ = $nonce; - let _ = $current_block; - let _ = $period; - let _ = $genesis; - let _ = $signer; - Err("`westend-native` feature not enabled") } }, - Chain::Unknown => Err("Unknown chain"), + Chain::Unknown => { + let _ = $nonce; + let _ = $current_block; + let _ = $period; + let _ = $genesis; + let _ = $signer; + + Err("Unknown chain") + }, } }; } @@ -130,10 +104,8 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { } fn build(&self, nonce: u32) -> std::result::Result { - let period = polkadot_runtime_common::BlockHashCount::get() - .checked_next_power_of_two() - .map(|c| c / 2) - .unwrap_or(2) as u64; + // We apply the extrinsic directly, so let's take some random period. + let period = 128; let genesis = self.client.usage_info().chain.best_hash; let signer = Sr25519Keyring::Bob.pair(); let current_block = 0; @@ -181,10 +153,8 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { fn build(&self, nonce: u32) -> std::result::Result { let signer = Sr25519Keyring::Bob.pair(); - let period = polkadot_runtime_common::BlockHashCount::get() - .checked_next_power_of_two() - .map(|c| c / 2) - .unwrap_or(2) as u64; + // We apply the extrinsic directly, so let's take some random period. + let period = 128; let genesis = self.client.usage_info().chain.best_hash; let current_block = 0; let _dest = self.dest.clone(); @@ -206,60 +176,6 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { } } -#[cfg(feature = "polkadot-native")] -fn polkadot_sign_call( - call: polkadot_runtime::RuntimeCall, - nonce: u32, - current_block: u64, - period: u64, - genesis: sp_core::H256, - acc: sp_core::sr25519::Pair, -) -> OpaqueExtrinsic { - use codec::Encode; - use polkadot_runtime as runtime; - use sp_core::Pair; - - let extra: 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::mortal( - period, - current_block, - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(0), - polkadot_runtime_common::claims::PrevalidateAttests::::new(), - ); - - let payload = runtime::SignedPayload::from_raw( - call.clone(), - extra.clone(), - ( - (), - runtime::VERSION.spec_version, - runtime::VERSION.transaction_version, - genesis, - genesis, - (), - (), - (), - (), - ), - ); - - let signature = payload.using_encoded(|p| acc.sign(p)); - runtime::UncheckedExtrinsic::new_signed( - call, - sp_runtime::AccountId32::from(acc.public()).into(), - polkadot_core_primitives::Signature::Sr25519(signature.clone()), - extra, - ) - .into() -} - #[cfg(feature = "westend-native")] fn westend_sign_call( call: westend_runtime::RuntimeCall, @@ -312,58 +228,6 @@ fn westend_sign_call( .into() } -#[cfg(feature = "kusama-native")] -fn kusama_sign_call( - call: kusama_runtime::RuntimeCall, - nonce: u32, - current_block: u64, - period: u64, - genesis: sp_core::H256, - acc: sp_core::sr25519::Pair, -) -> OpaqueExtrinsic { - use codec::Encode; - use kusama_runtime as runtime; - use sp_core::Pair; - - let extra: 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::mortal( - period, - current_block, - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ); - - let payload = runtime::SignedPayload::from_raw( - call.clone(), - extra.clone(), - ( - (), - runtime::VERSION.spec_version, - runtime::VERSION.transaction_version, - genesis, - genesis, - (), - (), - (), - ), - ); - - let signature = payload.using_encoded(|p| acc.sign(p)); - runtime::UncheckedExtrinsic::new_signed( - call, - sp_runtime::AccountId32::from(acc.public()).into(), - polkadot_core_primitives::Signature::Sr25519(signature.clone()), - extra, - ) - .into() -} - #[cfg(feature = "rococo-native")] fn rococo_sign_call( call: rococo_runtime::RuntimeCall, diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 1e5aaa807b8178989700902f0a7a80b1b1fe1d76..ce25c08b8773059497cdc9624f9fb1cd65d20031 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -18,22 +18,10 @@ use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; -#[cfg(feature = "kusama-native")] -use kusama_runtime as kusama; -#[cfg(feature = "kusama-native")] -use kusama_runtime_constants::currency::UNITS as KSM; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", -))] +#[cfg(feature = "westend-native")] use pallet_staking::Forcing; use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId}; -#[cfg(feature = "polkadot-native")] -use polkadot_runtime as polkadot; -#[cfg(feature = "polkadot-native")] -use polkadot_runtime_constants::currency::UNITS as DOT; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; @@ -42,48 +30,27 @@ use rococo_runtime as rococo; #[cfg(feature = "rococo-native")] use rococo_runtime_constants::currency::UNITS as ROC; use sc_chain_spec::ChainSpecExtension; -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", - feature = "rococo-native" -))] +#[cfg(any(feature = "westend-native", feature = "rococo-native"))] use sc_chain_spec::ChainType; use serde::{Deserialize, Serialize}; use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::IdentifyAccount; -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", -))] +#[cfg(feature = "westend-native")] use sp_runtime::Perbill; -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", - feature = "rococo-native" -))] +#[cfg(any(feature = "westend-native", feature = "rococo-native"))] use telemetry::TelemetryEndpoints; #[cfg(feature = "westend-native")] use westend_runtime as westend; #[cfg(feature = "westend-native")] use westend_runtime_constants::currency::UNITS as WND; -#[cfg(feature = "kusama-native")] -const KUSAMA_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; #[cfg(feature = "westend-native")] const WESTEND_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; #[cfg(feature = "rococo-native")] const ROCOCO_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; #[cfg(feature = "rococo-native")] const VERSI_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", - feature = "rococo-native" -))] +#[cfg(any(feature = "westend-native", feature = "rococo-native"))] const DEFAULT_PROTOCOL_ID: &str = "dot"; /// Node `ChainSpec` extensions. @@ -103,25 +70,8 @@ pub struct Extensions { pub light_sync_state: sc_sync_state_rpc::LightSyncStateExtension, } -/// The `ChainSpec` parameterized for the polkadot runtime. -#[cfg(feature = "polkadot-native")] -pub type PolkadotChainSpec = service::GenericChainSpec; - -// Dummy chain spec, in case when we don't have the native runtime. -pub type DummyChainSpec = service::GenericChainSpec<(), Extensions>; - -// Dummy chain spec, but that is fine when we don't have the native runtime. -#[cfg(not(feature = "polkadot-native"))] -pub type PolkadotChainSpec = DummyChainSpec; - -/// The `ChainSpec` parameterized for the kusama runtime. -#[cfg(feature = "kusama-native")] -pub type KusamaChainSpec = service::GenericChainSpec; - -/// The `ChainSpec` parameterized for the kusama runtime. -// Dummy chain spec, but that is fine when we don't have the native runtime. -#[cfg(not(feature = "kusama-native"))] -pub type KusamaChainSpec = DummyChainSpec; +// Generic chain spec, in case when we don't have the native runtime. +pub type GenericChainSpec = service::GenericChainSpec<(), Extensions>; /// The `ChainSpec` parameterized for the westend runtime. #[cfg(feature = "westend-native")] @@ -130,11 +80,11 @@ pub type WestendChainSpec = service::GenericChainSpec; +pub type RococoChainSpec = service::GenericChainSpec; /// The `ChainSpec` parameterized for the `versi` runtime. /// @@ -144,38 +94,14 @@ pub type VersiChainSpec = RococoChainSpec; /// The `ChainSpec` parameterized for the rococo runtime. // Dummy chain spec, but that is fine when we don't have the native runtime. #[cfg(not(feature = "rococo-native"))] -pub type RococoChainSpec = DummyChainSpec; +pub type RococoChainSpec = GenericChainSpec; -/// Extension for the Rococo genesis config to support a custom changes to the genesis state. -#[derive(serde::Serialize, serde::Deserialize)] -#[cfg(feature = "rococo-native")] -pub struct RococoGenesisExt { - /// The runtime genesis config. - runtime_genesis_config: rococo::RuntimeGenesisConfig, - /// The session length in blocks. - /// - /// If `None` is supplied, the default value is used. - session_length_in_blocks: Option, +pub fn polkadot_config() -> Result { + GenericChainSpec::from_json_bytes(&include_bytes!("../chain-specs/polkadot.json")[..]) } -#[cfg(feature = "rococo-native")] -impl sp_runtime::BuildStorage for RococoGenesisExt { - fn assimilate_storage(&self, storage: &mut sp_core::storage::Storage) -> Result<(), String> { - sp_state_machine::BasicExternalities::execute_with_storage(storage, || { - if let Some(length) = self.session_length_in_blocks.as_ref() { - rococo_runtime_constants::time::EpochDurationInBlocks::set(length); - } - }); - self.runtime_genesis_config.assimilate_storage(storage) - } -} - -pub fn polkadot_config() -> Result { - PolkadotChainSpec::from_json_bytes(&include_bytes!("../chain-specs/polkadot.json")[..]) -} - -pub fn kusama_config() -> Result { - KusamaChainSpec::from_json_bytes(&include_bytes!("../chain-specs/kusama.json")[..]) +pub fn kusama_config() -> Result { + GenericChainSpec::from_json_bytes(&include_bytes!("../chain-specs/kusama.json")[..]) } pub fn westend_config() -> Result { @@ -192,12 +118,7 @@ pub fn wococo_config() -> Result { } /// The default parachains host configuration. -#[cfg(any( - feature = "rococo-native", - feature = "kusama-native", - feature = "westend-native", - feature = "polkadot-native" -))] +#[cfg(any(feature = "rococo-native", feature = "westend-native",))] fn default_parachains_host_configuration( ) -> polkadot_runtime_parachains::configuration::HostConfiguration { @@ -236,57 +157,12 @@ fn default_parachains_host_configuration( } } -#[cfg(any( - feature = "rococo-native", - feature = "kusama-native", - feature = "westend-native", - feature = "polkadot-native" -))] +#[cfg(any(feature = "rococo-native", feature = "westend-native",))] #[test] fn default_parachains_host_configuration_is_consistent() { default_parachains_host_configuration().panic_if_not_consistent(); } -#[cfg(feature = "polkadot-native")] -fn polkadot_session_keys( - babe: BabeId, - grandpa: GrandpaId, - im_online: ImOnlineId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, -) -> polkadot::SessionKeys { - polkadot::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - } -} - -#[cfg(feature = "kusama-native")] -fn kusama_session_keys( - babe: BabeId, - grandpa: GrandpaId, - im_online: ImOnlineId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - beefy: BeefyId, -) -> kusama::SessionKeys { - kusama::SessionKeys { - babe, - grandpa, - im_online, - para_validator, - para_assignment, - authority_discovery, - beefy, - } -} - #[cfg(feature = "westend-native")] fn westend_session_keys( babe: BabeId, @@ -525,6 +401,7 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim vesting: westend::VestingConfig { vesting: vec![] }, sudo: westend::SudoConfig { key: Some(endowed_accounts[0].clone()) }, hrmp: Default::default(), + treasury: Default::default(), configuration: westend::ConfigurationConfig { config: default_parachains_host_configuration(), }, @@ -539,214 +416,6 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim } } -#[cfg(feature = "kusama-native")] -fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenesisConfig { - use hex_literal::hex; - use sp_core::crypto::UncheckedInto; - - // Following keys are used in genesis config for development chains. - // DO NOT use them in production chains as the secret seed is public. - // - // SECRET_SEED="explain impose opinion genius bar parrot erupt panther surround best expire - // album" subkey inspect -n kusama "$SECRET_SEED" - let endowed_accounts = vec![ - // FLN5cfhF7VCGJYefjPQJR2V6WwbfRmb9ozTwLAzBNeQQG6y - hex!["7a0fe424217ed176da7abf12e08198db0d0949298e1372c80a1930cb6dc21d3e"].into(), - ]; - - // SECRET=$SECRET_SEED ./scripts/prepare-test-net.sh 4 - let initial_authorities: Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ImOnlineId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )> = vec![ - ( - //5D5EsvSJf3KR3WHeZNG8rETdW6homig1cGHezspFt1P4o7sL - hex!["2ca4a9582244a3356a0d96e59d71f7e4d12aa88bca6d46f360ef11f6487cab1f"].into(), - //5Ev6RixvmK62UQE2PW19MPdLsYT4Nomwj85HKPdbnRECbDYh - hex!["7e237806f642b7f45f70ec45fbc41034516c8e5561bae2a62cd287129e1d0712"].into(), - //5GbjzK1uYVo6v1SaYhTeK3dbYy2GN9X4K5iwRkHEQ9eLS3We - hex!["c89cb7afc47ec0b5aac5824e5338a62959c92978167d3f841491836746e70b3d"] - .unchecked_into(), - //5GFz3YFW8QzEUsWhRjJzvDP7e5X5tPf5U12vUw32R8oJVgqb - hex!["b98b200021a608148f9817aeb553596b6968a5aa61b6d320c522f520ecc9cf9c"] - .unchecked_into(), - //5GzaFD8YsqnP5FYe5ijA9M4LQvzU9TPJmnBGdpuoqEvR1gQC - hex!["da0690438c0dd7a9aa26e03c9f1deaa58ba2b88d0bec0954b06478632164a401"] - .unchecked_into(), - //5CkZPtNy61PtbJpLqnjNFmbi1qukGkFdqFr5GKduSEthJ1cd - hex!["1e6554d35f6f17a37176c71801426204d6df400a1869114e4f00564b35d31150"] - .unchecked_into(), - //5CodnwweaYA1zB4QhdP4YVYFWnuZHY6W7zkN1NCRqJ9wZhap - hex!["20bddf09b1d0a2d93bafeb87fe19eb5bd59950c174f23a141a6d99736a5e700d"] - .unchecked_into(), - //5E7TSvNAP6QeJNeckdvYvADpHsx7v6aHXtGoQv5R2N1V3hEB - hex!["5a91b2546f1aac1c388eb0739c83e42d9972884d74360200ce32b7595bc65a04"] - .unchecked_into(), - //5GsoKeoM2HmjXPsdCua4oPu3Ms1Jgu4HbSnB81Lisa2tBFZp - hex!["02fd1e7e8455ab888ad054bbec7bc19409e6b1a5bb0300feefc6b58e60efae7e85"] - .unchecked_into(), - ), - ( - //5HMtKQuL2GQ7YvLBTh3vqFJEpkZW19sQh2X2mcUzAwBAe885 - hex!["ea478deab0ebfbeab7342febc236a9f1af5129ca0083fa25e6b0cf6a998d8354"].into(), - //5EFD5pLC3w5NFEcmQ6rGw9dUZ6fTSjWJemsvJZuaj7Qmq2WT - hex!["607b4e88129804eca8cd6fa26cbe2dd36667130e2a061050b08d9015871f4263"].into(), - //5DFztsnvC9hN85j5AP116atcnzFhAxnbzPodEp1AsYq1LYXu - hex!["34d949c39fae5801ba328ac6d0ddc76e469b7d5a4372a4a0d94f6aad6f9c1600"] - .unchecked_into(), - //5EZJNJ4j1eEEwCWusg7nYsZxTYBwoTH2drszxRqgMBTgNxMW - hex!["6e47830dcfc1f2b53a1b5db3f76702fc2760c1cc119119aceb00a57ec6658465"] - .unchecked_into(), - //5Dts3SrgDQMY9XCzKeQrxYSTh5MphPek994qkDCDk5c4neeF - hex!["50f6ef6326cd61ac500f167493e435f1204ce1d66ad18024bc5810d09673785e"] - .unchecked_into(), - //5DMKT99825TvA8F1yCQvE1ZcKTqg8T8Ad1KEjN6EuVpz4E6w - hex!["38e7fb2f6a1dcec73d93b07a0dc7cff1f9a9cc32cde8eb1e6ea1782f5316b431"] - .unchecked_into(), - //5EestuSehdMsWsBZ1hXCVo5YQiYiTPJwtV281x5fjUVtaqtP - hex!["72889a7b6ada28c3bd05a5a7298437f01d6d3270559768d16275efaf11864c0a"] - .unchecked_into(), - //5FNd5EabUbcReXEPwY9aASJMwSqyiic9w1Qt23YxNXj3dzbi - hex!["925f03f6211c68377987b0f78cd02aa882ad1fa9cc00c01fe6ce68e14c23340d"] - .unchecked_into(), - //5DxhuqfovpooTn8yH7WJGFjYw3pQxSEN9y9kvYUiGguHAj9D - hex!["030e77039e470ccdec7fe23dbc41c66f1c187ec8345e8919d3dc1250d975c3ce82"] - .unchecked_into(), - ), - ( - //5DAiYTKQ5KxwLncfNoTAH58dXBk2oDcQxtAXyDwMdKGLpGeY - hex!["30d203d942c1d056245b51e466a50b684f172a37c1cdde678f5346a0b3dbcd52"].into(), - //5Dq778qqNiAsjdF4qLVdkSBR8SftJKU35nyeBnkztRgniVhV - hex!["4e194bbafeec45647b2679e6b615b2a879d2e74fe706921930509ab3c9dbb22d"].into(), - //5E6iENoE1tXJUd7PkopQ8uqejg6xhPpqAnsVjS3hAQHWK1tm - hex!["5a0037b6bfc5e879ba5ef480ac29c59a12873854159686899082f41950ffd472"] - .unchecked_into(), - //5F8Dtgoc5dCaLAGYtaDqQUDg91fPQUynd497Fvhor8SYMdXp - hex!["87638aef8ab75db093150a6677c0919292ff66fc17f9f006a71fd0618415e164"] - .unchecked_into(), - //5EKsYx6Wj1Qg7LLc12U2YRjRUFmHa4Q3rNSoGZaP1ofS54km - hex!["6409c85a1125fa456b9dc6e85408a6d931aa8e04f48511c87fc147d1c103e902"] - .unchecked_into(), - //5H3UQy1NhCUUq3getmSEG8R1capY7Uy8JtKJz68UABmD9UxS - hex!["dc3cab0f94fa974cba826984f23dd4dc77ade20f25d935af5f07b85518da8044"] - .unchecked_into(), - //5DstCjokShCt9NppNnAcjg2nS4M5PKY3etn2BoFkZzMhQJ3w - hex!["50379866eb62e5c8aac31133efc4a1723e964a8e30c93c3ce2e7758bd03eb776"] - .unchecked_into(), - //5E4SCbSqUWKC4NVRCkMkJEnXCaVRiNQbSHL4upRB1ffd1Mk1 - hex!["5843c339c39d2c308bfb1841cd10beecfa157580492db05b66db8553e8d6512c"] - .unchecked_into(), - //5HNoMQ1PL3m7eBhp24FZxZUBtz4eh3AiwWq8i8jXLCRpJHsu - hex!["03c81d4e72cbdb96a7e6aad76830ae783b0b4650dc19703dde96866d8894dc921f"] - .unchecked_into(), - ), - ( - //5FNnjg8hXcPVLKASA69bPbooatacxcWNqkQAyXZfFiXi7T8r - hex!["927f8b12a0fa7185077353d9f6b4fe6bc6cd9682bd498642fa3801280909711a"].into(), - //5GipjBdL3rbex9qyxMinZpJYQbobbwk1ctbZp6B2mh3H25c6 - hex!["ce03638cd1e8496793b0540ba23370034511ea5d08837deb17f6c4d905b8d017"].into(), - //5GByn4uRpwmPe4i4MA4PjTQ8HXuycdue8HMWDhZ7vbU4WR9R - hex!["b67d3ed42ab1fcf3fcd7dee99bd6963bc22058ee22bcfddddb776492e85bd76e"] - .unchecked_into(), - //5GnZZ1rs7RE1jwPiyw1kts4JqaxnML5SdsWMuHV9TqCcuPWj - hex!["d0dd492b1a33d2f06a9aa7213e1aaa41d8820a6b56e95cd2462129b446574014"] - .unchecked_into(), - //5GKEKSAa3gbitHhvu5gm4f7q942azCVGDNhrw3hnsGPEMzyg - hex!["bc04e9764e23330b9f4e6922aa6437f87f3dd17b8590825e824724ae89d4ac51"] - .unchecked_into(), - //5H6QLnsfU7sAQ5ZACs9bPivsn9CXrqqwxhq4KKyoquZb5mVW - hex!["de78b26966c08357d66f7f56e7dcac7e4beb16aa0b74939290a42b3f5949bc36"] - .unchecked_into(), - //5FUUeYiAvFfXfB5yZLNkis2ZDy9T3CBLBPC6SwXFriGEjH5f - hex!["96d61fe92a50a79944ea93e3afc0a95a328773878e774cf8c8fbe8eba81cd95c"] - .unchecked_into(), - //5DLkWtgJahWG99cMcQxtftW9W14oduySyQi6hdhav7w3BiKq - hex!["38791c68ee472b94105c66cf150387979c49175062a687d1a1509119cfdc9e0c"] - .unchecked_into(), - //5Cjm1c3Jwt5jp6AaN2XfnncgZcswAmyfJn1buHEUaPauXAKK - hex!["025185a88886008267d27797fc74e34241e3aa8da767fafc9dd3ae5a59546802bb"] - .unchecked_into(), - ), - ]; - - const ENDOWMENT: u128 = 1_000_000 * KSM; - const STASH: u128 = 100 * KSM; - - kusama::RuntimeGenesisConfig { - system: kusama::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - balances: kusama::BalancesConfig { - balances: endowed_accounts - .iter() - .map(|k: &AccountId| (k.clone(), ENDOWMENT)) - .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) - .collect(), - }, - beefy: Default::default(), - indices: kusama::IndicesConfig { indices: vec![] }, - session: kusama::SessionConfig { - keys: initial_authorities - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - kusama_session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - x.8.clone(), - ), - ) - }) - .collect::>(), - }, - staking: kusama::StakingConfig { - validator_count: 50, - minimum_validator_count: 4, - stakers: initial_authorities - .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, kusama::StakerStatus::Validator)) - .collect(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), - force_era: Forcing::ForceNone, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: kusama::BabeConfig { - authorities: Default::default(), - epoch_config: Some(kusama::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - grandpa: Default::default(), - im_online: Default::default(), - authority_discovery: kusama::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() - }, - claims: kusama::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: kusama::VestingConfig { vesting: vec![] }, - treasury: Default::default(), - hrmp: Default::default(), - configuration: kusama::ConfigurationConfig { - config: default_parachains_host_configuration(), - }, - paras: Default::default(), - xcm_pallet: Default::default(), - nomination_pools: Default::default(), - nis_counterpart_balances: Default::default(), - } -} - #[cfg(feature = "rococo-native")] fn rococo_staging_testnet_config_genesis( wasm_binary: &[u8], @@ -1024,7 +693,6 @@ fn rococo_staging_testnet_config_genesis( }) .collect::>(), }, - phragmen_election: Default::default(), babe: rococo_runtime::BabeConfig { authorities: Default::default(), epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG), @@ -1032,13 +700,6 @@ fn rococo_staging_testnet_config_genesis( }, grandpa: Default::default(), im_online: Default::default(), - democracy: rococo_runtime::DemocracyConfig::default(), - council: rococo::CouncilConfig { members: vec![], phantom: Default::default() }, - technical_committee: rococo::TechnicalCommitteeConfig { - members: vec![], - phantom: Default::default(), - }, - technical_membership: Default::default(), treasury: Default::default(), authority_discovery: rococo_runtime::AuthorityDiscoveryConfig { keys: vec![], @@ -1062,39 +723,6 @@ fn rococo_staging_testnet_config_genesis( } } -/// Returns the properties for the [`PolkadotChainSpec`]. -pub fn polkadot_chain_spec_properties() -> serde_json::map::Map { - serde_json::json!({ - "tokenDecimals": 10, - }) - .as_object() - .expect("Map given; qed") - .clone() -} - -/// Staging testnet config. -#[cfg(feature = "kusama-native")] -pub fn kusama_staging_testnet_config() -> Result { - let wasm_binary = kusama::WASM_BINARY.ok_or("Kusama development wasm not available")?; - let boot_nodes = vec![]; - - Ok(KusamaChainSpec::from_genesis( - "Kusama Staging Testnet", - "kusama_staging_testnet", - ChainType::Live, - move || kusama_staging_testnet_config_genesis(wasm_binary), - boot_nodes, - Some( - TelemetryEndpoints::new(vec![(KUSAMA_STAGING_TELEMETRY_URL.to_string(), 0)]) - .expect("Kusama Staging telemetry url is valid; qed"), - ), - Some(DEFAULT_PROTOCOL_ID), - None, - None, - Default::default(), - )) -} - /// Westend staging testnet config. #[cfg(feature = "westend-native")] pub fn westend_staging_testnet_config() -> Result { @@ -1128,10 +756,7 @@ pub fn rococo_staging_testnet_config() -> Result { "Rococo Staging Testnet", "rococo_staging_testnet", ChainType::Live, - move || RococoGenesisExt { - runtime_genesis_config: rococo_staging_testnet_config_genesis(wasm_binary), - session_length_in_blocks: None, - }, + move || rococo_staging_testnet_config_genesis(wasm_binary), boot_nodes, Some( TelemetryEndpoints::new(vec![(ROCOCO_STAGING_TELEMETRY_URL.to_string(), 0)]) @@ -1165,10 +790,7 @@ pub fn versi_staging_testnet_config() -> Result { "Versi Staging Testnet", "versi_staging_testnet", ChainType::Live, - move || RococoGenesisExt { - runtime_genesis_config: rococo_staging_testnet_config_genesis(wasm_binary), - session_length_in_blocks: Some(100), - }, + move || rococo_staging_testnet_config_genesis(wasm_binary), boot_nodes, Some( TelemetryEndpoints::new(vec![(VERSI_STAGING_TELEMETRY_URL.to_string(), 0)]) @@ -1239,12 +861,7 @@ pub fn get_authority_keys_from_seed_no_beefy( ) } -#[cfg(any( - feature = "polkadot-native", - feature = "kusama-native", - feature = "westend-native", - feature = "rococo-native" -))] +#[cfg(any(feature = "westend-native", feature = "rococo-native"))] fn testnet_accounts() -> Vec { vec![ get_account_id_from_seed::("Alice"), @@ -1262,176 +879,6 @@ fn testnet_accounts() -> Vec { ] } -/// Helper function to create polkadot `RuntimeGenesisConfig` for testing -#[cfg(feature = "polkadot-native")] -pub fn polkadot_testnet_genesis( - wasm_binary: &[u8], - initial_authorities: Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ImOnlineId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - )>, - _root_key: AccountId, - endowed_accounts: Option>, -) -> polkadot::RuntimeGenesisConfig { - let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); - - const ENDOWMENT: u128 = 1_000_000 * DOT; - const STASH: u128 = 100 * DOT; - - polkadot::RuntimeGenesisConfig { - system: polkadot::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - indices: polkadot::IndicesConfig { indices: vec![] }, - balances: polkadot::BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), - }, - session: polkadot::SessionConfig { - keys: initial_authorities - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - polkadot_session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - }, - staking: polkadot::StakingConfig { - minimum_validator_count: 1, - validator_count: initial_authorities.len() as u32, - stakers: initial_authorities - .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, polkadot::StakerStatus::Validator)) - .collect(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), - force_era: Forcing::NotForcing, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: polkadot::BabeConfig { - authorities: Default::default(), - epoch_config: Some(polkadot::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - grandpa: Default::default(), - im_online: Default::default(), - authority_discovery: polkadot::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() - }, - claims: polkadot::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: polkadot::VestingConfig { vesting: vec![] }, - treasury: Default::default(), - hrmp: Default::default(), - configuration: polkadot::ConfigurationConfig { - config: default_parachains_host_configuration(), - }, - paras: Default::default(), - xcm_pallet: Default::default(), - nomination_pools: Default::default(), - } -} - -/// Helper function to create kusama `RuntimeGenesisConfig` for testing -#[cfg(feature = "kusama-native")] -pub fn kusama_testnet_genesis( - wasm_binary: &[u8], - initial_authorities: Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ImOnlineId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )>, - _root_key: AccountId, - endowed_accounts: Option>, -) -> kusama::RuntimeGenesisConfig { - let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); - - const ENDOWMENT: u128 = 1_000_000 * KSM; - const STASH: u128 = 100 * KSM; - - kusama::RuntimeGenesisConfig { - system: kusama::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() }, - indices: kusama::IndicesConfig { indices: vec![] }, - balances: kusama::BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), - }, - beefy: Default::default(), - session: kusama::SessionConfig { - keys: initial_authorities - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - kusama_session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - x.8.clone(), - ), - ) - }) - .collect::>(), - }, - staking: kusama::StakingConfig { - minimum_validator_count: 1, - validator_count: initial_authorities.len() as u32, - stakers: initial_authorities - .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, kusama::StakerStatus::Validator)) - .collect(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), - force_era: Forcing::NotForcing, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: kusama::BabeConfig { - authorities: Default::default(), - epoch_config: Some(kusama::BABE_GENESIS_EPOCH_CONFIG), - ..Default::default() - }, - grandpa: Default::default(), - im_online: Default::default(), - authority_discovery: kusama::AuthorityDiscoveryConfig { - keys: vec![], - ..Default::default() - }, - claims: kusama::ClaimsConfig { claims: vec![], vesting: vec![] }, - vesting: kusama::VestingConfig { vesting: vec![] }, - treasury: Default::default(), - hrmp: Default::default(), - configuration: kusama::ConfigurationConfig { - config: default_parachains_host_configuration(), - }, - paras: Default::default(), - xcm_pallet: Default::default(), - nomination_pools: Default::default(), - nis_counterpart_balances: Default::default(), - } -} - /// Helper function to create westend `RuntimeGenesisConfig` for testing #[cfg(feature = "westend-native")] pub fn westend_testnet_genesis( @@ -1508,6 +955,7 @@ pub fn westend_testnet_genesis( vesting: westend::VestingConfig { vesting: vec![] }, sudo: westend::SudoConfig { key: Some(root_key) }, hrmp: Default::default(), + treasury: Default::default(), configuration: westend::ConfigurationConfig { config: default_parachains_host_configuration(), }, @@ -1578,14 +1026,6 @@ pub fn rococo_testnet_genesis( }, grandpa: Default::default(), im_online: Default::default(), - phragmen_election: Default::default(), - democracy: rococo::DemocracyConfig::default(), - council: rococo::CouncilConfig { members: vec![], phantom: Default::default() }, - technical_committee: rococo::TechnicalCommitteeConfig { - members: vec![], - phantom: Default::default(), - }, - technical_membership: Default::default(), treasury: Default::default(), claims: rococo::ClaimsConfig { claims: vec![], vesting: vec![] }, vesting: rococo::VestingConfig { vesting: vec![] }, @@ -1612,26 +1052,6 @@ pub fn rococo_testnet_genesis( } } -#[cfg(feature = "polkadot-native")] -fn polkadot_development_config_genesis(wasm_binary: &[u8]) -> polkadot::RuntimeGenesisConfig { - polkadot_testnet_genesis( - wasm_binary, - vec![get_authority_keys_from_seed_no_beefy("Alice")], - get_account_id_from_seed::("Alice"), - None, - ) -} - -#[cfg(feature = "kusama-native")] -fn kusama_development_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenesisConfig { - kusama_testnet_genesis( - wasm_binary, - vec![get_authority_keys_from_seed("Alice")], - get_account_id_from_seed::("Alice"), - None, - ) -} - #[cfg(feature = "westend-native")] fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { westend_testnet_genesis( @@ -1652,44 +1072,6 @@ fn rococo_development_config_genesis(wasm_binary: &[u8]) -> rococo_runtime::Runt ) } -/// Polkadot development config (single validator Alice) -#[cfg(feature = "polkadot-native")] -pub fn polkadot_development_config() -> Result { - let wasm_binary = polkadot::WASM_BINARY.ok_or("Polkadot development wasm not available")?; - - Ok(PolkadotChainSpec::from_genesis( - "Development", - "polkadot_dev", - ChainType::Development, - move || polkadot_development_config_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - Some(polkadot_chain_spec_properties()), - Default::default(), - )) -} - -/// Kusama development config (single validator Alice) -#[cfg(feature = "kusama-native")] -pub fn kusama_development_config() -> Result { - let wasm_binary = kusama::WASM_BINARY.ok_or("Kusama development wasm not available")?; - - Ok(KusamaChainSpec::from_genesis( - "Development", - "kusama_dev", - ChainType::Development, - move || kusama_development_config_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, - Default::default(), - )) -} - /// Westend development config (single validator Alice) #[cfg(feature = "westend-native")] pub fn westend_development_config() -> Result { @@ -1718,11 +1100,7 @@ pub fn rococo_development_config() -> Result { "Development", "rococo_dev", ChainType::Development, - move || RococoGenesisExt { - runtime_genesis_config: rococo_development_config_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || rococo_development_config_genesis(wasm_binary), vec![], None, Some(DEFAULT_PROTOCOL_ID), @@ -1741,11 +1119,7 @@ pub fn versi_development_config() -> Result { "Development", "versi_dev", ChainType::Development, - move || RococoGenesisExt { - runtime_genesis_config: rococo_development_config_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || rococo_development_config_genesis(wasm_binary), vec![], None, Some("versi"), @@ -1765,11 +1139,7 @@ pub fn wococo_development_config() -> Result { "Development", "wococo_dev", ChainType::Development, - move || RococoGenesisExt { - runtime_genesis_config: rococo_development_config_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || rococo_development_config_genesis(wasm_binary), vec![], None, Some(WOCOCO_DEV_PROTOCOL_ID), @@ -1779,67 +1149,6 @@ pub fn wococo_development_config() -> Result { )) } -#[cfg(feature = "polkadot-native")] -fn polkadot_local_testnet_genesis(wasm_binary: &[u8]) -> polkadot::RuntimeGenesisConfig { - polkadot_testnet_genesis( - wasm_binary, - vec![ - get_authority_keys_from_seed_no_beefy("Alice"), - get_authority_keys_from_seed_no_beefy("Bob"), - ], - get_account_id_from_seed::("Alice"), - None, - ) -} - -/// Polkadot local testnet config (multivalidator Alice + Bob) -#[cfg(feature = "polkadot-native")] -pub fn polkadot_local_testnet_config() -> Result { - let wasm_binary = polkadot::WASM_BINARY.ok_or("Polkadot development wasm not available")?; - - Ok(PolkadotChainSpec::from_genesis( - "Local Testnet", - "local_testnet", - ChainType::Local, - move || polkadot_local_testnet_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - Some(polkadot_chain_spec_properties()), - Default::default(), - )) -} - -#[cfg(feature = "kusama-native")] -fn kusama_local_testnet_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenesisConfig { - kusama_testnet_genesis( - wasm_binary, - vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], - get_account_id_from_seed::("Alice"), - None, - ) -} - -/// Kusama local testnet config (multivalidator Alice + Bob) -#[cfg(feature = "kusama-native")] -pub fn kusama_local_testnet_config() -> Result { - let wasm_binary = kusama::WASM_BINARY.ok_or("Kusama development wasm not available")?; - - Ok(KusamaChainSpec::from_genesis( - "Kusama Local Testnet", - "kusama_local_testnet", - ChainType::Local, - move || kusama_local_testnet_genesis(wasm_binary), - vec![], - None, - Some(DEFAULT_PROTOCOL_ID), - None, - None, - Default::default(), - )) -} - #[cfg(feature = "westend-native")] fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { westend_testnet_genesis( @@ -1888,11 +1197,7 @@ pub fn rococo_local_testnet_config() -> Result { "Rococo Local Testnet", "rococo_local_testnet", ChainType::Local, - move || RococoGenesisExt { - runtime_genesis_config: rococo_local_testnet_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || rococo_local_testnet_genesis(wasm_binary), vec![], None, Some(DEFAULT_PROTOCOL_ID), @@ -1927,11 +1232,7 @@ pub fn wococo_local_testnet_config() -> Result { "Wococo Local Testnet", "wococo_local_testnet", ChainType::Local, - move || RococoGenesisExt { - runtime_genesis_config: wococo_local_testnet_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || wococo_local_testnet_genesis(wasm_binary), vec![], None, Some(DEFAULT_PROTOCOL_ID), @@ -1966,11 +1267,7 @@ pub fn versi_local_testnet_config() -> Result { "Versi Local Testnet", "versi_local_testnet", ChainType::Local, - move || RococoGenesisExt { - runtime_genesis_config: versi_local_testnet_genesis(wasm_binary), - // Use 1 minute session length. - session_length_in_blocks: Some(10), - }, + move || versi_local_testnet_genesis(wasm_binary), vec![], None, Some("versi"), diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 75e853d0ef85fb152468a4ee5ae6ddd92f446795..ced89c3843a24c3fb8c84c67bd7cf0cbaf78a80e 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -84,7 +84,7 @@ use telemetry::TelemetryWorker; #[cfg(feature = "full-node")] use telemetry::{Telemetry, TelemetryWorkerHandle}; -pub use chain_spec::{KusamaChainSpec, PolkadotChainSpec, RococoChainSpec, WestendChainSpec}; +pub use chain_spec::{GenericChainSpec, RococoChainSpec, WestendChainSpec}; pub use consensus_common::{Proposal, SelectChain}; use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use mmr_gadget::MmrGadget; @@ -104,10 +104,6 @@ pub use sp_runtime::{ traits::{self as runtime_traits, BlakeTwo256, Block as BlockT, Header as HeaderT, NumberFor}, }; -#[cfg(feature = "kusama-native")] -pub use {kusama_runtime, kusama_runtime_constants}; -#[cfg(feature = "polkadot-native")] -pub use {polkadot_runtime, polkadot_runtime_constants}; #[cfg(feature = "rococo-native")] pub use {rococo_runtime, rococo_runtime_constants}; #[cfg(feature = "westend-native")] @@ -753,11 +749,6 @@ pub fn new_full( Some(backoff) }; - // Warn the user that BEEFY is still experimental for Polkadot. - if enable_beefy && config.chain_spec.is_polkadot() { - gum::warn!("BEEFY is still experimental, usage on Polkadot network is discouraged."); - } - let disable_grandpa = config.disable_grandpa; let name = config.network.node_name.clone(); @@ -858,7 +849,7 @@ pub fn new_full( let (collation_req_v1_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); - let (collation_req_vstaging_receiver, cfg) = + let (collation_req_v2_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); let (available_data_req_receiver, cfg) = @@ -866,7 +857,7 @@ pub fn new_full( net_config.add_request_response_protocol(cfg); let (statement_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); - let (candidate_req_vstaging_receiver, cfg) = + let (candidate_req_v2_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); let (dispute_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); @@ -1055,10 +1046,10 @@ pub fn new_full( pov_req_receiver, chunk_req_receiver, collation_req_v1_receiver, - collation_req_vstaging_receiver, + collation_req_v2_receiver, available_data_req_receiver, statement_req_receiver, - candidate_req_vstaging_receiver, + candidate_req_v2_receiver, dispute_req_receiver, registry: prometheus_registry.as_ref(), spawner, diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 33127b638e5a51800d3c5f88af1ac420a941b48c..7d1add118241b123ad122b305264f95b46b8ee78 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -28,7 +28,7 @@ use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, request_response::{ - v1 as request_v1, vstaging as request_vstaging, IncomingRequestReceiver, ReqProtocolNames, + v1 as request_v1, v2 as request_v2, IncomingRequestReceiver, ReqProtocolNames, }, }; #[cfg(any(feature = "malus", test))] @@ -104,17 +104,15 @@ where pub chunk_req_receiver: IncomingRequestReceiver, /// Collations request receiver for network protocol v1. pub collation_req_v1_receiver: IncomingRequestReceiver, - /// Collations request receiver for network protocol vstaging. - pub collation_req_vstaging_receiver: - IncomingRequestReceiver, + /// Collations request receiver for network protocol v2. + pub collation_req_v2_receiver: IncomingRequestReceiver, /// Receiver for available data requests. pub available_data_req_receiver: IncomingRequestReceiver, /// Receiver for incoming large statement requests. pub statement_req_receiver: IncomingRequestReceiver, /// Receiver for incoming candidate requests. - pub candidate_req_vstaging_receiver: - IncomingRequestReceiver, + pub candidate_req_v2_receiver: IncomingRequestReceiver, /// Receiver for incoming disputes. pub dispute_req_receiver: IncomingRequestReceiver, /// Prometheus registry, commonly used for production systems, less so for test. @@ -158,10 +156,10 @@ pub fn prepared_overseer_builder( pov_req_receiver, chunk_req_receiver, collation_req_v1_receiver, - collation_req_vstaging_receiver, + collation_req_v2_receiver, available_data_req_receiver, statement_req_receiver, - candidate_req_vstaging_receiver, + candidate_req_v2_receiver, dispute_req_receiver, registry, spawner, @@ -288,7 +286,7 @@ where peer_id: network_service.local_peer_id(), collator_pair, request_receiver_v1: collation_req_v1_receiver, - request_receiver_vstaging: collation_req_vstaging_receiver, + request_receiver_v2: collation_req_v2_receiver, metrics: Metrics::register(registry)?, }, IsParachainNode::FullNode => ProtocolSide::None, @@ -309,7 +307,7 @@ where .statement_distribution(StatementDistributionSubsystem::new( keystore.clone(), statement_req_receiver, - candidate_req_vstaging_receiver, + candidate_req_v2_receiver, Metrics::register(registry)?, rand::rngs::StdRng::from_entropy(), )) diff --git a/polkadot/node/service/src/relay_chain_selection.rs b/polkadot/node/service/src/relay_chain_selection.rs index 189073783f0dc53eb06ceafe9015e9fd806b1f9e..5fae6a96de4ea73996042be8446220df51fc2e30 100644 --- a/polkadot/node/service/src/relay_chain_selection.rs +++ b/polkadot/node/service/src/relay_chain_selection.rs @@ -31,7 +31,7 @@ //! leaf returned from the chain selection subsystem by calling into other //! subsystems which yield information about approvals and disputes. //! -//! [chain-selection-guide]: https://w3f.github.io/parachain-implementers-guide/protocol-chain-selection.html +//! [chain-selection-guide]: https://paritytech.github.io/polkadot-sdk/book/protocol-chain-selection.html #![cfg(feature = "full-node")] diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index a53908d3c2cb384c1eb004fb0bde00b5d35b6a56..6bc874384594e93ac7970777c16d3a6276c5938a 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -39,12 +39,12 @@ use polkadot_node_primitives::{ ValidationResult, }; use polkadot_primitives::{ - slashing, vstaging as vstaging_primitives, AuthorityDiscoveryId, BackedCandidate, BlockNumber, - CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, - PvfCheckStatement, PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + async_backing, slashing, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, + CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, + CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, + Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; @@ -695,14 +695,14 @@ pub enum RuntimeApiRequest { ), /// Get the minimum required backing votes. MinimumBackingVotes(SessionIndex, RuntimeApiSender), - + /// Returns all disabled validators at a given block height. + DisabledValidators(RuntimeApiSender>), /// Get the backing state of the given para. - /// This is a staging API that will not be available on production runtimes. - StagingParaBackingState(ParaId, RuntimeApiSender>), + ParaBackingState(ParaId, RuntimeApiSender>), /// Get candidate's acceptance limitations for asynchronous backing for a relay parent. /// /// If it's not supported by the Runtime, the async backing is said to be disabled. - StagingAsyncBackingParams(RuntimeApiSender), + AsyncBackingParams(RuntimeApiSender), } impl RuntimeApiRequest { @@ -726,10 +726,11 @@ impl RuntimeApiRequest { /// `MinimumBackingVotes` pub const MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT: u32 = 6; - /// Minimum version for backing state, required for async backing. - /// - /// 99 for now, should be adjusted to VSTAGING/actual runtime version once released. - pub const STAGING_BACKING_STATE: u32 = 99; + /// Minimum version to enable asynchronous backing: `AsyncBackingParams` and `ParaBackingState`. + pub const ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT: u32 = 7; + + /// `DisabledValidators` + pub const DISABLED_VALIDATORS_RUNTIME_REQUIREMENT: u32 = 8; } /// A message to the Runtime API subsystem. diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 06aa351efb4bce18868893b9bbb2163f17e2cbe5..f7adcf9862b5d09829cb1d0edbb3f068b9c55713 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,9 +16,9 @@ use async_trait::async_trait; use polkadot_primitives::{ - runtime_api::ParachainHost, vstaging, Block, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id, InboundDownwardMessage, InboundHrmpMessage, + async_backing, runtime_api::ParachainHost, slashing, Block, BlockNumber, CandidateCommitments, + CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Hash, Id, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, @@ -190,7 +190,7 @@ pub trait RuntimeApiSubsystemClient { async fn unapplied_slashes( &self, at: Hash, - ) -> Result, ApiError>; + ) -> Result, ApiError>; /// Returns a merkle proof of a validator session key in a past session. /// @@ -199,7 +199,7 @@ pub trait RuntimeApiSubsystemClient { &self, at: Hash, validator_id: ValidatorId, - ) -> Result, ApiError>; + ) -> Result, ApiError>; /// Submits an unsigned extrinsic to slash validators who lost a dispute about /// a candidate of a past session. @@ -208,8 +208,8 @@ pub trait RuntimeApiSubsystemClient { async fn submit_report_dispute_lost( &self, at: Hash, - dispute_proof: vstaging::slashing::DisputeProof, - key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, + dispute_proof: slashing::DisputeProof, + key_ownership_proof: slashing::OpaqueKeyOwnershipProof, ) -> Result, ApiError>; // === BABE API === @@ -232,7 +232,7 @@ pub trait RuntimeApiSubsystemClient { session_index: SessionIndex, ) -> Result, ApiError>; - // === STAGING v6 === + // === v6 === /// Get the minimum number of backing votes. async fn minimum_backing_votes( &self, @@ -240,21 +240,25 @@ pub trait RuntimeApiSubsystemClient { session_index: SessionIndex, ) -> Result; - // === Asynchronous backing API === + // === v7: Asynchronous backing API === /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. - async fn staging_async_backing_params( + async fn async_backing_params( &self, at: Hash, - ) -> Result; + ) -> Result; /// Returns the state of parachain backing for a given para. /// This is a staging method! Do not use on production runtimes! - async fn staging_para_backing_state( + async fn para_backing_state( &self, at: Hash, para_id: Id, - ) -> Result, ApiError>; + ) -> Result, ApiError>; + + // === v8 === + /// Gets the disabled validators at a specific block height + async fn disabled_validators(&self, at: Hash) -> Result, ApiError>; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -454,7 +458,7 @@ where async fn unapplied_slashes( &self, at: Hash, - ) -> Result, ApiError> { + ) -> Result, ApiError> { self.client.runtime_api().unapplied_slashes(at) } @@ -462,15 +466,15 @@ where &self, at: Hash, validator_id: ValidatorId, - ) -> Result, ApiError> { + ) -> Result, ApiError> { self.client.runtime_api().key_ownership_proof(at, validator_id) } async fn submit_report_dispute_lost( &self, at: Hash, - dispute_proof: vstaging::slashing::DisputeProof, - key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, + dispute_proof: slashing::DisputeProof, + key_ownership_proof: slashing::OpaqueKeyOwnershipProof, ) -> Result, ApiError> { let mut runtime_api = self.client.runtime_api(); @@ -489,19 +493,22 @@ where self.client.runtime_api().minimum_backing_votes(at) } - async fn staging_para_backing_state( + async fn para_backing_state( &self, at: Hash, para_id: Id, - ) -> Result, ApiError> { - self.client.runtime_api().staging_para_backing_state(at, para_id) + ) -> Result, ApiError> { + self.client.runtime_api().para_backing_state(at, para_id) } - /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. - async fn staging_async_backing_params( + async fn async_backing_params( &self, at: Hash, - ) -> Result { - self.client.runtime_api().staging_async_backing_params(at) + ) -> Result { + self.client.runtime_api().async_backing_params(at) + } + + async fn disabled_validators(&self, at: Hash) -> Result, ApiError> { + self.client.runtime_api().disabled_validators(at) } } diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index 83c15fdef9593a3268b6c14f4ef67d2f4363dadb..a14536a17666c8e2d9183755e3579990f6185113 100644 --- a/polkadot/node/subsystem-util/src/backing_implicit_view.rs +++ b/polkadot/node/subsystem-util/src/backing_implicit_view.rs @@ -20,7 +20,7 @@ use polkadot_node_subsystem::{ messages::{ChainApiMessage, ProspectiveParachainsMessage}, SubsystemSender, }; -use polkadot_primitives::vstaging::{BlockNumber, Hash, Id as ParaId}; +use polkadot_primitives::{BlockNumber, Hash, Id as ParaId}; use std::collections::HashMap; diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index 1487077d9edaba66a6cbcfa97cb5adae067284cc..c7b91bffb3d705b27ee4c611985328dd1b1b7e77 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -11,4 +11,1437 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -pub mod staging; +/// # Overview +/// +/// A set of utilities for node-side code to emulate the logic the runtime uses for checking +/// parachain blocks in order to build prospective parachains that are produced ahead of the +/// relay chain. These utilities allow the node-side to predict, with high accuracy, what +/// the relay-chain will accept in the near future. +/// +/// This module has 2 key data types: [`Constraints`] and [`Fragment`]s. [`Constraints`] +/// exhaustively define the set of valid inputs and outputs to parachain execution. A +/// [`Fragment`] indicates a parachain block, anchored to the relay-chain at a particular +/// relay-chain block, known as the relay-parent. +/// +/// ## Fragment Validity +/// +/// Every relay-parent is implicitly associated with a unique set of [`Constraints`] that +/// describe the properties that must be true for a block to be included in a direct child of +/// that block, assuming there is no intermediate parachain block pending availability. +/// +/// However, the key factor that makes asynchronously-grown prospective chains +/// possible is the fact that the relay-chain accepts candidate blocks based on whether they +/// are valid under the constraints of the present moment, not based on whether they were +/// valid at the time of construction. +/// +/// As such, [`Fragment`]s are often, but not always constructed in such a way that they are +/// invalid at first and become valid later on, as the relay chain grows. +/// +/// # 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. +/// +/// ## Operating Constraints +/// +/// The *operating constraints* of a `Fragment` are the constraints with which that fragment +/// was intended to comply. The operating constraints are defined as the base constraints +/// of the relay-parent of the fragment modified by the cumulative modifications of all +/// fragments between the relay-parent and the current fragment. +/// +/// What the operating constraints are, in practice, is a prediction about the state of the +/// relay-chain in the future. The relay-chain is aware of some current state, and we want to +/// make an intelligent prediction about what might be accepted in the future based on +/// prior fragments that also exist off-chain. +/// +/// ## Fragment Trees +/// +/// 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. +/// +/// Avoiding fragment-tree blowup is beyond the scope of this module. +/// +/// ### Pruning Fragment Trees +/// +/// 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: +/// +/// 1. The root fragment is still valid under the new constraints. In this case, we do nothing. +/// This is the "prediction still uncertain" case. +/// +/// 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 descendents 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. +/// +/// 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 +/// 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 +/// +/// 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. +/// +/// ### 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. +/// +/// 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. +use polkadot_primitives::{ + async_backing::Constraints as PrimitiveConstraints, BlockNumber, CandidateCommitments, + CollatorId, CollatorSignature, Hash, HeadData, Id as ParaId, PersistedValidationData, + UpgradeRestriction, ValidationCodeHash, +}; +use std::{ + borrow::{Borrow, Cow}, + collections::HashMap, +}; + +/// Constraints on inbound HRMP channels. +#[derive(Debug, Clone, PartialEq)] +pub struct InboundHrmpLimitations { + /// An exhaustive set of all valid watermarks, sorted ascending + pub valid_watermarks: Vec, +} + +/// Constraints on outbound HRMP channels. +#[derive(Debug, Clone, PartialEq)] +pub struct OutboundHrmpChannelLimitations { + /// The maximum bytes that can be written to the channel. + pub bytes_remaining: usize, + /// The maximum messages that can be written to the channel. + pub messages_remaining: usize, +} + +/// Constraints on the actions that can be taken by a new parachain +/// block. These limitations are implicitly associated with some particular +/// parachain, which should be apparent from usage. +#[derive(Debug, Clone, PartialEq)] +pub struct Constraints { + /// The minimum relay-parent number accepted under these constraints. + pub min_relay_parent_number: BlockNumber, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: usize, + /// The maximum new validation code size allowed, in bytes. + pub max_code_size: usize, + /// The amount of UMP messages remaining. + pub ump_remaining: usize, + /// The amount of UMP bytes remaining. + pub ump_remaining_bytes: usize, + /// The maximum number of UMP messages allowed per candidate. + pub max_ump_num_per_candidate: usize, + /// Remaining DMP queue. Only includes sent-at block numbers. + pub dmp_remaining_messages: Vec, + /// The limitations of all registered inbound HRMP channels. + pub hrmp_inbound: InboundHrmpLimitations, + /// The limitations of all registered outbound HRMP channels. + pub hrmp_channels_out: HashMap, + /// The maximum number of HRMP messages allowed per candidate. + pub max_hrmp_num_per_candidate: usize, + /// The required parent head-data of the parachain. + pub required_parent: HeadData, + /// The expected validation-code-hash of this parachain. + pub validation_code_hash: ValidationCodeHash, + /// The code upgrade restriction signal as-of this parachain. + pub upgrade_restriction: Option, + /// The future validation code hash, if any, and at what relay-parent + /// number the upgrade would be minimally applied. + pub future_validation_code: Option<(BlockNumber, ValidationCodeHash)>, +} + +impl From for Constraints { + fn from(c: PrimitiveConstraints) -> Self { + Constraints { + min_relay_parent_number: c.min_relay_parent_number, + max_pov_size: c.max_pov_size as _, + max_code_size: c.max_code_size as _, + ump_remaining: c.ump_remaining as _, + ump_remaining_bytes: c.ump_remaining_bytes as _, + max_ump_num_per_candidate: c.max_ump_num_per_candidate as _, + dmp_remaining_messages: c.dmp_remaining_messages, + hrmp_inbound: InboundHrmpLimitations { + valid_watermarks: c.hrmp_inbound.valid_watermarks, + }, + hrmp_channels_out: c + .hrmp_channels_out + .into_iter() + .map(|(para_id, limits)| { + ( + para_id, + OutboundHrmpChannelLimitations { + bytes_remaining: limits.bytes_remaining as _, + messages_remaining: limits.messages_remaining as _, + }, + ) + }) + .collect(), + max_hrmp_num_per_candidate: c.max_hrmp_num_per_candidate as _, + required_parent: c.required_parent, + validation_code_hash: c.validation_code_hash, + upgrade_restriction: c.upgrade_restriction, + future_validation_code: c.future_validation_code, + } + } +} + +/// Kinds of errors that can occur when modifying constraints. +#[derive(Debug, Clone, PartialEq)] +pub enum ModificationError { + /// The HRMP watermark is not allowed. + DisallowedHrmpWatermark(BlockNumber), + /// No such HRMP outbound channel. + NoSuchHrmpChannel(ParaId), + /// Too many messages submitted to HRMP channel. + HrmpMessagesOverflow { + /// The ID of the recipient. + para_id: ParaId, + /// The amount of remaining messages in the capacity of the channel. + messages_remaining: usize, + /// The amount of messages submitted to the channel. + messages_submitted: usize, + }, + /// Too many bytes submitted to HRMP channel. + HrmpBytesOverflow { + /// The ID of the recipient. + para_id: ParaId, + /// The amount of remaining bytes in the capacity of the channel. + bytes_remaining: usize, + /// The amount of bytes submitted to the channel. + bytes_submitted: usize, + }, + /// Too many messages submitted to UMP. + UmpMessagesOverflow { + /// The amount of remaining messages in the capacity of UMP. + messages_remaining: usize, + /// The amount of messages submitted to UMP. + messages_submitted: usize, + }, + /// Too many bytes submitted to UMP. + UmpBytesOverflow { + /// The amount of remaining bytes in the capacity of UMP. + bytes_remaining: usize, + /// The amount of bytes submitted to UMP. + bytes_submitted: usize, + }, + /// Too many messages processed from DMP. + DmpMessagesUnderflow { + /// The amount of messages waiting to be processed from DMP. + messages_remaining: usize, + /// The amount of messages processed. + messages_processed: usize, + }, + /// No validation code upgrade to apply. + AppliedNonexistentCodeUpgrade, +} + +impl Constraints { + /// Check modifications against constraints. + pub fn check_modifications( + &self, + modifications: &ConstraintModifications, + ) -> Result<(), ModificationError> { + if let Some(HrmpWatermarkUpdate::Trunk(hrmp_watermark)) = modifications.hrmp_watermark { + // head updates are always valid. + if self.hrmp_inbound.valid_watermarks.iter().all(|w| w != &hrmp_watermark) { + return Err(ModificationError::DisallowedHrmpWatermark(hrmp_watermark)) + } + } + + for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { + if let Some(outbound) = self.hrmp_channels_out.get(&id) { + outbound.bytes_remaining.checked_sub(outbound_hrmp_mod.bytes_submitted).ok_or( + ModificationError::HrmpBytesOverflow { + para_id: *id, + bytes_remaining: outbound.bytes_remaining, + bytes_submitted: outbound_hrmp_mod.bytes_submitted, + }, + )?; + + outbound + .messages_remaining + .checked_sub(outbound_hrmp_mod.messages_submitted) + .ok_or(ModificationError::HrmpMessagesOverflow { + para_id: *id, + messages_remaining: outbound.messages_remaining, + messages_submitted: outbound_hrmp_mod.messages_submitted, + })?; + } else { + return Err(ModificationError::NoSuchHrmpChannel(*id)) + } + } + + self.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( + ModificationError::UmpMessagesOverflow { + messages_remaining: self.ump_remaining, + messages_submitted: modifications.ump_messages_sent, + }, + )?; + + self.ump_remaining_bytes.checked_sub(modifications.ump_bytes_sent).ok_or( + ModificationError::UmpBytesOverflow { + bytes_remaining: self.ump_remaining_bytes, + bytes_submitted: modifications.ump_bytes_sent, + }, + )?; + + self.dmp_remaining_messages + .len() + .checked_sub(modifications.dmp_messages_processed) + .ok_or(ModificationError::DmpMessagesUnderflow { + messages_remaining: self.dmp_remaining_messages.len(), + messages_processed: modifications.dmp_messages_processed, + })?; + + if self.future_validation_code.is_none() && modifications.code_upgrade_applied { + return Err(ModificationError::AppliedNonexistentCodeUpgrade) + } + + Ok(()) + } + + /// Apply modifications to these constraints. If this succeeds, it passes + /// all sanity-checks. + pub fn apply_modifications( + &self, + modifications: &ConstraintModifications, + ) -> Result { + let mut new = self.clone(); + + if let Some(required_parent) = modifications.required_parent.as_ref() { + new.required_parent = required_parent.clone(); + } + + if let Some(ref hrmp_watermark) = modifications.hrmp_watermark { + match new.hrmp_inbound.valid_watermarks.binary_search(&hrmp_watermark.watermark()) { + Ok(pos) => { + // Exact match, so this is OK in all cases. + let _ = new.hrmp_inbound.valid_watermarks.drain(..pos + 1); + }, + Err(pos) => match hrmp_watermark { + HrmpWatermarkUpdate::Head(_) => { + // Updates to Head are always OK. + let _ = new.hrmp_inbound.valid_watermarks.drain(..pos); + }, + HrmpWatermarkUpdate::Trunk(n) => { + // Trunk update landing on disallowed watermark is not OK. + return Err(ModificationError::DisallowedHrmpWatermark(*n)) + }, + }, + } + } + + for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { + if let Some(outbound) = new.hrmp_channels_out.get_mut(&id) { + outbound.bytes_remaining = outbound + .bytes_remaining + .checked_sub(outbound_hrmp_mod.bytes_submitted) + .ok_or(ModificationError::HrmpBytesOverflow { + para_id: *id, + bytes_remaining: outbound.bytes_remaining, + bytes_submitted: outbound_hrmp_mod.bytes_submitted, + })?; + + outbound.messages_remaining = outbound + .messages_remaining + .checked_sub(outbound_hrmp_mod.messages_submitted) + .ok_or(ModificationError::HrmpMessagesOverflow { + para_id: *id, + messages_remaining: outbound.messages_remaining, + messages_submitted: outbound_hrmp_mod.messages_submitted, + })?; + } else { + return Err(ModificationError::NoSuchHrmpChannel(*id)) + } + } + + new.ump_remaining = new.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( + ModificationError::UmpMessagesOverflow { + messages_remaining: new.ump_remaining, + messages_submitted: modifications.ump_messages_sent, + }, + )?; + + new.ump_remaining_bytes = new + .ump_remaining_bytes + .checked_sub(modifications.ump_bytes_sent) + .ok_or(ModificationError::UmpBytesOverflow { + bytes_remaining: new.ump_remaining_bytes, + bytes_submitted: modifications.ump_bytes_sent, + })?; + + if modifications.dmp_messages_processed > new.dmp_remaining_messages.len() { + return Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: new.dmp_remaining_messages.len(), + messages_processed: modifications.dmp_messages_processed, + }) + } else { + new.dmp_remaining_messages = + new.dmp_remaining_messages[modifications.dmp_messages_processed..].to_vec(); + } + + if modifications.code_upgrade_applied { + new.validation_code_hash = new + .future_validation_code + .take() + .ok_or(ModificationError::AppliedNonexistentCodeUpgrade)? + .1; + } + + Ok(new) + } +} + +/// Information about a relay-chain block. +#[derive(Debug, Clone, PartialEq)] +pub struct RelayChainBlockInfo { + /// The hash of the relay-chain block. + pub hash: Hash, + /// The number of the relay-chain block. + pub number: BlockNumber, + /// The storage-root of the relay-chain block. + pub storage_root: Hash, +} + +/// An update to outbound HRMP channels. +#[derive(Debug, Clone, PartialEq, Default)] +pub struct OutboundHrmpChannelModification { + /// The number of bytes submitted to the channel. + pub bytes_submitted: usize, + /// The number of messages submitted to the channel. + pub messages_submitted: usize, +} + +/// An update to the HRMP Watermark. +#[derive(Debug, Clone, PartialEq)] +pub enum HrmpWatermarkUpdate { + /// This is an update placing the watermark at the head of the chain, + /// which is always legal. + Head(BlockNumber), + /// This is an update placing the watermark behind the head of the + /// chain, which is only legal if it lands on a block where messages + /// were queued. + Trunk(BlockNumber), +} + +impl HrmpWatermarkUpdate { + fn watermark(&self) -> BlockNumber { + match *self { + HrmpWatermarkUpdate::Head(n) | HrmpWatermarkUpdate::Trunk(n) => n, + } + } +} + +/// Modifications to constraints as a result of prospective candidates. +#[derive(Debug, Clone, PartialEq)] +pub struct ConstraintModifications { + /// The required parent head to build upon. + pub required_parent: Option, + /// The new HRMP watermark + pub hrmp_watermark: Option, + /// Outbound HRMP channel modifications. + pub outbound_hrmp: HashMap, + /// The amount of UMP messages sent. + pub ump_messages_sent: usize, + /// The amount of UMP bytes sent. + pub ump_bytes_sent: usize, + /// The amount of DMP messages processed. + pub dmp_messages_processed: usize, + /// Whether a pending code upgrade has been applied. + pub code_upgrade_applied: bool, +} + +impl ConstraintModifications { + /// The 'identity' modifications: these can be applied to + /// any constraints and yield the exact same result. + pub fn identity() -> Self { + ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: HashMap::new(), + ump_messages_sent: 0, + ump_bytes_sent: 0, + dmp_messages_processed: 0, + code_upgrade_applied: false, + } + } + + /// Stack other modifications on top of these. + /// + /// This does no sanity-checking, so if `other` is garbage relative + /// to `self`, then the new value will be garbage as well. + /// + /// This is an addition which is not commutative. + pub fn stack(&mut self, other: &Self) { + if let Some(ref new_parent) = other.required_parent { + self.required_parent = Some(new_parent.clone()); + } + if let Some(ref new_hrmp_watermark) = other.hrmp_watermark { + self.hrmp_watermark = Some(new_hrmp_watermark.clone()); + } + + for (id, mods) in &other.outbound_hrmp { + let record = self.outbound_hrmp.entry(*id).or_default(); + record.messages_submitted += mods.messages_submitted; + record.bytes_submitted += mods.bytes_submitted; + } + + self.ump_messages_sent += other.ump_messages_sent; + self.ump_bytes_sent += other.ump_bytes_sent; + self.dmp_messages_processed += other.dmp_messages_processed; + self.code_upgrade_applied |= other.code_upgrade_applied; + } +} + +/// The prospective candidate. +/// +/// This comprises the key information that represent a candidate +/// without pinning it to a particular session. For example, everything +/// to do with the collator's signature and commitments are represented +/// 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> { + /// The commitments to the output of the execution. + pub commitments: Cow<'a, CandidateCommitments>, + /// The collator that created the candidate. + pub collator: CollatorId, + /// The signature of the collator on the payload. + pub collator_signature: CollatorSignature, + /// The persisted validation data used to create the candidate. + pub persisted_validation_data: PersistedValidationData, + /// The hash of the PoV. + pub pov_hash: Hash, + /// The validation code hash used by the candidate. + 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 { + /// The validation code of the candidate doesn't match the + /// operating constraints. + /// + /// Expected, Got + ValidationCodeMismatch(ValidationCodeHash, ValidationCodeHash), + /// The persisted-validation-data doesn't match. + /// + /// Expected, Got + PersistedValidationDataMismatch(PersistedValidationData, PersistedValidationData), + /// The outputs of the candidate are invalid under the operating + /// constraints. + OutputsInvalid(ModificationError), + /// New validation code size too big. + /// + /// Max allowed, new. + CodeSizeTooLarge(usize, usize), + /// Relay parent too old. + /// + /// Min allowed, current. + RelayParentTooOld(BlockNumber, BlockNumber), + /// Para is required to process at least one DMP message from the queue. + DmpAdvancementRule, + /// Too many messages upward messages submitted. + UmpMessagesPerCandidateOverflow { + /// The amount of messages a single candidate can submit. + messages_allowed: usize, + /// The amount of messages sent to all HRMP channels. + messages_submitted: usize, + }, + /// Too many messages submitted to all HRMP channels. + HrmpMessagesPerCandidateOverflow { + /// The amount of messages a single candidate can submit. + messages_allowed: usize, + /// The amount of messages sent to all HRMP channels. + messages_submitted: usize, + }, + /// Code upgrade not allowed. + CodeUpgradeRestricted, + /// HRMP messages are not ascending or are duplicate. + /// + /// The `usize` is the index into the outbound HRMP messages of + /// the candidate. + HrmpMessagesDescendingOrDuplicate(usize), +} + +/// A parachain fragment, representing another prospective parachain block. +/// +/// This is a type which guarantees that the candidate is valid under the +/// operating constraints. +#[derive(Debug, Clone, PartialEq)] +pub struct Fragment<'a> { + /// 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>, + /// Modifications to the constraints based on the outputs of + /// the candidate. + modifications: ConstraintModifications, +} + +impl<'a> Fragment<'a> { + /// Create a new fragment. + /// + /// This fails if the fragment isn't in line with the operating + /// constraints. That is, either its inputs or its outputs fail + /// checks against the constraints. + /// + /// This doesn't check that the collator signature is valid or + /// whether the PoV is small enough. + pub fn new( + relay_parent: RelayChainBlockInfo, + operating_constraints: Constraints, + candidate: ProspectiveCandidate<'a>, + ) -> Result { + let modifications = { + let commitments = &candidate.commitments; + ConstraintModifications { + required_parent: Some(commitments.head_data.clone()), + hrmp_watermark: Some({ + if commitments.hrmp_watermark == relay_parent.number { + HrmpWatermarkUpdate::Head(commitments.hrmp_watermark) + } else { + HrmpWatermarkUpdate::Trunk(commitments.hrmp_watermark) + } + }), + outbound_hrmp: { + let mut outbound_hrmp = HashMap::<_, OutboundHrmpChannelModification>::new(); + + let mut last_recipient = None::; + for (i, message) in commitments.horizontal_messages.iter().enumerate() { + if let Some(last) = last_recipient { + if last >= message.recipient { + return Err( + FragmentValidityError::HrmpMessagesDescendingOrDuplicate(i), + ) + } + } + + last_recipient = Some(message.recipient); + let record = outbound_hrmp.entry(message.recipient).or_default(); + + record.bytes_submitted += message.data.len(); + record.messages_submitted += 1; + } + + outbound_hrmp + }, + ump_messages_sent: commitments.upward_messages.len(), + ump_bytes_sent: commitments.upward_messages.iter().map(|msg| msg.len()).sum(), + dmp_messages_processed: commitments.processed_downward_messages as _, + code_upgrade_applied: operating_constraints + .future_validation_code + .map_or(false, |(at, _)| relay_parent.number >= at), + } + }; + + validate_against_constraints( + &operating_constraints, + &relay_parent, + &candidate, + &modifications, + )?; + + Ok(Fragment { relay_parent, operating_constraints, candidate, modifications }) + } + + /// Access the relay parent information. + pub fn relay_parent(&self) -> &RelayChainBlockInfo { + &self.relay_parent + } + + /// Access the operating constraints + pub fn operating_constraints(&self) -> &Constraints { + &self.operating_constraints + } + + /// Access the underlying prospective candidate. + pub fn candidate(&self) -> &ProspectiveCandidate<'a> { + &self.candidate + } + + /// Modifications to constraints based on the outputs of the candidate. + 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, + modifications: &ConstraintModifications, +) -> Result<(), FragmentValidityError> { + let expected_pvd = PersistedValidationData { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent.number, + relay_parent_storage_root: relay_parent.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }; + + if expected_pvd != candidate.persisted_validation_data { + return Err(FragmentValidityError::PersistedValidationDataMismatch( + expected_pvd, + candidate.persisted_validation_data.clone(), + )) + } + + if constraints.validation_code_hash != candidate.validation_code_hash { + return Err(FragmentValidityError::ValidationCodeMismatch( + constraints.validation_code_hash, + candidate.validation_code_hash, + )) + } + + if relay_parent.number < constraints.min_relay_parent_number { + return Err(FragmentValidityError::RelayParentTooOld( + constraints.min_relay_parent_number, + relay_parent.number, + )) + } + + if candidate.commitments.new_validation_code.is_some() { + match constraints.upgrade_restriction { + None => {}, + Some(UpgradeRestriction::Present) => + return Err(FragmentValidityError::CodeUpgradeRestricted), + } + } + + let announced_code_size = candidate + .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( + constraints.max_code_size, + announced_code_size, + )) + } + + if modifications.dmp_messages_processed == 0 { + if constraints + .dmp_remaining_messages + .get(0) + .map_or(false, |&msg_sent_at| msg_sent_at <= relay_parent.number) + { + return Err(FragmentValidityError::DmpAdvancementRule) + } + } + + if candidate.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(), + }) + } + + if candidate.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(), + }) + } + + constraints + .check_modifications(&modifications) + .map_err(FragmentValidityError::OutputsInvalid) +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_primitives::{ + CollatorPair, HorizontalMessages, OutboundHrmpMessage, ValidationCode, + }; + use sp_application_crypto::Pair; + + #[test] + fn stack_modifications() { + let para_a = ParaId::from(1u32); + let para_b = ParaId::from(2u32); + let para_c = ParaId::from(3u32); + + let a = ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map.insert( + para_b, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map + }, + ump_messages_sent: 6, + ump_bytes_sent: 1000, + dmp_messages_processed: 5, + code_upgrade_applied: true, + }; + + let b = ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_b, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map.insert( + para_c, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map + }, + ump_messages_sent: 6, + ump_bytes_sent: 1000, + dmp_messages_processed: 5, + code_upgrade_applied: true, + }; + + let mut c = a.clone(); + c.stack(&b); + + assert_eq!( + c, + ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_a, + OutboundHrmpChannelModification { + bytes_submitted: 100, + messages_submitted: 5, + }, + ); + + map.insert( + para_b, + OutboundHrmpChannelModification { + bytes_submitted: 200, + messages_submitted: 10, + }, + ); + + map.insert( + para_c, + OutboundHrmpChannelModification { + bytes_submitted: 100, + messages_submitted: 5, + }, + ); + + map + }, + ump_messages_sent: 12, + ump_bytes_sent: 2000, + dmp_messages_processed: 10, + code_upgrade_applied: true, + }, + ); + + let mut d = ConstraintModifications::identity(); + d.stack(&a); + d.stack(&b); + + assert_eq!(c, d); + } + + fn make_constraints() -> Constraints { + let para_a = ParaId::from(1u32); + let para_b = ParaId::from(2u32); + let para_c = ParaId::from(3u32); + + Constraints { + min_relay_parent_number: 5, + max_pov_size: 1000, + max_code_size: 1000, + ump_remaining: 10, + ump_remaining_bytes: 1024, + max_ump_num_per_candidate: 5, + dmp_remaining_messages: Vec::new(), + hrmp_inbound: InboundHrmpLimitations { valid_watermarks: vec![6, 8] }, + hrmp_channels_out: { + let mut map = HashMap::new(); + + map.insert( + para_a, + OutboundHrmpChannelLimitations { messages_remaining: 5, bytes_remaining: 512 }, + ); + + map.insert( + para_b, + OutboundHrmpChannelLimitations { + messages_remaining: 10, + bytes_remaining: 1024, + }, + ); + + map.insert( + para_c, + OutboundHrmpChannelLimitations { messages_remaining: 1, bytes_remaining: 128 }, + ); + + map + }, + max_hrmp_num_per_candidate: 5, + required_parent: HeadData::from(vec![1, 2, 3]), + validation_code_hash: ValidationCode(vec![4, 5, 6]).hash(), + upgrade_restriction: None, + future_validation_code: None, + } + } + + #[test] + fn constraints_disallowed_trunk_watermark() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Trunk(7)); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::DisallowedHrmpWatermark(7)), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::DisallowedHrmpWatermark(7)), + ); + } + + #[test] + fn constraints_always_allow_head_watermark() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Head(7)); + + assert!(constraints.check_modifications(&modifications).is_ok()); + + let new_constraints = constraints.apply_modifications(&modifications).unwrap(); + assert_eq!(new_constraints.hrmp_inbound.valid_watermarks, vec![8]); + } + + #[test] + fn constraints_no_such_hrmp_channel() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let bad_para = ParaId::from(100u32); + modifications.outbound_hrmp.insert( + bad_para, + OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 0 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::NoSuchHrmpChannel(bad_para)), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::NoSuchHrmpChannel(bad_para)), + ); + } + + #[test] + fn constraints_hrmp_messages_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let para_a = ParaId::from(1u32); + modifications.outbound_hrmp.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 6 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::HrmpMessagesOverflow { + para_id: para_a, + messages_remaining: 5, + messages_submitted: 6, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::HrmpMessagesOverflow { + para_id: para_a, + messages_remaining: 5, + messages_submitted: 6, + }), + ); + } + + #[test] + fn constraints_hrmp_bytes_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let para_a = ParaId::from(1u32); + modifications.outbound_hrmp.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 513, messages_submitted: 1 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::HrmpBytesOverflow { + para_id: para_a, + bytes_remaining: 512, + bytes_submitted: 513, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::HrmpBytesOverflow { + para_id: para_a, + bytes_remaining: 512, + bytes_submitted: 513, + }), + ); + } + + #[test] + fn constraints_ump_messages_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.ump_messages_sent = 11; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::UmpMessagesOverflow { + messages_remaining: 10, + messages_submitted: 11, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::UmpMessagesOverflow { + messages_remaining: 10, + messages_submitted: 11, + }), + ); + } + + #[test] + fn constraints_ump_bytes_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.ump_bytes_sent = 1025; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::UmpBytesOverflow { + bytes_remaining: 1024, + bytes_submitted: 1025, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::UmpBytesOverflow { + bytes_remaining: 1024, + bytes_submitted: 1025, + }), + ); + } + + #[test] + fn constraints_dmp_messages() { + let mut constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + assert!(constraints.check_modifications(&modifications).is_ok()); + assert!(constraints.apply_modifications(&modifications).is_ok()); + + modifications.dmp_messages_processed = 6; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: 0, + messages_processed: 6, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: 0, + messages_processed: 6, + }), + ); + + constraints.dmp_remaining_messages = vec![1, 4, 8, 10]; + modifications.dmp_messages_processed = 2; + assert!(constraints.check_modifications(&modifications).is_ok()); + let constraints = constraints + .apply_modifications(&modifications) + .expect("modifications are valid"); + + assert_eq!(&constraints.dmp_remaining_messages, &[8, 10]); + } + + #[test] + fn constraints_nonexistent_code_upgrade() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.code_upgrade_applied = true; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::AppliedNonexistentCodeUpgrade), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::AppliedNonexistentCodeUpgrade), + ); + } + + fn make_candidate( + constraints: &Constraints, + relay_parent: &RelayChainBlockInfo, + ) -> ProspectiveCandidate<'static> { + 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 { + 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 { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent.number, + relay_parent_storage_root: relay_parent.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }, + pov_hash: Hash::repeat_byte(1), + validation_code_hash: constraints.validation_code_hash, + } + } + + #[test] + fn fragment_validation_code_mismatch() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let expected_code = constraints.validation_code_hash; + let got_code = ValidationCode(vec![9, 9, 9]).hash(); + + candidate.validation_code_hash = got_code; + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::ValidationCodeMismatch(expected_code, got_code,)), + ) + } + + #[test] + fn fragment_pvd_mismatch() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let relay_parent_b = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0b), + storage_root: Hash::repeat_byte(0xee), + }; + + let constraints = make_constraints(); + let candidate = make_candidate(&constraints, &relay_parent); + + let expected_pvd = PersistedValidationData { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent_b.number, + relay_parent_storage_root: relay_parent_b.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }; + + let got_pvd = candidate.persisted_validation_data.clone(); + + assert_eq!( + Fragment::new(relay_parent_b, constraints, candidate), + Err(FragmentValidityError::PersistedValidationDataMismatch(expected_pvd, got_pvd,)), + ); + } + + #[test] + fn fragment_code_size_too_large() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + 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()); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::CodeSizeTooLarge(max_code_size, max_code_size + 1,)), + ); + } + + #[test] + fn fragment_relay_parent_too_old() { + let relay_parent = RelayChainBlockInfo { + number: 3, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let candidate = make_candidate(&constraints, &relay_parent); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::RelayParentTooOld(5, 3,)), + ); + } + + #[test] + fn fragment_hrmp_messages_overflow() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let max_hrmp = constraints.max_hrmp_num_per_candidate; + + candidate + .commitments_mut() + .horizontal_messages + .try_extend((0..max_hrmp + 1).map(|i| OutboundHrmpMessage { + recipient: ParaId::from(i as u32), + data: vec![1, 2, 3], + })) + .unwrap(); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { + messages_allowed: max_hrmp, + messages_submitted: max_hrmp + 1, + }), + ); + } + + #[test] + fn fragment_dmp_advancement_rule() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let mut constraints = make_constraints(); + 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()); + // 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()); + + 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()), + Err(FragmentValidityError::DmpAdvancementRule), + ); + } + + candidate.commitments.to_mut().processed_downward_messages = 1; + assert!(Fragment::new(relay_parent, constraints, candidate).is_ok()); + } + + #[test] + fn fragment_ump_messages_overflow() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let max_ump = constraints.max_ump_num_per_candidate; + + 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), + Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { + messages_allowed: max_ump, + messages_submitted: max_ump + 1, + }), + ); + } + + #[test] + fn fragment_code_upgrade_restricted() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let mut constraints = make_constraints(); + 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])); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::CodeUpgradeRestricted), + ); + } + + #[test] + fn fragment_hrmp_messages_descending_or_duplicate() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + candidate.commitments_mut().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()), + Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), + ); + + candidate.commitments_mut().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), + Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), + ); + } +} diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs deleted file mode 100644 index eb06322975282cd7ee7db14eec80b2d1556f57fd..0000000000000000000000000000000000000000 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/staging.rs +++ /dev/null @@ -1,1450 +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. - -//! The implementation of the inclusion emulator for the 'staging' runtime version. -//! -//! # Overview -//! -//! A set of utilities for node-side code to emulate the logic the runtime uses for checking -//! parachain blocks in order to build prospective parachains that are produced ahead of the -//! relay chain. These utilities allow the node-side to predict, with high accuracy, what -//! the relay-chain will accept in the near future. -//! -//! This module has 2 key data types: [`Constraints`] and [`Fragment`]s. [`Constraints`] -//! exhaustively define the set of valid inputs and outputs to parachain execution. A [`Fragment`] -//! indicates a parachain block, anchored to the relay-chain at a particular relay-chain block, -//! known as the relay-parent. -//! -//! ## Fragment Validity -//! -//! Every relay-parent is implicitly associated with a unique set of [`Constraints`] that describe -//! the properties that must be true for a block to be included in a direct child of that block, -//! assuming there is no intermediate parachain block pending availability. -//! -//! However, the key factor that makes asynchronously-grown prospective chains -//! possible is the fact that the relay-chain accepts candidate blocks based on whether they -//! are valid under the constraints of the present moment, not based on whether they were -//! valid at the time of construction. -//! -//! As such, [`Fragment`]s are often, but not always constructed in such a way that they are -//! invalid at first and become valid later on, as the relay chain grows. -//! -//! # 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. -//! -//! ## Operating Constraints -//! -//! The *operating constraints* of a `Fragment` are the constraints with which that fragment -//! was intended to comply. The operating constraints are defined as the base constraints -//! of the relay-parent of the fragment modified by the cumulative modifications of all -//! fragments between the relay-parent and the current fragment. -//! -//! What the operating constraints are, in practice, is a prediction about the state of the -//! relay-chain in the future. The relay-chain is aware of some current state, and we want to -//! make an intelligent prediction about what might be accepted in the future based on -//! prior fragments that also exist off-chain. -//! -//! ## Fragment Trees -//! -//! 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. -//! -//! Avoiding fragment-tree blowup is beyond the scope of this module. -//! -//! ### Pruning Fragment Trees -//! -//! 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: -//! -//! 1. The root fragment is still valid under the new constraints. In this case, we do nothing. This -//! is the "prediction still uncertain" case. -//! -//! 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 descendents 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. -//! -//! 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 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 -//! -//! 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. -//! -//! ### 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. -//! -//! 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. - -use polkadot_primitives::vstaging::{ - BlockNumber, CandidateCommitments, CollatorId, CollatorSignature, - Constraints as PrimitiveConstraints, Hash, HeadData, Id as ParaId, PersistedValidationData, - UpgradeRestriction, ValidationCodeHash, -}; -use std::{ - borrow::{Borrow, Cow}, - collections::HashMap, -}; - -/// Constraints on inbound HRMP channels. -#[derive(Debug, Clone, PartialEq)] -pub struct InboundHrmpLimitations { - /// An exhaustive set of all valid watermarks, sorted ascending - pub valid_watermarks: Vec, -} - -/// Constraints on outbound HRMP channels. -#[derive(Debug, Clone, PartialEq)] -pub struct OutboundHrmpChannelLimitations { - /// The maximum bytes that can be written to the channel. - pub bytes_remaining: usize, - /// The maximum messages that can be written to the channel. - pub messages_remaining: usize, -} - -/// Constraints on the actions that can be taken by a new parachain -/// block. These limitations are implicitly associated with some particular -/// parachain, which should be apparent from usage. -#[derive(Debug, Clone, PartialEq)] -pub struct Constraints { - /// The minimum relay-parent number accepted under these constraints. - pub min_relay_parent_number: BlockNumber, - /// The maximum Proof-of-Validity size allowed, in bytes. - pub max_pov_size: usize, - /// The maximum new validation code size allowed, in bytes. - pub max_code_size: usize, - /// The amount of UMP messages remaining. - pub ump_remaining: usize, - /// The amount of UMP bytes remaining. - pub ump_remaining_bytes: usize, - /// The maximum number of UMP messages allowed per candidate. - pub max_ump_num_per_candidate: usize, - /// Remaining DMP queue. Only includes sent-at block numbers. - pub dmp_remaining_messages: Vec, - /// The limitations of all registered inbound HRMP channels. - pub hrmp_inbound: InboundHrmpLimitations, - /// The limitations of all registered outbound HRMP channels. - pub hrmp_channels_out: HashMap, - /// The maximum number of HRMP messages allowed per candidate. - pub max_hrmp_num_per_candidate: usize, - /// The required parent head-data of the parachain. - pub required_parent: HeadData, - /// The expected validation-code-hash of this parachain. - pub validation_code_hash: ValidationCodeHash, - /// The code upgrade restriction signal as-of this parachain. - pub upgrade_restriction: Option, - /// The future validation code hash, if any, and at what relay-parent - /// number the upgrade would be minimally applied. - pub future_validation_code: Option<(BlockNumber, ValidationCodeHash)>, -} - -impl From for Constraints { - fn from(c: PrimitiveConstraints) -> Self { - Constraints { - min_relay_parent_number: c.min_relay_parent_number, - max_pov_size: c.max_pov_size as _, - max_code_size: c.max_code_size as _, - ump_remaining: c.ump_remaining as _, - ump_remaining_bytes: c.ump_remaining_bytes as _, - max_ump_num_per_candidate: c.max_ump_num_per_candidate as _, - dmp_remaining_messages: c.dmp_remaining_messages, - hrmp_inbound: InboundHrmpLimitations { - valid_watermarks: c.hrmp_inbound.valid_watermarks, - }, - hrmp_channels_out: c - .hrmp_channels_out - .into_iter() - .map(|(para_id, limits)| { - ( - para_id, - OutboundHrmpChannelLimitations { - bytes_remaining: limits.bytes_remaining as _, - messages_remaining: limits.messages_remaining as _, - }, - ) - }) - .collect(), - max_hrmp_num_per_candidate: c.max_hrmp_num_per_candidate as _, - required_parent: c.required_parent, - validation_code_hash: c.validation_code_hash, - upgrade_restriction: c.upgrade_restriction, - future_validation_code: c.future_validation_code, - } - } -} - -/// Kinds of errors that can occur when modifying constraints. -#[derive(Debug, Clone, PartialEq)] -pub enum ModificationError { - /// The HRMP watermark is not allowed. - DisallowedHrmpWatermark(BlockNumber), - /// No such HRMP outbound channel. - NoSuchHrmpChannel(ParaId), - /// Too many messages submitted to HRMP channel. - HrmpMessagesOverflow { - /// The ID of the recipient. - para_id: ParaId, - /// The amount of remaining messages in the capacity of the channel. - messages_remaining: usize, - /// The amount of messages submitted to the channel. - messages_submitted: usize, - }, - /// Too many bytes submitted to HRMP channel. - HrmpBytesOverflow { - /// The ID of the recipient. - para_id: ParaId, - /// The amount of remaining bytes in the capacity of the channel. - bytes_remaining: usize, - /// The amount of bytes submitted to the channel. - bytes_submitted: usize, - }, - /// Too many messages submitted to UMP. - UmpMessagesOverflow { - /// The amount of remaining messages in the capacity of UMP. - messages_remaining: usize, - /// The amount of messages submitted to UMP. - messages_submitted: usize, - }, - /// Too many bytes submitted to UMP. - UmpBytesOverflow { - /// The amount of remaining bytes in the capacity of UMP. - bytes_remaining: usize, - /// The amount of bytes submitted to UMP. - bytes_submitted: usize, - }, - /// Too many messages processed from DMP. - DmpMessagesUnderflow { - /// The amount of messages waiting to be processed from DMP. - messages_remaining: usize, - /// The amount of messages processed. - messages_processed: usize, - }, - /// No validation code upgrade to apply. - AppliedNonexistentCodeUpgrade, -} - -impl Constraints { - /// Check modifications against constraints. - pub fn check_modifications( - &self, - modifications: &ConstraintModifications, - ) -> Result<(), ModificationError> { - if let Some(HrmpWatermarkUpdate::Trunk(hrmp_watermark)) = modifications.hrmp_watermark { - // head updates are always valid. - if self.hrmp_inbound.valid_watermarks.iter().all(|w| w != &hrmp_watermark) { - return Err(ModificationError::DisallowedHrmpWatermark(hrmp_watermark)) - } - } - - for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { - if let Some(outbound) = self.hrmp_channels_out.get(&id) { - outbound.bytes_remaining.checked_sub(outbound_hrmp_mod.bytes_submitted).ok_or( - ModificationError::HrmpBytesOverflow { - para_id: *id, - bytes_remaining: outbound.bytes_remaining, - bytes_submitted: outbound_hrmp_mod.bytes_submitted, - }, - )?; - - outbound - .messages_remaining - .checked_sub(outbound_hrmp_mod.messages_submitted) - .ok_or(ModificationError::HrmpMessagesOverflow { - para_id: *id, - messages_remaining: outbound.messages_remaining, - messages_submitted: outbound_hrmp_mod.messages_submitted, - })?; - } else { - return Err(ModificationError::NoSuchHrmpChannel(*id)) - } - } - - self.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( - ModificationError::UmpMessagesOverflow { - messages_remaining: self.ump_remaining, - messages_submitted: modifications.ump_messages_sent, - }, - )?; - - self.ump_remaining_bytes.checked_sub(modifications.ump_bytes_sent).ok_or( - ModificationError::UmpBytesOverflow { - bytes_remaining: self.ump_remaining_bytes, - bytes_submitted: modifications.ump_bytes_sent, - }, - )?; - - self.dmp_remaining_messages - .len() - .checked_sub(modifications.dmp_messages_processed) - .ok_or(ModificationError::DmpMessagesUnderflow { - messages_remaining: self.dmp_remaining_messages.len(), - messages_processed: modifications.dmp_messages_processed, - })?; - - if self.future_validation_code.is_none() && modifications.code_upgrade_applied { - return Err(ModificationError::AppliedNonexistentCodeUpgrade) - } - - Ok(()) - } - - /// Apply modifications to these constraints. If this succeeds, it passes - /// all sanity-checks. - pub fn apply_modifications( - &self, - modifications: &ConstraintModifications, - ) -> Result { - let mut new = self.clone(); - - if let Some(required_parent) = modifications.required_parent.as_ref() { - new.required_parent = required_parent.clone(); - } - - if let Some(ref hrmp_watermark) = modifications.hrmp_watermark { - match new.hrmp_inbound.valid_watermarks.binary_search(&hrmp_watermark.watermark()) { - Ok(pos) => { - // Exact match, so this is OK in all cases. - let _ = new.hrmp_inbound.valid_watermarks.drain(..pos + 1); - }, - Err(pos) => match hrmp_watermark { - HrmpWatermarkUpdate::Head(_) => { - // Updates to Head are always OK. - let _ = new.hrmp_inbound.valid_watermarks.drain(..pos); - }, - HrmpWatermarkUpdate::Trunk(n) => { - // Trunk update landing on disallowed watermark is not OK. - return Err(ModificationError::DisallowedHrmpWatermark(*n)) - }, - }, - } - } - - for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { - if let Some(outbound) = new.hrmp_channels_out.get_mut(&id) { - outbound.bytes_remaining = outbound - .bytes_remaining - .checked_sub(outbound_hrmp_mod.bytes_submitted) - .ok_or(ModificationError::HrmpBytesOverflow { - para_id: *id, - bytes_remaining: outbound.bytes_remaining, - bytes_submitted: outbound_hrmp_mod.bytes_submitted, - })?; - - outbound.messages_remaining = outbound - .messages_remaining - .checked_sub(outbound_hrmp_mod.messages_submitted) - .ok_or(ModificationError::HrmpMessagesOverflow { - para_id: *id, - messages_remaining: outbound.messages_remaining, - messages_submitted: outbound_hrmp_mod.messages_submitted, - })?; - } else { - return Err(ModificationError::NoSuchHrmpChannel(*id)) - } - } - - new.ump_remaining = new.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( - ModificationError::UmpMessagesOverflow { - messages_remaining: new.ump_remaining, - messages_submitted: modifications.ump_messages_sent, - }, - )?; - - new.ump_remaining_bytes = new - .ump_remaining_bytes - .checked_sub(modifications.ump_bytes_sent) - .ok_or(ModificationError::UmpBytesOverflow { - bytes_remaining: new.ump_remaining_bytes, - bytes_submitted: modifications.ump_bytes_sent, - })?; - - if modifications.dmp_messages_processed > new.dmp_remaining_messages.len() { - return Err(ModificationError::DmpMessagesUnderflow { - messages_remaining: new.dmp_remaining_messages.len(), - messages_processed: modifications.dmp_messages_processed, - }) - } else { - new.dmp_remaining_messages = - new.dmp_remaining_messages[modifications.dmp_messages_processed..].to_vec(); - } - - if modifications.code_upgrade_applied { - new.validation_code_hash = new - .future_validation_code - .take() - .ok_or(ModificationError::AppliedNonexistentCodeUpgrade)? - .1; - } - - Ok(new) - } -} - -/// Information about a relay-chain block. -#[derive(Debug, Clone, PartialEq)] -pub struct RelayChainBlockInfo { - /// The hash of the relay-chain block. - pub hash: Hash, - /// The number of the relay-chain block. - pub number: BlockNumber, - /// The storage-root of the relay-chain block. - pub storage_root: Hash, -} - -/// An update to outbound HRMP channels. -#[derive(Debug, Clone, PartialEq, Default)] -pub struct OutboundHrmpChannelModification { - /// The number of bytes submitted to the channel. - pub bytes_submitted: usize, - /// The number of messages submitted to the channel. - pub messages_submitted: usize, -} - -/// An update to the HRMP Watermark. -#[derive(Debug, Clone, PartialEq)] -pub enum HrmpWatermarkUpdate { - /// This is an update placing the watermark at the head of the chain, - /// which is always legal. - Head(BlockNumber), - /// This is an update placing the watermark behind the head of the - /// chain, which is only legal if it lands on a block where messages - /// were queued. - Trunk(BlockNumber), -} - -impl HrmpWatermarkUpdate { - fn watermark(&self) -> BlockNumber { - match *self { - HrmpWatermarkUpdate::Head(n) | HrmpWatermarkUpdate::Trunk(n) => n, - } - } -} - -/// Modifications to constraints as a result of prospective candidates. -#[derive(Debug, Clone, PartialEq)] -pub struct ConstraintModifications { - /// The required parent head to build upon. - pub required_parent: Option, - /// The new HRMP watermark - pub hrmp_watermark: Option, - /// Outbound HRMP channel modifications. - pub outbound_hrmp: HashMap, - /// The amount of UMP messages sent. - pub ump_messages_sent: usize, - /// The amount of UMP bytes sent. - pub ump_bytes_sent: usize, - /// The amount of DMP messages processed. - pub dmp_messages_processed: usize, - /// Whether a pending code upgrade has been applied. - pub code_upgrade_applied: bool, -} - -impl ConstraintModifications { - /// The 'identity' modifications: these can be applied to - /// any constraints and yield the exact same result. - pub fn identity() -> Self { - ConstraintModifications { - required_parent: None, - hrmp_watermark: None, - outbound_hrmp: HashMap::new(), - ump_messages_sent: 0, - ump_bytes_sent: 0, - dmp_messages_processed: 0, - code_upgrade_applied: false, - } - } - - /// Stack other modifications on top of these. - /// - /// This does no sanity-checking, so if `other` is garbage relative - /// to `self`, then the new value will be garbage as well. - /// - /// This is an addition which is not commutative. - pub fn stack(&mut self, other: &Self) { - if let Some(ref new_parent) = other.required_parent { - self.required_parent = Some(new_parent.clone()); - } - if let Some(ref new_hrmp_watermark) = other.hrmp_watermark { - self.hrmp_watermark = Some(new_hrmp_watermark.clone()); - } - - for (id, mods) in &other.outbound_hrmp { - let record = self.outbound_hrmp.entry(*id).or_default(); - record.messages_submitted += mods.messages_submitted; - record.bytes_submitted += mods.bytes_submitted; - } - - self.ump_messages_sent += other.ump_messages_sent; - self.ump_bytes_sent += other.ump_bytes_sent; - self.dmp_messages_processed += other.dmp_messages_processed; - self.code_upgrade_applied |= other.code_upgrade_applied; - } -} - -/// The prospective candidate. -/// -/// This comprises the key information that represent a candidate -/// without pinning it to a particular session. For example, everything -/// to do with the collator's signature and commitments are represented -/// 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> { - /// The commitments to the output of the execution. - pub commitments: Cow<'a, CandidateCommitments>, - /// The collator that created the candidate. - pub collator: CollatorId, - /// The signature of the collator on the payload. - pub collator_signature: CollatorSignature, - /// The persisted validation data used to create the candidate. - pub persisted_validation_data: PersistedValidationData, - /// The hash of the PoV. - pub pov_hash: Hash, - /// The validation code hash used by the candidate. - 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 { - /// The validation code of the candidate doesn't match the - /// operating constraints. - /// - /// Expected, Got - ValidationCodeMismatch(ValidationCodeHash, ValidationCodeHash), - /// The persisted-validation-data doesn't match. - /// - /// Expected, Got - PersistedValidationDataMismatch(PersistedValidationData, PersistedValidationData), - /// The outputs of the candidate are invalid under the operating - /// constraints. - OutputsInvalid(ModificationError), - /// New validation code size too big. - /// - /// Max allowed, new. - CodeSizeTooLarge(usize, usize), - /// Relay parent too old. - /// - /// Min allowed, current. - RelayParentTooOld(BlockNumber, BlockNumber), - /// Para is required to process at least one DMP message from the queue. - DmpAdvancementRule, - /// Too many messages upward messages submitted. - UmpMessagesPerCandidateOverflow { - /// The amount of messages a single candidate can submit. - messages_allowed: usize, - /// The amount of messages sent to all HRMP channels. - messages_submitted: usize, - }, - /// Too many messages submitted to all HRMP channels. - HrmpMessagesPerCandidateOverflow { - /// The amount of messages a single candidate can submit. - messages_allowed: usize, - /// The amount of messages sent to all HRMP channels. - messages_submitted: usize, - }, - /// Code upgrade not allowed. - CodeUpgradeRestricted, - /// HRMP messages are not ascending or are duplicate. - /// - /// The `usize` is the index into the outbound HRMP messages of - /// the candidate. - HrmpMessagesDescendingOrDuplicate(usize), -} - -/// A parachain fragment, representing another prospective parachain block. -/// -/// This is a type which guarantees that the candidate is valid under the -/// operating constraints. -#[derive(Debug, Clone, PartialEq)] -pub struct Fragment<'a> { - /// 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>, - /// Modifications to the constraints based on the outputs of - /// the candidate. - modifications: ConstraintModifications, -} - -impl<'a> Fragment<'a> { - /// Create a new fragment. - /// - /// This fails if the fragment isn't in line with the operating - /// constraints. That is, either its inputs or its outputs fail - /// checks against the constraints. - /// - /// This doesn't check that the collator signature is valid or - /// whether the PoV is small enough. - pub fn new( - relay_parent: RelayChainBlockInfo, - operating_constraints: Constraints, - candidate: ProspectiveCandidate<'a>, - ) -> Result { - let modifications = { - let commitments = &candidate.commitments; - ConstraintModifications { - required_parent: Some(commitments.head_data.clone()), - hrmp_watermark: Some({ - if commitments.hrmp_watermark == relay_parent.number { - HrmpWatermarkUpdate::Head(commitments.hrmp_watermark) - } else { - HrmpWatermarkUpdate::Trunk(commitments.hrmp_watermark) - } - }), - outbound_hrmp: { - let mut outbound_hrmp = HashMap::<_, OutboundHrmpChannelModification>::new(); - - let mut last_recipient = None::; - for (i, message) in commitments.horizontal_messages.iter().enumerate() { - if let Some(last) = last_recipient { - if last >= message.recipient { - return Err( - FragmentValidityError::HrmpMessagesDescendingOrDuplicate(i), - ) - } - } - - last_recipient = Some(message.recipient); - let record = outbound_hrmp.entry(message.recipient).or_default(); - - record.bytes_submitted += message.data.len(); - record.messages_submitted += 1; - } - - outbound_hrmp - }, - ump_messages_sent: commitments.upward_messages.len(), - ump_bytes_sent: commitments.upward_messages.iter().map(|msg| msg.len()).sum(), - dmp_messages_processed: commitments.processed_downward_messages as _, - code_upgrade_applied: operating_constraints - .future_validation_code - .map_or(false, |(at, _)| relay_parent.number >= at), - } - }; - - validate_against_constraints( - &operating_constraints, - &relay_parent, - &candidate, - &modifications, - )?; - - Ok(Fragment { relay_parent, operating_constraints, candidate, modifications }) - } - - /// Access the relay parent information. - pub fn relay_parent(&self) -> &RelayChainBlockInfo { - &self.relay_parent - } - - /// Access the operating constraints - pub fn operating_constraints(&self) -> &Constraints { - &self.operating_constraints - } - - /// Access the underlying prospective candidate. - pub fn candidate(&self) -> &ProspectiveCandidate<'a> { - &self.candidate - } - - /// Modifications to constraints based on the outputs of the candidate. - 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, - modifications: &ConstraintModifications, -) -> Result<(), FragmentValidityError> { - let expected_pvd = PersistedValidationData { - parent_head: constraints.required_parent.clone(), - relay_parent_number: relay_parent.number, - relay_parent_storage_root: relay_parent.storage_root, - max_pov_size: constraints.max_pov_size as u32, - }; - - if expected_pvd != candidate.persisted_validation_data { - return Err(FragmentValidityError::PersistedValidationDataMismatch( - expected_pvd, - candidate.persisted_validation_data.clone(), - )) - } - - if constraints.validation_code_hash != candidate.validation_code_hash { - return Err(FragmentValidityError::ValidationCodeMismatch( - constraints.validation_code_hash, - candidate.validation_code_hash, - )) - } - - if relay_parent.number < constraints.min_relay_parent_number { - return Err(FragmentValidityError::RelayParentTooOld( - constraints.min_relay_parent_number, - relay_parent.number, - )) - } - - if candidate.commitments.new_validation_code.is_some() { - match constraints.upgrade_restriction { - None => {}, - Some(UpgradeRestriction::Present) => - return Err(FragmentValidityError::CodeUpgradeRestricted), - } - } - - let announced_code_size = candidate - .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( - constraints.max_code_size, - announced_code_size, - )) - } - - if modifications.dmp_messages_processed == 0 { - if constraints - .dmp_remaining_messages - .get(0) - .map_or(false, |&msg_sent_at| msg_sent_at <= relay_parent.number) - { - return Err(FragmentValidityError::DmpAdvancementRule) - } - } - - if candidate.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(), - }) - } - - if candidate.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(), - }) - } - - constraints - .check_modifications(&modifications) - .map_err(FragmentValidityError::OutputsInvalid) -} - -#[cfg(test)] -mod tests { - use super::*; - use polkadot_primitives::vstaging::{ - CollatorPair, HorizontalMessages, OutboundHrmpMessage, ValidationCode, - }; - use sp_application_crypto::Pair; - - #[test] - fn stack_modifications() { - let para_a = ParaId::from(1u32); - let para_b = ParaId::from(2u32); - let para_c = ParaId::from(3u32); - - let a = ConstraintModifications { - required_parent: None, - hrmp_watermark: None, - outbound_hrmp: { - let mut map = HashMap::new(); - map.insert( - para_a, - OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, - ); - - map.insert( - para_b, - OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, - ); - - map - }, - ump_messages_sent: 6, - ump_bytes_sent: 1000, - dmp_messages_processed: 5, - code_upgrade_applied: true, - }; - - let b = ConstraintModifications { - required_parent: None, - hrmp_watermark: None, - outbound_hrmp: { - let mut map = HashMap::new(); - map.insert( - para_b, - OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, - ); - - map.insert( - para_c, - OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, - ); - - map - }, - ump_messages_sent: 6, - ump_bytes_sent: 1000, - dmp_messages_processed: 5, - code_upgrade_applied: true, - }; - - let mut c = a.clone(); - c.stack(&b); - - assert_eq!( - c, - ConstraintModifications { - required_parent: None, - hrmp_watermark: None, - outbound_hrmp: { - let mut map = HashMap::new(); - map.insert( - para_a, - OutboundHrmpChannelModification { - bytes_submitted: 100, - messages_submitted: 5, - }, - ); - - map.insert( - para_b, - OutboundHrmpChannelModification { - bytes_submitted: 200, - messages_submitted: 10, - }, - ); - - map.insert( - para_c, - OutboundHrmpChannelModification { - bytes_submitted: 100, - messages_submitted: 5, - }, - ); - - map - }, - ump_messages_sent: 12, - ump_bytes_sent: 2000, - dmp_messages_processed: 10, - code_upgrade_applied: true, - }, - ); - - let mut d = ConstraintModifications::identity(); - d.stack(&a); - d.stack(&b); - - assert_eq!(c, d); - } - - fn make_constraints() -> Constraints { - let para_a = ParaId::from(1u32); - let para_b = ParaId::from(2u32); - let para_c = ParaId::from(3u32); - - Constraints { - min_relay_parent_number: 5, - max_pov_size: 1000, - max_code_size: 1000, - ump_remaining: 10, - ump_remaining_bytes: 1024, - max_ump_num_per_candidate: 5, - dmp_remaining_messages: Vec::new(), - hrmp_inbound: InboundHrmpLimitations { valid_watermarks: vec![6, 8] }, - hrmp_channels_out: { - let mut map = HashMap::new(); - - map.insert( - para_a, - OutboundHrmpChannelLimitations { messages_remaining: 5, bytes_remaining: 512 }, - ); - - map.insert( - para_b, - OutboundHrmpChannelLimitations { - messages_remaining: 10, - bytes_remaining: 1024, - }, - ); - - map.insert( - para_c, - OutboundHrmpChannelLimitations { messages_remaining: 1, bytes_remaining: 128 }, - ); - - map - }, - max_hrmp_num_per_candidate: 5, - required_parent: HeadData::from(vec![1, 2, 3]), - validation_code_hash: ValidationCode(vec![4, 5, 6]).hash(), - upgrade_restriction: None, - future_validation_code: None, - } - } - - #[test] - fn constraints_disallowed_trunk_watermark() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Trunk(7)); - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::DisallowedHrmpWatermark(7)), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::DisallowedHrmpWatermark(7)), - ); - } - - #[test] - fn constraints_always_allow_head_watermark() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Head(7)); - - assert!(constraints.check_modifications(&modifications).is_ok()); - - let new_constraints = constraints.apply_modifications(&modifications).unwrap(); - assert_eq!(new_constraints.hrmp_inbound.valid_watermarks, vec![8]); - } - - #[test] - fn constraints_no_such_hrmp_channel() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - let bad_para = ParaId::from(100u32); - modifications.outbound_hrmp.insert( - bad_para, - OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 0 }, - ); - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::NoSuchHrmpChannel(bad_para)), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::NoSuchHrmpChannel(bad_para)), - ); - } - - #[test] - fn constraints_hrmp_messages_overflow() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - let para_a = ParaId::from(1u32); - modifications.outbound_hrmp.insert( - para_a, - OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 6 }, - ); - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::HrmpMessagesOverflow { - para_id: para_a, - messages_remaining: 5, - messages_submitted: 6, - }), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::HrmpMessagesOverflow { - para_id: para_a, - messages_remaining: 5, - messages_submitted: 6, - }), - ); - } - - #[test] - fn constraints_hrmp_bytes_overflow() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - let para_a = ParaId::from(1u32); - modifications.outbound_hrmp.insert( - para_a, - OutboundHrmpChannelModification { bytes_submitted: 513, messages_submitted: 1 }, - ); - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::HrmpBytesOverflow { - para_id: para_a, - bytes_remaining: 512, - bytes_submitted: 513, - }), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::HrmpBytesOverflow { - para_id: para_a, - bytes_remaining: 512, - bytes_submitted: 513, - }), - ); - } - - #[test] - fn constraints_ump_messages_overflow() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - modifications.ump_messages_sent = 11; - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::UmpMessagesOverflow { - messages_remaining: 10, - messages_submitted: 11, - }), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::UmpMessagesOverflow { - messages_remaining: 10, - messages_submitted: 11, - }), - ); - } - - #[test] - fn constraints_ump_bytes_overflow() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - modifications.ump_bytes_sent = 1025; - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::UmpBytesOverflow { - bytes_remaining: 1024, - bytes_submitted: 1025, - }), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::UmpBytesOverflow { - bytes_remaining: 1024, - bytes_submitted: 1025, - }), - ); - } - - #[test] - fn constraints_dmp_messages() { - let mut constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - assert!(constraints.check_modifications(&modifications).is_ok()); - assert!(constraints.apply_modifications(&modifications).is_ok()); - - modifications.dmp_messages_processed = 6; - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::DmpMessagesUnderflow { - messages_remaining: 0, - messages_processed: 6, - }), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::DmpMessagesUnderflow { - messages_remaining: 0, - messages_processed: 6, - }), - ); - - constraints.dmp_remaining_messages = vec![1, 4, 8, 10]; - modifications.dmp_messages_processed = 2; - assert!(constraints.check_modifications(&modifications).is_ok()); - let constraints = constraints - .apply_modifications(&modifications) - .expect("modifications are valid"); - - assert_eq!(&constraints.dmp_remaining_messages, &[8, 10]); - } - - #[test] - fn constraints_nonexistent_code_upgrade() { - let constraints = make_constraints(); - let mut modifications = ConstraintModifications::identity(); - modifications.code_upgrade_applied = true; - - assert_eq!( - constraints.check_modifications(&modifications), - Err(ModificationError::AppliedNonexistentCodeUpgrade), - ); - - assert_eq!( - constraints.apply_modifications(&modifications), - Err(ModificationError::AppliedNonexistentCodeUpgrade), - ); - } - - fn make_candidate( - constraints: &Constraints, - relay_parent: &RelayChainBlockInfo, - ) -> ProspectiveCandidate<'static> { - 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 { - 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 { - parent_head: constraints.required_parent.clone(), - relay_parent_number: relay_parent.number, - relay_parent_storage_root: relay_parent.storage_root, - max_pov_size: constraints.max_pov_size as u32, - }, - pov_hash: Hash::repeat_byte(1), - validation_code_hash: constraints.validation_code_hash, - } - } - - #[test] - fn fragment_validation_code_mismatch() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - let mut candidate = make_candidate(&constraints, &relay_parent); - - let expected_code = constraints.validation_code_hash; - let got_code = ValidationCode(vec![9, 9, 9]).hash(); - - candidate.validation_code_hash = got_code; - - assert_eq!( - Fragment::new(relay_parent, constraints, candidate), - Err(FragmentValidityError::ValidationCodeMismatch(expected_code, got_code,)), - ) - } - - #[test] - fn fragment_pvd_mismatch() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let relay_parent_b = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0b), - storage_root: Hash::repeat_byte(0xee), - }; - - let constraints = make_constraints(); - let candidate = make_candidate(&constraints, &relay_parent); - - let expected_pvd = PersistedValidationData { - parent_head: constraints.required_parent.clone(), - relay_parent_number: relay_parent_b.number, - relay_parent_storage_root: relay_parent_b.storage_root, - max_pov_size: constraints.max_pov_size as u32, - }; - - let got_pvd = candidate.persisted_validation_data.clone(); - - assert_eq!( - Fragment::new(relay_parent_b, constraints, candidate), - Err(FragmentValidityError::PersistedValidationDataMismatch(expected_pvd, got_pvd,)), - ); - } - - #[test] - fn fragment_code_size_too_large() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - 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()); - - assert_eq!( - Fragment::new(relay_parent, constraints, candidate), - Err(FragmentValidityError::CodeSizeTooLarge(max_code_size, max_code_size + 1,)), - ); - } - - #[test] - fn fragment_relay_parent_too_old() { - let relay_parent = RelayChainBlockInfo { - number: 3, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - let candidate = make_candidate(&constraints, &relay_parent); - - assert_eq!( - Fragment::new(relay_parent, constraints, candidate), - Err(FragmentValidityError::RelayParentTooOld(5, 3,)), - ); - } - - #[test] - fn fragment_hrmp_messages_overflow() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - let mut candidate = make_candidate(&constraints, &relay_parent); - - let max_hrmp = constraints.max_hrmp_num_per_candidate; - - candidate - .commitments_mut() - .horizontal_messages - .try_extend((0..max_hrmp + 1).map(|i| OutboundHrmpMessage { - recipient: ParaId::from(i as u32), - data: vec![1, 2, 3], - })) - .unwrap(); - - assert_eq!( - Fragment::new(relay_parent, constraints, candidate), - Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { - messages_allowed: max_hrmp, - messages_submitted: max_hrmp + 1, - }), - ); - } - - #[test] - fn fragment_dmp_advancement_rule() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let mut constraints = make_constraints(); - 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()); - // 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()); - - 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()), - Err(FragmentValidityError::DmpAdvancementRule), - ); - } - - candidate.commitments.to_mut().processed_downward_messages = 1; - assert!(Fragment::new(relay_parent, constraints, candidate).is_ok()); - } - - #[test] - fn fragment_ump_messages_overflow() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - let mut candidate = make_candidate(&constraints, &relay_parent); - - let max_ump = constraints.max_ump_num_per_candidate; - - 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), - Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { - messages_allowed: max_ump, - messages_submitted: max_ump + 1, - }), - ); - } - - #[test] - fn fragment_code_upgrade_restricted() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let mut constraints = make_constraints(); - 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])); - - assert_eq!( - Fragment::new(relay_parent, constraints, candidate), - Err(FragmentValidityError::CodeUpgradeRestricted), - ); - } - - #[test] - fn fragment_hrmp_messages_descending_or_duplicate() { - let relay_parent = RelayChainBlockInfo { - number: 6, - hash: Hash::repeat_byte(0x0a), - storage_root: Hash::repeat_byte(0xff), - }; - - let constraints = make_constraints(); - let mut candidate = make_candidate(&constraints, &relay_parent); - - candidate.commitments_mut().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()), - Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), - ); - - candidate.commitments_mut().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), - Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), - ); - } -} diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index daee4a8350e5af321f9a040c2c943879588037bf..a5f3e9d4a0c0e08ebb3b738054ae758f1c98e822 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -43,7 +43,7 @@ use futures::channel::{mpsc, oneshot}; use parity_scale_codec::Encode; use polkadot_primitives::{ - vstaging as vstaging_primitives, AuthorityDiscoveryId, CandidateEvent, CandidateHash, + AsyncBackingParams, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, ValidationCode, ValidationCodeHash, @@ -226,8 +226,8 @@ specialize_requests! { fn request_unapplied_slashes() -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>; UnappliedSlashes; fn request_key_ownership_proof(validator_id: ValidatorId) -> Option; KeyOwnershipProof; fn request_submit_report_dispute_lost(dp: slashing::DisputeProof, okop: slashing::OpaqueKeyOwnershipProof) -> Option<()>; SubmitReportDisputeLost; - - fn request_staging_async_backing_params() -> vstaging_primitives::AsyncBackingParams; StagingAsyncBackingParams; + fn request_disabled_validators() -> Vec; DisabledValidators; + fn request_async_backing_params() -> AsyncBackingParams; AsyncBackingParams; } /// Requests executor parameters from the runtime effective at given relay-parent. First obtains diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index c078b17d217517c3cdb7fcccbfd590adf128bb3f..8d7cef88a70e082779cd6e0892502f27e486c7c6 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,16 +30,16 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, - SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + slashing, AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs, + ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, + ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use crate::{ - request_availability_cores, request_candidate_events, request_from_runtime, - request_key_ownership_proof, request_on_chain_votes, request_session_executor_params, - request_session_index_for_child, request_session_info, request_staging_async_backing_params, + request_async_backing_params, request_availability_cores, request_candidate_events, + request_from_runtime, request_key_ownership_proof, request_on_chain_votes, + request_session_executor_params, request_session_index_for_child, request_session_info, request_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash, request_validator_groups, }; @@ -377,7 +377,7 @@ where pub async fn get_unapplied_slashes( sender: &mut Sender, relay_parent: Hash, -) -> Result> +) -> Result> where Sender: SubsystemSender, { @@ -392,7 +392,7 @@ pub async fn key_ownership_proof( sender: &mut Sender, relay_parent: Hash, validator_id: ValidatorId, -) -> Result> +) -> Result> where Sender: SubsystemSender, { @@ -403,8 +403,8 @@ where pub async fn submit_report_dispute_lost( sender: &mut Sender, relay_parent: Hash, - dispute_proof: vstaging::slashing::DisputeProof, - key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, + dispute_proof: slashing::DisputeProof, + key_ownership_proof: slashing::OpaqueKeyOwnershipProof, ) -> Result> where Sender: SubsystemSender, @@ -429,7 +429,7 @@ where pub enum ProspectiveParachainsMode { /// Runtime API without support of `async_backing_params`: no prospective parachains. Disabled, - /// vstaging runtime API: prospective parachains. + /// v6 runtime API: prospective parachains. Enabled { /// The maximum number of para blocks between the para head in a relay parent /// and a new candidate. Restricts nodes from building arbitrary long chains @@ -457,8 +457,7 @@ pub async fn prospective_parachains_mode( where Sender: SubsystemSender, { - let result = - recv_runtime(request_staging_async_backing_params(relay_parent, sender).await).await; + let result = recv_runtime(request_async_backing_params(relay_parent, sender).await).await; if let Err(error::Error::RuntimeRequest(RuntimeApiError::NotSupported { runtime_api_name })) = &result @@ -472,7 +471,7 @@ where Ok(ProspectiveParachainsMode::Disabled) } else { - let vstaging::AsyncBackingParams { max_candidate_depth, allowed_ancestry_len } = result?; + let AsyncBackingParams { max_candidate_depth, allowed_ancestry_len } = result?; Ok(ProspectiveParachainsMode::Enabled { max_candidate_depth: max_candidate_depth as _, allowed_ancestry_len: allowed_ancestry_len as _, diff --git a/polkadot/node/test/performance-test/Cargo.toml b/polkadot/node/test/performance-test/Cargo.toml deleted file mode 100644 index 5747ac88b1e4f7dc95f80706c4dd749ecfd78f8a..0000000000000000000000000000000000000000 --- a/polkadot/node/test/performance-test/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "polkadot-performance-test" -publish = false -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.workspace = true - -[dependencies] -thiserror = "1.0.48" -quote = "1.0.28" -env_logger = "0.9" -log = "0.4" - -polkadot-node-core-pvf-prepare-worker = { path = "../../core/pvf/prepare-worker" } -polkadot-erasure-coding = { path = "../../../erasure-coding" } -polkadot-node-primitives = { path = "../../primitives" } -polkadot-primitives = { path = "../../../primitives" } - -sc-executor-common = { path = "../../../../substrate/client/executor/common" } -sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob" } - -kusama-runtime = { package = "staging-kusama-runtime", path = "../../../runtime/kusama" } - -[[bin]] -name = "gen-ref-constants" -path = "src/gen_ref_constants.rs" - -[features] -runtime-benchmarks = [ - "kusama-runtime/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", -] diff --git a/polkadot/node/test/performance-test/build.rs b/polkadot/node/test/performance-test/build.rs deleted file mode 100644 index 304b24c3b85f45d0a8a37915499078b095e03965..0000000000000000000000000000000000000000 --- a/polkadot/node/test/performance-test/build.rs +++ /dev/null @@ -1,21 +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 . - -fn main() { - if let Ok(profile) = std::env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); - } -} diff --git a/polkadot/node/test/performance-test/src/constants.rs b/polkadot/node/test/performance-test/src/constants.rs deleted file mode 100644 index 158646ffc6ecf71c5ca06ab8f6e36eb3599074fb..0000000000000000000000000000000000000000 --- a/polkadot/node/test/performance-test/src/constants.rs +++ /dev/null @@ -1,22 +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 . - -//! This file was automatically generated by `gen-ref-constants`. -//! Do not edit manually! - -use std::time::Duration; -pub const PVF_PREPARE_TIME_LIMIT: Duration = Duration::from_millis(4910u64); -pub const ERASURE_CODING_TIME_LIMIT: Duration = Duration::from_millis(466u64); diff --git a/polkadot/node/test/performance-test/src/gen_ref_constants.rs b/polkadot/node/test/performance-test/src/gen_ref_constants.rs deleted file mode 100644 index ba10ed215552da7d6b2960ab9680d1d25535e778..0000000000000000000000000000000000000000 --- a/polkadot/node/test/performance-test/src/gen_ref_constants.rs +++ /dev/null @@ -1,99 +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 . - -//! Generate reference performance check results. - -use polkadot_performance_test::PerfCheckError; - -fn main() -> Result<(), PerfCheckError> { - #[cfg(build_type = "release")] - { - run::run() - } - #[cfg(not(build_type = "release"))] - { - Err(PerfCheckError::WrongBuildType) - } -} - -#[cfg(build_type = "release")] -mod run { - use polkadot_node_primitives::VALIDATION_CODE_BOMB_LIMIT; - use polkadot_performance_test::{ - measure_erasure_coding, measure_pvf_prepare, PerfCheckError, ERASURE_CODING_N_VALIDATORS, - }; - use std::{ - fs::OpenOptions, - io::{self, Write}, - time::Duration, - }; - - const WARM_UP_RUNS: usize = 16; - const FILE_HEADER: &str = include_str!("../../../../file_header.txt"); - const DOC_COMMENT: &str = "//! This file was automatically generated by `gen-ref-constants`.\n//! Do not edit manually!"; - const FILE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/src/constants.rs"); - - fn save_constants(pvf_prepare: Duration, erasure_coding: Duration) -> io::Result<()> { - let mut output = - OpenOptions::new().truncate(true).create(true).write(true).open(FILE_PATH)?; - - writeln!(output, "{}\n\n{}\n", FILE_HEADER, DOC_COMMENT)?; - - let pvf_prepare_millis = pvf_prepare.as_millis() as u64; - let erasure_coding_millis = erasure_coding.as_millis() as u64; - - let token_stream = quote::quote! { - use std::time::Duration; - - pub const PVF_PREPARE_TIME_LIMIT: Duration = Duration::from_millis(#pvf_prepare_millis); - pub const ERASURE_CODING_TIME_LIMIT: Duration = Duration::from_millis(#erasure_coding_millis); - }; - - writeln!(output, "{}", token_stream.to_string())?; - Ok(()) - } - - pub fn run() -> Result<(), PerfCheckError> { - let _ = env_logger::builder().filter(None, log::LevelFilter::Info).try_init(); - - let wasm_code = - polkadot_performance_test::WASM_BINARY.ok_or(PerfCheckError::WasmBinaryMissing)?; - - log::info!("Running the benchmark, number of iterations: {}", WARM_UP_RUNS); - - let code = sp_maybe_compressed_blob::decompress(wasm_code, VALIDATION_CODE_BOMB_LIMIT) - .or(Err(PerfCheckError::CodeDecompressionFailed))?; - - let (pvf_prepare_time, erasure_coding_time) = (1..=WARM_UP_RUNS) - .map(|i| { - if i - 1 > 0 && (i - 1) % 5 == 0 { - log::info!("{} iterations done", i - 1); - } - ( - measure_pvf_prepare(code.as_ref()), - measure_erasure_coding(ERASURE_CODING_N_VALIDATORS, code.as_ref()), - ) - }) - .last() - .expect("`WARM_UP_RUNS` is greater than 1 and thus we have at least one element; qed"); - - save_constants(pvf_prepare_time?, erasure_coding_time?)?; - - log::info!("Successfully stored new reference values at {:?}. Make sure to format the file via `cargo +nightly fmt`", FILE_PATH); - - Ok(()) - } -} diff --git a/polkadot/node/test/performance-test/src/lib.rs b/polkadot/node/test/performance-test/src/lib.rs deleted file mode 100644 index 15073912654a4dd8cb24bae532ab305b5aa453e3..0000000000000000000000000000000000000000 --- a/polkadot/node/test/performance-test/src/lib.rs +++ /dev/null @@ -1,89 +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 Polkadot performance tests utilities. - -use polkadot_erasure_coding::{obtain_chunks, reconstruct}; -use polkadot_primitives::ExecutorParams; -use std::time::{Duration, Instant}; - -mod constants; - -pub use constants::*; -pub use polkadot_node_primitives::VALIDATION_CODE_BOMB_LIMIT; - -/// Value used for reference benchmark of erasure-coding. -pub const ERASURE_CODING_N_VALIDATORS: usize = 1024; - -pub use kusama_runtime::WASM_BINARY; - -#[allow(missing_docs)] -#[derive(thiserror::Error, Debug)] -pub enum PerfCheckError { - #[error("This subcommand is only available in release mode")] - WrongBuildType, - - #[error("No wasm code found for running the performance test")] - WasmBinaryMissing, - - #[error("Failed to decompress wasm code")] - CodeDecompressionFailed, - - #[error(transparent)] - Wasm(#[from] sc_executor_common::error::WasmError), - - #[error(transparent)] - ErasureCoding(#[from] polkadot_erasure_coding::Error), - - #[error(transparent)] - Io(#[from] std::io::Error), - - #[error( - "Performance check not passed: exceeded the {limit:?} time limit, elapsed: {elapsed:?}" - )] - TimeOut { elapsed: Duration, limit: Duration }, -} - -/// Measures the time it takes to compile arbitrary wasm code. -pub fn measure_pvf_prepare(wasm_code: &[u8]) -> Result { - let start = Instant::now(); - - let code = sp_maybe_compressed_blob::decompress(wasm_code, VALIDATION_CODE_BOMB_LIMIT) - .or(Err(PerfCheckError::CodeDecompressionFailed))?; - - // Recreate the pipeline from the pvf prepare worker. - let blob = polkadot_node_core_pvf_prepare_worker::prevalidate(code.as_ref()) - .map_err(PerfCheckError::from)?; - polkadot_node_core_pvf_prepare_worker::prepare(blob, &ExecutorParams::default()) - .map_err(PerfCheckError::from)?; - - Ok(start.elapsed()) -} - -/// Measure the time it takes to break arbitrary data into chunks and reconstruct it back. -pub fn measure_erasure_coding( - n_validators: usize, - data: &[u8], -) -> Result { - let start = Instant::now(); - - let chunks = obtain_chunks(n_validators, &data)?; - let indexed_chunks = chunks.iter().enumerate().map(|(i, chunk)| (chunk.as_slice(), i)); - - let _: Vec = reconstruct(n_validators, indexed_chunks)?; - - Ok(start.elapsed()) -} diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index ce4148b459ee92ade665fc0b015483b5afd098af..1924418a48565e12fa5f1b628943f604ba9c4116 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -11,6 +11,7 @@ futures = "0.3.21" hex = "0.4.3" gum = { package = "tracing-gum", path = "../../gum" } rand = "0.8.5" +serde_json = "1.0.106" tempfile = "3.2.0" tokio = "1.24.2" diff --git a/polkadot/node/test/service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs index 9aadd7d203c0d6ba6197a0b7c55c20172dcd6deb..bedb1250b2a9853a7bcf96867b717cee92f272c5 100644 --- a/polkadot/node/test/service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -20,9 +20,7 @@ use babe_primitives::AuthorityId as BabeId; use grandpa::AuthorityId as GrandpaId; use pallet_staking::Forcing; use polkadot_primitives::{AccountId, AssignmentId, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE}; -use polkadot_service::chain_spec::{ - get_account_id_from_seed, get_from_seed, polkadot_chain_spec_properties, Extensions, -}; +use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed, Extensions}; use polkadot_test_runtime::BABE_GENESIS_EPOCH_CONFIG; use sc_chain_spec::{ChainSpec, ChainType}; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; @@ -36,6 +34,16 @@ const DEFAULT_PROTOCOL_ID: &str = "dot"; pub type PolkadotChainSpec = sc_service::GenericChainSpec; +/// Returns the properties for the [`PolkadotChainSpec`]. +pub fn polkadot_chain_spec_properties() -> serde_json::map::Map { + serde_json::json!({ + "tokenDecimals": 10, + }) + .as_object() + .expect("Map given; qed") + .clone() +} + /// Local testnet config (multivalidator Alice + Bob) pub fn polkadot_local_testnet_config() -> PolkadotChainSpec { PolkadotChainSpec::from_genesis( diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index a2ce15c21db2aba90e1164da278fb26c5d12a3a1..70f2ae769a8f4cd5f59aaf2cc707053f0d3f35e2 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" @@ -39,6 +39,3 @@ sc-service = { path = "../../../../../substrate/client/service" } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } tokio = { version = "1.24.2", features = ["macros"] } - -[features] -network-protocol-staging = [ "polkadot-cli/network-protocol-staging" ] diff --git a/polkadot/parachain/test-parachains/adder/collator/src/cli.rs b/polkadot/parachain/test-parachains/adder/collator/src/cli.rs index 9a865d75b606663b00c51054418582c0280448e7..14b259706835f3649d93af8b3b814f19755f8e62 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/cli.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/cli.rs @@ -80,7 +80,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/polkadot/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 9a5e580af1b9800d73468f07d4ddad18f9370aa0..4569d4e153b19b6858f26acc77089d027e18be13 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs index ab37fe20eebb466ea50b3bae9b0f82fb19814016..cd16133dbf197019bac15e0bca381759eabce5b6 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs @@ -102,7 +102,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/polkadot/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 9121b3790858339352d04c7a4f83eb2800929940..4ba8b8b031fcc330bb66d1ec4bd329809958db07 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -19,8 +19,8 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -// `v5` is currently the latest stable version of the runtime API. -pub mod v5; +// `v6` is currently the latest stable version of the runtime API. +pub mod v6; // The 'staging' version is special - it contains primitives which are // still in development. Once they are considered stable, they will be @@ -33,19 +33,20 @@ pub mod runtime_api; // Current primitives not requiring versioning are exported here. // Primitives requiring versioning must not be exported and must be referred by an exact version. -pub use v5::{ - byzantine_threshold, check_candidate_backing, collator_signature_payload, - effective_minimum_backing_votes, metric_definitions, slashing, supermajority_threshold, - well_known_keys, AbridgedHostConfiguration, AbridgedHrmpChannel, AccountId, AccountIndex, - AccountPublic, ApprovalVote, AssignmentId, AuthorityDiscoveryId, AvailabilityBitfield, - BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, CandidateCommitments, - CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, - CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, CollatorSignature, - CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, CoreState, DisputeState, - DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, ExecutorParam, - ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, - Hash, HashT, HeadData, Header, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, - IndexedVec, InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce, +pub use v6::{ + async_backing, byzantine_threshold, check_candidate_backing, collator_signature_payload, + effective_minimum_backing_votes, executor_params, metric_definitions, slashing, + supermajority_threshold, well_known_keys, AbridgedHostConfiguration, AbridgedHrmpChannel, + AccountId, AccountIndex, AccountPublic, ApprovalVote, AssignmentId, AsyncBackingParams, + AuthorityDiscoveryId, AvailabilityBitfield, BackedCandidate, Balance, BlakeTwo256, Block, + BlockId, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, + CandidateIndex, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, + CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, + CoreIndex, CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, + EncodeAs, ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, + ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, Hash, HashT, HeadData, Header, + HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec, + InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce, OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, PvfPrepTimeoutKind, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, @@ -61,4 +62,4 @@ pub use v5::{ }; #[cfg(feature = "std")] -pub use v5::{AssignmentPair, CollatorPair, ValidatorPair}; +pub use v6::{AssignmentPair, CollatorPair, ValidatorPair}; diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index e5f1aa4276ef5ab993daf02cf778ecf652f4c712..5ec897c8cbb40a7b3fe6a36ead8c72d3479b13e2 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -114,10 +114,11 @@ //! separated from the stable primitives. use crate::{ - vstaging, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, slashing, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use parity_scale_codec::{Decode, Encode}; use polkadot_core_primitives as pcp; @@ -224,38 +225,44 @@ sp_api::decl_runtime_apis! { /// Returns a list of validators that lost a past session dispute and need to be slashed. /// NOTE: This function is only available since parachain host version 5. - fn unapplied_slashes() -> Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>; + fn unapplied_slashes() -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>; /// Returns a merkle proof of a validator session key. /// NOTE: This function is only available since parachain host version 5. fn key_ownership_proof( validator_id: ValidatorId, - ) -> Option; + ) -> Option; /// Submit an unsigned extrinsic to slash validators who lost a dispute about /// a candidate of a past session. /// NOTE: This function is only available since parachain host version 5. fn submit_report_dispute_lost( - dispute_proof: vstaging::slashing::DisputeProof, - key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, + dispute_proof: slashing::DisputeProof, + key_ownership_proof: slashing::OpaqueKeyOwnershipProof, ) -> Option<()>; - /***** Staging *****/ + /***** Added in v6 *****/ /// Get the minimum number of backing votes for a parachain candidate. /// This is a staging method! Do not use on production runtimes! #[api_version(6)] fn minimum_backing_votes() -> u32; - /***** Asynchronous backing *****/ + + /***** Added in v7: Asynchronous backing *****/ /// Returns the state of parachain backing for a given para. - /// This is a staging method! Do not use on production runtimes! - #[api_version(99)] - fn staging_para_backing_state(_: ppp::Id) -> Option>; + #[api_version(7)] + fn para_backing_state(_: ppp::Id) -> Option>; /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. - #[api_version(99)] - fn staging_async_backing_params() -> vstaging::AsyncBackingParams; + #[api_version(7)] + fn async_backing_params() -> AsyncBackingParams; + + /***** Added in v8 *****/ + + /// Returns a list of all disabled validators at the given block. + #[api_version(8)] + fn disabled_validators() -> Vec; } } diff --git a/polkadot/primitives/src/v5/executor_params.rs b/polkadot/primitives/src/v5/executor_params.rs deleted file mode 100644 index 6fbf3037fd6cd8c99780edda33763817dfb11941..0000000000000000000000000000000000000000 --- a/polkadot/primitives/src/v5/executor_params.rs +++ /dev/null @@ -1,153 +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 . - -//! Abstract execution environment parameter set. -//! -//! Parameter set is encoded as an opaque vector which structure depends on the execution -//! environment itself (except for environment type/version which is always represented -//! by the first element of the vector). Decoding to a usable semantics structure is -//! done in `polkadot-node-core-pvf`. - -use crate::{BlakeTwo256, HashT as _, PvfExecTimeoutKind, PvfPrepTimeoutKind}; -use parity_scale_codec::{Decode, Encode}; -use polkadot_core_primitives::Hash; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_std::{ops::Deref, time::Duration, vec, vec::Vec}; - -/// The different executor parameters for changing the execution environment semantics. -#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)] -pub enum ExecutorParam { - /// Maximum number of memory pages (64KiB bytes per page) the executor can allocate. - #[codec(index = 1)] - MaxMemoryPages(u32), - /// Wasm logical stack size limit (max. number of Wasm values on stack) - #[codec(index = 2)] - StackLogicalMax(u32), - /// Executor machine stack size limit, in bytes - #[codec(index = 3)] - StackNativeMax(u32), - /// Max. amount of memory the preparation worker is allowed to use during - /// pre-checking, in bytes - #[codec(index = 4)] - PrecheckingMaxMemory(u64), - /// PVF preparation timeouts, millisec - #[codec(index = 5)] - PvfPrepTimeout(PvfPrepTimeoutKind, u64), - /// PVF execution timeouts, millisec - #[codec(index = 6)] - PvfExecTimeout(PvfExecTimeoutKind, u64), - /// Enables WASM bulk memory proposal - #[codec(index = 7)] - WasmExtBulkMemory, -} - -/// Unit type wrapper around [`type@Hash`] that represents an execution parameter set hash. -/// -/// This type is produced by [`ExecutorParams::hash`]. -#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)] -pub struct ExecutorParamsHash(Hash); - -impl ExecutorParamsHash { - /// Create a new executor parameter hash from `H256` hash - pub fn from_hash(hash: Hash) -> Self { - Self(hash) - } -} - -impl sp_std::fmt::Display for ExecutorParamsHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - self.0.fmt(f) - } -} - -impl sp_std::fmt::Debug for ExecutorParamsHash { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "{:?}", self.0) - } -} - -impl sp_std::fmt::LowerHex for ExecutorParamsHash { - 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. -#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)] -pub struct ExecutorParams(Vec); - -impl ExecutorParams { - /// Creates a new, empty executor parameter set - pub fn new() -> Self { - ExecutorParams(vec![]) - } - - /// Returns hash of the set of execution environment parameters - pub fn hash(&self) -> ExecutorParamsHash { - ExecutorParamsHash(BlakeTwo256::hash(&self.encode())) - } - - /// Returns a PVF preparation timeout, if any - pub fn pvf_prep_timeout(&self, kind: PvfPrepTimeoutKind) -> Option { - for param in &self.0 { - if let ExecutorParam::PvfPrepTimeout(k, timeout) = param { - if kind == *k { - return Some(Duration::from_millis(*timeout)) - } - } - } - None - } - - /// Returns a PVF execution timeout, if any - pub fn pvf_exec_timeout(&self, kind: PvfExecTimeoutKind) -> Option { - for param in &self.0 { - if let ExecutorParam::PvfExecTimeout(k, timeout) = param { - if kind == *k { - return Some(Duration::from_millis(*timeout)) - } - } - } - None - } -} - -impl Deref for ExecutorParams { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From<&[ExecutorParam]> for ExecutorParams { - fn from(arr: &[ExecutorParam]) -> Self { - ExecutorParams(arr.to_vec()) - } -} - -impl Default for ExecutorParams { - fn default() -> Self { - ExecutorParams(vec![]) - } -} diff --git a/polkadot/primitives/src/v6/async_backing.rs b/polkadot/primitives/src/v6/async_backing.rs new file mode 100644 index 0000000000000000000000000000000000000000..1abe87b6dec433122a6918f2f834a4a8e57817e8 --- /dev/null +++ b/polkadot/primitives/src/v6/async_backing.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Asynchronous backing primitives. + +use super::*; + +use parity_scale_codec::{Decode, Encode}; +use primitives::RuntimeDebug; +use scale_info::TypeInfo; + +/// Candidate's acceptance limitations for asynchronous backing per relay parent. +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] + +pub struct AsyncBackingParams { + /// The maximum number of para blocks between the para head in a relay parent + /// and a new candidate. Restricts nodes from building arbitrary long chains + /// and spamming other validators. + /// + /// When async backing is disabled, the only valid value is 0. + pub max_candidate_depth: u32, + /// How many ancestors of a relay parent are allowed to build candidates on top + /// of. + /// + /// When async backing is disabled, the only valid value is 0. + pub allowed_ancestry_len: u32, +} + +/// Constraints on inbound HRMP channels. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct InboundHrmpLimitations { + /// An exhaustive set of all valid watermarks, sorted ascending. + /// + /// It's only expected to contain block numbers at which messages were + /// previously sent to a para, excluding most recent head. + pub valid_watermarks: Vec, +} + +/// Constraints on outbound HRMP channels. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct OutboundHrmpChannelLimitations { + /// The maximum bytes that can be written to the channel. + pub bytes_remaining: u32, + /// The maximum messages that can be written to the channel. + pub messages_remaining: u32, +} + +/// Constraints on the actions that can be taken by a new parachain +/// block. These limitations are implicitly associated with some particular +/// parachain, which should be apparent from usage. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct Constraints { + /// The minimum relay-parent number accepted under these constraints. + pub min_relay_parent_number: N, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: u32, + /// The maximum new validation code size allowed, in bytes. + pub max_code_size: u32, + /// The amount of UMP messages remaining. + pub ump_remaining: u32, + /// The amount of UMP bytes remaining. + pub ump_remaining_bytes: u32, + /// The maximum number of UMP messages allowed per candidate. + pub max_ump_num_per_candidate: u32, + /// Remaining DMP queue. Only includes sent-at block numbers. + pub dmp_remaining_messages: Vec, + /// The limitations of all registered inbound HRMP channels. + pub hrmp_inbound: InboundHrmpLimitations, + /// The limitations of all registered outbound HRMP channels. + pub hrmp_channels_out: Vec<(Id, OutboundHrmpChannelLimitations)>, + /// The maximum number of HRMP messages allowed per candidate. + pub max_hrmp_num_per_candidate: u32, + /// The required parent head-data of the parachain. + pub required_parent: HeadData, + /// The expected validation-code-hash of this parachain. + pub validation_code_hash: ValidationCodeHash, + /// The code upgrade restriction signal as-of this parachain. + pub upgrade_restriction: Option, + /// The future validation code hash, if any, and at what relay-parent + /// number the upgrade would be minimally applied. + pub future_validation_code: Option<(N, ValidationCodeHash)>, +} + +/// A candidate pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct CandidatePendingAvailability { + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// The candidate's descriptor. + pub descriptor: CandidateDescriptor, + /// The commitments of the candidate. + pub commitments: CandidateCommitments, + /// The candidate's relay parent's number. + pub relay_parent_number: N, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: u32, +} + +/// The per-parachain state of the backing system, including +/// state-machine constraints and candidates pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct BackingState { + /// The state-machine constraints of the parachain. + pub constraints: Constraints, + /// The candidates pending availability. These should be ordered, i.e. they should form + /// a sub-chain, where the first candidate builds on top of the required parent of the + /// constraints and each subsequent builds on top of the previous head-data. + pub pending_availability: Vec>, +} diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v6/executor_params.rs new file mode 100644 index 0000000000000000000000000000000000000000..8ea0889bd23b043f7a89e2dae756a6033243421d --- /dev/null +++ b/polkadot/primitives/src/v6/executor_params.rs @@ -0,0 +1,339 @@ +// 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 . + +//! Abstract execution environment parameter set. +//! +//! Parameter set is encoded as an opaque vector which structure depends on the execution +//! environment itself (except for environment type/version which is always represented +//! by the first element of the vector). Decoding to a usable semantics structure is +//! done in `polkadot-node-core-pvf`. + +use crate::{BlakeTwo256, HashT as _, PvfExecTimeoutKind, PvfPrepTimeoutKind}; +use parity_scale_codec::{Decode, Encode}; +use polkadot_core_primitives::Hash; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_std::{collections::btree_map::BTreeMap, ops::Deref, time::Duration, vec, vec::Vec}; + +/// Default maximum number of wasm values allowed for the stack during execution of a PVF. +pub const DEFAULT_LOGICAL_STACK_MAX: u32 = 65536; +/// Default maximum number of bytes devoted for the stack during execution of a PVF. +pub const DEFAULT_NATIVE_STACK_MAX: u32 = 256 * 1024 * 1024; + +/// The limit of [`ExecutorParam::MaxMemoryPages`]. +pub const MEMORY_PAGES_MAX: u32 = 65536; +/// The lower bound of [`ExecutorParam::StackLogicalMax`]. +pub const LOGICAL_MAX_LO: u32 = 1024; +/// The upper bound of [`ExecutorParam::StackLogicalMax`]. +pub const LOGICAL_MAX_HI: u32 = 2 * 65536; +/// The lower bound of [`ExecutorParam::PrecheckingMaxMemory`]. +pub const PRECHECK_MEM_MAX_LO: u64 = 256 * 1024 * 1024; +/// The upper bound of [`ExecutorParam::PrecheckingMaxMemory`]. +pub const PRECHECK_MEM_MAX_HI: u64 = 16 * 1024 * 1024 * 1024; + +// Default PVF timeouts. Must never be changed! Use executor environment parameters to adjust them. +// See also `PvfPrepTimeoutKind` and `PvfExecTimeoutKind` docs. + +/// Default PVF preparation timeout for prechecking requests. +pub const DEFAULT_PRECHECK_PREPARATION_TIMEOUT: Duration = Duration::from_secs(60); +/// Default PVF preparation timeout for execution requests. +pub const DEFAULT_LENIENT_PREPARATION_TIMEOUT: Duration = Duration::from_secs(360); +/// Default PVF execution timeout for backing. +pub const DEFAULT_BACKING_EXECUTION_TIMEOUT: Duration = Duration::from_secs(2); +/// Default PVF execution timeout for approval or disputes. +pub const DEFAULT_APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12); + +const DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS: u64 = + DEFAULT_PRECHECK_PREPARATION_TIMEOUT.as_millis() as u64; +const DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS: u64 = + DEFAULT_LENIENT_PREPARATION_TIMEOUT.as_millis() as u64; +const DEFAULT_BACKING_EXECUTION_TIMEOUT_MS: u64 = + DEFAULT_BACKING_EXECUTION_TIMEOUT.as_millis() as u64; +const DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS: u64 = + DEFAULT_APPROVAL_EXECUTION_TIMEOUT.as_millis() as u64; + +/// The different executor parameters for changing the execution environment semantics. +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)] +pub enum ExecutorParam { + /// Maximum number of memory pages (64KiB bytes per page) the executor can allocate. + /// A valid value lies within (0, 65536]. + #[codec(index = 1)] + MaxMemoryPages(u32), + /// Wasm logical stack size limit (max. number of Wasm values on stack). + /// A valid value lies within [[`LOGICAL_MAX_LO`], [`LOGICAL_MAX_HI`]]. + /// + /// For WebAssembly, the stack limit is subject to implementations, meaning that it may vary on + /// different platforms. However, we want execution to be deterministic across machines of + /// different architectures, including failures like stack overflow. For deterministic + /// overflow, we rely on a **logical** limit, the maximum number of values allowed to be pushed + /// on the stack. + #[codec(index = 2)] + StackLogicalMax(u32), + /// Executor machine stack size limit, in bytes. + /// If `StackLogicalMax` is also present, a valid value should not fall below + /// 128 * `StackLogicalMax`. + /// + /// For deterministic overflow, `StackLogicalMax` should be reached before the native stack is + /// exhausted. + #[codec(index = 3)] + StackNativeMax(u32), + /// Max. amount of memory the preparation worker is allowed to use during + /// pre-checking, in bytes. + /// Valid max. memory ranges from [`PRECHECK_MEM_MAX_LO`] to [`PRECHECK_MEM_MAX_HI`]. + #[codec(index = 4)] + PrecheckingMaxMemory(u64), + /// PVF preparation timeouts, in millisecond. + /// Always ensure that `precheck_timeout` < `lenient_timeout`. + /// When absent, the default values will be used. + #[codec(index = 5)] + PvfPrepTimeout(PvfPrepTimeoutKind, u64), + /// PVF execution timeouts, in millisecond. + /// Always ensure that `backing_timeout` < `approval_timeout`. + /// When absent, the default values will be used. + #[codec(index = 6)] + PvfExecTimeout(PvfExecTimeoutKind, u64), + /// Enables WASM bulk memory proposal + #[codec(index = 7)] + WasmExtBulkMemory, +} + +/// Possible inconsistencies of executor params. +#[derive(Debug)] +pub enum ExecutorParamError { + /// A param is duplicated. + DuplicatedParam(&'static str), + /// A param value exceeds its limitation. + OutsideLimit(&'static str), + /// Two param values are incompatible or senseless when put together. + IncompatibleValues(&'static str, &'static str), +} + +/// Unit type wrapper around [`type@Hash`] that represents an execution parameter set hash. +/// +/// This type is produced by [`ExecutorParams::hash`]. +#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)] +pub struct ExecutorParamsHash(Hash); + +impl ExecutorParamsHash { + /// Create a new executor parameter hash from `H256` hash + pub fn from_hash(hash: Hash) -> Self { + Self(hash) + } +} + +impl sp_std::fmt::Display for ExecutorParamsHash { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + self.0.fmt(f) + } +} + +impl sp_std::fmt::Debug for ExecutorParamsHash { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl sp_std::fmt::LowerHex for ExecutorParamsHash { + 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. +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)] +pub struct ExecutorParams(Vec); + +impl ExecutorParams { + /// Creates a new, empty executor parameter set + pub fn new() -> Self { + ExecutorParams(vec![]) + } + + /// Returns hash of the set of execution environment parameters + pub fn hash(&self) -> ExecutorParamsHash { + ExecutorParamsHash(BlakeTwo256::hash(&self.encode())) + } + + /// Returns a PVF preparation timeout, if any + pub fn pvf_prep_timeout(&self, kind: PvfPrepTimeoutKind) -> Option { + for param in &self.0 { + if let ExecutorParam::PvfPrepTimeout(k, timeout) = param { + if kind == *k { + return Some(Duration::from_millis(*timeout)) + } + } + } + None + } + + /// Returns a PVF execution timeout, if any + pub fn pvf_exec_timeout(&self, kind: PvfExecTimeoutKind) -> Option { + for param in &self.0 { + if let ExecutorParam::PvfExecTimeout(k, timeout) = param { + if kind == *k { + return Some(Duration::from_millis(*timeout)) + } + } + } + None + } + + /// Check params coherence. + pub fn check_consistency(&self) -> Result<(), ExecutorParamError> { + use ExecutorParam::*; + use ExecutorParamError::*; + + let mut seen = BTreeMap::<&str, u64>::new(); + + macro_rules! check { + ($param:ident, $val:expr $(,)?) => { + if seen.contains_key($param) { + return Err(DuplicatedParam($param)) + } + seen.insert($param, $val as u64); + }; + + // should check existence before range + ($param:ident, $val:expr, $out_of_limit:expr $(,)?) => { + if seen.contains_key($param) { + return Err(DuplicatedParam($param)) + } + if $out_of_limit { + return Err(OutsideLimit($param)) + } + seen.insert($param, $val as u64); + }; + } + + for param in &self.0 { + // should ensure to be unique + let param_ident = match *param { + MaxMemoryPages(_) => "MaxMemoryPages", + StackLogicalMax(_) => "StackLogicalMax", + StackNativeMax(_) => "StackNativeMax", + PrecheckingMaxMemory(_) => "PrecheckingMaxMemory", + PvfPrepTimeout(kind, _) => match kind { + PvfPrepTimeoutKind::Precheck => "PvfPrepTimeoutKind::Precheck", + PvfPrepTimeoutKind::Lenient => "PvfPrepTimeoutKind::Lenient", + }, + PvfExecTimeout(kind, _) => match kind { + PvfExecTimeoutKind::Backing => "PvfExecTimeoutKind::Backing", + PvfExecTimeoutKind::Approval => "PvfExecTimeoutKind::Approval", + }, + WasmExtBulkMemory => "WasmExtBulkMemory", + }; + + match *param { + MaxMemoryPages(val) => { + check!(param_ident, val, val == 0 || val > MEMORY_PAGES_MAX,); + }, + + StackLogicalMax(val) => { + check!(param_ident, val, val < LOGICAL_MAX_LO || val > LOGICAL_MAX_HI,); + }, + + StackNativeMax(val) => { + check!(param_ident, val); + }, + + PrecheckingMaxMemory(val) => { + check!( + param_ident, + val, + val < PRECHECK_MEM_MAX_LO || val > PRECHECK_MEM_MAX_HI, + ); + }, + + PvfPrepTimeout(_, val) => { + check!(param_ident, val); + }, + + PvfExecTimeout(_, val) => { + check!(param_ident, val); + }, + + WasmExtBulkMemory => { + check!(param_ident, 1); + }, + } + } + + if let (Some(lm), Some(nm)) = ( + seen.get("StackLogicalMax").or(Some(&(DEFAULT_LOGICAL_STACK_MAX as u64))), + seen.get("StackNativeMax").or(Some(&(DEFAULT_NATIVE_STACK_MAX as u64))), + ) { + if *nm < 128 * *lm { + return Err(IncompatibleValues("StackLogicalMax", "StackNativeMax")) + } + } + + if let (Some(precheck), Some(lenient)) = ( + seen.get("PvfPrepTimeoutKind::Precheck") + .or(Some(&DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS)), + seen.get("PvfPrepTimeoutKind::Lenient") + .or(Some(&DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS)), + ) { + if *precheck >= *lenient { + return Err(IncompatibleValues( + "PvfPrepTimeoutKind::Precheck", + "PvfPrepTimeoutKind::Lenient", + )) + } + } + + if let (Some(backing), Some(approval)) = ( + seen.get("PvfExecTimeoutKind::Backing") + .or(Some(&DEFAULT_BACKING_EXECUTION_TIMEOUT_MS)), + seen.get("PvfExecTimeoutKind::Approval") + .or(Some(&DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS)), + ) { + if *backing >= *approval { + return Err(IncompatibleValues( + "PvfExecTimeoutKind::Backing", + "PvfExecTimeoutKind::Approval", + )) + } + } + + Ok(()) + } +} + +impl Deref for ExecutorParams { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<&[ExecutorParam]> for ExecutorParams { + fn from(arr: &[ExecutorParam]) -> Self { + ExecutorParams(arr.to_vec()) + } +} + +impl Default for ExecutorParams { + fn default() -> Self { + ExecutorParams(vec![]) + } +} diff --git a/polkadot/primitives/src/v5/metrics.rs b/polkadot/primitives/src/v6/metrics.rs similarity index 100% rename from polkadot/primitives/src/v5/metrics.rs rename to polkadot/primitives/src/v6/metrics.rs diff --git a/polkadot/primitives/src/v5/mod.rs b/polkadot/primitives/src/v6/mod.rs similarity index 99% rename from polkadot/primitives/src/v5/mod.rs rename to polkadot/primitives/src/v6/mod.rs index 81743225403d6159fd86a48e5d8e7fa38d84d06a..9371b3db406b3e6247f4ac9c12dc5ba053a77f01 100644 --- a/polkadot/primitives/src/v5/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! `V2` Primitives. +//! `V6` Primitives. use bitvec::vec::BitVec; use parity_scale_codec::{Decode, Encode}; @@ -57,8 +57,13 @@ pub use sp_staking::SessionIndex; mod signed; pub use signed::{EncodeAs, Signed, UncheckedSigned}; +pub mod async_backing; +pub mod executor_params; pub mod slashing; +pub use async_backing::AsyncBackingParams; +pub use executor_params::{ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash}; + mod metrics; pub use metrics::{ metric_definitions, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, @@ -1116,7 +1121,7 @@ pub struct AbridgedHostConfiguration { /// The delay, in blocks, before a validation upgrade is applied. pub validation_upgrade_delay: BlockNumber, /// Asynchronous backing parameters. - pub async_backing_params: super::vstaging::AsyncBackingParams, + pub async_backing_params: AsyncBackingParams, } /// Abridged version of `HrmpChannel` (from the `Hrmp` parachains host runtime module) meant to be @@ -1803,9 +1808,6 @@ pub enum PvfExecTimeoutKind { Approval, } -pub mod executor_params; -pub use executor_params::{ExecutorParam, ExecutorParams, ExecutorParamsHash}; - #[cfg(test)] mod tests { use super::*; diff --git a/polkadot/primitives/src/v5/signed.rs b/polkadot/primitives/src/v6/signed.rs similarity index 100% rename from polkadot/primitives/src/v5/signed.rs rename to polkadot/primitives/src/v6/signed.rs diff --git a/polkadot/primitives/src/v5/slashing.rs b/polkadot/primitives/src/v6/slashing.rs similarity index 100% rename from polkadot/primitives/src/v5/slashing.rs rename to polkadot/primitives/src/v6/slashing.rs diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index ea341ee5b4fc973b587ecd0c23a415b5807c6350..1429b0c326aceef4b9088bd4ddef6828f8dcfbd8 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -17,121 +17,3 @@ //! Staging Primitives. // Put any primitives used by staging APIs functions here -pub use crate::v5::*; -use sp_std::prelude::*; - -use parity_scale_codec::{Decode, Encode}; -use primitives::RuntimeDebug; -use scale_info::TypeInfo; - -/// Useful type alias for Para IDs. -pub type ParaId = Id; - -/// Candidate's acceptance limitations for asynchronous backing per relay parent. -#[derive( - RuntimeDebug, - Copy, - Clone, - PartialEq, - Encode, - Decode, - TypeInfo, - serde::Serialize, - serde::Deserialize, -)] - -pub struct AsyncBackingParams { - /// The maximum number of para blocks between the para head in a relay parent - /// and a new candidate. Restricts nodes from building arbitrary long chains - /// and spamming other validators. - /// - /// When async backing is disabled, the only valid value is 0. - pub max_candidate_depth: u32, - /// How many ancestors of a relay parent are allowed to build candidates on top - /// of. - /// - /// When async backing is disabled, the only valid value is 0. - pub allowed_ancestry_len: u32, -} - -/// Constraints on inbound HRMP channels. -#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] -pub struct InboundHrmpLimitations { - /// An exhaustive set of all valid watermarks, sorted ascending. - /// - /// It's only expected to contain block numbers at which messages were - /// previously sent to a para, excluding most recent head. - pub valid_watermarks: Vec, -} - -/// Constraints on outbound HRMP channels. -#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] -pub struct OutboundHrmpChannelLimitations { - /// The maximum bytes that can be written to the channel. - pub bytes_remaining: u32, - /// The maximum messages that can be written to the channel. - pub messages_remaining: u32, -} - -/// Constraints on the actions that can be taken by a new parachain -/// block. These limitations are implicitly associated with some particular -/// parachain, which should be apparent from usage. -#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] -pub struct Constraints { - /// The minimum relay-parent number accepted under these constraints. - pub min_relay_parent_number: N, - /// The maximum Proof-of-Validity size allowed, in bytes. - pub max_pov_size: u32, - /// The maximum new validation code size allowed, in bytes. - pub max_code_size: u32, - /// The amount of UMP messages remaining. - pub ump_remaining: u32, - /// The amount of UMP bytes remaining. - pub ump_remaining_bytes: u32, - /// The maximum number of UMP messages allowed per candidate. - pub max_ump_num_per_candidate: u32, - /// Remaining DMP queue. Only includes sent-at block numbers. - pub dmp_remaining_messages: Vec, - /// The limitations of all registered inbound HRMP channels. - pub hrmp_inbound: InboundHrmpLimitations, - /// The limitations of all registered outbound HRMP channels. - pub hrmp_channels_out: Vec<(ParaId, OutboundHrmpChannelLimitations)>, - /// The maximum number of HRMP messages allowed per candidate. - pub max_hrmp_num_per_candidate: u32, - /// The required parent head-data of the parachain. - pub required_parent: HeadData, - /// The expected validation-code-hash of this parachain. - pub validation_code_hash: ValidationCodeHash, - /// The code upgrade restriction signal as-of this parachain. - pub upgrade_restriction: Option, - /// The future validation code hash, if any, and at what relay-parent - /// number the upgrade would be minimally applied. - pub future_validation_code: Option<(N, ValidationCodeHash)>, -} - -/// A candidate pending availability. -#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] -pub struct CandidatePendingAvailability { - /// The hash of the candidate. - pub candidate_hash: CandidateHash, - /// The candidate's descriptor. - pub descriptor: CandidateDescriptor, - /// The commitments of the candidate. - pub commitments: CandidateCommitments, - /// The candidate's relay parent's number. - pub relay_parent_number: N, - /// The maximum Proof-of-Validity size allowed, in bytes. - pub max_pov_size: u32, -} - -/// The per-parachain state of the backing system, including -/// state-machine constraints and candidates pending availability. -#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] -pub struct BackingState { - /// The state-machine constraints of the parachain. - pub constraints: Constraints, - /// The candidates pending availability. These should be ordered, i.e. they should form - /// a sub-chain, where the first candidate builds on top of the required parent of the - /// constraints and each subsequent builds on top of the previous head-data. - pub pending_availability: Vec>, -} diff --git a/polkadot/roadmap/implementers-guide/README.md b/polkadot/roadmap/implementers-guide/README.md index 996041f176bb2cbce5446ac2e800fe3e155fb884..e03c0c45ddba009821861cc5ba39a77c7c03dd59 100644 --- a/polkadot/roadmap/implementers-guide/README.md +++ b/polkadot/roadmap/implementers-guide/README.md @@ -4,7 +4,7 @@ The implementers' guide is compiled from several source files with [`mdBook`](ht ## Hosted build -This is available [here](https://paritytech.github.io/polkadot/book/). +This is available [here](https://paritytech.github.io/polkadot-sdk/book/). ## Local build 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 a48444a46e402b6c30e2280f3923db50943ef2ce..286aeddb986d3db3c7077d8d6227ebcf979073cb 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md @@ -122,7 +122,7 @@ prospective validation data. This is unlikely to change. ### Outgoing -- `RuntimeApiRequest::StagingParaBackingState` +- `RuntimeApiRequest::ParaBackingState` - Gets the backing state of the given para (the constraints of the para and candidates pending availability). - `RuntimeApiRequest::AvailabilityCores` diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md index daba416e2639edbd93431a9f65a13120d52d6d25..a9cb2741b0838fb9859435d3e780f16c1025100f 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md @@ -79,7 +79,7 @@ game, so we are not too woried about colluding approval voters getting away slas maintained anyway. There is however a separate problem, from colluding approval-voters, that is "lazy" approval voters. If it were easy and reliable for approval-voters to reconsider their vote, in case of an actual dispute, then they don't have a direct incentive (apart from playing a part in securing the network) to properly run the validation function at -all - they could just always vote "valid" totally risk free. (While they would alwasy risk a slash by voting invalid.) +all - they could just always vote "valid" totally risk free. (While they would always risk a slash by voting invalid.) So we do want to fetch approval votes from approval-voting. Importing votes is most efficient when batched. At the same @@ -125,7 +125,7 @@ moment the dispute concludes! Two concerns that come to mind, are easily address enough: We are worried about lazy approval checkers, the system does not need to be perfect. It should be enough if there is some risk of getting caught. 2. We are not worried about the dispute not concluding, as nodes will always send their own vote, regardless of it being - an explict or an already existing approval-vote. + an explicit or an already existing approval-vote. Conclusion: As long as we make sure, if our own approval vote gets imported (which would prevent dispute participation) to also distribute it via dispute-distribution, disputes can conclude. To mitigate raciness with approval-voting @@ -307,7 +307,7 @@ spam, then spam slots for the disputed candidate hash are cleared. This decremen which had voted invalid. To keep spam slots from filling up unnecessarily we want to clear spam slots whenever a candidate is seen to be backed -or included. Fortunately this behavior is acheived by clearing slots on vote import as described above. Because on chain +or included. Fortunately this behavior is achieved by clearing slots on vote import as described above. Because on chain backing votes are processed when a block backing the disputed candidate is discovered, spam slots are cleared for every backed candidate. Included candidates have also been seen as backed on the same fork, so decrementing spam slots is handled in that case as well. @@ -422,7 +422,7 @@ from them, so they would be an easy DoS target. In summary: The availability system was designed for raising disputes in a meaningful and secure way after availability was reached. Trying to raise disputes before does not meaningfully contribute to the systems security/might even weaken -it as attackers are warned before availability is reached, while at the same time adding signficant amount of +it as attackers are warned before availability is reached, while at the same time adding significant amount of complexity. We therefore punt on such disputes and concentrate on disputes the system was designed to handle. ### No Disputes for Already Finalized Blocks diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md index bcf01b61f2173f024dc50cccacc877534f22aaf2..6a14a3a013d45f2e823be5ef8cf35617e2614dbe 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md @@ -121,10 +121,10 @@ So what are we actually worried about? Things that come to mind: ### Restricting file-system access -A basic security mechanism is to make sure that any thread directly interfacing -with untrusted code does not have access to the file-system. This provides some -protection against attackers accessing sensitive data or modifying data on the -host machine. +A basic security mechanism is to make sure that any process directly interfacing +with untrusted code does not have unnecessary access to the file-system. This +provides some protection against attackers accessing sensitive data or modifying +data on the host machine. ### Clearing env vars diff --git a/polkadot/roadmap/parachains.md b/polkadot/roadmap/parachains.md index 77e9743367673265a86be795715992291369743a..5d6fafffd39a5f908874602a16baeea046966ef1 100644 --- a/polkadot/roadmap/parachains.md +++ b/polkadot/roadmap/parachains.md @@ -178,7 +178,7 @@ It is the responsibility of the full nodes of the _sending_ para to maintain all the link where `b` is less than the watermark of the _receiving_ para. Full nodes of the para will be aware of the head of all MQCs for its channels because they are produced by execution of -the block. This will take collaboration with the Cumulus team (https://github.com/paritytech/cumulus) on APIs. +the block. This will take collaboration with the Cumulus team (https://github.com/paritytech/polkadot-sdk) on APIs. We will need a network where collators of paras can discover and fetch the relevant portion of the MQC incoming from all channels. diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 17617bf4ada3fd6e567c9453656f717266615c5d..2d1aad6a575e7bda03220e433b728192e7ddeba6 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -38,6 +38,7 @@ pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-featur pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } +pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false } pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false } frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } @@ -50,6 +51,7 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac slot-range-helper = { path = "slot_range_helper", default-features = false } xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } [dev-dependencies] hex-literal = "0.4.1" @@ -74,6 +76,7 @@ std = [ "inherents/std", "libsecp256k1/std", "log/std", + "pallet-asset-rate/std", "pallet-authorship/std", "pallet-balances/std", "pallet-election-provider-multi-phase/std", @@ -100,6 +103,7 @@ std = [ "sp-session/std", "sp-staking/std", "sp-std/std", + "xcm-builder/std", "xcm/std", ] runtime-benchmarks = [ @@ -109,6 +113,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "libsecp256k1/hmac", "libsecp256k1/static-context", + "pallet-asset-rate/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", @@ -121,12 +126,14 @@ runtime-benchmarks = [ "runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", "frame-support-test/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-authorship/try-runtime", "pallet-babe?/try-runtime", "pallet-balances/try-runtime", diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 0d0dee2e9ad9187123d3828c71c7f5d208880f7d..590593745ed040652c79e5aab86877862aeff0e4 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -18,8 +18,10 @@ use crate::NegativeImbalance; use frame_support::traits::{Currency, Imbalance, OnUnbalanced}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::Balance; -use sp_runtime::Perquintill; +use sp_runtime::{traits::TryConvert, Perquintill, RuntimeDebug}; +use xcm::VersionedMultiLocation; /// Logic for the author to get a portion of fees. pub struct ToAuthor(sp_std::marker::PhantomData); @@ -98,13 +100,104 @@ pub fn era_payout( (staking_payout, rest) } +/// Versioned locatable asset type which contains both an XCM `location` and `asset_id` to identify +/// an asset which exists on some chain. +#[derive( + Encode, Decode, Eq, PartialEq, Clone, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] +pub enum VersionedLocatableAsset { + #[codec(index = 3)] + V3 { + /// The (relative) location in which the asset ID is meaningful. + location: xcm::v3::MultiLocation, + /// The asset's ID. + asset_id: xcm::v3::AssetId, + }, +} + +/// Converts the [`VersionedLocatableAsset`] to the [`xcm_builder::LocatableAssetId`]. +pub struct LocatableAssetConverter; +impl TryConvert + for LocatableAssetConverter +{ + fn try_convert( + asset: VersionedLocatableAsset, + ) -> Result { + match asset { + VersionedLocatableAsset::V3 { location, asset_id } => + Ok(xcm_builder::LocatableAssetId { asset_id, location }), + } + } +} + +/// Converts the [`VersionedMultiLocation`] to the [`xcm::latest::MultiLocation`]. +pub struct VersionedMultiLocationConverter; +impl TryConvert<&VersionedMultiLocation, xcm::latest::MultiLocation> + for VersionedMultiLocationConverter +{ + fn try_convert( + location: &VersionedMultiLocation, + ) -> Result { + let latest = match location.clone() { + VersionedMultiLocation::V2(l) => l.try_into().map_err(|_| location)?, + VersionedMultiLocation::V3(l) => l, + }; + Ok(latest) + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarks { + use super::VersionedLocatableAsset; + use pallet_asset_rate::AssetKindFactory; + use pallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory; + use xcm::prelude::*; + + /// Provides a factory method for the [`VersionedLocatableAsset`]. + /// The location of the asset is determined as a Parachain with an ID equal to the passed seed. + pub struct AssetRateArguments; + impl AssetKindFactory for AssetRateArguments { + fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { + VersionedLocatableAsset::V3 { + location: xcm::v3::MultiLocation::new(0, X1(Parachain(seed))), + asset_id: xcm::v3::MultiLocation::new( + 0, + X2(PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())), + ) + .into(), + } + } + } + + /// Provide factory methods for the [`VersionedLocatableAsset`] and the `Beneficiary` of the + /// [`VersionedMultiLocation`]. The location of the asset is determined as a Parachain with an + /// ID equal to the passed seed. + pub struct TreasuryArguments; + impl TreasuryArgumentsFactory + for TreasuryArguments + { + fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { + AssetRateArguments::create_asset_kind(seed) + } + fn create_beneficiary(seed: [u8; 32]) -> VersionedMultiLocation { + VersionedMultiLocation::V3(xcm::v3::MultiLocation::new( + 0, + X1(AccountId32 { network: None, id: seed }), + )) + } + } +} + #[cfg(test)] mod tests { use super::*; use frame_support::{ dispatch::DispatchClass, parameter_types, - traits::{ConstU32, FindAuthor}, + traits::{ + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstU32, FindAuthor, + }, weights::Weight, PalletId, }; @@ -189,6 +282,7 @@ mod tests { parameter_types! { pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); } impl pallet_treasury::Config for Test { @@ -208,6 +302,14 @@ mod tests { type MaxApprovals = MaxApprovals; type WeightInfo = (); type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } pub struct OneAuthor; diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index f2751803a413395b11ccc7126c81ee693ab981ce..8b8c6d89d0185c9eb2b1f620f6809890859b37d8 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -29,7 +29,7 @@ use frame_system::{self, ensure_root, ensure_signed}; use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID}; use runtime_parachains::{ configuration, ensure_parachain, - paras::{self, ParaGenesisArgs}, + paras::{self, ParaGenesisArgs, SetGoAhead}, Origin, ParaLifecycle, }; use sp_std::{prelude::*, result}; @@ -412,7 +412,7 @@ pub mod pallet { new_code: ValidationCode, ) -> DispatchResult { Self::ensure_root_para_or_owner(origin, para)?; - runtime_parachains::schedule_code_upgrade::(para, new_code)?; + runtime_parachains::schedule_code_upgrade::(para, new_code, SetGoAhead::No)?; Ok(()) } diff --git a/polkadot/runtime/kusama/Cargo.toml b/polkadot/runtime/kusama/Cargo.toml deleted file mode 100644 index 565b34637e29875169f2de6701e4862f2e7ea984..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/Cargo.toml +++ /dev/null @@ -1,350 +0,0 @@ -[package] -name = "staging-kusama-runtime" -build = "build.rs" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.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"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } -rustc-hex = { version = "2.1.0", default-features = false } -serde = { version = "1.0.188", default-features = false } -serde_derive = { version = "1.0.117", optional = true } -static_assertions = "1.1.0" -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 } -beefy-primitives = { package = "sp-consensus-beefy", path = "../../../substrate/primitives/consensus/beefy", default-features = false } -binary-merkle-tree = { path = "../../../substrate/utils/binary-merkle-tree", default-features = false } -kusama-runtime-constants = { package = "kusama-runtime-constants", path = "constants", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -inherents = { package = "sp-inherents", path = "../../../substrate/primitives/inherents", default-features = false } -offchain-primitives = { package = "sp-offchain", path = "../../../substrate/primitives/offchain", default-features = false } -sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } -sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-storage = { path = "../../../substrate/primitives/storage", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } -tx-pool-api = { package = "sp-transaction-pool", path = "../../../substrate/primitives/transaction-pool", default-features = false } -block-builder-api = { package = "sp-block-builder", path = "../../../substrate/primitives/block-builder", default-features = false } -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false } - -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-bags-list = { path = "../../../substrate/frame/bags-list", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-beefy = { path = "../../../substrate/frame/beefy", default-features = false } -pallet-beefy-mmr = { path = "../../../substrate/frame/beefy-mmr", default-features = false } -pallet-bounties = { path = "../../../substrate/frame/bounties", default-features = false } -pallet-child-bounties = { path = "../../../substrate/frame/child-bounties", 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 } -pallet-nomination-pools-runtime-api = { path = "../../../substrate/frame/nomination-pools/runtime-api", default-features = false } -pallet-collective = { path = "../../../substrate/frame/collective", default-features = false } -pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } -pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false } -pallet-elections-phragmen = { path = "../../../substrate/frame/elections-phragmen", default-features = false } -pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false } -pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } -pallet-nis = { path = "../../../substrate/frame/nis", default-features = false } -pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } -pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } -pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range", default-features = false } -pallet-multisig = { path = "../../../substrate/frame/multisig", default-features = false } -pallet-nomination-pools = { path = "../../../substrate/frame/nomination-pools", default-features = false } -pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } -pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } -pallet-ranked-collective = { path = "../../../substrate/frame/ranked-collective", default-features = false } -pallet-recovery = { path = "../../../substrate/frame/recovery", default-features = false } -pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } -pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -pallet-society = { path = "../../../substrate/frame/society", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migration", default-features = false } -pallet-staking-runtime-api = { path = "../../../substrate/frame/staking/runtime-api", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-tips = { path = "../../../substrate/frame/tips", default-features = false } -pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } -pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } -pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } - -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } -pallet-offences-benchmarking = { path = "../../../substrate/frame/offences/benchmarking", default-features = false, optional = true } -pallet-session-benchmarking = { path = "../../../substrate/frame/session/benchmarking", default-features = false, optional = true } -pallet-nomination-pools-benchmarking = { path = "../../../substrate/frame/nomination-pools/benchmarking", default-features = false, optional = true } -frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -pallet-election-provider-support-benchmarking = { path = "../../../substrate/frame/election-provider-support/benchmarking", default-features = false, optional = true } -hex-literal = "0.4.1" - -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } -runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } -primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } - -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } - -[dev-dependencies] -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -sp-trie = { path = "../../../substrate/primitives/trie" } -separator = "0.4.1" -serde_json = "1.0.107" -remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } -tokio = { version = "1.24.2", features = ["macros"] } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } - -[features] -default = [ "std" ] -no_std = [] -only-staking = [] -std = [ - "authority-discovery-primitives/std", - "babe-primitives/std", - "beefy-primitives/std", - "binary-merkle-tree/std", - "bitvec/std", - "block-builder-api/std", - "frame-benchmarking?/std", - "frame-election-provider-support/std", - "frame-executive/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime/std", - "inherents/std", - "kusama-runtime-constants/std", - "log/std", - "offchain-primitives/std", - "pallet-authority-discovery/std", - "pallet-authorship/std", - "pallet-babe/std", - "pallet-bags-list/std", - "pallet-balances/std", - "pallet-beefy-mmr/std", - "pallet-beefy/std", - "pallet-bounties/std", - "pallet-child-bounties/std", - "pallet-collective/std", - "pallet-conviction-voting/std", - "pallet-democracy/std", - "pallet-election-provider-multi-phase/std", - "pallet-election-provider-support-benchmarking?/std", - "pallet-elections-phragmen/std", - "pallet-fast-unstake/std", - "pallet-grandpa/std", - "pallet-identity/std", - "pallet-im-online/std", - "pallet-indices/std", - "pallet-membership/std", - "pallet-message-queue/std", - "pallet-mmr/std", - "pallet-multisig/std", - "pallet-nis/std", - "pallet-nomination-pools-benchmarking?/std", - "pallet-nomination-pools-runtime-api/std", - "pallet-nomination-pools/std", - "pallet-offences-benchmarking?/std", - "pallet-offences/std", - "pallet-preimage/std", - "pallet-proxy/std", - "pallet-ranked-collective/std", - "pallet-recovery/std", - "pallet-referenda/std", - "pallet-scheduler/std", - "pallet-session-benchmarking?/std", - "pallet-session/std", - "pallet-society/std", - "pallet-staking-runtime-api/std", - "pallet-staking/std", - "pallet-state-trie-migration/std", - "pallet-timestamp/std", - "pallet-tips/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-treasury/std", - "pallet-utility/std", - "pallet-vesting/std", - "pallet-whitelist/std", - "pallet-xcm-benchmarks?/std", - "pallet-xcm/std", - "parity-scale-codec/std", - "primitives/std", - "runtime-common/std", - "runtime-parachains/std", - "rustc-hex/std", - "scale-info/std", - "serde/std", - "serde_derive", - "sp-api/std", - "sp-application-crypto/std", - "sp-arithmetic/std", - "sp-core/std", - "sp-io/std", - "sp-mmr-primitives/std", - "sp-npos-elections/std", - "sp-runtime/std", - "sp-session/std", - "sp-staking/std", - "sp-std/std", - "sp-storage/std", - "sp-tracing/std", - "sp-version/std", - "tx-pool-api/std", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-babe/runtime-benchmarks", - "pallet-bags-list/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-bounties/runtime-benchmarks", - "pallet-child-bounties/runtime-benchmarks", - "pallet-collective/runtime-benchmarks", - "pallet-conviction-voting/runtime-benchmarks", - "pallet-democracy/runtime-benchmarks", - "pallet-election-provider-multi-phase/runtime-benchmarks", - "pallet-election-provider-support-benchmarking/runtime-benchmarks", - "pallet-elections-phragmen/runtime-benchmarks", - "pallet-fast-unstake/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", - "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", - "pallet-indices/runtime-benchmarks", - "pallet-membership/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-mmr/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-nis/runtime-benchmarks", - "pallet-nomination-pools-benchmarking/runtime-benchmarks", - "pallet-nomination-pools/runtime-benchmarks", - "pallet-offences-benchmarking/runtime-benchmarks", - "pallet-offences/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-ranked-collective/runtime-benchmarks", - "pallet-recovery/runtime-benchmarks", - "pallet-referenda/runtime-benchmarks", - "pallet-scheduler/runtime-benchmarks", - "pallet-session-benchmarking/runtime-benchmarks", - "pallet-society/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", - "pallet-state-trie-migration/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-tips/runtime-benchmarks", - "pallet-treasury/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-vesting/runtime-benchmarks", - "pallet-whitelist/runtime-benchmarks", - "pallet-xcm-benchmarks/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "primitives/runtime-benchmarks", - "runtime-common/runtime-benchmarks", - "runtime-parachains/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "sp-staking/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime", - "frame-try-runtime/try-runtime", - "pallet-authority-discovery/try-runtime", - "pallet-authorship/try-runtime", - "pallet-babe/try-runtime", - "pallet-bags-list/try-runtime", - "pallet-balances/try-runtime", - "pallet-beefy-mmr/try-runtime", - "pallet-beefy/try-runtime", - "pallet-bounties/try-runtime", - "pallet-child-bounties/try-runtime", - "pallet-collective/try-runtime", - "pallet-conviction-voting/try-runtime", - "pallet-democracy/try-runtime", - "pallet-election-provider-multi-phase/try-runtime", - "pallet-elections-phragmen/try-runtime", - "pallet-fast-unstake/try-runtime", - "pallet-grandpa/try-runtime", - "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", - "pallet-indices/try-runtime", - "pallet-membership/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-mmr/try-runtime", - "pallet-multisig/try-runtime", - "pallet-nis/try-runtime", - "pallet-nomination-pools/try-runtime", - "pallet-offences/try-runtime", - "pallet-preimage/try-runtime", - "pallet-proxy/try-runtime", - "pallet-ranked-collective/try-runtime", - "pallet-recovery/try-runtime", - "pallet-referenda/try-runtime", - "pallet-scheduler/try-runtime", - "pallet-session/try-runtime", - "pallet-society/try-runtime", - "pallet-staking/try-runtime", - "pallet-state-trie-migration/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-tips/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-treasury/try-runtime", - "pallet-utility/try-runtime", - "pallet-vesting/try-runtime", - "pallet-whitelist/try-runtime", - "pallet-xcm/try-runtime", - "runtime-common/try-runtime", - "runtime-parachains/try-runtime", - "sp-runtime/try-runtime", -] - -# A feature that should be enabled when the runtime should be build for on-chain -# deployment. This will disable stuff that shouldn't be part of the on-chain wasm -# to make it smaller like logging for example. -on-chain-release-build = [ "sp-api/disable-logging" ] - -# Set timing constants (e.g. session period) to faster versions to speed up testing. -fast-runtime = [] - -runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] diff --git a/polkadot/runtime/kusama/constants/Cargo.toml b/polkadot/runtime/kusama/constants/Cargo.toml deleted file mode 100644 index e8daac10cf448d83b60fc062fa044d00dd61c63d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/constants/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "kusama-runtime-constants" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.workspace = true - -[dependencies] -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/kusama/constants/src/lib.rs b/polkadot/runtime/kusama/constants/src/lib.rs deleted file mode 100644 index 78f96b35106503f8b2596e773e3af70e6ff4795e..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/constants/src/lib.rs +++ /dev/null @@ -1,128 +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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod weights; - -/// Money matters. -pub mod currency { - use primitives::Balance; - - /// The existential deposit. - pub const EXISTENTIAL_DEPOSIT: Balance = 1 * CENTS; - - pub const UNITS: Balance = 1_000_000_000_000; - pub const QUID: Balance = UNITS / 30; - pub const CENTS: Balance = QUID / 100; - pub const GRAND: Balance = QUID * 1_000; - pub const MILLICENTS: Balance = CENTS / 1_000; - - pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 2_000 * CENTS + (bytes as Balance) * 100 * MILLICENTS - } -} - -/// Time and blocks. -pub mod time { - use primitives::{BlockNumber, Moment}; - use runtime_common::prod_or_fast; - pub const MILLISECS_PER_BLOCK: Moment = 6000; - pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; - pub const EPOCH_DURATION_IN_SLOTS: BlockNumber = prod_or_fast!(1 * HOURS, 1 * MINUTES); - - // These time units are defined in number of blocks. - pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); - pub const HOURS: BlockNumber = MINUTES * 60; - pub const DAYS: BlockNumber = HOURS * 24; - pub const WEEKS: BlockNumber = DAYS * 7; - - // 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); -} - -/// Fee-related. -pub mod fee { - use crate::weights::ExtrinsicBaseWeight; - use frame_support::weights::{ - WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, - }; - use primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// The block saturation level. Fees will be updates based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); - - /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the - /// node's balance type. - /// - /// This should typically create a mapping between the following ranges: - /// - [0, `MAXIMUM_BLOCK_WEIGHT`] - /// - [Balance::min, Balance::max] - /// - /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: - /// - Setting it to `0` will essentially disable the weight fee. - /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. - pub struct WeightToFee; - impl WeightToFeePolynomial for WeightToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - let p = super::currency::CENTS; - let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -#[cfg(test)] -mod tests { - use super::{ - currency::{CENTS, MILLICENTS}, - fee::WeightToFee, - }; - use crate::weights::ExtrinsicBaseWeight; - use frame_support::weights::WeightToFee as WeightToFeeT; - use runtime_common::MAXIMUM_BLOCK_WEIGHT; - - #[test] - // Test that the fee for `MAXIMUM_BLOCK_WEIGHT` of weight has sane bounds. - fn full_block_fee_is_correct() { - // A full block should cost between 1,000 and 10,000 CENTS. - let full_block = WeightToFee::weight_to_fee(&MAXIMUM_BLOCK_WEIGHT); - assert!(full_block >= 1_000 * CENTS); - assert!(full_block <= 10_000 * CENTS); - } - - #[test] - // This function tests that the fee for `ExtrinsicBaseWeight` of weight is correct - fn extrinsic_base_fee_is_correct() { - // `ExtrinsicBaseWeight` should cost 1/10 of a CENT - println!("Base: {}", ExtrinsicBaseWeight::get()); - let x = WeightToFee::weight_to_fee(&ExtrinsicBaseWeight::get()); - let y = CENTS / 10; - assert!(x.max(y) - x.min(y) < MILLICENTS); - } -} diff --git a/polkadot/runtime/kusama/constants/src/weights/block_weights.rs b/polkadot/runtime/kusama/constants/src/weights/block_weights.rs deleted file mode 100644 index 8423e1f810c551166572a4d86b1c3bea3ba5af2b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/constants/src/weights/block_weights.rs +++ /dev/null @@ -1,81 +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 . - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! -//! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` -//! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/kusama/constants/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark -// overhead -// --chain=kusama-dev -// --execution=wasm -// --wasm-execution=compiled -// --weight-path=runtime/kusama/constants/src/weights/ -// --warmup=10 -// --repeat=100 -// --header=./file_header.txt - -use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; - -parameter_types! { - /// Time to execute an empty block. - /// Calculated by multiplying the *Average* with `1.0` and adding `0`. - /// - /// Stats nanoseconds: - /// Min, Max: 14_012_555, 15_267_251 - /// Average: 14_278_073 - /// Median: 14_244_231 - /// Std-Dev: 180701.37 - /// - /// Percentiles nanoseconds: - /// 99th: 14_916_615 - /// 95th: 14_622_262 - /// 75th: 14_317_299 - pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(14_278_073), 0); -} - -#[cfg(test)] -mod test_weights { - use sp_weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::BlockExecutionWeight::get(); - - // At least 100 µs. - assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 100 µs." - ); - // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); - } -} diff --git a/polkadot/runtime/kusama/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/kusama/constants/src/weights/extrinsic_weights.rs deleted file mode 100644 index 6a2fb7dd206e11de7c79cb7905c2e9a459cabf13..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/constants/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,81 +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 . - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! -//! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` -//! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/kusama/constants/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark -// overhead -// --chain=kusama-dev -// --execution=wasm -// --wasm-execution=compiled -// --weight-path=runtime/kusama/constants/src/weights/ -// --warmup=10 -// --repeat=100 -// --header=./file_header.txt - -use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; - -parameter_types! { - /// Time to execute a NO-OP extrinsic, for example `System::remark`. - /// Calculated by multiplying the *Average* with `1.0` and adding `0`. - /// - /// Stats nanoseconds: - /// Min, Max: 123_598, 126_451 - /// Average: 124_706 - /// Median: 124_675 - /// Std-Dev: 548.81 - /// - /// Percentiles nanoseconds: - /// 99th: 126_070 - /// 95th: 125_605 - /// 75th: 125_041 - pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(124_706), 0); -} - -#[cfg(test)] -mod test_weights { - use sp_weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::ExtrinsicBaseWeight::get(); - - // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); - // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); - } -} diff --git a/polkadot/runtime/kusama/src/bag_thresholds.rs b/polkadot/runtime/kusama/src/bag_thresholds.rs deleted file mode 100644 index 82dc4c3a8119e8e38bdacd767d26f8dd5c4d0a7c..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/bag_thresholds.rs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated voter bag thresholds. -//! -//! Generated on 2021-07-05T14:34:44.453491278+00:00 -//! for the kusama runtime. - -/// Existential weight for this runtime. -#[cfg(any(test, feature = "std"))] -#[allow(unused)] -pub const EXISTENTIAL_WEIGHT: u64 = 33_333_333; - -/// Constant ratio between bags for this runtime. -#[cfg(any(test, feature = "std"))] -#[allow(unused)] -pub const CONSTANT_RATIO: f64 = 1.1455399939091000; - -/// Upper thresholds delimiting the bag list. -pub const THRESHOLDS: [u64; 200] = [ - 33_333_333, - 38_184_666, - 43_742_062, - 50_108_281, - 57_401_040, - 65_755_187, - 75_325_197, - 86_288_026, - 98_846_385, - 113_232_487, - 129_712_342, - 148_590_675, - 170_216_561, - 194_989_878, - 223_368_704, - 255_877_784, - 293_118_235, - 335_778_661, - 384_647_885, - 440_629_536, - 504_758_756, - 578_221_342, - 662_375_673, - 758_777_824, - 869_210_344, - 995_715_212, - 1_140_631_598, - 1_306_639_114, - 1_496_807_363, - 1_714_652_697, - 1_964_203_240, - 2_250_073_368, - 2_577_549_032, - 2_952_685_502, - 3_382_419_332, - 3_874_696_621, - 4_438_619_944, - 5_084_616_664, - 5_824_631_742, - 6_672_348_610, - 7_643_442_186, - 8_755_868_715, - 10_030_197_794, - 11_489_992_720, - 13_162_246_190, - 15_077_879_420, - 17_272_313_899, - 19_786_126_359, - 22_665_799_069, - 25_964_579_327, - 29_743_464_044, - 34_072_327_620, - 39_031_213_974, - 44_711_816_618, - 51_219_174_136, - 58_673_612_428, - 67_212_969_623, - 76_995_144_813, - 88_201_017_720, - 101_037_793_302, - 115_742_833_124, - 132_588_044_352, - 151_884_907_519, - 173_990_236_034, - 199_312_773_927, - 228_320_753_830, - 261_550_554_952, - 299_616_621_127, - 343_222_822_341, - 393_175_469_814, - 450_398_225_296, - 515_949_180_262, - 591_040_420_815, - 677_060_440_060, - 775_599_812_382, - 888_480_604_352, - 1_017_790_066_098, - 1_165_919_226_119, - 1_335_607_103_187, - 1_529_991_352_850, - 1_752_666_285_025, - 2_007_749_325_472, - 2_299_957_150_072, - 2_634_692_899_685, - 3_018_146_088_258, - 3_457_407_051_560, - 3_960_598_052_785, - 4_537_023_469_264, - 5_197_341_837_346, - 5_953_762_936_697, - 6_820_273_558_240, - 7_812_896_130_365, - 8_949_984_985_591, - 10_252_565_745_880, - 11_744_724_102_088, - 13_454_051_176_370, - 15_412_153_702_632, - 17_655_238_458_639, - 20_224_781_756_373, - 23_168_296_370_008, - 26_540_210_082_583, - 30_402_872_096_348, - 34_827_705_916_070, - 39_896_530_022_963, - 45_703_070_759_499, - 52_354_695_399_464, - 59_974_397_449_015, - 68_703_070_888_447, - 78_702_115_407_088, - 90_156_420_804_069, - 103_277_785_738_759, - 118_308_834_046_123, - 135_527_501_032_588, - 155_252_172_707_386, - 177_847_572_977_594, - 203_731_507_665_501, - 233_382_590_050_230, - 267_349_090_784_630, - 306_259_075_829_029, - 350_832_019_859_793, - 401_892_109_893_305, - 460_383_485_119_292, - 527_387_694_739_404, - 604_143_696_619_511, - 692_070_766_545_736, - 792_794_741_693_469, - 908_178_083_570_703, - 1_040_354_316_321_961, - 1_191_767_477_182_765, - 1_365_217_308_553_008, - 1_563_911_027_324_411, - 1_791_522_628_715_580, - 2_052_260_821_186_860, - 2_350_946_848_602_280, - 2_693_103_638_628_474, - 3_085_057_925_791_037, - 3_534_057_237_519_885, - 4_048_403_906_342_940, - 4_637_608_586_213_668, - 5_312_566_111_603_995, - 6_085_756_951_128_531, - 6_971_477_980_728_040, - 7_986_106_843_580_624, - 9_148_404_784_952_770, - 10_479_863_561_632_778, - 12_005_102_840_561_012, - 13_752_325_434_854_380, - 15_753_838_794_879_048, - 18_046_652_397_130_688, - 20_673_162_077_088_732, - 23_681_933_959_870_064, - 27_128_602_484_145_260, - 31_076_899_124_450_156, - 35_599_830_833_736_348, - 40_781_029_996_443_328, - 46_716_300_853_732_512, - 53_515_390_995_440_424, - 61_304_020_674_959_928, - 70_226_207_470_596_936, - 80_446_929_278_126_800, - 92_155_174_875_271_168, - 105_567_438_465_310_176, - 120_931_722_816_550_704, - 138_532_125_018_688_464, - 158_694_089_650_123_072, - 181_790_426_491_212_160, - 208_248_204_055_475_872, - 238_556_646_405_290_848, - 273_276_179_270_092_192, - 313_048_792_736_563_520, - 358_609_912_124_694_080, - 410_801_996_551_064_960, - 470_590_116_626_953_088, - 539_079_799_334_522_496, - 617_537_470_046_187_776, - 707_413_869_675_350_912, - 810_370_879_959_114_368, - 928_312_252_892_475_904, - 1_063_418_812_524_189_696, - 1_218_188_780_021_782_528, - 1_395_483_967_646_286_592, - 1_598_582_695_797_773_824, - 1_831_240_411_607_374_592, - 2_097_759_129_958_809_600, - 2_403_066_980_955_773_440, - 2_752_809_334_727_236_096, - 3_153_453_188_536_351_744, - 3_612_406_746_388_564_480, - 4_138_156_402_255_148_032, - 4_740_423_659_834_265_600, - 5_430_344_890_413_097_984, - 6_220_677_252_688_132_096, - 7_126_034_582_154_840_064, - 8_163_157_611_837_691_904, - 9_351_223_520_943_572_992, - 10_712_200_535_224_332_288, - 12_271_254_135_873_939_456, - 14_057_212_388_066_050_048, - 16_103_098_993_404_108_800, - 18_446_744_073_709_551_615, -]; diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs deleted file mode 100644 index 5cf2b3b83b1fe43cdd298ea82acd75b7234f9166..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/lib.rs +++ /dev/null @@ -1,2738 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! The Kusama runtime. This can be compiled with `#[no_std]`, ready for Wasm. - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit. -#![recursion_limit = "512"] - -use pallet_nis::WithMaximumOf; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use primitives::{ - slashing, AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionInfo, Signature, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, LOWEST_PUBLIC_ID, - PARACHAIN_KEY_TYPE_ID, -}; -use runtime_common::{ - auctions, claims, crowdloan, impl_runtime_weights, impls::DealWithFees, paras_registrar, - prod_or_fast, slots, BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, - SlowAdjustingFeeUpdate, U256ToBalance, -}; -use scale_info::TypeInfo; -use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; - -use runtime_parachains::{ - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, - dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, - inclusion::{AggregateMessageOrigin, UmpQueueId}, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, - runtime_api_impl::v5 as parachains_runtime_api_impl, - scheduler as parachains_scheduler, session_info as parachains_session_info, - shared as parachains_shared, -}; - -use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use beefy_primitives::{ - ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, - mmr::{BeefyDataProvider, MmrLeafVersion}, -}; -use frame_election_provider_support::{ - bounds::ElectionBoundsBuilder, generate_solution_type, onchain, NposSolution, - SequentialPhragmen, -}; -use frame_support::{ - construct_runtime, parameter_types, - traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - StorageMapShim, WithdrawReasons, - }, - weights::{ConstantMultiplier, WeightMeter}, - PalletId, -}; -use frame_system::EnsureRoot; -use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use pallet_session::historical as session_historical; -use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; -use sp_core::{ConstU128, OpaqueMetadata, H256}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, - Keccak256, OpaqueKeys, SaturatedConversion, Verify, - }, - transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, -}; -use sp_staking::SessionIndex; -#[cfg(any(feature = "std", test))] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; -use xcm::latest::Junction; - -pub use frame_system::Call as SystemCall; -pub use pallet_balances::Call as BalancesCall; -pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; -#[cfg(feature = "std")] -pub use pallet_staking::StakerStatus; -use pallet_staking::UseValidatorsMap; -use sp_runtime::traits::Get; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; - -/// Constant values used within the runtime. -use kusama_runtime_constants::{currency::*, fee::*, time::*}; - -// Weights used in the runtime. -mod weights; - -// Voter bag threshold definitions. -mod bag_thresholds; - -// Historical information of society finances. -mod past_payouts; - -// XCM configurations. -pub mod xcm_config; - -// Governance configurations. -pub mod governance; -use governance::{ - pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, StakingAdmin, - Treasurer, TreasurySpender, -}; - -#[cfg(test)] -mod tests; - -impl_runtime_weights!(kusama_runtime_constants); - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -/// Runtime version (Kusama). -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("kusama"), - impl_name: create_runtime_str!("parity-kusama"), - authoring_version: 2, - spec_version: 9430, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 23, - state_version: 1, -}; - -/// The BABE epoch configuration at genesis. -pub const BABE_GENESIS_EPOCH_CONFIG: babe_primitives::BabeEpochConfiguration = - babe_primitives::BabeEpochConfiguration { - c: PRIMARY_PROBABILITY, - allowed_slots: babe_primitives::AllowedSlots::PrimaryAndSecondaryVRFSlots, - }; - -/// Native version. -#[cfg(any(feature = "std", test))] -pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } -} - -/// We currently allow all calls. -pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(_c: &RuntimeCall) -> bool { - true - } -} - -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - pub const SS58Prefix: u8 = 2; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = BlockLength; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = Nonce; - type Hash = Hash; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = AccountIdLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = RocksDbWeight; - type Version = Version; - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = weights::frame_system::WeightInfo; - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; - pub const NoPreimagePostponement: Option = Some(10); -} - -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; - -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { - if left == right { - return Some(Ordering::Equal) - } - - match (left, right) { - // Root is greater than anything. - (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), - // For every other origin we don't care, as they are not used for `ScheduleOrigin`. - _ => None, - } - } -} - -impl pallet_scheduler::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of - // OpenGov to schedule periodic auctions. - // Also allow Treasurer to schedule recurring payments. - type ScheduleOrigin = EitherOf, AuctionAdmin>, Treasurer>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = weights::pallet_scheduler::WeightInfo; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type Preimages = Preimage; -} - -parameter_types! { - pub const PreimageBaseDeposit: Balance = deposit(2, 64); - pub const PreimageByteDeposit: Balance = deposit(0, 1); - pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); -} - -impl pallet_preimage::Config for Runtime { - type WeightInfo = weights::pallet_preimage::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ManagerOrigin = EnsureRoot; - type Consideration = HoldConsideration< - AccountId, - Balances, - PreimageHoldReason, - LinearStoragePrice, - >; -} - -parameter_types! { - pub EpochDuration: u64 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS as u64, - 2 * MINUTES as u64, - "KSM_EPOCH_DURATION" - ); - pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; - pub ReportLongevity: u64 = - BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); -} - -impl pallet_babe::Config for Runtime { - type EpochDuration = EpochDuration; - type ExpectedBlockTime = ExpectedBlockTime; - - // session module is the trigger - type EpochChangeTrigger = pallet_babe::ExternalTrigger; - - type DisabledValidators = Session; - - type KeyOwnerProof = - >::Proof; - - type EquivocationReportSystem = - pallet_babe::EquivocationReportSystem; - - type WeightInfo = (); - - type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; -} - -parameter_types! { - pub const IndexDeposit: Balance = 100 * CENTS; -} - -impl pallet_indices::Config for Runtime { - type AccountIndex = AccountIndex; - type Currency = Balances; - type Deposit = IndexDeposit; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_indices::WeightInfo; -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = weights::pallet_balances::WeightInfo; - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = RuntimeHoldReason; - type MaxHolds = ConstU32<1>; -} - -parameter_types! { - pub BeefySetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); -} - -impl pallet_beefy::Config for Runtime { - type BeefyId = BeefyId; - type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; - type MaxSetIdSessionEntries = BeefySetIdSessionEntries; - type OnNewValidatorSet = BeefyMmrLeaf; - type WeightInfo = (); - type KeyOwnerProof = >::Proof; - type EquivocationReportSystem = - pallet_beefy::EquivocationReportSystem; -} - -impl pallet_mmr::Config for Runtime { - const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; - type Hashing = Keccak256; - type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); - type LeafData = pallet_beefy_mmr::Pallet; -} - -/// MMR helper types. -mod mmr { - use super::Runtime; - pub use pallet_mmr::primitives::*; - - pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; - pub type Hashing = ::Hashing; - pub type Hash = ::Output; -} - -parameter_types! { - /// Version of the produced MMR leaf. - /// - /// The version consists of two parts; - /// - `major` (3 bits) - /// - `minor` (5 bits) - /// - /// `major` should be updated only if decoding the previous MMR Leaf format from the payload - /// is not possible (i.e. backward incompatible change). - /// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE - /// encoding does not prevent old leafs from being decoded. - /// - /// Hence we expect `major` to be changed really rarely (think never). - /// See [`MmrLeafVersion`] type documentation for more details. - pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); -} - -/// A BEEFY data provider that merkelizes all the parachain heads at the current block -/// (sorted by their parachain id). -pub struct ParaHeadsRootProvider; -impl BeefyDataProvider for ParaHeadsRootProvider { - fn extra_data() -> H256 { - let mut para_heads: Vec<(u32, Vec)> = Paras::parachains() - .into_iter() - .filter_map(|id| Paras::para_head(&id).map(|head| (id.into(), head.0))) - .collect(); - para_heads.sort_by_key(|k| k.0); - binary_merkle_tree::merkle_root::( - para_heads.into_iter().map(|pair| pair.encode()), - ) - .into() - } -} - -impl pallet_beefy_mmr::Config for Runtime { - type LeafVersion = LeafVersion; - type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; - type LeafExtra = H256; - type BeefyDataProvider = ParaHeadsRootProvider; -} - -parameter_types! { - pub const TransactionByteFee: Balance = 10 * MILLICENTS; - /// This value increases the priority of `Operational` transactions by adding - /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`. - pub const OperationalFeeMultiplier: u8 = 5; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter>; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; -} - -parameter_types! { - pub const MinimumPeriod: u64 = SLOT_DURATION / 2; -} -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = Babe; - type MinimumPeriod = MinimumPeriod; - type WeightInfo = weights::pallet_timestamp::WeightInfo; -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (Staking, ImOnline); -} - -impl_opaque_keys! { - pub struct OldSessionKeys { - pub grandpa: Grandpa, - pub babe: Babe, - pub im_online: ImOnline, - pub para_validator: Initializer, - pub para_assignment: ParaSessionInfo, - pub authority_discovery: AuthorityDiscovery, - } -} - -impl_opaque_keys! { - pub struct SessionKeys { - pub grandpa: Grandpa, - pub babe: Babe, - pub im_online: ImOnline, - pub para_validator: Initializer, - pub para_assignment: ParaSessionInfo, - pub authority_discovery: AuthorityDiscovery, - pub beefy: Beefy, - } -} - -// remove this when removing `OldSessionKeys` -fn transform_session_keys(v: AccountId, old: OldSessionKeys) -> SessionKeys { - SessionKeys { - grandpa: old.grandpa, - babe: old.babe, - im_online: old.im_online, - para_validator: old.para_validator, - para_assignment: old.para_assignment, - authority_discovery: old.authority_discovery, - beefy: { - // From Session::upgrade_keys(): - // - // Care should be taken that the raw versions of the - // added keys are unique for every `ValidatorId, KeyTypeId` combination. - // This is an invariant that the session pallet typically maintains internally. - // - // So, produce a dummy value that's unique for the `ValidatorId, KeyTypeId` combination. - let mut id: BeefyId = sp_application_crypto::ecdsa::Public::from_raw([0u8; 33]).into(); - let id_raw: &mut [u8] = id.as_mut(); - id_raw[1..33].copy_from_slice(v.as_ref()); - id_raw[0..4].copy_from_slice(b"beef"); - id - }, - } -} - -impl pallet_session::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = AccountId; - type ValidatorIdOf = pallet_staking::StashOf; - type ShouldEndSession = Babe; - type NextSessionRotation = Babe; - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - type WeightInfo = weights::pallet_session::WeightInfo; -} - -impl pallet_session::historical::Config for Runtime { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -parameter_types! { - // phase durations. 1/4 of the last session for each. - // in testing: 1min or half of the session for each - pub SignedPhase: u32 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS / 4, - (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2), - "KSM_SIGNED_PHASE" - ); - pub UnsignedPhase: u32 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS / 4, - (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2), - "KSM_UNSIGNED_PHASE" - ); - - // signed config - pub const SignedMaxSubmissions: u32 = 16; - pub const SignedMaxRefunds: u32 = 16 / 4; - pub const SignedFixedDeposit: Balance = deposit(2, 0); - pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); - pub const SignedDepositByte: Balance = deposit(0, 10) / 1024; - // Each good submission will get 1/10 KSM as reward - pub SignedRewardBase: Balance = UNITS / 10; - pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(5u32, 10_000); - - // 1 hour session, 15 minutes unsigned phase, 8 offchain executions. - pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 8; - - pub const MaxElectingVoters: u32 = 12_500; - /// We take the top 12500 nominators as electing voters and all of the validators as electable - /// targets. Whilst this is the case, we cannot and shall not increase the size of the - /// validator intentions. - pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = - ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); - pub NposSolutionPriority: TransactionPriority = - Perbill::from_percent(90) * TransactionPriority::max_value(); - /// Setup election pallet to support maximum winners upto 2000. This will mean Staking Pallet - /// cannot have active validators higher than this count. - pub const MaxActiveValidators: u32 = 2000; -} - -generate_solution_type!( - #[compact] - pub struct NposCompactSolution24::< - VoterIndex = u32, - TargetIndex = u16, - Accuracy = sp_runtime::PerU16, - MaxVoters = MaxElectingVoters, - >(24) -); - -pub struct OnChainSeqPhragmen; -impl onchain::Config for OnChainSeqPhragmen { - type System = Runtime; - type Solver = SequentialPhragmen; - type DataProvider = Staking; - type WeightInfo = weights::frame_election_provider_support::WeightInfo; - type MaxWinners = MaxActiveValidators; - type Bounds = ElectionBounds; -} - -impl pallet_election_provider_multi_phase::MinerConfig for Runtime { - type AccountId = AccountId; - type MaxLength = OffchainSolutionLengthLimit; - type MaxWeight = OffchainSolutionWeightLimit; - type Solution = NposCompactSolution24; - type MaxVotesPerVoter = < - ::DataProvider - as - frame_election_provider_support::ElectionDataProvider - >::MaxVotesPerVoter; - type MaxWinners = MaxActiveValidators; - - // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their - // weight estimate function is wired to this call's weight. - fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { - < - ::WeightInfo - as - pallet_election_provider_multi_phase::WeightInfo - >::submit_unsigned(v, t, a, d) - } -} - -impl pallet_election_provider_multi_phase::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EstimateCallFee = TransactionPayment; - type UnsignedPhase = UnsignedPhase; - type SignedMaxSubmissions = SignedMaxSubmissions; - type SignedMaxRefunds = SignedMaxRefunds; - type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = - GeometricDepositBase; - type SignedDepositByte = SignedDepositByte; - type SignedDepositWeight = (); - type SignedMaxWeight = - ::MaxWeight; - type MinerConfig = Self; - type SlashHandler = (); // burn slashes - type RewardHandler = (); // nothing to do upon rewards - type SignedPhase = SignedPhase; - type BetterUnsignedThreshold = BetterUnsignedThreshold; - type BetterSignedThreshold = (); - type OffchainRepeat = OffchainRepeat; - type MinerTxPriority = NposSolutionPriority; - type DataProvider = Staking; - #[cfg(any(feature = "fast-runtime", feature = "runtime-benchmarks"))] - type Fallback = onchain::OnChainExecution; - #[cfg(not(any(feature = "fast-runtime", feature = "runtime-benchmarks")))] - type Fallback = frame_election_provider_support::NoElection<( - AccountId, - BlockNumber, - Staking, - MaxActiveValidators, - )>; - type GovernanceFallback = onchain::OnChainExecution; - type Solver = SequentialPhragmen< - AccountId, - pallet_election_provider_multi_phase::SolutionAccuracyOf, - (), - >; - type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; - type ForceOrigin = EitherOf, StakingAdmin>; - type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxWinners = MaxActiveValidators; - type ElectionBounds = ElectionBounds; -} - -parameter_types! { - pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS; -} - -type VoterBagsListInstance = pallet_bags_list::Instance1; -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ScoreProvider = Staking; - type WeightInfo = weights::pallet_bags_list::WeightInfo; - type BagThresholds = BagThresholds; - type Score = sp_npos_elections::VoteWeight; -} - -pub struct EraPayout; -impl pallet_staking::EraPayout for EraPayout { - fn era_payout( - total_staked: Balance, - _total_issuance: Balance, - era_duration_millis: u64, - ) -> (Balance, Balance) { - // all para-ids that are currently active. - let auctioned_slots = Paras::parachains() - .into_iter() - // all active para-ids that do not belong to a system chain is the number - // of parachains that we should take into account for inflation. - .filter(|i| *i >= LOWEST_PUBLIC_ID) - .count() as u64; - - const MAX_ANNUAL_INFLATION: Perquintill = Perquintill::from_percent(10); - const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; - - runtime_common::impls::era_payout( - total_staked, - Nis::issuance().other, - MAX_ANNUAL_INFLATION, - Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR), - auctioned_slots, - ) - } -} - -parameter_types! { - // Six sessions in an era (6 hours). - pub const SessionsPerEra: SessionIndex = prod_or_fast!(6, 1); - - // 28 eras for unbonding (7 days). - pub BondingDuration: sp_staking::EraIndex = prod_or_fast!( - 28, - 28, - "DOT_BONDING_DURATION" - ); - // 27 eras in which slashes can be cancelled (slightly less than 7 days). - pub SlashDeferDuration: sp_staking::EraIndex = prod_or_fast!( - 27, - 27, - "DOT_SLASH_DEFER_DURATION" - ); - pub const MaxNominatorRewardedPerValidator: u32 = 512; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); - // 24 - pub const MaxNominations: u32 = ::LIMIT as u32; -} - -impl pallet_staking::Config for Runtime { - type Currency = Balances; - type CurrencyBalance = Balance; - type UnixTime = Timestamp; - type CurrencyToVote = CurrencyToVote; - type ElectionProvider = ElectionProviderMultiPhase; - type GenesisElectionProvider = onchain::OnChainExecution; - type RewardRemainder = Treasury; - type RuntimeEvent = RuntimeEvent; - type Slash = Treasury; - type Reward = (); - type SessionsPerEra = SessionsPerEra; - type BondingDuration = BondingDuration; - type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = EitherOf, StakingAdmin>; - type SessionInterface = Self; - type EraPayout = EraPayout; - type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type VoterList = VoterList; - type TargetList = UseValidatorsMap; - type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; - type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; - type HistoryDepth = frame_support::traits::ConstU32<84>; - type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; - type EventListeners = NominationPools; - type WeightInfo = weights::pallet_staking::WeightInfo; -} - -impl pallet_fast_unstake::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BatchSize = frame_support::traits::ConstU32<64>; - type Deposit = frame_support::traits::ConstU128<{ CENTS * 100 }>; - type ControlOrigin = EnsureRoot; - type Staking = Staking; - type MaxErasToCheckPerBlock = ConstU32<1>; - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; - type WeightInfo = weights::pallet_fast_unstake::WeightInfo; -} - -parameter_types! { - pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: Balance = 2000 * CENTS; - pub const ProposalBondMaximum: Balance = 1 * GRAND; - pub const SpendPeriod: BlockNumber = 6 * DAYS; - pub const Burn: Permill = Permill::from_perthousand(2); - pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - - pub const TipCountdown: BlockNumber = 1 * DAYS; - pub const TipFindersFee: Percent = Percent::from_percent(20); - pub const TipReportDepositBase: Balance = 100 * CENTS; - pub const DataDepositPerByte: Balance = 1 * CENTS; - pub const MaxApprovals: u32 = 100; - pub const MaxAuthorities: u32 = 100_000; - pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; -} - -impl pallet_treasury::Config for Runtime { - type PalletId = TreasuryPalletId; - type Currency = Balances; - type ApproveOrigin = EitherOfDiverse, Treasurer>; - type RejectOrigin = EitherOfDiverse, Treasurer>; - type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; - type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type ProposalBondMaximum = ProposalBondMaximum; - type SpendPeriod = SpendPeriod; - type Burn = Burn; - type BurnDestination = Society; - type MaxApprovals = MaxApprovals; - type WeightInfo = weights::pallet_treasury::WeightInfo; - type SpendFunds = Bounties; - type SpendOrigin = TreasurySpender; -} - -parameter_types! { - pub const BountyDepositBase: Balance = 100 * CENTS; - pub const BountyDepositPayoutDelay: BlockNumber = 4 * DAYS; - pub const BountyUpdatePeriod: BlockNumber = 90 * DAYS; - pub const MaximumReasonLength: u32 = 16384; - pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); - pub const CuratorDepositMin: Balance = 10 * CENTS; - pub const CuratorDepositMax: Balance = 500 * CENTS; - pub const BountyValueMinimum: Balance = 200 * CENTS; -} - -impl pallet_bounties::Config for Runtime { - type BountyDepositBase = BountyDepositBase; - type BountyDepositPayoutDelay = BountyDepositPayoutDelay; - type BountyUpdatePeriod = BountyUpdatePeriod; - type CuratorDepositMultiplier = CuratorDepositMultiplier; - type CuratorDepositMin = CuratorDepositMin; - type CuratorDepositMax = CuratorDepositMax; - type BountyValueMinimum = BountyValueMinimum; - type ChildBountyManager = ChildBounties; - type DataDepositPerByte = DataDepositPerByte; - type RuntimeEvent = RuntimeEvent; - type MaximumReasonLength = MaximumReasonLength; - type WeightInfo = weights::pallet_bounties::WeightInfo; -} - -parameter_types! { - pub const MaxActiveChildBountyCount: u32 = 100; - pub const ChildBountyValueMinimum: Balance = BountyValueMinimum::get() / 10; -} - -impl pallet_child_bounties::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type MaxActiveChildBountyCount = MaxActiveChildBountyCount; - type ChildBountyValueMinimum = ChildBountyValueMinimum; - type WeightInfo = weights::pallet_child_bounties::WeightInfo; -} - -impl pallet_offences::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type IdentificationTuple = pallet_session::historical::IdentificationTuple; - type OnOffenceHandler = Staking; -} - -impl pallet_authority_discovery::Config for Runtime { - type MaxAuthorities = MaxAuthorities; -} - -parameter_types! { - pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); -} - -impl pallet_im_online::Config for Runtime { - type AuthorityId = ImOnlineId; - type RuntimeEvent = RuntimeEvent; - type ValidatorSet = Historical; - type NextSessionRotation = Babe; - type ReportUnresponsiveness = Offences; - type UnsignedPriority = ImOnlineUnsignedPriority; - type WeightInfo = weights::pallet_im_online::WeightInfo; - type MaxKeys = MaxKeys; - type MaxPeerInHeartbeats = MaxPeerInHeartbeats; -} - -parameter_types! { - pub MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); -} - -impl pallet_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - - type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; - type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - - type KeyOwnerProof = >::Proof; - - type EquivocationReportSystem = - pallet_grandpa::EquivocationReportSystem; -} - -/// Submits transaction with the node's public and signature type. Adheres to the signed extension -/// format of the chain. -impl frame_system::offchain::CreateSignedTransaction for Runtime -where - RuntimeCall: From, -{ - fn create_transaction>( - call: RuntimeCall, - public: ::Signer, - account: AccountId, - nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { - use sp_runtime::traits::StaticLookup; - // take the biggest period possible. - let period = - BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; - - let current_block = System::block_number() - .saturated_into::() - // The `System::block_number` is initialized with `n+1`, - // so the actual block number is `n`. - .saturating_sub(1); - let tip = 0; - let extra: SignedExtra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(generic::Era::mortal( - period, - current_block, - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); - let raw_payload = SignedPayload::new(call, extra) - .map_err(|e| { - log::warn!("Unable to create signed payload: {:?}", e); - }) - .ok()?; - let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); - let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) - } -} - -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; -} - -impl frame_system::offchain::SendTransactionTypes for Runtime -where - RuntimeCall: From, -{ - type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; -} - -parameter_types! { - pub Prefix: &'static [u8] = b"Pay KSMs to the Kusama account:"; -} - -impl claims::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type VestingSchedule = Vesting; - type Prefix = Prefix; - type MoveClaimOrigin = EnsureRoot; - type WeightInfo = weights::runtime_common_claims::WeightInfo; -} - -parameter_types! { - // Minimum 100 bytes/KSM deposited (1 CENT/byte) - pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain - pub const FieldDeposit: Balance = 250 * CENTS; // 66 bytes on-chain - pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain - pub const MaxSubAccounts: u32 = 100; - pub const MaxAdditionalFields: u32 = 100; - pub const MaxRegistrars: u32 = 20; -} - -impl pallet_identity::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; - type MaxRegistrars = MaxRegistrars; - type Slashed = Treasury; - type ForceOrigin = EitherOf, GeneralAdmin>; - type RegistrarOrigin = EitherOf, GeneralAdmin>; - type WeightInfo = weights::pallet_identity::WeightInfo; -} - -impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = weights::pallet_utility::WeightInfo; -} - -parameter_types! { - // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. - pub const DepositBase: Balance = deposit(1, 88); - // Additional storage item size of 32 bytes. - pub const DepositFactor: Balance = deposit(0, 32); - pub const MaxSignatories: u32 = 100; -} - -impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = MaxSignatories; - type WeightInfo = weights::pallet_multisig::WeightInfo; -} - -parameter_types! { - pub const ConfigDepositBase: Balance = 500 * CENTS; - pub const FriendDepositFactor: Balance = 50 * CENTS; - pub const MaxFriends: u16 = 9; - pub const RecoveryDeposit: Balance = 500 * CENTS; -} - -impl pallet_recovery::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ConfigDepositBase = ConfigDepositBase; - type FriendDepositFactor = FriendDepositFactor; - type MaxFriends = MaxFriends; - type RecoveryDeposit = RecoveryDeposit; -} - -parameter_types! { - pub const SocietyPalletId: PalletId = PalletId(*b"py/socie"); -} - -impl pallet_society::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type GraceStrikes = ConstU32<10>; - type PeriodSpend = ConstU128<{ 500 * QUID }>; - type VotingPeriod = ConstU32<{ 5 * DAYS }>; - type ClaimPeriod = ConstU32<{ 2 * DAYS }>; - type MaxLockDuration = ConstU32<{ 36 * 30 * DAYS }>; - type FounderSetOrigin = EnsureRoot; - type ChallengePeriod = ConstU32<{ 7 * DAYS }>; - type MaxPayouts = ConstU32<8>; - type MaxBids = ConstU32<512>; - type PalletId = SocietyPalletId; - type WeightInfo = weights::pallet_society::WeightInfo; -} - -parameter_types! { - pub const MinVestedTransfer: Balance = 100 * CENTS; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); -} - -impl pallet_vesting::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BlockNumberToBalance = ConvertInto; - type MinVestedTransfer = MinVestedTransfer; - type WeightInfo = weights::pallet_vesting::WeightInfo; - type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - const MAX_VESTING_SCHEDULES: u32 = 28; -} - -parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 8); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 32; - pub const AnnouncementDepositBase: Balance = deposit(1, 8); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 32; -} - -/// The type used to represent the kinds of proxying allowed. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - TypeInfo, -)] -pub enum ProxyType { - Any, - NonTransfer, - Governance, - Staking, - IdentityJudgement, - CancelProxy, - Auction, - Society, - NominationPools, -} - -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} - -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::NonTransfer => matches!( - c, - RuntimeCall::System(..) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(pallet_indices::Call::claim {..}) | - RuntimeCall::Indices(pallet_indices::Call::free {..}) | - RuntimeCall::Indices(pallet_indices::Call::freeze {..}) | - // Specifically omitting Indices `transfer`, `force_transfer` - // Specifically omitting the entire Balances pallet - RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda(..) | - RuntimeCall::FellowshipCollective(..) | - RuntimeCall::FellowshipReferenda(..) | - RuntimeCall::Whitelist(..) | - RuntimeCall::Claims(..) | - RuntimeCall::Utility(..) | - RuntimeCall::Identity(..) | - RuntimeCall::Society(..) | - RuntimeCall::Recovery(pallet_recovery::Call::as_recovered {..}) | - RuntimeCall::Recovery(pallet_recovery::Call::vouch_recovery {..}) | - RuntimeCall::Recovery(pallet_recovery::Call::claim_recovery {..}) | - RuntimeCall::Recovery(pallet_recovery::Call::close_recovery {..}) | - RuntimeCall::Recovery(pallet_recovery::Call::remove_recovery {..}) | - RuntimeCall::Recovery(pallet_recovery::Call::cancel_recovered {..}) | - // Specifically omitting Recovery `create_recovery`, `initiate_recovery` - RuntimeCall::Vesting(pallet_vesting::Call::vest {..}) | - RuntimeCall::Vesting(pallet_vesting::Call::vest_other {..}) | - // Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer` - RuntimeCall::Scheduler(..) | - RuntimeCall::Proxy(..) | - RuntimeCall::Multisig(..) | - RuntimeCall::Nis(..) | - RuntimeCall::Registrar(paras_registrar::Call::register {..}) | - RuntimeCall::Registrar(paras_registrar::Call::deregister {..}) | - // Specifically omitting Registrar `swap` - RuntimeCall::Registrar(paras_registrar::Call::reserve {..}) | - RuntimeCall::Crowdloan(..) | - RuntimeCall::Slots(..) | - RuntimeCall::Auctions(..) | // Specifically omitting the entire XCM Pallet - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools(..) | - RuntimeCall::FastUnstake(..) - ), - ProxyType::Governance => matches!( - c, - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::Utility(..) | - RuntimeCall::ChildBounties(..) | - // OpenGov calls - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda(..) | - RuntimeCall::FellowshipCollective(..) | - RuntimeCall::FellowshipReferenda(..) | - RuntimeCall::Whitelist(..) - ), - ProxyType::Staking => { - matches!( - c, - RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | - RuntimeCall::FastUnstake(..) | - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools(..) - ) - }, - ProxyType::NominationPools => { - matches!(c, RuntimeCall::NominationPools(..) | RuntimeCall::Utility(..)) - }, - ProxyType::IdentityJudgement => matches!( - c, - RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | - RuntimeCall::Utility(..) - ), - ProxyType::CancelProxy => { - matches!(c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })) - }, - ProxyType::Auction => matches!( - c, - RuntimeCall::Auctions(..) | - RuntimeCall::Crowdloan(..) | - RuntimeCall::Registrar(..) | - RuntimeCall::Slots(..) - ), - ProxyType::Society => matches!(c, RuntimeCall::Society(..)), - } - } - fn is_superset(&self, o: &Self) -> bool { - match (self, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::NonTransfer, _) => true, - _ => false, - } - } -} - -impl pallet_proxy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - type ProxyDepositBase = ProxyDepositBase; - type ProxyDepositFactor = ProxyDepositFactor; - type MaxProxies = MaxProxies; - type WeightInfo = weights::pallet_proxy::WeightInfo; - type MaxPending = MaxPending; - type CallHasher = BlakeTwo256; - type AnnouncementDepositBase = AnnouncementDepositBase; - type AnnouncementDepositFactor = AnnouncementDepositFactor; -} - -impl parachains_origin::Config for Runtime {} - -impl parachains_configuration::Config for Runtime { - type WeightInfo = weights::runtime_parachains_configuration::WeightInfo; -} - -impl parachains_shared::Config for Runtime {} - -impl parachains_session_info::Config for Runtime { - type ValidatorSet = Historical; -} - -impl parachains_inclusion::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type DisputesHandler = ParasDisputes; - type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; - type MessageQueue = MessageQueue; - type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo; -} - -parameter_types! { - pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); -} - -impl parachains_paras::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::runtime_parachains_paras::WeightInfo; - type UnsignedPriority = ParasUnsignedPriority; - type QueueFootprinter = ParaInclusion; - type NextSessionRotation = Babe; - type OnNewHead = Registrar; -} - -parameter_types! { - /// Amount of weight that can be spent per block to service messages. - /// - /// # WARNING - /// - /// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight. - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block; - 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; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = MessageProcessor; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = - pallet_message_queue::mock_helpers::NoopMessageProcessor; - type QueueChangeHandler = ParaInclusion; - type QueuePausedQuery = (); - type WeightInfo = weights::pallet_message_queue::WeightInfo; -} - -impl parachains_dmp::Config for Runtime {} - -impl parachains_hrmp::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type ChannelManager = EitherOf, GeneralAdmin>; - type Currency = Balances; - type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; -} - -impl parachains_paras_inherent::Config for Runtime { - type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; -} - -impl parachains_scheduler::Config for Runtime { - type AssignmentProvider = ParaAssignmentProvider; -} - -impl parachains_assigner_parachains::Config for Runtime {} - -impl parachains_initializer::Config for Runtime { - type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type ForceOrigin = EnsureRoot; - type WeightInfo = weights::runtime_parachains_initializer::WeightInfo; -} - -impl parachains_disputes::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; - type SlashingHandler = parachains_slashing::SlashValidatorsForDisputes; - type WeightInfo = weights::runtime_parachains_disputes::WeightInfo; -} - -impl parachains_slashing::Config for Runtime { - type KeyOwnerProofSystem = Historical; - type KeyOwnerProof = - >::Proof; - type KeyOwnerIdentification = >::IdentificationTuple; - type HandleReports = parachains_slashing::SlashingReportHandler< - Self::KeyOwnerIdentification, - Offences, - ReportLongevity, - >; - type WeightInfo = weights::runtime_parachains_disputes_slashing::WeightInfo; - type BenchmarkingConfig = parachains_slashing::BenchConfig<1000>; -} - -parameter_types! { - pub const ParaDeposit: Balance = 40 * UNITS; -} - -impl paras_registrar::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type OnSwap = (Crowdloan, Slots); - type ParaDeposit = ParaDeposit; - type DataDepositPerByte = DataDepositPerByte; - type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; -} - -parameter_types! { - // 6 weeks - pub LeasePeriod: BlockNumber = prod_or_fast!(6 * WEEKS, 6 * WEEKS, "KSM_LEASE_PERIOD"); -} - -impl slots::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type Registrar = Registrar; - type LeasePeriod = LeasePeriod; - type LeaseOffset = (); - type ForceOrigin = EitherOf, LeaseAdmin>; - type WeightInfo = weights::runtime_common_slots::WeightInfo; -} - -parameter_types! { - pub const CrowdloanId: PalletId = PalletId(*b"py/cfund"); - pub const OldSubmissionDeposit: Balance = 3 * GRAND; // ~ 10 KSM - pub const MinContribution: Balance = 3_000 * CENTS; // ~ .1 KSM - pub const RemoveKeysLimit: u32 = 1000; - // Allow 32 bytes for an additional memo to a crowdloan. - pub const MaxMemoLength: u8 = 32; -} - -impl crowdloan::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletId = CrowdloanId; - type SubmissionDeposit = OldSubmissionDeposit; - type MinContribution = MinContribution; - type RemoveKeysLimit = RemoveKeysLimit; - type Registrar = Registrar; - type Auctioneer = Auctions; - type MaxMemoLength = MaxMemoLength; - type WeightInfo = weights::runtime_common_crowdloan::WeightInfo; -} - -parameter_types! { - // The average auction is 7 days long, so this will be 70% for ending period. - // 5 Days = 72000 Blocks @ 6 sec per block - pub const EndingPeriod: BlockNumber = 5 * DAYS; - // ~ 1000 samples per day -> ~ 20 blocks per sample -> 2 minute samples - pub const SampleLength: BlockNumber = 2 * MINUTES; -} - -impl auctions::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Leaser = Slots; - type Registrar = Registrar; - type EndingPeriod = EndingPeriod; - type SampleLength = SampleLength; - type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type InitiateOrigin = EitherOf, AuctionAdmin>; - type WeightInfo = weights::runtime_common_auctions::WeightInfo; -} - -type NisCounterpartInstance = pallet_balances::Instance2; -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU128<10_000_000_000>; // One KTC cent - type AccountStore = StorageMapShim< - pallet_balances::Account, - AccountId, - pallet_balances::AccountData, - >; - type MaxLocks = ConstU32<4>; - type MaxReserves = ConstU32<4>; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = weights::pallet_balances_nis_counterpart_balances::WeightInfo; - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - pub const NisBasePeriod: BlockNumber = 7 * DAYS; - pub const MinBid: Balance = 100 * QUID; - pub MinReceipt: Perquintill = Perquintill::from_rational(1u64, 10_000_000u64); - pub const IntakePeriod: BlockNumber = 5 * MINUTES; - pub MaxIntakeWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10; - pub const ThawThrottle: (Perquintill, BlockNumber) = (Perquintill::from_percent(25), 5); - pub storage NisTarget: Perquintill = Perquintill::zero(); - pub const NisPalletId: PalletId = PalletId(*b"py/nis "); -} - -impl pallet_nis::Config for Runtime { - type WeightInfo = weights::pallet_nis::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type CurrencyBalance = Balance; - type FundOrigin = frame_system::EnsureSigned; - type Counterpart = NisCounterpartBalances; - type CounterpartAmount = WithMaximumOf>; - type Deficit = (); // Mint - type IgnoredIssuance = (); - type Target = NisTarget; - type PalletId = NisPalletId; - type QueueCount = ConstU32<500>; - type MaxQueueLen = ConstU32<1000>; - type FifoQueueLen = ConstU32<250>; - type BasePeriod = NisBasePeriod; - type MinBid = MinBid; - type MinReceipt = MinReceipt; - type IntakePeriod = IntakePeriod; - type MaxIntakeWeight = MaxIntakeWeight; - type ThawThrottle = ThawThrottle; - type RuntimeHoldReason = RuntimeHoldReason; -} - -parameter_types! { - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub const MaxPointsToBalance: u8 = 10; -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_nomination_pools::WeightInfo; - type Currency = Balances; - type RewardCounter = FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type Staking = Staking; - type PostUnbondingPoolsWindow = ConstU32<4>; - type MaxMetadataLen = ConstU32<256>; - // we use the same number of allowed unlocking chunks as with staking. - type MaxUnbonding = ::MaxUnlockingChunks; - type PalletId = PoolsPalletId; - type MaxPointsToBalance = MaxPointsToBalance; -} - -parameter_types! { - // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) - pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; - pub const MigrationSignedDepositBase: Balance = 20 * CENTS * 100; - pub const MigrationMaxKeyLen: u32 = 512; -} - -impl pallet_state_trie_migration::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type SignedDepositPerItem = MigrationSignedDepositPerItem; - type SignedDepositBase = MigrationSignedDepositBase; - type ControlOrigin = EnsureRoot; - type SignedFilter = frame_support::traits::NeverEnsureOrigin; - - // Use same weights as substrate ones. - type WeightInfo = pallet_state_trie_migration::weights::SubstrateWeight; - type MaxKeyLen = MigrationMaxKeyLen; -} - -construct_runtime! { - pub enum Runtime - { - // Basic stuff; balances is uncallable initially. - System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, - - // Babe must be before session. - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 1, - - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2, - Indices: pallet_indices::{Pallet, Call, Storage, Config, Event} = 3, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 4, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 33, - - // Consensus support. - // Authorship must be before session in order to note author in the correct session and era - // for im-online and staking. - Authorship: pallet_authorship::{Pallet, Storage} = 5, - Staking: pallet_staking::{Pallet, Call, Storage, Config, Event} = 6, - Offences: pallet_offences::{Pallet, Storage, Event} = 7, - Historical: session_historical::{Pallet} = 34, - - // BEEFY Bridges support. - Beefy: pallet_beefy::{Pallet, Call, Storage, Config, ValidateUnsigned} = 200, - // MMR leaf construction must be before session in order to have leaf contents - // refer to block consistently. see substrate issue #11797 for details. - Mmr: pallet_mmr::{Pallet, Storage} = 201, - BeefyMmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 202, - - Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 8, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 10, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 11, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 12, - - // Governance stuff. - Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 18, - ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 20, - Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 21, -// pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; - FellowshipCollective: pallet_ranked_collective::::{ - Pallet, Call, Storage, Event - } = 22, -// pub type FellowshipReferendaInstance = pallet_referenda::Instance2; - FellowshipReferenda: pallet_referenda::::{ - Pallet, Call, Storage, Event - } = 23, - Origins: pallet_custom_origins::{Origin} = 43, - Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 44, - - // Claims. Usable initially. - Claims: claims::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 19, - - // Utility module. - Utility: pallet_utility::{Pallet, Call, Event} = 24, - - // Less simple identity module. - Identity: pallet_identity::{Pallet, Call, Storage, Event} = 25, - - // Society module. - Society: pallet_society::{Pallet, Call, Storage, Event} = 26, - - // Social recovery module. - Recovery: pallet_recovery::{Pallet, Call, Storage, Event} = 27, - - // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config} = 28, - - // System scheduler. - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 29, - - // Proxy module. Late addition. - Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 30, - - // Multisig module. Late addition. - Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 31, - - // Preimage registrar. - Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 32, - - // Bounties modules. - Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 35, - ChildBounties: pallet_child_bounties = 40, - - // Election pallet. Only works with staking, but placed here to maintain indices. - ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 37, - - // NIS pallet. - Nis: pallet_nis::{Pallet, Call, Storage, Event, HoldReason} = 38, -// pub type NisCounterpartInstance = pallet_balances::Instance2; - NisCounterpartBalances: pallet_balances:: = 45, - - // Provides a semi-sorted list of nominators for staking. - VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 39, - - // nomination pools: extension to staking. - NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event, Config} = 41, - - // Fast unstake pallet: extension to staking. - FastUnstake: pallet_fast_unstake = 42, - - // Parachains pallets. Start indices at 50 to leave room. - ParachainsOrigin: parachains_origin::{Pallet, Origin} = 50, - Configuration: parachains_configuration::{Pallet, Call, Storage, Config} = 51, - ParasShared: parachains_shared::{Pallet, Call, Storage} = 52, - ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event} = 53, - ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 54, - ParaScheduler: parachains_scheduler::{Pallet, Storage} = 55, - Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56, - Initializer: parachains_initializer::{Pallet, Call, Storage} = 57, - Dmp: parachains_dmp::{Pallet, Storage} = 58, - Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event, Config} = 60, - ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, - ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 62, - ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, - ParaAssignmentProvider: parachains_assigner_parachains::{Pallet, Storage} = 64, - - // Parachain Onboarding Pallets. Start indices at 70 to leave room. - Registrar: paras_registrar::{Pallet, Call, Storage, Event} = 70, - Slots: slots::{Pallet, Call, Storage, Event} = 71, - Auctions: auctions::{Pallet, Call, Storage, Event} = 72, - Crowdloan: crowdloan::{Pallet, Call, Storage, Event} = 73, - - // State trie migration pallet, only temporary. - StateTrieMigration: pallet_state_trie_migration = 98, - - // Pallet for sending XCM. - XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, - - // Generalized message queue - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 100, - } -} - -/// The address format for describing accounts. -pub type Address = sp_runtime::MultiAddress; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// `BlockId` type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckMortality, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, -); - -pub struct NominationPoolsMigrationV4OldPallet; -impl Get for NominationPoolsMigrationV4OldPallet { - fn get() -> Perbill { - Perbill::from_percent(10) - } -} - -/// All migrations that will run on the next runtime upgrade. -/// -/// This contains the combined migrations of the last 10 releases. It allows to skip runtime -/// upgrades in case governance decides to do so. THE ORDER IS IMPORTANT. -pub type Migrations = migrations::Unreleased; - -/// The runtime migrations per release. -#[allow(deprecated, missing_docs)] -pub mod migrations { - use super::*; - use frame_support::traits::LockIdentifier; - use frame_system::pallet_prelude::BlockNumberFor; - - parameter_types! { - pub const DemocracyPalletName: &'static str = "Democracy"; - pub const CouncilPalletName: &'static str = "Council"; - pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; - pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; - pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; - pub const TipsPalletName: &'static str = "Tips"; - pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; - } - - // Special Config for Gov V1 pallets, allowing us to run migrations for them without - // implementing their configs on [`Runtime`]. - pub struct UnlockConfig; - impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { - type Currency = Balances; - type MaxVotes = ConstU32<100>; - type MaxDeposits = ConstU32<100>; - type AccountId = AccountId; - type BlockNumber = BlockNumberFor; - type DbWeight = ::DbWeight; - type PalletName = DemocracyPalletName; - } - impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig - for UnlockConfig - { - type Currency = Balances; - type MaxVotesPerVoter = ConstU32<16>; - type PalletId = PhragmenElectionPalletId; - type AccountId = AccountId; - type DbWeight = ::DbWeight; - type PalletName = PhragmenElectionPalletName; - } - impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { - type Currency = Balances; - type Hash = Hash; - type DataDepositPerByte = DataDepositPerByte; - type TipReportDepositBase = TipReportDepositBase; - type AccountId = AccountId; - type BlockNumber = BlockNumberFor; - type DbWeight = ::DbWeight; - type PalletName = TipsPalletName; - } - - /// Upgrade Session keys to include BEEFY key. - /// When this is removed, should also remove `OldSessionKeys`. - pub struct UpgradeSessionKeys; - impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { - fn on_runtime_upgrade() -> Weight { - Session::upgrade_keys::(transform_session_keys); - Perbill::from_percent(50) * BlockWeights::get().max_block - } - } - - pub struct ParachainsToUnlock; - impl Contains for ParachainsToUnlock { - fn contains(id: &ParaId) -> bool { - let id: u32 = (*id).into(); - // ksuama parachains/parathreads that are locked and never produced block - match id { - 2003 | 2008 | 2018 | 2077 | 2089 | 2111 | 2112 | 2120 | 2126 | 2127 | 2130 | - 2226 | 2227 | 2231 | 2233 | 2237 | 2256 | 2257 | 2261 | 2268 | 2275 => true, - _ => false, - } - } - } - - /// Unreleased migrations. Add new ones here: - pub type Unreleased = ( - init_state_migration::InitMigrate, - pallet_society::migrations::VersionCheckedMigrateToV2< - Runtime, - (), - past_payouts::PastPayouts, - >, - pallet_im_online::migration::v1::Migration, - parachains_configuration::migration::v7::MigrateToV7, - parachains_scheduler::migration::v1::MigrateToV1, - parachains_configuration::migration::v8::MigrateToV8, - - // Unlock/unreserve balances from Gov v1 pallets that hold them - // https://github.com/paritytech/polkadot/issues/6749 - pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, - - // Delete storage key/values from all Gov v1 pallets - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - - // Upgrade SessionKeys to include BEEFY key - UpgradeSessionKeys, - - parachains_configuration::migration::v9::MigrateToV9, - // Migrate parachain info format - paras_registrar::migration::VersionCheckedMigrateToV1, - ); -} - -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, - Migrations, ->; -/// The payload being signed in the transactions. -pub type SignedPayload = generic::SignedPayload; - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - frame_benchmarking::define_benchmarks!( - // Polkadot - // NOTE: Make sure to prefix these with `runtime_common::` so - // that the path resolves correctly in the generated file. - [runtime_common::auctions, Auctions] - [runtime_common::crowdloan, Crowdloan] - [runtime_common::claims, Claims] - [runtime_common::slots, Slots] - [runtime_common::paras_registrar, Registrar] - [runtime_parachains::configuration, Configuration] - [runtime_parachains::hrmp, Hrmp] - [runtime_parachains::disputes, ParasDisputes] - [runtime_parachains::disputes::slashing, ParasSlashing] - [runtime_parachains::inclusion, ParaInclusion] - [runtime_parachains::initializer, Initializer] - [runtime_parachains::paras_inherent, ParaInherent] - [runtime_parachains::paras, Paras] - // Substrate - [pallet_balances, Balances] - [pallet_balances, NisCounterpartBalances] - [pallet_bags_list, VoterList] - [frame_benchmarking::baseline, Baseline::] - [pallet_bounties, Bounties] - [pallet_child_bounties, ChildBounties] - [pallet_conviction_voting, ConvictionVoting] - [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] - [frame_election_provider_support, ElectionProviderBench::] - [pallet_fast_unstake, FastUnstake] - [pallet_nis, Nis] - [pallet_identity, Identity] - [pallet_im_online, ImOnline] - [pallet_indices, Indices] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_nomination_pools, NominationPoolsBench::] - [pallet_offences, OffencesBench::] - [pallet_preimage, Preimage] - [pallet_proxy, Proxy] - [pallet_ranked_collective, FellowshipCollective] - [pallet_recovery, Recovery] - [pallet_referenda, Referenda] - [pallet_referenda, FellowshipReferenda] - [pallet_scheduler, Scheduler] - [pallet_session, SessionBench::] - [pallet_society, Society] - [pallet_staking, Staking] - [frame_system, SystemBench::] - [pallet_timestamp, Timestamp] - [pallet_treasury, Treasury] - [pallet_utility, Utility] - [pallet_vesting, Vesting] - [pallet_whitelist, Whitelist] - // XCM - [pallet_xcm, XcmPallet] - [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] - [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::] - ); -} - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block); - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> sp_std::vec::Vec { - Runtime::metadata_versions() - } - } - - impl block_builder_api::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: inherents::InherentData, - ) -> inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl tx_pool_api::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl offchain_primitives::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl primitives::runtime_api::ParachainHost for Runtime { - fn validators() -> Vec { - parachains_runtime_api_impl::validators::() - } - - fn validator_groups() -> (Vec>, GroupRotationInfo) { - parachains_runtime_api_impl::validator_groups::() - } - - fn availability_cores() -> Vec> { - parachains_runtime_api_impl::availability_cores::() - } - - fn persisted_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option> { - parachains_runtime_api_impl::persisted_validation_data::(para_id, assumption) - } - - fn assumed_validation_data( - para_id: ParaId, - expected_persisted_validation_data_hash: Hash, - ) -> Option<(PersistedValidationData, ValidationCodeHash)> { - parachains_runtime_api_impl::assumed_validation_data::( - para_id, - expected_persisted_validation_data_hash, - ) - } - - fn check_validation_outputs( - para_id: ParaId, - outputs: primitives::CandidateCommitments, - ) -> bool { - parachains_runtime_api_impl::check_validation_outputs::(para_id, outputs) - } - - fn session_index_for_child() -> SessionIndex { - parachains_runtime_api_impl::session_index_for_child::() - } - - fn validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option { - parachains_runtime_api_impl::validation_code::(para_id, assumption) - } - - fn candidate_pending_availability(para_id: ParaId) -> Option> { - parachains_runtime_api_impl::candidate_pending_availability::(para_id) - } - - fn candidate_events() -> Vec> { - parachains_runtime_api_impl::candidate_events::(|ev| { - match ev { - RuntimeEvent::ParaInclusion(ev) => { - Some(ev) - } - _ => None, - } - }) - } - - fn session_info(index: SessionIndex) -> Option { - parachains_runtime_api_impl::session_info::(index) - } - - fn session_executor_params(session_index: SessionIndex) -> Option { - parachains_runtime_api_impl::session_executor_params::(session_index) - } - - fn dmq_contents(recipient: ParaId) -> Vec> { - parachains_runtime_api_impl::dmq_contents::(recipient) - } - - fn inbound_hrmp_channels_contents( - recipient: ParaId - ) -> BTreeMap>> { - parachains_runtime_api_impl::inbound_hrmp_channels_contents::(recipient) - } - - fn validation_code_by_hash(hash: ValidationCodeHash) -> Option { - parachains_runtime_api_impl::validation_code_by_hash::(hash) - } - - fn on_chain_votes() -> Option> { - parachains_runtime_api_impl::on_chain_votes::() - } - - fn submit_pvf_check_statement( - stmt: primitives::PvfCheckStatement, - signature: primitives::ValidatorSignature, - ) { - parachains_runtime_api_impl::submit_pvf_check_statement::(stmt, signature) - } - - fn pvfs_require_precheck() -> Vec { - parachains_runtime_api_impl::pvfs_require_precheck::() - } - - fn validation_code_hash(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option - { - parachains_runtime_api_impl::validation_code_hash::(para_id, assumption) - } - - fn disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState)> { - parachains_runtime_api_impl::get_session_disputes::() - } - - fn unapplied_slashes( - ) -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)> { - parachains_runtime_api_impl::unapplied_slashes::() - } - - fn key_ownership_proof( - validator_id: ValidatorId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((PARACHAIN_KEY_TYPE_ID, validator_id)) - .map(|p| p.encode()) - .map(slashing::OpaqueKeyOwnershipProof::new) - } - - fn submit_report_dispute_lost( - dispute_proof: slashing::DisputeProof, - key_ownership_proof: slashing::OpaqueKeyOwnershipProof, - ) -> Option<()> { - parachains_runtime_api_impl::submit_unsigned_slashing_report::( - dispute_proof, - key_ownership_proof, - ) - } - } - - impl beefy_primitives::BeefyApi for Runtime { - fn beefy_genesis() -> Option { - Beefy::genesis_block() - } - - fn validator_set() -> Option> { - Beefy::validator_set() - } - - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: beefy_primitives::EquivocationProof< - BlockNumber, - BeefyId, - BeefySignature, - >, - key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - let key_owner_proof = key_owner_proof.decode()?; - - Beefy::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - } - - fn generate_key_ownership_proof( - _set_id: beefy_primitives::ValidatorSetId, - authority_id: BeefyId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((beefy_primitives::KEY_TYPE, authority_id)) - .map(|p| p.encode()) - .map(beefy_primitives::OpaqueKeyOwnershipProof::new) - } - } - - impl mmr::MmrApi for Runtime { - fn mmr_root() -> Result { - Ok(Mmr::mmr_root()) - } - - fn mmr_leaf_count() -> Result { - Ok(Mmr::mmr_leaves()) - } - - fn generate_proof( - block_numbers: Vec, - best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { - Mmr::generate_proof(block_numbers, best_known_block_number).map( - |(leaves, proof)| { - ( - leaves - .into_iter() - .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) - .collect(), - proof, - ) - }, - ) - } - - fn verify_proof(leaves: Vec, proof: mmr::Proof) - -> Result<(), mmr::Error> - { - let leaves = leaves.into_iter().map(|leaf| - leaf.into_opaque_leaf() - .try_decode() - .ok_or(mmr::Error::Verify)).collect::, mmr::Error>>()?; - Mmr::verify_leaves(leaves, proof) - } - - fn verify_proof_stateless( - root: mmr::Hash, - leaves: Vec, - proof: mmr::Proof - ) -> 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) - } - } - - impl pallet_beefy_mmr::BeefyMmrApi for RuntimeApi { - fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { - BeefyMmrLeaf::authority_set_proof() - } - - fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet { - BeefyMmrLeaf::next_authority_set_proof() - } - } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> Vec<(GrandpaId, u64)> { - Grandpa::grandpa_authorities() - } - - fn current_set_id() -> fg_primitives::SetId { - Grandpa::current_set_id() - } - - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: fg_primitives::EquivocationProof< - ::Hash, - sp_runtime::traits::NumberFor, - >, - key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - let key_owner_proof = key_owner_proof.decode()?; - - Grandpa::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - } - - fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, - authority_id: fg_primitives::AuthorityId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((fg_primitives::KEY_TYPE, authority_id)) - .map(|p| p.encode()) - .map(fg_primitives::OpaqueKeyOwnershipProof::new) - } - } - - impl babe_primitives::BabeApi for Runtime { - fn configuration() -> babe_primitives::BabeConfiguration { - let epoch_config = Babe::epoch_config().unwrap_or(BABE_GENESIS_EPOCH_CONFIG); - babe_primitives::BabeConfiguration { - slot_duration: Babe::slot_duration(), - epoch_length: EpochDuration::get(), - c: epoch_config.c, - authorities: Babe::authorities().to_vec(), - randomness: Babe::randomness(), - allowed_slots: epoch_config.allowed_slots, - } - } - - fn current_epoch_start() -> babe_primitives::Slot { - Babe::current_epoch_start() - } - - fn current_epoch() -> babe_primitives::Epoch { - Babe::current_epoch() - } - - fn next_epoch() -> babe_primitives::Epoch { - Babe::next_epoch() - } - - fn generate_key_ownership_proof( - _slot: babe_primitives::Slot, - authority_id: babe_primitives::AuthorityId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((babe_primitives::KEY_TYPE, authority_id)) - .map(|p| p.encode()) - .map(babe_primitives::OpaqueKeyOwnershipProof::new) - } - - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: babe_primitives::EquivocationProof<::Header>, - key_owner_proof: babe_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - let key_owner_proof = key_owner_proof.decode()?; - - Babe::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - } - } - - impl authority_discovery_primitives::AuthorityDiscoveryApi for Runtime { - fn authorities() -> Vec { - parachains_runtime_api_impl::relevant_authority_ids::() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, sp_core::crypto::KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Nonce { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< - Block, - Balance, - > for Runtime { - fn query_info(uxt: ::Extrinsic, len: u32) -> RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_nomination_pools_runtime_api::NominationPoolsApi< - Block, - AccountId, - Balance, - > for Runtime { - fn pending_rewards(member: AccountId) -> Balance { - NominationPools::api_pending_rewards(member).unwrap_or_default() - } - - fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { - NominationPools::api_points_to_balance(pool_id, points) - } - - fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { - NominationPools::api_balance_to_points(pool_id, new_funds) - } - } - - impl pallet_staking_runtime_api::StakingApi for Runtime { - fn nominations_quota(balance: Balance) -> u32 { - Staking::api_nominations_quota(balance) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - log::info!("try-runtime::on_runtime_upgrade kusama."); - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, BlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - - use pallet_session_benchmarking::Pallet as SessionBench; - use pallet_offences_benchmarking::Pallet as OffencesBench; - use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; - use frame_system_benchmarking::Pallet as SystemBench; - use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; - use frame_benchmarking::baseline::Pallet as Baseline; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - return (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result< - Vec, - sp_runtime::RuntimeString, - > { - use frame_support::traits::WhitelistedStorageKeys; - use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; - use sp_storage::TrackedStorageKey; - // Trying to add benchmarks directly to some pallets caused cyclic dependency issues. - // To get around that, we separated the benchmarks into its own crate. - use pallet_session_benchmarking::Pallet as SessionBench; - use pallet_offences_benchmarking::Pallet as OffencesBench; - use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; - use frame_system_benchmarking::Pallet as SystemBench; - use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; - use frame_benchmarking::baseline::Pallet as Baseline; - use xcm::latest::prelude::*; - use xcm_config::{ - LocalCheckAccount, SovereignAccountOf, Statemine, TokenLocation, XcmConfig, - }; - - impl pallet_session_benchmarking::Config for Runtime {} - impl pallet_offences_benchmarking::Config for Runtime {} - impl pallet_election_provider_support_benchmarking::Config for Runtime {} - impl frame_system_benchmarking::Config for Runtime {} - impl frame_benchmarking::baseline::Config for Runtime {} - impl pallet_nomination_pools_benchmarking::Config for Runtime {} - impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = XcmConfig; - type AccountIdConverter = SovereignAccountOf; - fn valid_destination() -> Result { - Ok(Statemine::get()) - } - fn worst_case_holding(_depositable_count: u32) -> MultiAssets { - // Kusama only knows about KSM. - vec![MultiAsset{ - id: Concrete(TokenLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }].into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - Statemine::get(), - MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) }, - )); - pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; - } - - impl pallet_xcm_benchmarks::fungible::Config for Runtime { - type TransactAsset = Balances; - - type CheckedAccount = LocalCheckAccount; - type TrustedTeleporter = TrustedTeleporter; - type TrustedReserve = TrustedReserve; - - fn get_multi_asset() -> MultiAsset { - MultiAsset { - id: Concrete(TokenLocation::get()), - fun: Fungible(1 * UNITS), - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type RuntimeCall = RuntimeCall; - - fn worst_case_response() -> (u64, Response) { - (0u64, Response::Version(Default::default())) - } - - fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> { - // Kusama doesn't support asset exchanges - Err(BenchmarkError::Skip) - } - - fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { - // The XCM executor of Kusama doesn't have a configured `UniversalAliases` - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((Statemine::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(Statemine::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = Statemine::get(); - let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); - let ticket = MultiLocation { parents: 0, interior: Here }; - Ok((origin, ticket, assets)) - } - - fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> { - // Kusama doesn't support asset locking - Err(BenchmarkError::Skip) - } - - fn export_message_origin_and_destination( - ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - // Kusama doesn't support exporting messages - Err(BenchmarkError::Skip) - } - - fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { - // The XCM executor of Kusama doesn't have a configured `Aliasers` - Err(BenchmarkError::Skip) - } - } - - let mut whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); - let treasury_key = frame_system::Account::::hashed_key_for(Treasury::account_id()); - whitelist.push(treasury_key.to_vec().into()); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - - add_benchmarks!(params, batches); - - Ok(batches) - } - } -} - -#[cfg(test)] -mod fees_tests { - use super::*; - use sp_runtime::assert_eq_error_rate; - - #[test] - fn signed_deposit_is_sensible() { - // ensure this number does not change, or that it is checked after each change. - // a 1 MB solution should need around 0.16 KSM deposit - let deposit = SignedFixedDeposit::get() + (SignedDepositByte::get() * 1024 * 1024); - assert_eq_error_rate!(deposit, UNITS * 167 / 100, UNITS / 100); - } -} - -#[cfg(test)] -mod multiplier_tests { - use super::*; - use frame_support::{dispatch::DispatchInfo, traits::OnFinalize}; - use runtime_common::{MinimumMultiplier, TargetBlockFullness}; - use separator::Separatable; - use sp_runtime::traits::Convert; - - fn run_with_system_weight(w: Weight, mut assertions: F) - where - F: FnMut() -> (), - { - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - t.execute_with(|| { - System::set_block_consumed_resources(w, 0); - assertions() - }); - } - - #[test] - fn multiplier_can_grow_from_zero() { - let minimum_multiplier = MinimumMultiplier::get(); - let target = TargetBlockFullness::get() * - BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); - // if the min is too small, then this will not change, and we are doomed forever. - // the weight is 1/100th bigger than target. - run_with_system_weight(target.saturating_mul(101) / 100, || { - let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); - assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); - }) - } - - #[test] - fn fast_unstake_estimate() { - use pallet_fast_unstake::WeightInfo; - let block_time = BlockWeights::get().max_block.ref_time() as f32; - let on_idle = weights::pallet_fast_unstake::WeightInfo::::on_idle_check( - 1000, - ::BatchSize::get(), - ) - .ref_time() as f32; - println!("ratio of block weight for full batch fast-unstake {}", on_idle / block_time); - assert!(on_idle / block_time <= 0.5f32) - } - - #[test] - #[ignore] - fn multiplier_growth_simulator() { - // assume the multiplier is initially set to its minimum. We update it with values twice the - //target (target is 25%, thus 50%) and we see at which point it reaches 1. - let mut multiplier = MinimumMultiplier::get(); - let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); - let mut blocks = 0; - let mut fees_paid = 0; - - frame_system::Pallet::::set_block_consumed_resources(Weight::MAX, 0); - let info = DispatchInfo { weight: Weight::MAX, ..Default::default() }; - - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - // set the minimum - t.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::set(MinimumMultiplier::get()); - }); - - while multiplier <= Multiplier::from_u32(1) { - t.execute_with(|| { - // imagine this tx was called. - let fee = TransactionPayment::compute_fee(0, &info, 0); - fees_paid += fee; - - // this will update the multiplier. - System::set_block_consumed_resources(block_weight, 0); - TransactionPayment::on_finalize(1); - let next = TransactionPayment::next_fee_multiplier(); - - assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); - multiplier = next; - - println!( - "block = {} / multiplier {:?} / fee = {:?} / fess so far {:?}", - blocks, - multiplier, - fee.separated_string(), - fees_paid.separated_string() - ); - }); - blocks += 1; - } - } - - #[test] - #[ignore] - fn multiplier_cool_down_simulator() { - // assume the multiplier is initially set to its minimum. We update it with values twice the - //target (target is 25%, thus 50%) and we see at which point it reaches 1. - let mut multiplier = Multiplier::from_u32(2); - let mut blocks = 0; - - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - // set the minimum - t.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); - }); - - while multiplier > Multiplier::from_u32(0) { - t.execute_with(|| { - // this will update the multiplier. - TransactionPayment::on_finalize(1); - let next = TransactionPayment::next_fee_multiplier(); - - assert!(next < multiplier, "{:?} !>= {:?}", next, multiplier); - multiplier = next; - - println!("block = {} / multiplier {:?}", blocks, multiplier); - }); - blocks += 1; - } - } -} - -#[cfg(all(test, feature = "try-runtime"))] -mod remote_tests { - use super::*; - use frame_try_runtime::{runtime_decl_for_try_runtime::TryRuntime, UpgradeCheckSelect}; - use remote_externalities::{ - Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport, - }; - use std::env::var; - - #[tokio::test] - async fn run_migrations() { - if var("RUN_MIGRATION_TESTS").is_err() { - return - } - - sp_tracing::try_init_simple(); - let transport: Transport = - var("WS").unwrap_or("wss://kusama-rpc.polkadot.io:443".to_string()).into(); - let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); - let mut ext = Builder::::default() - .mode(if let Some(state_snapshot) = maybe_state_snapshot { - Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - ..Default::default() - }, - ) - } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) - }) - .build() - .await - .unwrap(); - ext.execute_with(|| Runtime::on_runtime_upgrade(UpgradeCheckSelect::PreAndPost)); - } - - #[tokio::test] - #[ignore = "this test is meant to be executed manually"] - async fn try_fast_unstake_all() { - sp_tracing::try_init_simple(); - let transport: Transport = - var("WS").unwrap_or("wss://kusama-rpc.polkadot.io:443".to_string()).into(); - let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); - let mut ext = Builder::::default() - .mode(if let Some(state_snapshot) = maybe_state_snapshot { - Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - ..Default::default() - }, - ) - } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) - }) - .build() - .await - .unwrap(); - ext.execute_with(|| { - pallet_fast_unstake::ErasToCheckPerBlock::::put(1); - runtime_common::try_runtime::migrate_all_inactive_nominators::() - }); - } -} - -mod init_state_migration { - use super::Runtime; - use frame_support::traits::OnRuntimeUpgrade; - use pallet_state_trie_migration::{AutoLimits, MigrationLimits, MigrationProcess}; - #[cfg(feature = "try-runtime")] - use sp_runtime::DispatchError; - #[cfg(not(feature = "std"))] - use sp_std::prelude::*; - - /// Initialize an automatic migration process. - pub struct InitMigrate; - impl OnRuntimeUpgrade for InitMigrate { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, DispatchError> { - frame_support::ensure!( - AutoLimits::::get().is_none(), - DispatchError::Other("Automigration already started.") - ); - Ok(Default::default()) - } - - fn on_runtime_upgrade() -> frame_support::weights::Weight { - if MigrationProcess::::get() == Default::default() && - AutoLimits::::get().is_none() - { - // We use limits to target 600ko proofs per block and - // avg 800_000_000_000 of weight per block. - // See spreadsheet 4800_400 in - // https://raw.githubusercontent.com/cheme/substrate/try-runtime-mig/ksm.ods - AutoLimits::::put(Some(MigrationLimits { item: 4_800, size: 204800 * 2 })); - log::info!("Automatic trie migration started."); - ::DbWeight::get().reads_writes(2, 1) - } else { - log::info!("Automatic trie migration not started."); - ::DbWeight::get().reads(2) - } - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), DispatchError> { - frame_support::ensure!( - AutoLimits::::get().is_some(), - DispatchError::Other("Automigration started.") - ); - Ok(()) - } - } -} diff --git a/polkadot/runtime/kusama/src/past_payouts.rs b/polkadot/runtime/kusama/src/past_payouts.rs deleted file mode 100644 index 2d8b67902b89184867a3f35b651ca8e37425204d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/past_payouts.rs +++ /dev/null @@ -1,312 +0,0 @@ -// This file is part of Polkadot. - -// 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 hex_literal::hex; -use pallet_society::migrations::from_raw_past_payouts; - -parameter_types! { - pub PastPayouts: Vec<(AccountId, Balance)> = from_raw_past_payouts::(vec![ - (hex!["04152389a92e4356ed03ed30625afba062b9c4496116cba888e89f347834a31e"], 89000000000000u128), - (hex!["0483de2b96cd3756f05301eb1bca875166ae5be67a81f86a1dad152bccad6909"], 54666600000000u128), - (hex!["048a62b89589f7573c5f80584de850b9c8bcd4cb7a8766948d3db713d8a57204"], 83000000000000u128), - (hex!["060e1eacd9f4460ae43b28d39e472078784482139e483307436344019a48f26e"], 15513300000000u128), - (hex!["0ab0b61984dfcfe2fcb82147f0a2f00f992fa8a6b5ee81490387f8210a1ab678"], 6766666600u128), - (hex!["0c6e31c65ee1e82129879a145eb0c0d4de45e60c3dcab1d2219628cd70673a6b"], 69000000000000u128), - (hex!["10e9e630de91310a60b0bc7a4a2303a60b703afde9239750921514deb2655a0d"], 54333200000000u128), - (hex!["162eb21266fef25e25eb8286994264450b8c80ccf2911967cc42ee4cc55c2061"], 14223300000000u128), - (hex!["183f8c4d5084d96816ae7d82d44373b99bb134a16845d1589df4467671e3b56a"], 23333300000000u128), - (hex!["18b2624ddf0eca6c9698496801dcda614580367a4d54833fe75bbf54a9a09966"], 52999900000000u128), - (hex!["18b44d4c64c3aa3fb20d88b016a412d8f27000912fa7b350ed270ac8f55b3a27"], 5135000000000u128), - (hex!["1aa23df47ab442adc15f6c923cfd0f6c4255b2cacc19538028685e37410a691f"], 54000000000000u128), - (hex!["1ce0527c225ce227c1cceed0317eae0817bd600be3aa87489a704678c95a5451"], 41166600000000u128), - (hex!["1e20318bd5c0bc44576955b7205354b8ed9c8e4a783ba9da70d5cee0e11b4740"], 11000000000000u128), - (hex!["1e6fa8ff46b01fe3b8c52ea50a5ab61313ffac31393a28f621625840a6b3776d"], 11556600000000u128), - (hex!["20243c6b74a5f83b89ec202a337bd06ebc985fe7b1557184bfd012dc9bc97873"], 13000000000000u128), - (hex!["22cabf36e0954f0c013af666e27e46cb9a41f7a0db46ccec245f43b5ba438452"], 31000000000000u128), - (hex!["24172a563943291c97d252def71e17abf467a1626bca358728a90a82b3de3118"], 200000000000000u128), - (hex!["247f22a3073d04a85ab417505bb7667a5941ed74cfa596dfc7402813198a0560"], 68999000000000u128), - (hex!["28250c422851313e923c89cc0a41fec2af80cc124290343ae250f77ff60d767d"], 6993300000000u128), - (hex!["2c709012f807af8fc3f0d2abb0c51ca9a88d4ef24d1a092bf89dacf5ce63ea1d"], 333333333332u128), - (hex!["305b27652a4dc8038c587df4cf1d7758b413fe18a97b3a3a5c7d609f50092e11"], 39000000000000u128), - (hex!["3063796fb70f0bcde597bb7ed4d50f6ec7755686c894c7dbaa1ea2e33103876e"], 11650000000000u128), - (hex!["325c848b9000d5430844bd5486d34d844acd89e11964ed1b535bf45557e1c87f"], 10666600000000u128), - (hex!["3a632ab63a0ec92f1b67af756a49c8849f5722a345e54ef51cb294bef569070b"], 14993300000000u128), - (hex!["3c97e1879015dfb64a367e0f0eb32f16968fb6be6a48da7de7776bc8953c854d"], 18149900000000u128), - (hex!["3e8eb90cd422b7d72f166f135ed3db2137d0d9216e14cfdbd0ca75d2a18e2235"], 83000000000000u128), - (hex!["3ea89a71ac11ea023bf42d9d6215a9d8c775e626a2ee38d574b297f42c58a622"], 15056500000000u128), - (hex!["402d95c5f6d37ab03ecbec4628d290b2cc7571ff790ee5757b21bbcba4108924"], 12666600000000u128), - (hex!["40300fe00bcfb90f3ded42dc082b775dd9a8a8ea491261a262a78155a069a268"], 112000000000000u128), - (hex!["406855a4bb07710384d3876cf37cacbd66f2f1dab2346ebea130b00f63d0d317"], 83500000000000u128), - (hex!["40c6e021d4d80b9b38d850b1c5334ea88b2bcc148d07e83f5be1b45b8ceb3740"], 9893300000000u128), - (hex!["40f8a816b07bd23e166d2e479cfd5a3e5118f3937230ca5088eff9e33c84b552"], 12790000000000u128), - (hex!["422286e0da2fb826f04e46d2f6ef1319a43412261d0f8d91274a81eee21af24e"], 69000000000000u128), - (hex!["484a648ebe737d7dbee39d8e169d5ded94d29f70100e4d3ee87162c4a8bbdf73"], 2483300000000u128), - (hex!["4c4a2f66cd9f5000968f0913f01ac1181ccd2db137d6af152252ee3de689450b"], 2000000000000u128), - (hex!["505eb7820f60d0949697617b2f3366bd616d8c7e96724aa681e0113f6bf45c46"], 898900000000u128), - (hex!["569f5ab70b93bb40ecb5a8888bbbc781c785ac3709863e9866422f0fd62f2477"], 8000000000000u128), - (hex!["5c1be3d517926a6c194d42131d996140f3e8d7398764423cab176341b882ee7b"], 8490000000000u128), - (hex!["5c32313c22eebc15ecf28ebb75ed8e264d53e50429a5ce09ed3a86e72732c56d"], 5000000000000u128), - (hex!["5c436629095023be4d2ed2120002497bc18295fb485a11e83e529e617412626f"], 6999900000000u128), - (hex!["5c81f3afd924f4cdd7c151d539c7abc3cd3de33eebd59403b81b568b8efa2d3b"], 15000000000000u128), - (hex!["602d798e4d6f076cb28719b4bc757645ff0894a591173bd923bc8cb631fdeb0c"], 201660000000000u128), - (hex!["621014fccda62dbd21d32b3628691f68cecafa887a62d641ba8876e3e7e4c068"], 8000000000000u128), - (hex!["6613962cf897114a56ba84bbad47f52c46dc56960aae8ccfc71805cfc3fced19"], 32666600000000u128), - (hex!["662ef2fa0d3a90f1f9691d05daee187d35fb17482cc72b3e03922358d0bdcc6f"], 10000000000000u128), - (hex!["687b7e0289f5d116a2b68cf9d0496f62de37e579ea777ce39d81471c09ec142b"], 275000000000000u128), - (hex!["688de40f61eb6ecc19b4c3702267c0bbf052ed9ee843ff6d346d765f89ed6067"], 7000000000000u128), - (hex!["68fae6be10c90d572388d42129e074005005baf68d116a993073c5648ec78865"], 6356600000000u128), - (hex!["6a8cafed3a670189545d5b242aec4d52bb4fe90f5af2f5984d8a14eb44713a70"], 12780000000000u128), - (hex!["6c64f0ac3b73174aa0b0cd935b5576611e405c8485ef13a0be8bf2ea3a48da6f"], 8000000000000u128), - (hex!["6eb31a06ff9d943b174f683f8327e3b4847a02e197e951f01ac7759b4c102f10"], 52333300000000u128), - (hex!["6ed537e76f1ef68764d7544cd7a8be19cbaba2ef8af181090d281d80105fd963"], 175000000000000u128), - (hex!["7241b3a590243df346a79a2d0ebf79dc990f07c1c499145d0424f3769ca4c826"], 81000000000000u128), - (hex!["728ea7cd638962b92ec6405e7b5572b67cfbc96c7c2fc7becf4cddb22b50b02c"], 11890000000000u128), - (hex!["7a91a646fd4d7592aabed6ad7f3c1d9f12371f200ae3d644454c80272b8e8c14"], 44000000000000u128), - (hex!["7c9ae158bf660dbd429592d055efe4897fad8a07c4ed61accd1861380c5c3843"], 24666600000000u128), - (hex!["7cb95b196a81bb0b7952e94ff0624b9b1429e81bee0f03c8bf2f3cea5213c611"], 5805000000000u128), - (hex!["7ec0c61a682519e78e65026c51ceea52273870636814605a33518f02ad543317"], 6969600000000u128), - (hex!["802c32932fca84ba9c80d57e4b0ebccc8404ee75a346ae0b50a17666bb38c01c"], 4986600000000u128), - (hex!["806369b4f04792b7bd1a0d8586b7aa528591ba732362e3fb3d52d7b01e741b18"], 8660866667000u128), - (hex!["80a551df4b4b67586a512356fc0e513d641e39f62172d185465dfee61e67143a"], 15160000000000u128), - (hex!["821e24cd21f1da627bea7b7077d591b9c8a48f93dd87eb7f3f1ac4ec512f7b5f"], 7500000000000u128), - (hex!["84c62d27805ac9c7a62086e31dfae23703ac9dfb37fbd31bec95aa611c5d2c33"], 999666600000000u128), - (hex!["865facd74193d96f1b35a702efe05116e7be752d77f46c7fe4720905728ccb36"], 6993300000000u128), - (hex!["88077737732044369dc52dd7f7bf400cfb493a219f013fbfdd46f7cd52673d6f"], 67666600000000u128), - (hex!["8865278958eaaba42406d1ae16545267c944113c216fffc386edb4d6a8cffd36"], 5000000000000u128), - (hex!["8ad06fa44a5669702a29b394424560714a1af90ad9efb57f3864b93b1ff7961c"], 100000000000u128), - (hex!["8e7215d5218f170d0865fcbe16b2ceb752db7e7bfce3f3d487ecb60e776a2c36"], 39333200000000u128), - (hex!["8ef7167c4d50be846c6a03591e13005fa68ef858d87321bb79428b121e105a11"], 9166600000000u128), - (hex!["90bc6fc1133c3df447222e89b5ceaa028b69348ee381385239377b31df275248"], 15000000000000u128), - (hex!["90da58a51d922ae69f27d8020d52e2fc71a5e5af1b63571bae81ddb87f8ff424"], 6696900000000u128), - (hex!["92af8236baeef25f6e85ed30d85b758f5604c5c4c4c3637657fea1946a3da61b"], 13000000000000u128), - (hex!["969fe4cba88544e8d3d71f31790cc1d377cf85a89e1b3d03e7a8b932aed1d312"], 84000000000000u128), - (hex!["96be4635aeb775be58f3c0843bd8bc1832d257e56905525dcb3d38126d8f855e"], 12166600000000u128), - (hex!["9822df7da6d3c119f5118587b29eaa30aaf00839e2a03161c2df4222a0d8744e"], 8999900000000u128), - (hex!["9cb774a6051717a844657f0c037a93173f70afc000babd2f7f0be7d1e8475436"], 9000000000000u128), - (hex!["9eb27cde65b09610cbe8a3d3b82c6730f5a5dd51aeb082fdd74236c4765a040a"], 8890000000000u128), - (hex!["a0c6e8d74992d1ea3e43081624b2cddbd98b50d7a75998662ce6adbb2290aa64"], 175000000000000u128), - (hex!["a2b8bfb3c0c1f04346134e7b27cb5b63de8a7af0d57c502d09c05ba7b3dd1e28"], 9326600000000u128), - (hex!["a415a980463876c54b503c358613b5c02d8ac9781c13378797c54ab37fc07c05"], 8666600000000u128), - (hex!["a48539457aa2e54048493ccaf980be18253d8cabd6eecd295e6b62e6a357352f"], 8879900000000u128), - (hex!["a60b82ce304c28aad744e2a95924b3e1e560803a75e5a39fc91300556e9a9538"], 83499000000000u128), - (hex!["a673009c77c4734fbc09f3bf505e3414282f714e89688ca3fa9292921cb7e51d"], 93000000000000u128), - (hex!["a69f19b16dfdfb01b1d480c59512b0d589e600538cd9102de9619ef419211f1b"], 11993300000000u128), - (hex!["aa17e09d3e9685a53d52d5123cc7f4f6f9fc7f3ab34f268a6f8860de68f2b612"], 15000000000000u128), - (hex!["aa893ab408a0c0b8bb175ed7fa2b042e0fd30915e6ab8f66a9ac524e552d167f"], 11480000000000u128), - (hex!["accd5106f4794d9052617617a993556b15c6e62859282bad7edb24592d728a69"], 94999000000000u128), - (hex!["ae4bada5af908d3bddd0cb7e250d38da99cf9d6508a6b1118a89dc59fb372a4a"], 17000000000000u128), - (hex!["b2012e8078883fdd9693d75c90bb669834f7b2c302def049e6eb486e56dc7365"], 13500000000000u128), - (hex!["b2fa9763f56890cabe29a1ea971851a3234aecd03584c44f822e036fbd9c5156"], 8554600000000u128), - (hex!["b8a750597d770430e4f9771829cf964825ea6750a6229deb06dc515371c7033f"], 96600000000u128), - (hex!["ba8a15ff06ff808a77b93ad335884ac66e3744a5cea908f8b8a865d98a934541"], 21333300000000u128), - (hex!["baf98d06056833e2e887c85c938aeb1c31dff74a91d35d9863327abc8ec93f4a"], 7500000000000u128), - (hex!["c2487c00d0e309fdb96d1e0ed7bb2da173d777b3ae26b25c1369992add25972d"], 21000000000000u128), - (hex!["c2fc6a3cc910e05c508c8b252f32c6df760858d12c6a636b256135e966edcf7e"], 9715500000000u128), - (hex!["c443922426297f4ded0e635f0a92b8e31823b2e6893398b1e8351c34a728fe34"], 6493300000000u128), - (hex!["c4f4760edf86fffa05380f31bf047c72837cccfc684d9dd9b1d7fa4e3503ce51"], 14500000000000u128), - (hex!["c676a26c89e3be0451afa1126516b8f88b3da99511aba215ec99707ac5f08e3c"], 14833300000000u128), - (hex!["d25af2fedd4eb672f218932fde44f97f10c1d7788efd0079957ffad4f186ae78"], 100000000000000u128), - (hex!["d4610b986b4e4cb505ce0003142df98f803b7c3413acc9f7805992dc2a00483c"], 110000000000000u128), - (hex!["d80cb19a68fb4ae325cd0209e8563cf3d5ff0368e2ede5530940f29371a02a25"], 19000000000000u128), - (hex!["dc8f45881886ba4d2e2409ea49661b14a29a72e64d7a59d98465a9cee8084107"], 34666600000000u128), - (hex!["de3898d3824e41435b6519f2095d25af51954af6be4a946d5d2df46df3ea264f"], 110000000000000u128), - (hex!["e2094a5bcc479f2e6c83bfdbc88fe3658b817522ba1fb240f804b131ffa81600"], 41000000000000u128), - (hex!["e27bc8259449251380d0b6c848cd607b12a09b0fa8fd8875ae3f6eea70c3fd69"], 1993300000000u128), - (hex!["e45c09f0387a72f3a1eeb9e1a8f23feb738bc48d56d99ab88c8a910807c48a0c"], 18646600000000u128), - (hex!["e62321ed84ec54791122f2ec72e9e36d3cb336ed358d6848a65b8410b405650a"], 9216100000000u128), - (hex!["e80d8a511c20f08d8abbd69f1258fa27c28181ffa8fbee0989f706e7b6c48b21"], 9000000000000u128), - (hex!["ea53405eb9054ddf0b6b82de940a4646c70cb815ba4c4616394fe0488030bb32"], 72333300000000u128), - (hex!["eedfb6337bed7b15d7a0338820e8a4981d96fe7284e444885c7f478fe649012f"], 14566600000000u128), - (hex!["f20f603b0314b04a4c3b295cbfc7b53c11370cc0349ddb3cd32c91c5b416fc51"], 7493300000000u128), - (hex!["f4fa6e013f0a33b809b8c1dc8d73c1461407a474106f5def66c109a3d7c4f556"], 56666600000000u128), - (hex!["faaede0e8cfb95d55e325e29a4737decb4a20960a525384003248c5610405b7d"], 1893300000000u128), - (hex!["fae2f8b2e08e32c333e0332b4254119241c2f15421846b76b693eba714b3e571"], 20333300000000u128), - (hex!["44152e29de73d969a8d5bc6d0b3497f31ee7e7f6e01722a5a91fccadd6bcce76"], 14900000000000u128), - (hex!["4adb5df8ae7001c508d3e630deda167bce1760aa0e7c8544a1e3b70358ac3b45"], 15900000000000u128), - (hex!["f04581f47bc54daf59437fe8a8e7e76ab3f034d8b30f3629652a6a013f7e0b38"], 13986600000000u128), - (hex!["9c107fbcac10f60dc1910e27210283c39f8d5951816f8d7c8f5f96d0c71dbb29"], 26666666400u128), - ].into_iter()); -} - -#[test] -fn check_addresses() { - use sp_core::{ - crypto::{AccountId32, Ss58Codec}, - hexdisplay::HexDisplay, - }; - - let payouts: Vec<(&'static str, f64)> = vec![ - ("CffzJo8UPWwvwPF73VcbEv4jSG4ckvGwNePL9V52hYh743X", 89f64), - ("CgEt8AwW9SThQXpLBAZy3MpKgNG7ZHaEDGeV5MLqHVPVoJg", 54.6666f64), - ("CgGpRVgE8WXd2hjc3GBVxGpnG9KpjkvEGNkM6AAaCBmhQY9", 83f64), - ("CiFzvmP1wyXB8nUHh6rA1j7tFQFBx2akg57TwdTGjRAXicm", 15.5133f64), - ("CpLVRWcUd7PxDPSmtXwQC3628dwEYiMd3GbqZTnqvphMN3B", 0.0067666666f64), - ("CrcpvEZP2Z82iYFUPConih1t46VFwttrX7Tv19NW6hoCzKG", 69f64), - ("CxVmQoEyZKimVp3eMgtNHSwiFrEU3gwF1NGNPBo2gUNSr1g", 54.3332f64), - ("D5QSdd589pFWeJm9bz1j3RTyy14ejKpnUKyEa4GBW9kYkVC", 14.2233f64), - ("D87YYjk4agajQXHr1VyiW1qpzfm5QV4L8bk7XduhimVVS7H", 23.3333f64), - ("D8hf8DjZ2eb8X6cyNAYx14fRa7hVUqB52ejx5YNc2ed81gC", 52.9999f64), - ("D8iEArcApNbkH9BxEvc2AfLLWMD1sWS9F2XdRXyY9J6QDpi", 5.135f64), - ("DBExZRq4qoK8xiZaHTR7iP9tWmQ8FL9JSQG8DLyLL8yV2J8", 54f64), - ("DEBVjNhPic2eVBw2y42xJpTJfCSvDXXA6ibs7MzpXp2s2hj", 41.1666f64), - ("DFpWz9jGga5ZKcRghQGchhMhSHURUcUc2TaT7dMB4pQhkeB", 11f64), - ("DGE8ATd2NaitqX4jdvZNXFNMmY9Qui6swnfoheCiz7efWGG", 11.5566f64), - ("DJTpC2pbDJeoJ2CTHSQBurbkbd9ZgkD2WYNDtCmJhem3swh", 13f64), - ("DMwNfM1mwrraAoSG3LSnZcwGzuUcKipqYmRsFeCuvTvrdgL", 31f64), - ("DPe86fQfixDTfejAiEJbRt2mvbtcGkWdGXsyCFDu37iKYVu", 200f64), - ("DQB1TYcr7dw4UsHaNbNhM2jtyYaoQQrBoWS7jLb95D39XGb", 68.999f64), - ("DUxSQ29BxeZWDXin4jZN7ogArgxJDohyeuKsqY83WqPhT4h", 6.9933f64), - ("DaViizibrmJZwyUchRMRebv5YMXadS4PbYBLuZhbfMTtxPm", 0f64), - ("Dab4bfYTZRUDMWjYAUQuFbDreQ9mt7nULWu3Dw7jodbzVe9", 0.333333333332f64), - ("DfitqjAjNxJykJYaigWQmSRw7T847hfytxwVRuAwscdtYUh", 39f64), - ("DfmNCWtsVSG9D8KWazZ84VdkSVgxot6989W1qL7bHEAP7SF", 11.65f64), - ("DiMPtqB6HeYpYkjJJKNR6btJjmUNeG8yyhSg1N8UL3st5Um", 10.6666f64), - ("Dikw9VJqJ4fJFcXuKaSqu3eSwBQM6zC8ja9rdAP3RbfeK1Y", 0f64), - ("Dtskg3rQsxSpxxBG4pJYjTujm9fo48Q7qnEYtBfJ6UDqtSS", 14.9933f64), - ("DwmWULE1g84ZMYyM4du8SmcQCkuz7VL7C6GmaWKoRXSG6vJ", 18.1499f64), - ("DzLtEdo7ScPi1o3izPETynSm9kdXJF8H1Y68b3eFbsQUgm6", 83f64), - ("DzUa9PynyTKBEJ9Yjk27o44aav9XaJG8p57YHKVNaorxbZu", 15.0565f64), - ("E2U89NfSnVCmY3hBQHEdJ9KV6shd6B8h4EWkNLcSJCPRAk8", 12.6666f64), - ("E2UrpeDCGs2mb9SZLzAk8E89yWaZncAvjFD5VnbYbDp44Xo", 112f64), - ("E2maNj3d7YZZhpeUwCGGeThD7JX2zk1W8AUQ1Rqb2K9oDBR", 83.5f64), - ("E3FfH6nbxCwQ9bg3oHAmBFpS3qEtWLbQ4QV8XUqn6qQaaab", 9.8933f64), - ("E3WSzAdgZtu3o8NjTJdwweJjpmSGwcf42pZAFDR7CsNTrrr", 12.79f64), - ("E52wAv1fTdLGUNR4CNSbeCmj1yNUeSFnj1CPKbRzTubt3YU", 69f64), - ("ED74i7eA79DtKFu5WXbcLXLWT2E1XSDEdJSAEkU3ePN7LE4", 2.4833f64), - ("EDQWMYr6a9aLjTbsMtKFAcoUsVA6qvm66RJsyJsNgbpxCFx", 0f64), - ("EJ4FuvmVpU7Ri2GRMtQVhhfHsHzGLYngbKJzJ58RkmRrzJm", 0f64), - ("EJMCExEPNyuq6EofbvwD2ErZKwuZCJVTFhiDcDwuW12c187", 2f64), - ("EPhV6vifCet2sJPPCNGnUZdRhsQpfcsbxRvDkjsMPPCCvwR", 0.8989f64), - ("EQ12pCgs4H3XHgDTc5n44xfXo6WNNkAg33b4aDFv3eUSgZd", 0f64), - ("EXtySo37DkJUdQb5425KGzUCG8ecYL4nVkcNB5XZpDQPH73", 8f64), - ("Ef6D2jpq92FoX8wSKihodFCg8juMjFu9CBnMwwBQDbYi4XU", 8.49f64), - ("EfCqHrWEwRnRq2ekmTmWvKzYwKtcgD4uaJAm3T92wx3ekUx", 5f64), - ("EfHwkqXCDup8Hi7DVWsPTDQoGiaW55HXgbQV3XzVSCEu1ii", 6.9999f64), - ("EfcXWwDMt9UoYhj6KRfEA4NLccsZK2eQ2AFpGw4EGatNwcj", 15f64), - ("EkRd7vCKiDZi6BM6tHKs5YAeGmE3MmQgChrrbtkRkf6SBwW", 201.66f64), - ("EntzFKky1rX9oYWzEiv4K4D997XGtCH9BHCmairrXhrW2gb", 8f64), - ("EtADjuauj4ETanscktz4jpejZdkCMVPnRxKos6AwgpzLdHM", 32.6666f64), - ("EtJMBiUVsHm3bwfMhWksQ14mv1P69BHjp7ELYDWdqXynR6K", 10f64), - ("EwKBYgaaELEEB5Vm9QAgArinAtps3dRUmb9bwBVTg5HqvxJ", 275f64), - ("EwQeYkCGQtBHMgKvNZ7NZ9Dy9tqKJDqN3DknJm5XF8czbYB", 7f64), - ("Ewy2kju7jdqBFbp95Nw1go31KyiMHS9rRVaevGkM62F1btd", 6.3566f64), - ("Ez2PN6BKn31byeQTrTBqP6MAv4WF7eKF3J8UXXxaaAd1Kuv", 12.78f64), - ("F2Sg6L8dTASXBz4rn9Rv4xsfaCKPn21pDzAX9HSAR8krMzR", 8f64), - ("F5TzLdntQpfz5RXcqCqJM4NKrjS7jVnAcNRKhu5FpLLWm2i", 52.3333f64), - ("F5e8A2i3XZvA5jZTYmwcUiHzVsoTAhJDgMxZEnsFe8dq2VA", 175f64), - ("FA8VcXg8Yzg9RvVrTdhcKk5JLSH1hcwrS9fr7pjFraCRWcm", 81f64), - ("FAXMVgYUWh6s2SFaX9h33mrjXXeq8HTcNwFHEy9D1eimrLK", 11.89f64), - ("FM2dJMRnBkbJDbdtqhRpLfgRbwJBkiw6iKT8u6UJ7pojypt", 44f64), - ("FPhTtxHSTKZM4fTndfgBSSXyTpdMkpEnqojAvGTS1c8hv9S", 24.6666f64), - ("FPrWyj8aDy3dofjmXZE5mx4o6Kf82MnEGGpjVEHjH7khReo", 5.805f64), - ("FSWpLozBJnXdVhE8t7LXYEpBybwse3S795WYFKiobhZWKVE", 6.9696f64), - ("FUNmzDNdzWtXK51EZmwbDJXQALhcYGCQUeo8E4rtcx9QBX7", 4.9866f64), - ("FUfBKr2pDxKrxmExGp4hjU6St4BDgffzKcyAqv6pruGnez1", 8.660866667f64), - ("FUzksiAhxzSvvPqiYvUEwK32rFf6Fmyug9GZEdbMaoLmwh5", 15.16f64), - ("FWvhQBV91wrvaqWiqDZfq4QPYYPFS28UV8zNgeJYyUexxXm", 7.5f64), - ("FaQi6AhM49SdjBd7oZJftAPE6tt9mrH8AdySztpYUU1B6Vq", 999.6666f64), - ("FcWMb9VtQutzQ5hxguyQrWKtN28zaXKuXLbL3D9oX6AJbiC", 6.9933f64), - ("FcxNWVy5RESDsErjwyZmPCW6Z8Y3fbfLzmou34YZTrbcraL", 0f64), - ("FegFL7hjGtjwRWvDMabMuPFGTzToioEWu4BLxjRxYPfvCpn", 67.6666f64), - ("FfA5YrMeaPzBYB4rE4JBuauXua6BEAQoJPTd8dRCLCdRdhM", 5f64), - ("FiL3XNxVpx5Cgnh4WPpPWms5Ed9tGqA44YEtHVDyPacHVGt", 0.1f64), - ("Fo6D1N9EjneyZYYPGxiW1WNKsj1S9Gx1nxcrMCkKGQ1bwDM", 39.3332f64), - ("Fomib3HNL24Cv6CbLJUf59yDF5shGFyDg8Wx7eGtmDdwrRF", 9.1666f64), - ("Fr6PbzHWKrTvmFJmiYy7MD1iaUpTKHN91VS5iQZZgo7BWCw", 15f64), - ("FrFGwHJKqLTyGDwqWfLgGYFDkjP12yAATQuh4oNpZMhpFzM", 6.6969f64), - ("Ft2cSCw4V47d2S7V9nN2S6V5ByGmAnkfbkFbWUVuHVuaMvW", 0f64), - ("FtG8FbxJXfDj6fcGp3eTL9tKJzkfqT9k8PREKXDgKmbnSDR", 0f64), - ("FteeR6d11cvmoRUmvoBeYYHNpMd5onPnpGy5PUcR6Vo7dJX", 13f64), - ("FypCVBt2MU61ZVL3N6mePXaUXrFX9nvGK6h5yqR89jc6JeW", 84f64), - ("FyyDvxKBmKr81HwQWtbugiFRiu2P1JpSqBDid56AfFevuTV", 12.1666f64), - ("G1o9z4HVf2pW7bbyKKNRP9MnmGEN4n7Ada3yJRpNzaiPoKd", 8.9999f64), - ("G7oV7X7FzJJ2g8TetMvAaC4GvM1ZCzPCnfSk5KcnVy2PJEF", 9f64), - ("GAQ75C8zHzVjWJLDH5PqFbLxfyck89wLJkhCzMZTXBFV5L7", 8.89f64), - ("GD8GVB4Ai4uCSzMCiX6C4vuY4DVkBctQRT6QMqD6y5mJfr9", 175f64), - ("GFgA4KV6Mm2TsHwEYtXfXZCf6QzebuN7c69UJGcRF2vCDTD", 9.3266f64), - ("GHTohCLUcLyB8w4xMr4TyDkvUzDnim6fadWfJ7edPke971d", 8.6666f64), - ("GJ2wraBjTtXH3m2TUxsVEc1bQdiuo6yiZUfczsws19uioX9", 8.8799f64), - ("GL2tM9Q6KL6XxMEWBg5jdjLezP4EzYsh3bqR1pjTmwDY1Mf", 83.499f64), - ("GLZdTryDdiHe3gVwFdncm2a6pKN6EiMxTGJQFHq5RxcNJZt", 93f64), - ("GLnjFi1U2jk6hDs7HCL1Y8XHsVLPHd2UAQh3AqRgpcUAUcn", 11.9933f64), - ("GRLkXUQUNqQMxKnNH1cM5TvWmu2H3yxGx9ohvJXSxRHUyJq", 15f64), - ("GRvRXw8jB2H9EGojmmjM4vZCeofuu91W2Zpbtr2QC5f7iLb", 11.48f64), - ("GUtkCnQKsVXzjqJvSZkiHtvdwZoEyukZrDE1iLTyV8F7tH6", 94.999f64), - ("GWrL9KsayVkniG2GmkYoTRDaFHhpTTSf6fL25e623bHVkRt", 17f64), - ("GbiPhuH4m4BCYiiLpqo2S2TyFxvgpfdSKWMdp9ZrbKdtXeM", 13.5f64), - ("GczUwD9zRdzJnTCr9kyREURmVeYpZAg1wNWrZMjqqimHcds", 8.5546f64), - ("GkS2m7UK6RSUkFiCHYPRtp8GCKdPtrBwP1wj7448gWoiut8", 0.0966f64), - ("Gnh63rW5fy3FAbnZQPkajyrQXxQGkg56Waoe2Ede1RjRjrJ", 0f64), - ("GnkMTVovNUith3JMaN5yvpuuwPzVeFbjM15wzg6LrAQSN6P", 0f64), - ("GnuSjJqE7VWMUGYsEEqsMioXwzNXfhu7FPMvdfKCiVazJwD", 21.3333f64), - ("GoUZE6g169BskxYVFV6prDUN4siKxa6Mr8VZD8B6TU9MEtX", 7.5f64), - ("Gy4LfGahVbR4eM8Sj2aCC4hHFk4fbUWGZCWQV5pjSGwJRZb", 21f64), - ("GyynnvzZzcJt24FQ6DNNg77Mgbfe8ddLdUiQG6nssoBVpmE", 9.7155f64), - ("H1eyZGi1DKxTGdtM8UQRA1RGEe6kGhvKC4onRpy97qKqiPE", 6.4933f64), - ("H2ZXJi5QAVB29d48oWgM1oBAmg2ngiofft4yEeyq58pViwt", 14.5f64), - ("H4YEv9v4DzU6WJsF2pxSHGcVxZEZDS761XWYsnRKX7P3aMQ", 14.8333f64), - ("H9eSvWe34vQDJAWckeTHWSqSChRat8bgKHG39GC1fjvEm7y", 0f64), - ("HJHs8fpzT916HTQgdGf6s69qp5zwNmZpTTnGXmm6qNqaQyW", 0f64), - ("HL8bEp8YicBdrUmJocCAWVLKUaR2dd1y6jnD934pbre3un1", 100f64), - ("HNnVpuhqgXRRDL8h4H39EgvvXtVYEtFSPi1XBWHcEW4cEYc", 110f64), - ("HTbdbMAMsFkUVeoMQ6pbH341DgQ1a4MpdCcaBu5N6uShJBq", 19f64), - ("HZWcWK1Px51bWgu1BD5d9M6A1djczFsdRWVwhVpRrU6VUJH", 34.6666f64), - ("Hbgxh54N33ApEZrpnYGhhvPJNYWD5LNprZodPVnSHq7QDDh", 110f64), - ("Hgh6jDVF9SXHs5pw6TfAXMWj4qHXpU6Q4dXh7h8zpx26cdw", 41f64), - ("HhH7NMA7FEkj327ZktSzkthknuQU591tLr1vX8zuc4E4JkB", 1.9933f64), - ("Hjjn1CmyGWKCswCmVZJFTFMJkruTtgeycEmvR4rWJYU7izQ", 18.6466f64), - ("HkRdC1w5XDvQQadAS2nL58mPRBCLyUCZAAiaV7DUWJgj7P8", 0f64), - ("Hn4y5xom4rBD49e2eMTpsEbqAJgE7uSR62VGLVv78ZqCuxT", 9.2161f64), - ("Hpaecetm5cBAJYDVqN9VeFUgVNQh3AAJAqUKAFW8PZGRst6", 9f64), - ("HsZTGLU5foma6bWoC7BGAs51aRu9TNc2RKRQBcfaHhJES1z", 72.3333f64), - ("HyXNSykBLZFMK8eAdys5L97ncetUhnStnLKMpuSp7kM9bCU", 14.5666f64), - ("J3hg1qmm6VeU6WWcxGQnKaMnD8wYAxnFQwaysE7RhVXbNvs", 7.4933f64), - ("J7XbTDFU4SRUaW6t6mYiK4tzDXtguhwa5ZK13EVCE5F2qak", 56.6666f64), - ("J9c2fcmRhhNaJAxA8yLMkxap7PEWuYc1UaaTqxunfKscjG3", 0f64), - ("JBfNxpntp7DaRM7pzg4XEm9TYX3gCaAVZvwgZW25ZzwXjy2", 0f64), - ("JEzQAbxmotcDNAXFFgcDcjgEF9gbuxaxer4bhGdKEfQqyRw", 0f64), - ("JF1SD3o1qZFdLBWmKTRHcHgBsXZRGGJhkwLeStYNoHs7ep1", 1.8933f64), - ("JFGuwWzqiyJZ3MPM8NRy7kK75MdxwSkh7GNZcsVd6BpZq2h", 20.3333f64), - ("D5WYdgC7f4W6jGCkQaQ3Lfe5P5F7JvfhYBAX9G6CBToMYe4", 0f64), - ("EJgdRddcYSd6XWnwr8oZkkzxJJX8SLwig38d5yxZSRgJGQZ", 0f64), - ("FXRK8xzufVJ45bCXuCCRr6FuS1dCfx9VjiuwqZDSqzEWgLm", 0f64), - ("Gt8ferkwFEX9jLbxpuhLYqKdNzP9KtjZcGYVN2mMbuCwhAP", 0f64), - ("HHCd33jjDBJJDZic7rbQZMuMaoe5ddYaRkaLf7tDURHpE56", 0f64), - ("E7b4mfFEhpnbw7iKdhvnBw7fXoQ1QFQE4TtTRhseWMU1H2E", 14.9000f64), - ("EGUE7VyrVLVSoaG43XVrEf3eKcgzJC8p3mFRtPUTMNLhdYs", 15.9000f64), - ("EtommijqrHDFWFvBxP515oUbkXx9vK2qohzrmwpCXbU7Yx2", 0f64), - ("GxzBsXcxZXXaKcLXj4CWGDdoCaXRVmcRkyiUAHFc1AfTMEV", 0f64), - ("H1heyw8DdkexFHAJ85GhuJr5om72Kx2DdK6sHsmb2f9ebUJ", 0f64), - ("J1Mf8RWcRWpuCRBAQVq6yRgb9exuHdKJdfV2NymtbXdkTF4", 13.9866f64), - ("FX6PCBQr4gtejvdR5dCdstrxmS3oFrzjZHtAKXSBumEse96", 0f64), - ("EdE26hU1nVmmVoteHWGKX8BuayykEg84iz7x3MCmzfocn2u", 0f64), - ("DzN3bMAAKKam6DBr9co4r1TBSj5X6Looh3JvNmfegiVrUgy", 0f64), - ("Dx2p54FSAxrqvFVN4ptvjV9LoUHkKQirM8SbLjD9PVnAonv", 0f64), - ("G6wtWujSHgT24UxXhDHVaVbnY5fBkUJLsjykyWBvtNs2aGQ", 0.0266666664f64), - ("DMrWWv31QiiDDESjGjyVcGhoCYMkPvrSTHHUDK5mR1riV2A", 0f64), - ("EkahQVDKRCe97ZT9TgS1YyfTzLgPah5PHa8NsfGFLsPKpjo", 0f64), - ("GhQ3gB8oaLZfjSd6gyeYZgymnJ2LEmvaUrSELBbva9342Y6", 0f64), - ]; - for (who, amount) in payouts.into_iter().filter(|&(_, amount)| amount > 0f64) { - println!( - "(hex![\"{}\"], {}u128),", - HexDisplay::from(AsRef::<[u8; 32]>::as_ref(&AccountId32::from_string(who).unwrap())), - (amount * 1_000_000_000_000f64).round() as u128, - ) - } -} diff --git a/polkadot/runtime/kusama/src/tests.rs b/polkadot/runtime/kusama/src/tests.rs deleted file mode 100644 index 053c3054ab463fa8c99fc4c430dc6b4bfc726efa..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/tests.rs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Tests for the Kusama Runtime Configuration - -use crate::*; -use frame_support::{ - dispatch::GetDispatchInfo, traits::WhitelistedStorageKeys, weights::WeightToFee as WeightToFeeT, -}; -use keyring::Sr25519Keyring::Charlie; -use pallet_transaction_payment::Multiplier; -use parity_scale_codec::Encode; -use runtime_common::MinimumMultiplier; -use separator::Separatable; -use sp_core::hexdisplay::HexDisplay; -use sp_runtime::FixedPointNumber; -use std::collections::HashSet; - -#[test] -fn nis_hold_reason_encoding_is_correct() { - assert_eq!(RuntimeHoldReason::Nis(pallet_nis::HoldReason::NftReceipt).encode(), [38, 0]); -} - -#[test] -fn remove_keys_weight_is_sensible() { - use runtime_common::crowdloan::WeightInfo; - let max_weight = ::WeightInfo::refund(RemoveKeysLimit::get()); - // Max remove keys limit should be no more than half the total block weight. - assert!((max_weight * 2).all_lt(BlockWeights::get().max_block)); -} - -#[test] -fn sample_size_is_sensible() { - use runtime_common::auctions::WeightInfo; - // Need to clean up all samples at the end of an auction. - let samples: BlockNumber = EndingPeriod::get() / SampleLength::get(); - let max_weight: Weight = RocksDbWeight::get().reads_writes(samples.into(), samples.into()); - // Max sample cleanup should be no more than half the total block weight. - assert!((max_weight * 2).all_lt(BlockWeights::get().max_block)); - assert!((::WeightInfo::on_initialize() * 2) - .all_lt(BlockWeights::get().max_block)); -} - -#[test] -fn payout_weight_portion() { - use pallet_staking::WeightInfo; - let payout_weight = - ::WeightInfo::payout_stakers_alive_staked( - MaxNominatorRewardedPerValidator::get(), - ) - .ref_time() as f64; - let block_weight = BlockWeights::get().max_block.ref_time() as f64; - - println!( - "a full payout takes {:.2} of the block weight [{} / {}]", - payout_weight / block_weight, - payout_weight, - block_weight - ); - assert!(payout_weight * 2f64 < block_weight); -} - -#[test] -#[ignore] -fn block_cost() { - let max_block_weight = BlockWeights::get().max_block; - let raw_fee = WeightToFee::weight_to_fee(&max_block_weight); - - println!( - "Full Block weight == {} // WeightToFee(full_block) == {} plank", - max_block_weight, - raw_fee.separated_string(), - ); -} - -#[test] -#[ignore] -fn transfer_cost_min_multiplier() { - let min_multiplier = MinimumMultiplier::get(); - let call = pallet_balances::Call::::transfer_keep_alive { - dest: Charlie.to_account_id().into(), - value: Default::default(), - }; - let info = call.get_dispatch_info(); - // convert to outer call. - let call = RuntimeCall::Balances(call); - let len = call.using_encoded(|e| e.len()) as u32; - - let mut ext = sp_io::TestExternalities::new_empty(); - let mut test_with_multiplier = |m| { - ext.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::put(m); - let fee = TransactionPayment::compute_fee(len, &info, 0); - println!( - "weight = {:?} // multiplier = {:?} // full transfer fee = {:?}", - info.weight.ref_time().separated_string(), - pallet_transaction_payment::NextFeeMultiplier::::get(), - fee.separated_string(), - ); - }); - }; - - test_with_multiplier(min_multiplier); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000_000_000u128)); -} - -#[test] -fn nominator_limit() { - use pallet_election_provider_multi_phase::WeightInfo; - // starting point of the nominators. - let all_voters: u32 = 10_000; - - // assuming we want around 5k candidates and 1k active validators. - let all_targets: u32 = 5_000; - let desired: u32 = 1_000; - let weight_with = |active| { - ::WeightInfo::submit_unsigned( - all_voters.max(active), - all_targets, - active, - desired, - ) - }; - - let mut active = 1; - while weight_with(active).all_lte(OffchainSolutionWeightLimit::get()) || active == all_voters { - active += 1; - } - - println!("can support {} nominators to yield a weight of {}", active, weight_with(active)); -} - -#[test] -fn call_size() { - RuntimeCall::assert_size_under(256); -} - -#[test] -fn check_whitelist() { - let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() - .iter() - .map(|e| HexDisplay::from(&e.key).to_string()) - .collect(); - - // Block number - assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")); - // Total issuance - assert!(whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")); - // Execution phase - assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")); - // Event count - assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")); - // System events - assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")); - // Configuration ActiveConfig - assert!(whitelist.contains("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385")); - // XcmPallet VersionDiscoveryQueue - assert!(whitelist.contains("1405f2411d0af5a7ff397e7c9dc68d194a222ba0333561192e474c59ed8e30e1")); - // XcmPallet SafeXcmVersion - assert!(whitelist.contains("1405f2411d0af5a7ff397e7c9dc68d196323ae84c43568be0d1394d5d0d522c4")); -} diff --git a/polkadot/runtime/kusama/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/kusama/src/weights/frame_benchmarking_baseline.rs deleted file mode 100644 index e9f934f56564e5093d2567b535a0218b5707860e..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/frame_benchmarking_baseline.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_benchmarking::baseline` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_benchmarking::baseline -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/frame_benchmarking_baseline.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_benchmarking::baseline`. -pub struct WeightInfo(PhantomData); -impl frame_benchmarking::baseline::WeightInfo for WeightInfo { - /// The range of component `i` is `[0, 1000000]`. - fn addition(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 173_000 picoseconds. - Weight::from_parts(235_396, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn subtraction(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 177_000 picoseconds. - Weight::from_parts(228_745, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn multiplication(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 178_000 picoseconds. - Weight::from_parts(233_063, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn division(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 167_000 picoseconds. - Weight::from_parts(224_853, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn hashing() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 23_298_471_000 picoseconds. - Weight::from_parts(23_321_832_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 100]`. - fn sr25519_verification(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 228_000 picoseconds. - Weight::from_parts(8_448_493, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 18_878 - .saturating_add(Weight::from_parts(55_611_437, 0).saturating_mul(i.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/frame_election_provider_support.rs b/polkadot/runtime/kusama/src/weights/frame_election_provider_support.rs deleted file mode 100644 index 9cdbd67d5e1db379958c12516e5e2f999379ef9b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/frame_election_provider_support.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_election_provider_support` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_election_provider_support -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_election_provider_support`. -pub struct WeightInfo(PhantomData); -impl frame_election_provider_support::WeightInfo for WeightInfo { - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_647_123_000 picoseconds. - Weight::from_parts(6_809_648_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 139_689 - .saturating_add(Weight::from_parts(6_171_199, 0).saturating_mul(v.into())) - // Standard Error: 14_281_333 - .saturating_add(Weight::from_parts(1_423_059_328, 0).saturating_mul(d.into())) - } - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_616_850_000 picoseconds. - Weight::from_parts(4_769_028_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 123_691 - .saturating_add(Weight::from_parts(4_925_892, 0).saturating_mul(v.into())) - // Standard Error: 12_645_798 - .saturating_add(Weight::from_parts(1_357_902_261, 0).saturating_mul(d.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/frame_system.rs b/polkadot/runtime/kusama/src/weights/frame_system.rs deleted file mode 100644 index 927977e9be0119a70de110f3c566608bbbbd6845..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/frame_system.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_system -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system`. -pub struct WeightInfo(PhantomData); -impl frame_system::WeightInfo for WeightInfo { - /// The range of component `b` is `[0, 3932160]`. - fn remark(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_951_000 picoseconds. - Weight::from_parts(2_015_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(431, 0).saturating_mul(b.into())) - } - /// The range of component `b` is `[0, 3932160]`. - fn remark_with_event(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_410_000 picoseconds. - Weight::from_parts(7_603_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_793, 0).saturating_mul(b.into())) - } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) - /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) - fn set_heap_pages() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 3_736_000 picoseconds. - Weight::from_parts(3_922_000, 0) - .saturating_add(Weight::from_parts(0, 1485)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a636f6465` (r:0 w:1) - /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) - fn set_code() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 93_052_017_000 picoseconds. - Weight::from_parts(98_271_042_000, 0) - .saturating_add(Weight::from_parts(0, 1485)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1000]`. - fn set_storage(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_100_000 picoseconds. - Weight::from_parts(2_131_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_975 - .saturating_add(Weight::from_parts(744_852, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1000]`. - fn kill_storage(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_089_000 picoseconds. - Weight::from_parts(2_129_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_093 - .saturating_add(Weight::from_parts(568_923, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[0, 1000]`. - fn kill_prefix(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `105 + p * (69 ±0)` - // Estimated: `118 + p * (70 ±0)` - // Minimum execution time: 3_913_000 picoseconds. - Weight::from_parts(4_056_000, 0) - .saturating_add(Weight::from_parts(0, 118)) - // Standard Error: 2_452 - .saturating_add(Weight::from_parts(1_281_244, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/mod.rs b/polkadot/runtime/kusama/src/weights/mod.rs deleted file mode 100644 index b3642d49d46390d2551b5f5420ef1b5626f40678..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A list of the different weight modules for our runtime. - -pub mod frame_election_provider_support; -pub mod frame_system; -pub mod pallet_bags_list; -pub mod pallet_balances; -pub mod pallet_balances_nis_counterpart_balances; -pub mod pallet_bounties; -pub mod pallet_child_bounties; -pub mod pallet_collective_council; -pub mod pallet_collective_technical_committee; -pub mod pallet_conviction_voting; -pub mod pallet_democracy; -pub mod pallet_election_provider_multi_phase; -pub mod pallet_elections_phragmen; -pub mod pallet_fast_unstake; -pub mod pallet_identity; -pub mod pallet_im_online; -pub mod pallet_indices; -pub mod pallet_membership; -pub mod pallet_message_queue; -pub mod pallet_multisig; -pub mod pallet_nis; -pub mod pallet_nomination_pools; -pub mod pallet_preimage; -pub mod pallet_proxy; -pub mod pallet_ranked_collective; -pub mod pallet_referenda_fellowship_referenda; -pub mod pallet_referenda_referenda; -pub mod pallet_scheduler; -pub mod pallet_session; -pub mod pallet_society; -pub mod pallet_staking; -pub mod pallet_timestamp; -pub mod pallet_tips; -pub mod pallet_treasury; -pub mod pallet_utility; -pub mod pallet_vesting; -pub mod pallet_whitelist; -pub mod pallet_xcm; -pub mod runtime_common_auctions; -pub mod runtime_common_claims; -pub mod runtime_common_crowdloan; -pub mod runtime_common_paras_registrar; -pub mod runtime_common_slots; -pub mod runtime_parachains_configuration; -pub mod runtime_parachains_disputes; -pub mod runtime_parachains_disputes_slashing; -pub mod runtime_parachains_hrmp; -pub mod runtime_parachains_inclusion; -pub mod runtime_parachains_initializer; -pub mod runtime_parachains_paras; -pub mod runtime_parachains_paras_inherent; -pub mod xcm; diff --git a/polkadot/runtime/kusama/src/weights/pallet_bags_list.rs b/polkadot/runtime/kusama/src/weights/pallet_bags_list.rs deleted file mode 100644 index b138ae3003b7e40360a6bb9b3b9ddd17957738a2..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_bags_list.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_bags_list` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_bags_list -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_bags_list`. -pub struct WeightInfo(PhantomData); -impl pallet_bags_list::WeightInfo for WeightInfo { - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn rebag_non_terminal() -> Weight { - // Proof Size summary in bytes: - // Measured: `1654` - // Estimated: `11506` - // Minimum execution time: 60_661_000 picoseconds. - Weight::from_parts(62_784_000, 0) - .saturating_add(Weight::from_parts(0, 11506)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn rebag_terminal() -> Weight { - // Proof Size summary in bytes: - // Measured: `1548` - // Estimated: `8877` - // Minimum execution time: 58_537_000 picoseconds. - Weight::from_parts(60_665_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn put_in_front_of() -> Weight { - // Proof Size summary in bytes: - // Measured: `1857` - // Estimated: `11506` - // Minimum execution time: 66_168_000 picoseconds. - Weight::from_parts(67_855_000, 0) - .saturating_add(Weight::from_parts(0, 11506)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(6)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_balances.rs b/polkadot/runtime/kusama/src/weights/pallet_balances.rs deleted file mode 100644 index a8498f52f8bc4ef05669a8f59de55747f7bc6f1b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_balances.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_balances` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_balances -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_balances`. -pub struct WeightInfo(PhantomData); -impl pallet_balances::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) - fn transfer_allow_death() -> Weight { - // Minimum execution time: 40_902 nanoseconds. - Weight::from_parts(41_638_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: System Account (r:1 w:1) - fn transfer_keep_alive() -> Weight { - // Minimum execution time: 30_093 nanoseconds. - Weight::from_parts(30_732_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: System Account (r:1 w:1) - fn force_set_balance_creating() -> Weight { - // Minimum execution time: 23_901 nanoseconds. - Weight::from_parts(24_238_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: System Account (r:1 w:1) - fn force_set_balance_killing() -> Weight { - // Minimum execution time: 26_402 nanoseconds. - Weight::from_parts(27_026_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: System Account (r:2 w:2) - fn force_transfer() -> Weight { - // Minimum execution time: 40_328 nanoseconds. - Weight::from_parts(41_242_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: System Account (r:1 w:1) - fn transfer_all() -> Weight { - // Minimum execution time: 35_401 nanoseconds. - Weight::from_parts(36_122_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: System Account (r:1 w:1) - fn force_unreserve() -> Weight { - // Minimum execution time: 20_178 nanoseconds. - Weight::from_parts(20_435_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - fn upgrade_accounts(_: u32) -> Weight { - Weight::from_parts(0, 0) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_balances_balances.rs b/polkadot/runtime/kusama/src/weights/pallet_balances_balances.rs deleted file mode 100644 index f65c5722d8be347e086d4833e87591475a2ea385..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_balances_balances.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_balances` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_balances -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_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) - fn transfer_allow_death() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 55_712_000 picoseconds. - Weight::from_parts(56_594_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer_keep_alive() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 42_461_000 picoseconds. - Weight::from_parts(43_407_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_set_balance_creating() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 15_909_000 picoseconds. - Weight::from_parts(16_376_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_set_balance_killing() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 23_026_000 picoseconds. - Weight::from_parts(23_599_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `6196` - // Minimum execution time: 57_520_000 picoseconds. - Weight::from_parts(58_933_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) - fn transfer_all() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 51_663_000 picoseconds. - Weight::from_parts(52_494_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_unreserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 18_726_000 picoseconds. - Weight::from_parts(19_172_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]`. - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (135 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 18_041_000 picoseconds. - Weight::from_parts(18_377_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 12_295 - .saturating_add(Weight::from_parts(16_146_961, 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())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_balances_nis_counterpart_balances.rs b/polkadot/runtime/kusama/src/weights/pallet_balances_nis_counterpart_balances.rs deleted file mode 100644 index 730d622e9abce38a90d69d3b1a1fa3baf85708b5..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_balances_nis_counterpart_balances.rs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_balances` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_balances -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_balances`. -pub struct WeightInfo(PhantomData); -impl pallet_balances::WeightInfo for WeightInfo { - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:2 w:2) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer_allow_death() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `6164` - // Minimum execution time: 56_458_000 picoseconds. - Weight::from_parts(57_881_000, 0) - .saturating_add(Weight::from_parts(0, 6164)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:0) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:2 w:2) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer_keep_alive() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `6164` - // Minimum execution time: 43_014_000 picoseconds. - Weight::from_parts(44_098_000, 0) - .saturating_add(Weight::from_parts(0, 6164)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - fn force_set_balance_creating() -> Weight { - // Proof Size summary in bytes: - // Measured: `217` - // Estimated: `3577` - // Minimum execution time: 14_712_000 picoseconds. - Weight::from_parts(15_189_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) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - fn force_set_balance_killing() -> Weight { - // Proof Size summary in bytes: - // Measured: `393` - // Estimated: `3593` - // Minimum execution time: 25_131_000 picoseconds. - Weight::from_parts(25_796_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:2 w:2) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, 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: `322` - // Estimated: `6196` - // Minimum execution time: 58_350_000 picoseconds. - Weight::from_parts(59_738_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: NisCounterpartBalances Account (r:2 w:2) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:0) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer_all() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `6164` - // Minimum execution time: 52_544_000 picoseconds. - Weight::from_parts(53_454_000, 0) - .saturating_add(Weight::from_parts(0, 6164)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_unreserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `391` - // Estimated: `3593` - // Minimum execution time: 20_615_000 picoseconds. - Weight::from_parts(21_215_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NisCounterpartBalances Account (r:999 w:999) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// 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]`. - /// The range of component `u` is `[1, 1000]`. - fn upgrade_accounts(u: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + u * (256 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 20_150_000 picoseconds. - Weight::from_parts(20_438_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 26_020 - .saturating_add(Weight::from_parts(18_369_413, 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())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_bounties.rs b/polkadot/runtime/kusama/src/weights/pallet_bounties.rs deleted file mode 100644 index 07ddb5240e6a1d43340f5b87f589d3f003600b64..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_bounties.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_bounties` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_bounties -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_bounties`. -pub struct WeightInfo(PhantomData); -impl pallet_bounties::WeightInfo for WeightInfo { - /// Storage: Bounties BountyCount (r:1 w:1) - /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:0 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// The range of component `d` is `[0, 16384]`. - fn propose_bounty(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `3593` - // Minimum execution time: 28_620_000 picoseconds. - Weight::from_parts(30_319_265, 0) - .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(715, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - fn approve_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3642` - // Minimum execution time: 10_397_000 picoseconds. - Weight::from_parts(10_777_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - fn propose_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `3642` - // Minimum execution time: 9_065_000 picoseconds. - Weight::from_parts(9_477_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn unassign_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `3642` - // Minimum execution time: 42_565_000 picoseconds. - Weight::from_parts(43_956_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn accept_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `461` - // Estimated: `3642` - // Minimum execution time: 27_461_000 picoseconds. - Weight::from_parts(28_307_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - fn award_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `405` - // Estimated: `3642` - // Minimum execution time: 19_269_000 picoseconds. - Weight::from_parts(19_884_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn claim_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `769` - // Estimated: `8799` - // Minimum execution time: 120_844_000 picoseconds. - Weight::from_parts(125_606_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_bounty_proposed() -> Weight { - // Proof Size summary in bytes: - // Measured: `449` - // Estimated: `3642` - // Minimum execution time: 47_439_000 picoseconds. - Weight::from_parts(48_838_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_bounty_active() -> Weight { - // Proof Size summary in bytes: - // Measured: `685` - // Estimated: `6196` - // Minimum execution time: 81_354_000 picoseconds. - Weight::from_parts(83_515_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - fn extend_bounty_expiry() -> Weight { - // Proof Size summary in bytes: - // Measured: `325` - // Estimated: `3642` - // Minimum execution time: 14_850_000 picoseconds. - Weight::from_parts(15_365_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:100 w:100) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:200 w:200) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `b` is `[0, 100]`. - fn spend_funds(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + b * (297 ±0)` - // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 4_606_000 picoseconds. - Weight::from_parts(4_691_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 15_735 - .saturating_add(Weight::from_parts(44_695_416, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_child_bounties.rs b/polkadot/runtime/kusama/src/weights/pallet_child_bounties.rs deleted file mode 100644 index 252060ba37b3b187841e080db84a4bcdd1398c76..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_child_bounties.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_child_bounties` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_child_bounties -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_child_bounties`. -pub struct WeightInfo(PhantomData); -impl pallet_child_bounties::WeightInfo for WeightInfo { - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyCount (r:1 w:1) - /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:0 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// The range of component `d` is `[0, 16384]`. - fn add_child_bounty(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `545` - // Estimated: `6196` - // Minimum execution time: 69_355_000 picoseconds. - Weight::from_parts(72_208_416, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 10 - .saturating_add(Weight::from_parts(705, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - fn propose_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `599` - // Estimated: `3642` - // Minimum execution time: 17_313_000 picoseconds. - Weight::from_parts(18_161_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn accept_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `745` - // Estimated: `3642` - // Minimum execution time: 32_629_000 picoseconds. - Weight::from_parts(33_843_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn unassign_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `745` - // Estimated: `3642` - // Minimum execution time: 47_994_000 picoseconds. - Weight::from_parts(49_346_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - fn award_child_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `642` - // Estimated: `3642` - // Minimum execution time: 21_866_000 picoseconds. - Weight::from_parts(22_532_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn claim_child_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `614` - // Estimated: `8799` - // Minimum execution time: 116_595_000 picoseconds. - Weight::from_parts(118_921_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_child_bounty_added() -> Weight { - // Proof Size summary in bytes: - // Measured: `845` - // Estimated: `6196` - // Minimum execution time: 76_806_000 picoseconds. - Weight::from_parts(79_568_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_child_bounty_active() -> Weight { - // Proof Size summary in bytes: - // Measured: `1032` - // Estimated: `8799` - // Minimum execution time: 93_885_000 picoseconds. - Weight::from_parts(96_680_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_collective_council.rs b/polkadot/runtime/kusama/src/weights/pallet_collective_council.rs deleted file mode 100644 index 84157595f7cb04f636965d998493c18cb16de550..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_collective_council.rs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: Council Members (r:1 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:100 w:100) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `19164 + m * (7799 ±17) + p * (10110 ±17)` - // Minimum execution time: 17_032_000 picoseconds. - Weight::from_parts(17_263_000, 0) - .saturating_add(Weight::from_parts(0, 19164)) - // Standard Error: 51_363 - .saturating_add(Weight::from_parts(5_779_193, 0).saturating_mul(m.into())) - // Standard Error: 51_363 - .saturating_add(Weight::from_parts(8_434_866, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `136 + m * (32 ±0)` - // Estimated: `1622 + m * (32 ±0)` - // Minimum execution time: 15_686_000 picoseconds. - Weight::from_parts(15_185_500, 0) - .saturating_add(Weight::from_parts(0, 1622)) - // Standard Error: 26 - .saturating_add(Weight::from_parts(1_363, 0).saturating_mul(b.into())) - // Standard Error: 277 - .saturating_add(Weight::from_parts(15_720, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:0) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `136 + m * (32 ±0)` - // Estimated: `5224 + m * (64 ±0)` - // Minimum execution time: 18_314_000 picoseconds. - Weight::from_parts(17_659_522, 0) - .saturating_add(Weight::from_parts(0, 5224)) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_153, 0).saturating_mul(b.into())) - // Standard Error: 237 - .saturating_add(Weight::from_parts(25_439, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalCount (r:1 w:1) - /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `426 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `9685 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 23_916_000 picoseconds. - Weight::from_parts(25_192_989, 0) - .saturating_add(Weight::from_parts(0, 9685)) - // Standard Error: 50 - .saturating_add(Weight::from_parts(2_327, 0).saturating_mul(b.into())) - // Standard Error: 528 - .saturating_add(Weight::from_parts(17_763, 0).saturating_mul(m.into())) - // Standard Error: 522 - .saturating_add(Weight::from_parts(116_903, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `875 + m * (64 ±0)` - // Estimated: `6698 + m * (128 ±0)` - // Minimum execution time: 21_641_000 picoseconds. - Weight::from_parts(22_373_888, 0) - .saturating_add(Weight::from_parts(0, 6698)) - // Standard Error: 299 - .saturating_add(Weight::from_parts(41_168, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `464 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `8211 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 26_158_000 picoseconds. - Weight::from_parts(27_675_242, 0) - .saturating_add(Weight::from_parts(0, 8211)) - // Standard Error: 845 - .saturating_add(Weight::from_parts(10_799, 0).saturating_mul(m.into())) - // Standard Error: 824 - .saturating_add(Weight::from_parts(141_199, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `766 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `12372 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 37_601_000 picoseconds. - Weight::from_parts(41_302_278, 0) - .saturating_add(Weight::from_parts(0, 12372)) - // Standard Error: 67 - .saturating_add(Weight::from_parts(1_608, 0).saturating_mul(b.into())) - // Standard Error: 716 - .saturating_add(Weight::from_parts(14_628, 0).saturating_mul(m.into())) - // Standard Error: 698 - .saturating_add(Weight::from_parts(129_997, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `484 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `10240 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 29_185_000 picoseconds. - Weight::from_parts(30_594_183, 0) - .saturating_add(Weight::from_parts(0, 10240)) - // Standard Error: 865 - .saturating_add(Weight::from_parts(30_165, 0).saturating_mul(m.into())) - // Standard Error: 844 - .saturating_add(Weight::from_parts(131_623, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `786 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `14575 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 43_157_000 picoseconds. - Weight::from_parts(43_691_874, 0) - .saturating_add(Weight::from_parts(0, 14575)) - // Standard Error: 61 - .saturating_add(Weight::from_parts(1_862, 0).saturating_mul(b.into())) - // Standard Error: 654 - .saturating_add(Weight::from_parts(17_183, 0).saturating_mul(m.into())) - // Standard Error: 638 - .saturating_add(Weight::from_parts(133_193, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) - } - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `293 + p * (32 ±0)` - // Estimated: `2364 + p * (96 ±0)` - // Minimum execution time: 14_666_000 picoseconds. - Weight::from_parts(16_623_386, 0) - .saturating_add(Weight::from_parts(0, 2364)) - // Standard Error: 430 - .saturating_add(Weight::from_parts(111_461, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_collective_technical_committee.rs b/polkadot/runtime/kusama/src/weights/pallet_collective_technical_committee.rs deleted file mode 100644 index 0bf5d2839b0a2c40e9894460202419c13ca21ed8..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_collective_technical_committee.rs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: TechnicalCommittee Members (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:100 w:100) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `19320 + m * (7799 ±16) + p * (10110 ±16)` - // Minimum execution time: 17_755_000 picoseconds. - Weight::from_parts(18_022_000, 0) - .saturating_add(Weight::from_parts(0, 19320)) - // Standard Error: 48_475 - .saturating_add(Weight::from_parts(5_505_299, 0).saturating_mul(m.into())) - // Standard Error: 48_475 - .saturating_add(Weight::from_parts(8_260_850, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `175 + m * (32 ±0)` - // Estimated: `1661 + m * (32 ±0)` - // Minimum execution time: 16_765_000 picoseconds. - Weight::from_parts(15_653_912, 0) - .saturating_add(Weight::from_parts(0, 1661)) - // Standard Error: 25 - .saturating_add(Weight::from_parts(1_539, 0).saturating_mul(b.into())) - // Standard Error: 261 - .saturating_add(Weight::from_parts(17_896, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:0) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `175 + m * (32 ±0)` - // Estimated: `5302 + m * (64 ±0)` - // Minimum execution time: 19_194_000 picoseconds. - Weight::from_parts(18_366_867, 0) - .saturating_add(Weight::from_parts(0, 5302)) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_342, 0).saturating_mul(b.into())) - // Standard Error: 200 - .saturating_add(Weight::from_parts(22_738, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalCount (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `465 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `9880 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 24_958_000 picoseconds. - Weight::from_parts(25_925_520, 0) - .saturating_add(Weight::from_parts(0, 9880)) - // Standard Error: 54 - .saturating_add(Weight::from_parts(2_430, 0).saturating_mul(b.into())) - // Standard Error: 570 - .saturating_add(Weight::from_parts(17_303, 0).saturating_mul(m.into())) - // Standard Error: 563 - .saturating_add(Weight::from_parts(119_736, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `914 + m * (64 ±0)` - // Estimated: `6776 + m * (128 ±0)` - // Minimum execution time: 22_620_000 picoseconds. - Weight::from_parts(23_356_968, 0) - .saturating_add(Weight::from_parts(0, 6776)) - // Standard Error: 273 - .saturating_add(Weight::from_parts(40_919, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `503 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `8367 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 27_667_000 picoseconds. - Weight::from_parts(29_094_490, 0) - .saturating_add(Weight::from_parts(0, 8367)) - // Standard Error: 842 - .saturating_add(Weight::from_parts(25_691, 0).saturating_mul(m.into())) - // Standard Error: 821 - .saturating_add(Weight::from_parts(133_244, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `805 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `12528 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 41_678_000 picoseconds. - Weight::from_parts(42_218_269, 0) - .saturating_add(Weight::from_parts(0, 12528)) - // Standard Error: 59 - .saturating_add(Weight::from_parts(1_661, 0).saturating_mul(b.into())) - // Standard Error: 624 - .saturating_add(Weight::from_parts(16_946, 0).saturating_mul(m.into())) - // Standard Error: 608 - .saturating_add(Weight::from_parts(129_170, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `523 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `10435 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 30_447_000 picoseconds. - Weight::from_parts(32_661_910, 0) - .saturating_add(Weight::from_parts(0, 10435)) - // Standard Error: 531 - .saturating_add(Weight::from_parts(29_960, 0).saturating_mul(m.into())) - // Standard Error: 517 - .saturating_add(Weight::from_parts(120_475, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `825 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `14770 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 44_068_000 picoseconds. - Weight::from_parts(44_673_420, 0) - .saturating_add(Weight::from_parts(0, 14770)) - // Standard Error: 59 - .saturating_add(Weight::from_parts(1_779, 0).saturating_mul(b.into())) - // Standard Error: 625 - .saturating_add(Weight::from_parts(17_794, 0).saturating_mul(m.into())) - // Standard Error: 609 - .saturating_add(Weight::from_parts(134_062, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `332 + p * (32 ±0)` - // Estimated: `2481 + p * (96 ±0)` - // Minimum execution time: 15_528_000 picoseconds. - Weight::from_parts(17_434_864, 0) - .saturating_add(Weight::from_parts(0, 2481)) - // Standard Error: 405 - .saturating_add(Weight::from_parts(111_909, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_democracy.rs b/polkadot/runtime/kusama/src/weights/pallet_democracy.rs deleted file mode 100644 index 794c8c8159660e8fe7f1eb27f3b1b3905d5dc5df..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_democracy.rs +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_democracy` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_democracy -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_democracy`. -pub struct WeightInfo(PhantomData); -impl pallet_democracy::WeightInfo for WeightInfo { - /// Storage: Democracy PublicPropCount (r:1 w:1) - /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:0 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `4768` - // Estimated: `26379` - // Minimum execution time: 35_098_000 picoseconds. - Weight::from_parts(35_696_000, 0) - .saturating_add(Weight::from_parts(0, 26379)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn second() -> Weight { - // Proof Size summary in bytes: - // Measured: `3523` - // Estimated: `6695` - // Minimum execution time: 32_218_000 picoseconds. - Weight::from_parts(32_458_000, 0) - .saturating_add(Weight::from_parts(0, 6695)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn vote_new() -> Weight { - // Proof Size summary in bytes: - // Measured: `3437` - // Estimated: `15690` - // Minimum execution time: 46_641_000 picoseconds. - Weight::from_parts(47_324_000, 0) - .saturating_add(Weight::from_parts(0, 15690)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn vote_existing() -> Weight { - // Proof Size summary in bytes: - // Measured: `3459` - // Estimated: `15690` - // Minimum execution time: 47_172_000 picoseconds. - Weight::from_parts(47_732_000, 0) - .saturating_add(Weight::from_parts(0, 15690)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Cancellations (r:1 w:1) - /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn emergency_cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `10682` - // Minimum execution time: 25_744_000 picoseconds. - Weight::from_parts(26_226_000, 0) - .saturating_add(Weight::from_parts(0, 10682)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:3 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:0 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn blacklist() -> Weight { - // Proof Size summary in bytes: - // Measured: `5877` - // Estimated: `42332` - // Minimum execution time: 88_365_000 picoseconds. - Weight::from_parts(90_080_000, 0) - .saturating_add(Weight::from_parts(0, 42332)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn external_propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `3383` - // Estimated: `8320` - // Minimum execution time: 12_868_000 picoseconds. - Weight::from_parts(13_178_000, 0) - .saturating_add(Weight::from_parts(0, 8320)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_majority() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_714_000 picoseconds. - Weight::from_parts(3_895_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_default() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_565_000 picoseconds. - Weight::from_parts(3_831_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:1) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:2) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn fast_track() -> Weight { - // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `6624` - // Minimum execution time: 26_453_000 picoseconds. - Weight::from_parts(26_938_000, 0) - .saturating_add(Weight::from_parts(0, 6624)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn veto_external() -> Weight { - // Proof Size summary in bytes: - // Measured: `3486` - // Estimated: `11838` - // Minimum execution time: 30_869_000 picoseconds. - Weight::from_parts(31_397_000, 0) - .saturating_add(Weight::from_parts(0, 11838)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn cancel_proposal() -> Weight { - // Proof Size summary in bytes: - // Measured: `5788` - // Estimated: `31993` - // Minimum execution time: 72_692_000 picoseconds. - Weight::from_parts(73_692_000, 0) - .saturating_add(Weight::from_parts(0, 31993)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn cancel_referendum() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3518` - // Minimum execution time: 19_506_000 picoseconds. - Weight::from_parts(19_823_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `211 + r * (86 ±0)` - // Estimated: `3968 + r * (2676 ±0)` - // Minimum execution time: 6_019_000 picoseconds. - Weight::from_parts(9_632_674, 0) - .saturating_add(Weight::from_parts(0, 3968)) - // Standard Error: 6_651 - .saturating_add(Weight::from_parts(2_769_264, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy LastTabledWasExternal (r:1 w:0) - /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `211 + r * (86 ±0)` - // Estimated: `25258 + r * (2676 ±0)` - // Minimum execution time: 9_143_000 picoseconds. - Weight::from_parts(12_247_629, 0) - .saturating_add(Weight::from_parts(0, 25258)) - // Standard Error: 6_077 - .saturating_add(Weight::from_parts(2_764_547, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:3 w:3) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn delegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `797 + r * (108 ±0)` - // Estimated: `25554 + r * (2676 ±0)` - // Minimum execution time: 41_153_000 picoseconds. - Weight::from_parts(42_787_487, 0) - .saturating_add(Weight::from_parts(0, 25554)) - // Standard Error: 7_883 - .saturating_add(Weight::from_parts(3_862_521, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:2 w:2) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn undelegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `460 + r * (108 ±0)` - // Estimated: `14520 + r * (2676 ±0)` - // Minimum execution time: 20_767_000 picoseconds. - Weight::from_parts(21_768_239, 0) - .saturating_add(Weight::from_parts(0, 14520)) - // Standard Error: 9_791 - .saturating_add(Weight::from_parts(3_862_103, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy PublicProps (r:0 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - fn clear_public_proposals() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_663_000 picoseconds. - Weight::from_parts(3_798_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_remove(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `15617` - // Minimum execution time: 19_923_000 picoseconds. - Weight::from_parts(25_945_279, 0) - .saturating_add(Weight::from_parts(0, 15617)) - // Standard Error: 1_366 - .saturating_add(Weight::from_parts(22_003, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_set(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `531 + r * (22 ±0)` - // Estimated: `15617` - // Minimum execution time: 24_393_000 picoseconds. - Weight::from_parts(25_690_593, 0) - .saturating_add(Weight::from_parts(0, 15617)) - // Standard Error: 553 - .saturating_add(Weight::from_parts(59_042, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `695 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 15_551_000 picoseconds. - Weight::from_parts(17_809_948, 0) - .saturating_add(Weight::from_parts(0, 10926)) - // Standard Error: 1_907 - .saturating_add(Weight::from_parts(86_496, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_other_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `695 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 16_027_000 picoseconds. - Weight::from_parts(17_860_077, 0) - .saturating_add(Weight::from_parts(0, 10926)) - // Standard Error: 1_950 - .saturating_add(Weight::from_parts(87_722, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `323` - // Estimated: `5173` - // Minimum execution time: 17_551_000 picoseconds. - Weight::from_parts(17_776_000, 0) - .saturating_add(Weight::from_parts(0, 5173)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `5135` - // Minimum execution time: 16_020_000 picoseconds. - Weight::from_parts(16_477_000, 0) - .saturating_add(Weight::from_parts(0, 5135)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4855` - // Estimated: `21743` - // Minimum execution time: 33_144_000 picoseconds. - Weight::from_parts(33_457_000, 0) - .saturating_add(Weight::from_parts(0, 21743)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4789` - // Estimated: `21705` - // Minimum execution time: 31_022_000 picoseconds. - Weight::from_parts(31_534_000, 0) - .saturating_add(Weight::from_parts(0, 21705)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 14_512_000 picoseconds. - Weight::from_parts(14_769_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `7184` - // Minimum execution time: 17_966_000 picoseconds. - Weight::from_parts(18_270_000, 0) - .saturating_add(Weight::from_parts(0, 7184)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_election_provider_multi_phase.rs b/polkadot/runtime/kusama/src/weights/pallet_election_provider_multi_phase.rs deleted file mode 100644 index d670d324aba04543a2fe98b654ae341f55009c38..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_election_provider_multi_phase.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_election_provider_multi_phase` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_election_provider_multi_phase -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_election_provider_multi_phase`. -pub struct WeightInfo(PhantomData); -impl pallet_election_provider_multi_phase::WeightInfo for WeightInfo { - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentPlannedSession (r:1 w:0) - /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Babe EpochIndex (r:1 w:0) - /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe GenesisSlot (r:1 w:0) - /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Staking ForceEra (r:1 w:0) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_nothing() -> Weight { - // Proof Size summary in bytes: - // Measured: `959` - // Estimated: `3481` - // Minimum execution time: 21_207_000 picoseconds. - Weight::from_parts(22_059_000, 0) - .saturating_add(Weight::from_parts(0, 3481)) - .saturating_add(T::DbWeight::get().reads(8)) - } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_open_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `1565` - // Minimum execution time: 11_472_000 picoseconds. - Weight::from_parts(11_772_000, 0) - .saturating_add(Weight::from_parts(0, 1565)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_open_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `1565` - // Minimum execution time: 12_466_000 picoseconds. - Weight::from_parts(12_954_000, 0) - .saturating_add(Weight::from_parts(0, 1565)) - .saturating_add(T::DbWeight::get().reads(2)) - .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: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - fn finalize_signed_phase_accept_solution() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 31_347_000 picoseconds. - Weight::from_parts(32_088_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .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) - fn finalize_signed_phase_reject_solution() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 21_061_000 picoseconds. - Weight::from_parts(21_819_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 796_200_000 picoseconds. - Weight::from_parts(848_268_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_942 - .saturating_add(Weight::from_parts(625_196, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn elect_queued(a: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `832 + a * (1152 ±0) + d * (47 ±0)` - // Estimated: `4282 + a * (1152 ±0) + d * (48 ±0)` - // Minimum execution time: 598_364_000 picoseconds. - Weight::from_parts(3_028_177, 0) - .saturating_add(Weight::from_parts(0, 4282)) - // Standard Error: 29_462 - .saturating_add(Weight::from_parts(1_292_240, 0).saturating_mul(a.into())) - // Standard Error: 44_163 - .saturating_add(Weight::from_parts(113_479, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(9)) - .saturating_add(Weight::from_parts(0, 1152).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(d.into())) - } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) - /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - fn submit() -> Weight { - // Proof Size summary in bytes: - // Measured: `1170` - // Estimated: `2655` - // Minimum execution time: 50_887_000 picoseconds. - Weight::from_parts(53_335_000, 0) - .saturating_add(Weight::from_parts(0, 2655)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `185 + t * (32 ±0) + v * (809 ±0)` - // Estimated: `1670 + t * (32 ±0) + v * (809 ±0)` - // Minimum execution time: 9_246_269_000 picoseconds. - Weight::from_parts(9_558_256_000, 0) - .saturating_add(Weight::from_parts(0, 1670)) - // Standard Error: 40_767 - .saturating_add(Weight::from_parts(476_361, 0).saturating_mul(v.into())) - // Standard Error: 120_810 - .saturating_add(Weight::from_parts(7_762_441, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 809).saturating_mul(v.into())) - } - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `160 + t * (32 ±0) + v * (809 ±0)` - // Estimated: `1645 + t * (32 ±0) + v * (809 ±0)` - // Minimum execution time: 7_414_707_000 picoseconds. - Weight::from_parts(7_699_413_000, 0) - .saturating_add(Weight::from_parts(0, 1645)) - // Standard Error: 29_542 - .saturating_add(Weight::from_parts(312_856, 0).saturating_mul(v.into())) - // Standard Error: 87_545 - .saturating_add(Weight::from_parts(5_993_730, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 809).saturating_mul(v.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_elections_phragmen.rs b/polkadot/runtime/kusama/src/weights/pallet_elections_phragmen.rs deleted file mode 100644 index a5c1c4dfd3d0ee5b34d98c935c6d3c10a46aa429..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_elections_phragmen.rs +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_elections_phragmen` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_elections_phragmen -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_elections_phragmen`. -pub struct WeightInfo(PhantomData); -impl pallet_elections_phragmen::WeightInfo for WeightInfo { - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 16]`. - fn vote_equal(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 27_353_000 picoseconds. - Weight::from_parts(28_103_445, 0) - .saturating_add(Weight::from_parts(0, 14292)) - // Standard Error: 4_556 - .saturating_add(Weight::from_parts(117_766, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_more(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `371 + v * (80 ±0)` - // Estimated: `14164 + v * (320 ±0)` - // Minimum execution time: 36_885_000 picoseconds. - Weight::from_parts(37_769_975, 0) - .saturating_add(Weight::from_parts(0, 14164)) - // Standard Error: 6_586 - .saturating_add(Weight::from_parts(123_567, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_less(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 36_610_000 picoseconds. - Weight::from_parts(37_524_808, 0) - .saturating_add(Weight::from_parts(0, 14292)) - // Standard Error: 6_164 - .saturating_add(Weight::from_parts(147_944, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn remove_voter() -> Weight { - // Proof Size summary in bytes: - // Measured: `925` - // Estimated: `9154` - // Minimum execution time: 33_052_000 picoseconds. - Weight::from_parts(33_677_000, 0) - .saturating_add(Weight::from_parts(0, 9154)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn submit_candidacy(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2712 + c * (48 ±0)` - // Estimated: `12585 + c * (144 ±0)` - // Minimum execution time: 32_163_000 picoseconds. - Weight::from_parts(24_757_419, 0) - .saturating_add(Weight::from_parts(0, 12585)) - // Standard Error: 902 - .saturating_add(Weight::from_parts(79_765, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `284 + c * (48 ±0)` - // Estimated: `1756 + c * (48 ±0)` - // Minimum execution time: 24_805_000 picoseconds. - Weight::from_parts(17_940_635, 0) - .saturating_add(Weight::from_parts(0, 1756)) - // Standard Error: 888 - .saturating_add(Weight::from_parts(59_369, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_members() -> Weight { - // Proof Size summary in bytes: - // Measured: `2986` - // Estimated: `20870` - // Minimum execution time: 42_908_000 picoseconds. - Weight::from_parts(43_409_000, 0) - .saturating_add(Weight::from_parts(0, 20870)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_runners_up() -> Weight { - // Proof Size summary in bytes: - // Measured: `1681` - // Estimated: `3166` - // Minimum execution time: 27_419_000 picoseconds. - Weight::from_parts(27_912_000, 0) - .saturating_add(Weight::from_parts(0, 3166)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn remove_member_without_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn remove_member_with_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `2986` - // Estimated: `24463` - // Minimum execution time: 57_465_000 picoseconds. - Weight::from_parts(58_107_000, 0) - .saturating_add(Weight::from_parts(0, 24463)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: PhragmenElection Voting (r:10001 w:10000) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `35989 + v * (808 ±0)` - // Estimated: `154956 + v * (12084 ±0)` - // Minimum execution time: 319_677_473_000 picoseconds. - Weight::from_parts(320_382_361_000, 0) - .saturating_add(Weight::from_parts(0, 154956)) - // Standard Error: 270_292 - .saturating_add(Weight::from_parts(38_671_603, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 12084).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:10001 w:0) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:962 w:962) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection ElectionRounds (r:1 w:1) - /// Proof Skipped: PhragmenElection ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + v * (607 ±0) + e * (28 ±0)` - // Estimated: `4839313 + v * (5481 ±4) + e * (123 ±0) + c * (2560 ±0)` - // Minimum execution time: 30_795_431_000 picoseconds. - Weight::from_parts(30_861_700_000, 0) - .saturating_add(Weight::from_parts(0, 4839313)) - // Standard Error: 482_348 - .saturating_add(Weight::from_parts(37_626_560, 0).saturating_mul(v.into())) - // Standard Error: 30_954 - .saturating_add(Weight::from_parts(2_016_889, 0).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(265)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5481).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 123).saturating_mul(e.into())) - .saturating_add(Weight::from_parts(0, 2560).saturating_mul(c.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_fast_unstake.rs b/polkadot/runtime/kusama/src/weights/pallet_fast_unstake.rs deleted file mode 100644 index 34fec8e784f73538d5d9cddbc948e989c70b5455..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_fast_unstake.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_fast_unstake` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_fast_unstake -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_fast_unstake`. -pub struct WeightInfo(PhantomData); -impl pallet_fast_unstake::WeightInfo for WeightInfo { - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(3191), added: 3686, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:64 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Bonded (r:64 w:64) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:64 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:64 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: System Account (r:64 w:64) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:64 w:64) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:64 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:64) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:64) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// The range of component `b` is `[1, 64]`. - fn on_idle_unstake(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1176 + b * (343 ±0)` - // Estimated: `4676 + b * (3774 ±0)` - // Minimum execution time: 90_522_000 picoseconds. - Weight::from_parts(30_621_885, 0) - .saturating_add(Weight::from_parts(0, 4676)) - // Standard Error: 35_474 - .saturating_add(Weight::from_parts(58_149_619, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(3191), added: 3686, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:257 w:0) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[1, 256]`. - /// The range of component `b` is `[1, 64]`. - fn on_idle_check(v: u32, b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1344 + b * (48 ±0) + v * (18487 ±0)` - // Estimated: `4676 + b * (49 ±0) + v * (20963 ±0)` - // Minimum execution time: 1_633_429_000 picoseconds. - Weight::from_parts(1_647_031_000, 0) - .saturating_add(Weight::from_parts(0, 4676)) - // Standard Error: 14_231_088 - .saturating_add(Weight::from_parts(454_485_752, 0).saturating_mul(v.into())) - // Standard Error: 56_940_204 - .saturating_add(Weight::from_parts(1_784_096_716, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 20963).saturating_mul(v.into())) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(3191), added: 3686, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn register_fast_unstake() -> Weight { - // Proof Size summary in bytes: - // Measured: `1826` - // Estimated: `4764` - // Minimum execution time: 120_577_000 picoseconds. - Weight::from_parts(123_610_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(15)) - .saturating_add(T::DbWeight::get().writes(9)) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(3191), added: 3686, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn deregister() -> Weight { - // Proof Size summary in bytes: - // Measured: `1084` - // Estimated: `4676` - // Minimum execution time: 42_258_000 picoseconds. - Weight::from_parts(43_647_000, 0) - .saturating_add(Weight::from_parts(0, 4676)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn control() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(2_654_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_identity.rs b/polkadot/runtime/kusama/src/weights/pallet_identity.rs deleted file mode 100644 index f4952db592b421cd67fd61b802c1ddc7a431780f..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_identity.rs +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_identity` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_identity -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_identity`. -pub struct WeightInfo(PhantomData); -impl pallet_identity::WeightInfo for WeightInfo { - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn add_registrar(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 11_854_000 picoseconds. - Weight::from_parts(12_968_221, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 5_813 - .saturating_add(Weight::from_parts(102_873, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn set_identity(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `442 + r * (5 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_800_000 picoseconds. - Weight::from_parts(28_706_621, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 12_190 - .saturating_add(Weight::from_parts(261_969, 0).saturating_mul(r.into())) - // Standard Error: 2_378 - .saturating_add(Weight::from_parts(500_617, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:100 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn set_subs_new(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `11003 + s * (2589 ±0)` - // Minimum execution time: 8_815_000 picoseconds. - Weight::from_parts(21_946_444, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_757 - .saturating_add(Weight::from_parts(3_241_262, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. - fn set_subs_old(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `194 + p * (32 ±0)` - // Estimated: `11003` - // Minimum execution time: 8_892_000 picoseconds. - Weight::from_parts(21_343_974, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_109 - .saturating_add(Weight::from_parts(1_410_415, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[0, 100]`. - /// The range of component `x` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 60_331_000 picoseconds. - Weight::from_parts(29_115_598, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 21_877 - .saturating_add(Weight::from_parts(216_644, 0).saturating_mul(r.into())) - // Standard Error: 4_272 - .saturating_add(Weight::from_parts(1_420_433, 0).saturating_mul(s.into())) - // Standard Error: 4_272 - .saturating_add(Weight::from_parts(311_436, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn request_judgement(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 33_470_000 picoseconds. - Weight::from_parts(32_277_730, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 4_577 - .saturating_add(Weight::from_parts(121_062, 0).saturating_mul(r.into())) - // Standard Error: 893 - .saturating_add(Weight::from_parts(496_715, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `398 + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_626_000 picoseconds. - Weight::from_parts(28_419_375, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_566 - .saturating_add(Weight::from_parts(143_337, 0).saturating_mul(r.into())) - // Standard Error: 1_086 - .saturating_add(Weight::from_parts(487_332, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_fee(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_221_000 picoseconds. - Weight::from_parts(7_708_979, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_516 - .saturating_add(Weight::from_parts(101_163, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_account_id(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_288_000 picoseconds. - Weight::from_parts(7_757_754, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_365 - .saturating_add(Weight::from_parts(95_345, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_fields(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_204_000 picoseconds. - Weight::from_parts(7_679_617, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_358 - .saturating_add(Weight::from_parts(100_186, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - /// The range of component `x` is `[0, 100]`. - fn provide_judgement(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 23_125_000 picoseconds. - Weight::from_parts(22_392_893, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_154 - .saturating_add(Weight::from_parts(121_813, 0).saturating_mul(r.into())) - // Standard Error: 953 - .saturating_add(Weight::from_parts(806_355, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[0, 100]`. - /// The range of component `x` is `[0, 100]`. - fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 76_226_000 picoseconds. - Weight::from_parts(35_456_327, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 18_829 - .saturating_add(Weight::from_parts(615_512, 0).saturating_mul(r.into())) - // Standard Error: 3_677 - .saturating_add(Weight::from_parts(1_462_016, 0).saturating_mul(s.into())) - // Standard Error: 3_677 - .saturating_add(Weight::from_parts(328_050, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 99]`. - fn add_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `475 + s * (36 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_381_000 picoseconds. - Weight::from_parts(33_288_068, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_624 - .saturating_add(Weight::from_parts(120_173, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn rename_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `591 + s * (3 ±0)` - // Estimated: `11003` - // Minimum execution time: 12_418_000 picoseconds. - Weight::from_parts(13_798_930, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 856 - .saturating_add(Weight::from_parts(43_306, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn remove_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `638 + s * (35 ±0)` - // Estimated: `11003` - // Minimum execution time: 33_242_000 picoseconds. - Weight::from_parts(36_552_253, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_385 - .saturating_add(Weight::from_parts(98_359, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 99]`. - fn quit_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `704 + s * (37 ±0)` - // Estimated: `6723` - // Minimum execution time: 24_017_000 picoseconds. - Weight::from_parts(27_149_414, 0) - .saturating_add(Weight::from_parts(0, 6723)) - // Standard Error: 1_769 - .saturating_add(Weight::from_parts(79_539, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_im_online.rs b/polkadot/runtime/kusama/src/weights/pallet_im_online.rs deleted file mode 100644 index 3bb3d65c4a6b0e462aab3e179c77203a121b5a14..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_im_online.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_im_online` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_im_online -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_im_online`. -pub struct WeightInfo(PhantomData); -impl pallet_im_online::WeightInfo for WeightInfo { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 1000]`. - fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `361 + k * (32 ±0)` - // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 82_038_000 picoseconds. - Weight::from_parts(100_726_620, 0) - .saturating_add(Weight::from_parts(0, 321487)) - // Standard Error: 600 - .saturating_add(Weight::from_parts(30_346, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_indices.rs b/polkadot/runtime/kusama/src/weights/pallet_indices.rs deleted file mode 100644 index b26562975cf80b4bd095956ad5be0a804bceed9c..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_indices.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_indices` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_indices -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_indices`. -pub struct WeightInfo(PhantomData); -impl pallet_indices::WeightInfo for WeightInfo { - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3534` - // Minimum execution time: 25_322_000 picoseconds. - Weight::from_parts(26_124_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `341` - // Estimated: `3593` - // Minimum execution time: 36_790_000 picoseconds. - Weight::from_parts(37_218_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn free() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3534` - // Minimum execution time: 25_968_000 picoseconds. - Weight::from_parts(26_450_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `341` - // Estimated: `3593` - // Minimum execution time: 27_734_000 picoseconds. - Weight::from_parts(28_523_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn freeze() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3534` - // Minimum execution time: 27_980_000 picoseconds. - Weight::from_parts(28_448_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_membership.rs b/polkadot/runtime/kusama/src/weights/pallet_membership.rs deleted file mode 100644 index 6b144bc879494612c89052ed84bf5d221075aa60..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_membership.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_membership` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_membership -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_membership`. -pub struct WeightInfo(PhantomData); -impl pallet_membership::WeightInfo for WeightInfo { - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 99]`. - fn add_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `208 + m * (64 ±0)` - // Estimated: `6793 + m * (192 ±0)` - // Minimum execution time: 15_847_000 picoseconds. - Weight::from_parts(16_597_325, 0) - .saturating_add(Weight::from_parts(0, 6793)) - // Standard Error: 411 - .saturating_add(Weight::from_parts(35_801, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn remove_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` - // Estimated: `8622 + m * (192 ±0)` - // Minimum execution time: 18_412_000 picoseconds. - Weight::from_parts(19_251_698, 0) - .saturating_add(Weight::from_parts(0, 8622)) - // Standard Error: 474 - .saturating_add(Weight::from_parts(32_206, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn swap_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` - // Estimated: `8622 + m * (192 ±0)` - // Minimum execution time: 18_502_000 picoseconds. - Weight::from_parts(19_583_888, 0) - .saturating_add(Weight::from_parts(0, 8622)) - // Standard Error: 619 - .saturating_add(Weight::from_parts(44_408, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn reset_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` - // Estimated: `8622 + m * (192 ±0)` - // Minimum execution time: 18_088_000 picoseconds. - Weight::from_parts(19_292_324, 0) - .saturating_add(Weight::from_parts(0, 8622)) - // Standard Error: 759 - .saturating_add(Weight::from_parts(162_348, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn change_key(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `312 + m * (64 ±0)` - // Estimated: `8622 + m * (192 ±0)` - // Minimum execution time: 19_134_000 picoseconds. - Weight::from_parts(20_242_466, 0) - .saturating_add(Weight::from_parts(0, 8622)) - // Standard Error: 962 - .saturating_add(Weight::from_parts(47_779, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:0) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn set_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `4719 + m * (32 ±0)` - // Minimum execution time: 6_726_000 picoseconds. - Weight::from_parts(6_966_055, 0) - .saturating_add(Weight::from_parts(0, 4719)) - // Standard Error: 255 - .saturating_add(Weight::from_parts(13_950, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_010_000 picoseconds. - Weight::from_parts(3_196_429, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 78 - .saturating_add(Weight::from_parts(471, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_message_queue.rs b/polkadot/runtime/kusama/src/weights/pallet_message_queue.rs deleted file mode 100644 index f149eef194fb5895665cd853cd7fa2ffd58600df..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_message_queue -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `6050` - // Minimum execution time: 11_603_000 picoseconds. - Weight::from_parts(11_953_000, 0) - .saturating_add(Weight::from_parts(0, 6050)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `6050` - // Minimum execution time: 10_668_000 picoseconds. - Weight::from_parts(11_105_000, 0) - .saturating_add(Weight::from_parts(0, 6050)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `3520` - // Minimum execution time: 4_158_000 picoseconds. - Weight::from_parts(4_379_000, 0) - .saturating_add(Weight::from_parts(0, 3520)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `69051` - // Minimum execution time: 5_873_000 picoseconds. - Weight::from_parts(6_002_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `69051` - // Minimum execution time: 6_110_000 picoseconds. - Weight::from_parts(6_385_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_page_item() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 92_242_000 picoseconds. - Weight::from_parts(92_796_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `3520` - // Minimum execution time: 6_386_000 picoseconds. - Weight::from_parts(6_629_000, 0) - .saturating_add(Weight::from_parts(0, 3520)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `65714` - // Estimated: `69051` - // Minimum execution time: 59_294_000 picoseconds. - Weight::from_parts(60_608_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `65714` - // Estimated: `69051` - // Minimum execution time: 75_134_000 picoseconds. - Weight::from_parts(76_729_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `65714` - // Estimated: `69051` - // Minimum execution time: 117_320_000 picoseconds. - Weight::from_parts(119_640_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_nis.rs b/polkadot/runtime/kusama/src/weights/pallet_nis.rs deleted file mode 100644 index 2dc8b261eb57ac2fb6b73a34f6a11480fc66e718..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_nis.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_nis` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_nis -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_nis`. -pub struct WeightInfo(PhantomData); -impl pallet_nis::WeightInfo for WeightInfo { - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(10002), added: 10497, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 999]`. - fn place_bid(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `10210 + l * (48 ±0)` - // Estimated: `51487` - // Minimum execution time: 49_318_000 picoseconds. - Weight::from_parts(47_894_330, 0) - .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 1_184 - .saturating_add(Weight::from_parts(110_633, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(10002), added: 10497, mode: MaxEncodedLen) - fn place_bid_max() -> Weight { - // Proof Size summary in bytes: - // Measured: `58212` - // Estimated: `51487` - // Minimum execution time: 162_699_000 picoseconds. - Weight::from_parts(171_243_000, 0) - .saturating_add(Weight::from_parts(0, 51487)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(10002), added: 10497, mode: MaxEncodedLen) - /// The range of component `l` is `[1, 1000]`. - fn retract_bid(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `10210 + l * (48 ±0)` - // Estimated: `51487` - // Minimum execution time: 51_827_000 picoseconds. - Weight::from_parts(44_282_033, 0) - .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 1_145 - .saturating_add(Weight::from_parts(121_058, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Nis Summary (r:1 w:0) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn fund_deficit() -> Weight { - // Proof Size summary in bytes: - // Measured: `225` - // Estimated: `3593` - // Minimum execution time: 39_765_000 picoseconds. - Weight::from_parts(40_525_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - fn communify() -> Weight { - // Proof Size summary in bytes: - // Measured: `470` - // Estimated: `3593` - // Minimum execution time: 75_890_000 picoseconds. - Weight::from_parts(77_519_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - fn privatize() -> Weight { - // Proof Size summary in bytes: - // Measured: `660` - // Estimated: `3593` - // Minimum execution time: 92_622_000 picoseconds. - Weight::from_parts(94_127_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - fn thaw_private() -> Weight { - // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `3593` - // Minimum execution time: 49_336_000 picoseconds. - Weight::from_parts(50_333_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn thaw_communal() -> Weight { - // Proof Size summary in bytes: - // Measured: `604` - // Estimated: `3593` - // Minimum execution time: 98_220_000 picoseconds. - Weight::from_parts(100_348_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(10002), added: 10497, mode: MaxEncodedLen) - fn process_queues() -> Weight { - // Proof Size summary in bytes: - // Measured: `10658` - // Estimated: `11487` - // Minimum execution time: 33_893_000 picoseconds. - Weight::from_parts(37_495_000, 0) - .saturating_add(Weight::from_parts(0, 11487)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - fn process_queue() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `51487` - // Minimum execution time: 4_173_000 picoseconds. - Weight::from_parts(4_322_000, 0) - .saturating_add(Weight::from_parts(0, 51487)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Nis Receipts (r:0 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - fn process_bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_747_000 picoseconds. - Weight::from_parts(6_952_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_nomination_pools.rs b/polkadot/runtime/kusama/src/weights/pallet_nomination_pools.rs deleted file mode 100644 index 65bb76860b3055aa5d27b3363d4629be4b9ec6e1..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_nomination_pools.rs +++ /dev/null @@ -1,603 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_nomination_pools` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_nomination_pools -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_nomination_pools`. -pub struct WeightInfo(PhantomData); -impl pallet_nomination_pools::WeightInfo for WeightInfo { - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn join() -> Weight { - // Proof Size summary in bytes: - // Measured: `3229` - // Estimated: `8877` - // Minimum execution time: 198_640_000 picoseconds. - Weight::from_parts(205_158_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().writes(12)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `3239` - // Estimated: `8877` - // Minimum execution time: 191_638_000 picoseconds. - Weight::from_parts(200_580_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(12)) - } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `3304` - // Estimated: `8877` - // Minimum execution time: 232_697_000 picoseconds. - Weight::from_parts(238_503_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(17)) - .saturating_add(T::DbWeight::get().writes(13)) - } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn claim_payout() -> Weight { - // Proof Size summary in bytes: - // Measured: `1171` - // Estimated: `4182` - // Minimum execution time: 79_834_000 picoseconds. - Weight::from_parts(81_793_000, 0) - .saturating_add(Weight::from_parts(0, 4182)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `3506` - // Estimated: `8877` - // Minimum execution time: 175_155_000 picoseconds. - Weight::from_parts(179_781_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(20)) - .saturating_add(T::DbWeight::get().writes(13)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn pool_withdraw_unbonded(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1608` - // Estimated: `4764` - // Minimum execution time: 63_367_000 picoseconds. - Weight::from_parts(65_562_125, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_722 - .saturating_add(Weight::from_parts(47_690, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2036` - // Estimated: `4764` - // Minimum execution time: 132_738_000 picoseconds. - Weight::from_parts(136_968_458, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_891 - .saturating_add(Weight::from_parts(75_317, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2394` - // Estimated: `6196` - // Minimum execution time: 223_915_000 picoseconds. - Weight::from_parts(229_729_576, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 5_670 - .saturating_add(Weight::from_parts(38_117, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(21)) - .saturating_add(T::DbWeight::get().writes(18)) - } - /// Storage: NominationPools LastPoolId (r:1 w:1) - /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:1 w:0) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:1 w:0) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `1222` - // Estimated: `6196` - // Minimum execution time: 193_054_000 picoseconds. - Weight::from_parts(200_888_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(22)) - .saturating_add(T::DbWeight::get().writes(15)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:25 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 24]`. - fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1774` - // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 67_269_000 picoseconds. - Weight::from_parts(68_792_502, 0) - .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 6_020 - .saturating_add(Weight::from_parts(1_407_587, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - fn set_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `1363` - // Estimated: `4556` - // Minimum execution time: 35_349_000 picoseconds. - Weight::from_parts(36_869_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForMetadata (r:1 w:1) - /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 256]`. - fn set_metadata(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3735` - // Minimum execution time: 13_767_000 picoseconds. - Weight::from_parts(14_685_113, 0) - .saturating_add(Weight::from_parts(0, 3735)) - // Standard Error: 303 - .saturating_add(Weight::from_parts(1_304, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools MinJoinBond (r:0 w:1) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:0 w:1) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:0 w:1) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:0 w:1) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_configs() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_044_000 picoseconds. - Weight::from_parts(6_296_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn update_roles() -> Weight { - // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_642_000 picoseconds. - Weight::from_parts(20_205_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1937` - // Estimated: `4556` - // Minimum execution time: 65_923_000 picoseconds. - Weight::from_parts(68_711_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `770` - // Estimated: `3685` - // Minimum execution time: 32_824_000 picoseconds. - Weight::from_parts(33_654_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn set_commission_max() -> Weight { - // Proof Size summary in bytes: - // Measured: `571` - // Estimated: `3685` - // Minimum execution time: 18_577_000 picoseconds. - Weight::from_parts(19_317_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn set_commission_change_rate() -> Weight { - // Proof Size summary in bytes: - // Measured: `531` - // Estimated: `3685` - // Minimum execution time: 19_228_000 picoseconds. - Weight::from_parts(20_070_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools PoolMembers (r:1 w:0) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:1 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - fn set_claim_permission() -> Weight { - // Proof Size summary in bytes: - // Measured: `542` - // Estimated: `4182` - // Minimum execution time: 14_300_000 picoseconds. - Weight::from_parts(14_678_000, 0) - .saturating_add(Weight::from_parts(0, 4182)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn claim_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `968` - // Estimated: `3685` - // Minimum execution time: 65_367_000 picoseconds. - Weight::from_parts(67_417_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_offences.rs b/polkadot/runtime/kusama/src/weights/pallet_offences.rs deleted file mode 100644 index 12a045d66761c2214abfe782a1b52efd5fa6421c..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_offences.rs +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_offences` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_offences -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_offences`. -pub struct WeightInfo(PhantomData); -impl pallet_offences::WeightInfo for WeightInfo { - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:100 w:100) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:100 w:100) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:2500 w:2500) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:2500 w:2500) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:100 w:100) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:299 w:299) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:100 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:2400 w:2400) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[1, 100]`. - /// The range of component `o` is `[2, 100]`. - /// The range of component `n` is `[0, 24]`. - fn report_offence_im_online(_r: u32, o: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (2863 ±0) + o * (1226 ±0)` - // Estimated: `128540 + n * (156186 ±29) + o * (38402 ±7)` - // Minimum execution time: 695_466_000 picoseconds. - Weight::from_parts(705_203_000, 0) - .saturating_add(Weight::from_parts(0, 128540)) - // Standard Error: 4_753_384 - .saturating_add(Weight::from_parts(476_947_930, 0).saturating_mul(o.into())) - // Standard Error: 19_364_925 - .saturating_add(Weight::from_parts(573_438_006, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(172)) - .saturating_add(T::DbWeight::get().reads((51_u64).saturating_mul(o.into()))) - .saturating_add(T::DbWeight::get().reads((185_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(165)) - .saturating_add(T::DbWeight::get().writes((50_u64).saturating_mul(o.into()))) - .saturating_add(T::DbWeight::get().writes((185_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 156186).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 38402).saturating_mul(o.into())) - } - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:25 w:25) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:25 w:25) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:24 w:24) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 24]`. - fn report_offence_grandpa(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1831 + n * (48 ±0)` - // Estimated: `5686 + n * (2551 ±0)` - // Minimum execution time: 92_093_000 picoseconds. - Weight::from_parts(104_573_662, 0) - .saturating_add(Weight::from_parts(0, 5686)) - // Standard Error: 22_045 - .saturating_add(Weight::from_parts(10_859_187, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(13)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2551).saturating_mul(n.into())) - } - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:25 w:25) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:25 w:25) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:24 w:24) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 24]`. - fn report_offence_babe(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1831 + n * (48 ±0)` - // Estimated: `5686 + n * (2551 ±0)` - // Minimum execution time: 92_097_000 picoseconds. - Weight::from_parts(104_496_920, 0) - .saturating_add(Weight::from_parts(0, 5686)) - // Standard Error: 25_384 - .saturating_add(Weight::from_parts(10_982_115, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(13)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2551).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_preimage.rs b/polkadot/runtime/kusama/src/weights/pallet_preimage.rs deleted file mode 100644 index d0bf205666097d11b644fe7c31da4b86838f9e72..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_preimage.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_preimage` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_preimage -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_preimage`. -pub struct WeightInfo(PhantomData); -impl pallet_preimage::WeightInfo for WeightInfo { - fn ensure_updated(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(2_000_000, 3593) - // Standard Error: 13_720 - .saturating_add(Weight::from_parts(17_309_199, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) - } - - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `143` - // Estimated: `3556` - // Minimum execution time: 29_231_000 picoseconds. - Weight::from_parts(29_712_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_593, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_requested_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 15_753_000 picoseconds. - Weight::from_parts(15_927_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_585, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 15_147_000 picoseconds. - Weight::from_parts(15_364_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_553, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unnote_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `3556` - // Minimum execution time: 52_018_000 picoseconds. - Weight::from_parts(57_037_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unnote_no_deposit_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 32_110_000 picoseconds. - Weight::from_parts(35_435_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `188` - // Estimated: `3556` - // Minimum execution time: 28_380_000 picoseconds. - Weight::from_parts(31_692_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_no_deposit_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 18_218_000 picoseconds. - Weight::from_parts(20_005_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_unnoted_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `3556` - // Minimum execution time: 24_225_000 picoseconds. - Weight::from_parts(27_623_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_requested_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 11_614_000 picoseconds. - Weight::from_parts(12_372_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unrequest_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 30_214_000 picoseconds. - Weight::from_parts(32_682_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn unrequest_unnoted_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 10_659_000 picoseconds. - Weight::from_parts(12_066_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn unrequest_multi_referenced_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 10_770_000 picoseconds. - Weight::from_parts(11_745_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_proxy.rs b/polkadot/runtime/kusama/src/weights/pallet_proxy.rs deleted file mode 100644 index d30547d7d01cd95a766a13ff9a26a73418b059b5..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_proxy.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_proxy` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_proxy -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_proxy`. -pub struct WeightInfo(PhantomData); -impl pallet_proxy::WeightInfo for WeightInfo { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 15_098_000 picoseconds. - Weight::from_parts(15_489_847, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_263 - .saturating_add(Weight::from_parts(63_093, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `554 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 39_651_000 picoseconds. - Weight::from_parts(40_543_916, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 4_675 - .saturating_add(Weight::from_parts(155_883, 0).saturating_mul(a.into())) - // Standard Error: 4_830 - .saturating_add(Weight::from_parts(30_475, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_096_000 picoseconds. - Weight::from_parts(25_043_982, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 2_018 - .saturating_add(Weight::from_parts(161_362, 0).saturating_mul(a.into())) - // Standard Error: 2_085 - .saturating_add(Weight::from_parts(5_869, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, _p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_544_000 picoseconds. - Weight::from_parts(25_464_879, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(157_224, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn announce(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `486 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 33_869_000 picoseconds. - Weight::from_parts(36_671_590, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 4_508 - .saturating_add(Weight::from_parts(170_494, 0).saturating_mul(a.into())) - // Standard Error: 4_657 - .saturating_add(Weight::from_parts(29_881, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn add_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_378_000 picoseconds. - Weight::from_parts(26_232_312, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_337 - .saturating_add(Weight::from_parts(62_294, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_306_000 picoseconds. - Weight::from_parts(26_702_472, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_760 - .saturating_add(Weight::from_parts(52_636, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxies(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 22_177_000 picoseconds. - Weight::from_parts(22_859_150, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_374 - .saturating_add(Weight::from_parts(51_085, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `4706` - // Minimum execution time: 27_010_000 picoseconds. - Weight::from_parts(27_910_735, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_618 - .saturating_add(Weight::from_parts(10_864, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 30]`. - fn kill_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `264 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_039_000 picoseconds. - Weight::from_parts(23_903_487, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 2_434 - .saturating_add(Weight::from_parts(45_603, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_ranked_collective.rs b/polkadot/runtime/kusama/src/weights/pallet_ranked_collective.rs deleted file mode 100644 index 21f3f651f2e3b2baf5015f7090b09880dc13b87a..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_ranked_collective.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_ranked_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_ranked_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_ranked_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_ranked_collective::WeightInfo for WeightInfo { - /// Storage: FellowshipCollective Members (r:1 w:1) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:1) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IndexToId (r:0 w:1) - /// Proof: FellowshipCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IdToIndex (r:0 w:1) - /// Proof: FellowshipCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - fn add_member() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3507` - // Minimum execution time: 16_103_000 picoseconds. - Weight::from_parts(16_743_000, 0) - .saturating_add(Weight::from_parts(0, 3507)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipCollective Members (r:1 w:1) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:11 w:11) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IdToIndex (r:11 w:11) - /// Proof: FellowshipCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IndexToId (r:11 w:11) - /// Proof: FellowshipCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 10]`. - fn remove_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `550 + r * (281 ±0)` - // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 27_225_000 picoseconds. - Weight::from_parts(31_460_102, 0) - .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 23_877 - .saturating_add(Weight::from_parts(12_798_296, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) - } - /// Storage: FellowshipCollective Members (r:1 w:1) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:1) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IndexToId (r:0 w:1) - /// Proof: FellowshipCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IdToIndex (r:0 w:1) - /// Proof: FellowshipCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 10]`. - fn promote_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `248 + r * (17 ±0)` - // Estimated: `3507` - // Minimum execution time: 18_964_000 picoseconds. - Weight::from_parts(19_901_082, 0) - .saturating_add(Weight::from_parts(0, 3507)) - // Standard Error: 4_560 - .saturating_add(Weight::from_parts(326_770, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipCollective Members (r:1 w:1) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:1) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IdToIndex (r:1 w:1) - /// Proof: FellowshipCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// Storage: FellowshipCollective IndexToId (r:1 w:1) - /// Proof: FellowshipCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 10]`. - fn demote_member(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `566 + r * (72 ±0)` - // Estimated: `3519` - // Minimum execution time: 27_310_000 picoseconds. - Weight::from_parts(30_386_652, 0) - .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 33_721 - .saturating_add(Weight::from_parts(667_118, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipCollective Members (r:1 w:0) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective Voting (r:1 w:1) - /// Proof: FellowshipCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `638` - // Estimated: `83866` - // Minimum execution time: 50_373_000 picoseconds. - Weight::from_parts(51_359_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective VotingCleanup (r:1 w:0) - /// Proof: FellowshipCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: FellowshipCollective Voting (r:100 w:100) - /// Proof: FellowshipCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 100]`. - fn cleanup_poll(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `434 + n * (50 ±0)` - // Estimated: `4365 + n * (2540 ±0)` - // Minimum execution time: 14_237_000 picoseconds. - Weight::from_parts(16_304_970, 0) - .saturating_add(Weight::from_parts(0, 4365)) - // Standard Error: 2_460 - .saturating_add(Weight::from_parts(1_185_342, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_recovery.rs b/polkadot/runtime/kusama/src/weights/pallet_recovery.rs deleted file mode 100644 index 6f2fdfa334f6eadb351a91174316741f79ac5c7a..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_recovery.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_recovery` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_recovery -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_recovery`. -pub struct WeightInfo(PhantomData); -impl pallet_recovery::WeightInfo for WeightInfo { - /// Storage: Recovery Proxy (r:1 w:0) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - fn as_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `182` - // Estimated: `3545` - // Minimum execution time: 9_088_000 picoseconds. - Weight::from_parts(9_345_000, 0) - .saturating_add(Weight::from_parts(0, 3545)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: Recovery Proxy (r:0 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - fn set_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_810_000 picoseconds. - Weight::from_parts(9_033_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery Recoverable (r:1 w:1) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 9]`. - fn create_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3816` - // Minimum execution time: 25_748_000 picoseconds. - Weight::from_parts(26_517_291, 0) - .saturating_add(Weight::from_parts(0, 3816)) - // Standard Error: 4_572 - .saturating_add(Weight::from_parts(103_064, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery Recoverable (r:1 w:0) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) - /// Storage: Recovery ActiveRecoveries (r:1 w:1) - /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) - fn initiate_recovery() -> Weight { - // Proof Size summary in bytes: - // Measured: `173` - // Estimated: `3854` - // Minimum execution time: 28_593_000 picoseconds. - Weight::from_parts(29_386_000, 0) - .saturating_add(Weight::from_parts(0, 3854)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery Recoverable (r:1 w:0) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) - /// Storage: Recovery ActiveRecoveries (r:1 w:1) - /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 9]`. - fn vouch_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `261 + n * (64 ±0)` - // Estimated: `3854` - // Minimum execution time: 18_621_000 picoseconds. - Weight::from_parts(19_241_387, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 5_538 - .saturating_add(Weight::from_parts(263_385, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery Recoverable (r:1 w:0) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) - /// Storage: Recovery ActiveRecoveries (r:1 w:0) - /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) - /// Storage: Recovery Proxy (r:1 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 9]`. - fn claim_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `293 + n * (64 ±0)` - // Estimated: `3854` - // Minimum execution time: 22_870_000 picoseconds. - Weight::from_parts(23_779_105, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 4_668 - .saturating_add(Weight::from_parts(149_312, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery ActiveRecoveries (r:1 w:1) - /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 9]`. - fn close_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `414 + n * (32 ±0)` - // Estimated: `3854` - // Minimum execution time: 34_111_000 picoseconds. - Weight::from_parts(35_420_404, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 5_909 - .saturating_add(Weight::from_parts(46_955, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Recovery ActiveRecoveries (r:1 w:0) - /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) - /// Storage: Recovery Recoverable (r:1 w:1) - /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 9]`. - fn remove_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `170 + n * (32 ±0)` - // Estimated: `3854` - // Minimum execution time: 30_441_000 picoseconds. - Weight::from_parts(31_553_945, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 7_463 - .saturating_add(Weight::from_parts(119_815, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Recovery Proxy (r:1 w:1) - /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - fn cancel_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `182` - // Estimated: `3545` - // Minimum execution time: 10_937_000 picoseconds. - Weight::from_parts(11_333_000, 0) - .saturating_add(Weight::from_parts(0, 3545)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_scheduler.rs b/polkadot/runtime/kusama/src/weights/pallet_scheduler.rs deleted file mode 100644 index 3e8e8810b2e5fae3c1bae957a37d27502cf60080..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_scheduler.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_scheduler` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_scheduler -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_scheduler`. -pub struct WeightInfo(PhantomData); -impl pallet_scheduler::WeightInfo for WeightInfo { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn service_agendas_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1489` - // Minimum execution time: 4_091_000 picoseconds. - Weight::from_parts(4_209_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 50]`. - fn service_agenda_base(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 3_545_000 picoseconds. - Weight::from_parts(6_437_280, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_955 - .saturating_add(Weight::from_parts(892_412, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_679_000 picoseconds. - Weight::from_parts(5_799_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: Preimage PreimageFor (r:1 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// The range of component `s` is `[128, 4194304]`. - fn service_task_fetched(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `179 + s * (1 ±0)` - // Estimated: `3644 + s * (1 ±0)` - // Minimum execution time: 19_438_000 picoseconds. - Weight::from_parts(19_663_000, 0) - .saturating_add(Weight::from_parts(0, 3644)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_513, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) - } - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - fn service_task_named() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_131_000 picoseconds. - Weight::from_parts(7_388_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_periodic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_761_000 picoseconds. - Weight::from_parts(5_896_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_530_000 picoseconds. - Weight::from_parts(2_632_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_548_000 picoseconds. - Weight::from_parts(2_632_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 49]`. - fn schedule(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 12_757_000 picoseconds. - Weight::from_parts(15_453_687, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_121 - .saturating_add(Weight::from_parts(920_922, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 50]`. - fn cancel(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 17_412_000 picoseconds. - Weight::from_parts(16_293_532, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_448 - .saturating_add(Weight::from_parts(1_635_003, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 49]`. - fn schedule_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `293 + s * (185 ±0)` - // Estimated: `42428` - // Minimum execution time: 16_149_000 picoseconds. - Weight::from_parts(19_661_866, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_641 - .saturating_add(Weight::from_parts(952_864, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 50]`. - fn cancel_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `319 + s * (185 ±0)` - // Estimated: `42428` - // Minimum execution time: 18_858_000 picoseconds. - Weight::from_parts(18_380_802, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 3_271 - .saturating_add(Weight::from_parts(1_687_802, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_session.rs b/polkadot/runtime/kusama/src/weights/pallet_session.rs deleted file mode 100644 index 3f5469477e5816412a52de10066500df50448fbe..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_session.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_session` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_session -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_session`. -pub struct WeightInfo(PhantomData); -impl pallet_session::WeightInfo for WeightInfo { - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:6 w:6) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - fn set_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `2050` - // Estimated: `17890` - // Minimum execution time: 60_102_000 picoseconds. - Weight::from_parts(63_699_000, 0) - .saturating_add(Weight::from_parts(0, 17890)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:0 w:6) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - fn purge_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `1914` - // Estimated: `5379` - // Minimum execution time: 42_242_000 picoseconds. - Weight::from_parts(43_575_000, 0) - .saturating_add(Weight::from_parts(0, 5379)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_society.rs b/polkadot/runtime/kusama/src/weights/pallet_society.rs deleted file mode 100644 index 2b564349b413cc4499f98e819ff6133e2bf39934..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_society.rs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_society` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_society -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_society`. -pub struct WeightInfo(PhantomData); -impl pallet_society::WeightInfo for WeightInfo { - /// Storage: Society Bids (r:1 w:1) - /// Proof Skipped: Society Bids (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Candidates (r:1 w:0) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:1 w:0) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society SuspendedMembers (r:1 w:0) - /// Proof Skipped: Society SuspendedMembers (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Parameters (r:1 w:0) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `416` - // Estimated: `3881` - // Minimum execution time: 35_388_000 picoseconds. - Weight::from_parts(36_165_000, 0) - .saturating_add(Weight::from_parts(0, 3881)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Society Bids (r:1 w:1) - /// Proof Skipped: Society Bids (max_values: Some(1), max_size: None, mode: Measured) - fn unbid() -> Weight { - // Proof Size summary in bytes: - // Measured: `433` - // Estimated: `1918` - // Minimum execution time: 28_387_000 picoseconds. - Weight::from_parts(29_224_000, 0) - .saturating_add(Weight::from_parts(0, 1918)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Society Bids (r:1 w:1) - /// Proof Skipped: Society Bids (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Candidates (r:1 w:0) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:2 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society SuspendedMembers (r:1 w:0) - /// Proof Skipped: Society SuspendedMembers (max_values: None, max_size: None, mode: Measured) - fn vouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `453` - // Estimated: `6393` - // Minimum execution time: 25_337_000 picoseconds. - Weight::from_parts(26_143_000, 0) - .saturating_add(Weight::from_parts(0, 6393)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Bids (r:1 w:1) - /// Proof Skipped: Society Bids (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Members (r:1 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - fn unvouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `507` - // Estimated: `3972` - // Minimum execution time: 17_975_000 picoseconds. - Weight::from_parts(18_695_000, 0) - .saturating_add(Weight::from_parts(0, 3972)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:1 w:0) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Votes (r:1 w:1) - /// Proof Skipped: Society Votes (max_values: None, max_size: None, mode: Measured) - fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `541` - // Estimated: `4006` - // Minimum execution time: 23_173_000 picoseconds. - Weight::from_parts(23_764_000, 0) - .saturating_add(Weight::from_parts(0, 4006)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Defending (r:1 w:1) - /// Proof Skipped: Society Defending (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Members (r:1 w:0) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society ChallengeRoundCount (r:1 w:0) - /// Proof Skipped: Society ChallengeRoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society DefenderVotes (r:1 w:1) - /// Proof Skipped: Society DefenderVotes (max_values: None, max_size: None, mode: Measured) - fn defender_vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `533` - // Estimated: `3998` - // Minimum execution time: 21_744_000 picoseconds. - Weight::from_parts(22_406_000, 0) - .saturating_add(Weight::from_parts(0, 3998)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Members (r:1 w:0) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Payouts (r:1 w:1) - /// Proof Skipped: Society Payouts (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn payout() -> Weight { - // Proof Size summary in bytes: - // Measured: `622` - // Estimated: `4087` - // Minimum execution time: 50_058_000 picoseconds. - Weight::from_parts(51_077_000, 0) - .saturating_add(Weight::from_parts(0, 4087)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Members (r:1 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Payouts (r:1 w:1) - /// Proof Skipped: Society Payouts (max_values: None, max_size: None, mode: Measured) - fn waive_repay() -> Weight { - // Proof Size summary in bytes: - // Measured: `519` - // Estimated: `3984` - // Minimum execution time: 21_305_000 picoseconds. - Weight::from_parts(22_020_000, 0) - .saturating_add(Weight::from_parts(0, 3984)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Head (r:1 w:1) - /// Proof Skipped: Society Head (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberCount (r:1 w:1) - /// Proof Skipped: Society MemberCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberByIndex (r:0 w:1) - /// Proof Skipped: Society MemberByIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Founder (r:0 w:1) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Rules (r:0 w:1) - /// Proof Skipped: Society Rules (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Members (r:0 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Parameters (r:0 w:1) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - fn found_society() -> Weight { - // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `1599` - // Minimum execution time: 19_952_000 picoseconds. - Weight::from_parts(20_365_000, 0) - .saturating_add(Weight::from_parts(0, 1599)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Society Founder (r:1 w:1) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberCount (r:1 w:1) - /// Proof Skipped: Society MemberCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Members (r:5 w:5) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society MemberByIndex (r:5 w:5) - /// Proof Skipped: Society MemberByIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Votes (r:4 w:4) - /// Proof Skipped: Society Votes (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Candidates (r:4 w:4) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Head (r:0 w:1) - /// Proof Skipped: Society Head (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Defending (r:0 w:1) - /// Proof Skipped: Society Defending (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society ChallengeRoundCount (r:0 w:1) - /// Proof Skipped: Society ChallengeRoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Skeptic (r:0 w:1) - /// Proof Skipped: Society Skeptic (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Pot (r:0 w:1) - /// Proof Skipped: Society Pot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Rules (r:0 w:1) - /// Proof Skipped: Society Rules (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:0 w:1) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Bids (r:0 w:1) - /// Proof Skipped: Society Bids (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Parameters (r:0 w:1) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society NextHead (r:0 w:1) - /// Proof Skipped: Society NextHead (max_values: Some(1), max_size: None, mode: Measured) - fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1626` - // Estimated: `14991` - // Minimum execution time: 64_547_000 picoseconds. - Weight::from_parts(66_190_000, 0) - .saturating_add(Weight::from_parts(0, 14991)) - .saturating_add(T::DbWeight::get().reads(20)) - .saturating_add(T::DbWeight::get().writes(30)) - } - /// Storage: Society Founder (r:1 w:0) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society SuspendedMembers (r:1 w:1) - /// Proof Skipped: Society SuspendedMembers (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Payouts (r:1 w:0) - /// Proof Skipped: Society Payouts (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Pot (r:1 w:1) - /// Proof Skipped: Society Pot (max_values: Some(1), max_size: None, mode: Measured) - fn judge_suspended_member() -> Weight { - // Proof Size summary in bytes: - // Measured: `456` - // Estimated: `3921` - // Minimum execution time: 22_276_000 picoseconds. - Weight::from_parts(22_817_000, 0) - .saturating_add(Weight::from_parts(0, 3921)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Founder (r:1 w:0) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberCount (r:1 w:0) - /// Proof Skipped: Society MemberCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Parameters (r:0 w:1) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - fn set_parameters() -> Weight { - // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `1844` - // Minimum execution time: 14_857_000 picoseconds. - Weight::from_parts(15_268_000, 0) - .saturating_add(Weight::from_parts(0, 1844)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Skeptic (r:1 w:0) - /// Proof Skipped: Society Skeptic (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Votes (r:1 w:0) - /// Proof Skipped: Society Votes (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:1 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Parameters (r:1 w:0) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - fn punish_skeptic() -> Weight { - // Proof Size summary in bytes: - // Measured: `608` - // Estimated: `4073` - // Minimum execution time: 24_995_000 picoseconds. - Weight::from_parts(25_968_000, 0) - .saturating_add(Weight::from_parts(0, 4073)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Parameters (r:1 w:0) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberCount (r:1 w:1) - /// Proof Skipped: Society MemberCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society NextHead (r:1 w:1) - /// Proof Skipped: Society NextHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Society MemberByIndex (r:0 w:1) - /// Proof Skipped: Society MemberByIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:0 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - fn claim_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `604` - // Estimated: `4069` - // Minimum execution time: 41_570_000 picoseconds. - Weight::from_parts(42_576_000, 0) - .saturating_add(Weight::from_parts(0, 4069)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Society Founder (r:1 w:0) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Parameters (r:1 w:0) - /// Proof Skipped: Society Parameters (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society MemberCount (r:1 w:1) - /// Proof Skipped: Society MemberCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society NextHead (r:1 w:1) - /// Proof Skipped: Society NextHead (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Society MemberByIndex (r:0 w:1) - /// Proof Skipped: Society MemberByIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Members (r:0 w:1) - /// Proof Skipped: Society Members (max_values: None, max_size: None, mode: Measured) - fn bestow_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `622` - // Estimated: `4087` - // Minimum execution time: 43_450_000 picoseconds. - Weight::from_parts(44_330_000, 0) - .saturating_add(Weight::from_parts(0, 4087)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Society Founder (r:1 w:0) - /// Proof Skipped: Society Founder (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn kick_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `748` - // Estimated: `6196` - // Minimum execution time: 43_754_000 picoseconds. - Weight::from_parts(44_431_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn resign_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `718` - // Estimated: `6196` - // Minimum execution time: 38_184_000 picoseconds. - Weight::from_parts(38_748_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Society Candidates (r:1 w:1) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society RoundCount (r:1 w:0) - /// Proof Skipped: Society RoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn drop_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `730` - // Estimated: `6196` - // Minimum execution time: 38_442_000 picoseconds. - Weight::from_parts(39_150_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Society Candidates (r:1 w:0) - /// Proof Skipped: Society Candidates (max_values: None, max_size: None, mode: Measured) - /// Storage: Society VoteClearCursor (r:1 w:0) - /// Proof Skipped: Society VoteClearCursor (max_values: None, max_size: None, mode: Measured) - /// Storage: Society Votes (r:2 w:2) - /// Proof Skipped: Society Votes (max_values: None, max_size: None, mode: Measured) - fn cleanup_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `524` - // Estimated: `6464` - // Minimum execution time: 17_373_000 picoseconds. - Weight::from_parts(18_288_000, 0) - .saturating_add(Weight::from_parts(0, 6464)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Society ChallengeRoundCount (r:1 w:0) - /// Proof Skipped: Society ChallengeRoundCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Society DefenderVotes (r:1 w:1) - /// Proof Skipped: Society DefenderVotes (max_values: None, max_size: None, mode: Measured) - fn cleanup_challenge() -> Weight { - // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `3947` - // Minimum execution time: 12_642_000 picoseconds. - Weight::from_parts(13_281_000, 0) - .saturating_add(Weight::from_parts(0, 3947)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_staking.rs b/polkadot/runtime/kusama/src/weights/pallet_staking.rs deleted file mode 100644 index a7268a21bb99622be7c89b28e43f0c8d363b6e26..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_staking.rs +++ /dev/null @@ -1,796 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_staking` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_staking -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_staking`. -pub struct WeightInfo(PhantomData); -impl pallet_staking::WeightInfo for WeightInfo { - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn bond() -> Weight { - // Proof Size summary in bytes: - // Measured: `980` - // Estimated: `4764` - // Minimum execution time: 51_609_000 picoseconds. - Weight::from_parts(52_360_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra() -> Weight { - // Proof Size summary in bytes: - // Measured: `1955` - // Estimated: `8877` - // Minimum execution time: 94_514_000 picoseconds. - Weight::from_parts(96_430_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `2166` - // Estimated: `8877` - // Minimum execution time: 97_981_000 picoseconds. - Weight::from_parts(102_906_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `944` - // Estimated: `4764` - // Minimum execution time: 44_962_000 picoseconds. - Weight::from_parts(46_452_900, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_541 - .saturating_add(Weight::from_parts(40_855, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2217 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 94_257_000 picoseconds. - Weight::from_parts(102_162_641, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 4_137 - .saturating_add(Weight::from_parts(1_401_944, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:1 w:0) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:1 w:0) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn validate() -> Weight { - // Proof Size summary in bytes: - // Measured: `1341` - // Estimated: `4556` - // Minimum execution time: 57_139_000 picoseconds. - Weight::from_parts(58_021_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:128 w:128) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 128]`. - fn kick(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1326 + k * (823 ±0)` - // Estimated: `4556 + k * (3289 ±0)` - // Minimum execution time: 36_112_000 picoseconds. - Weight::from_parts(31_474_845, 0) - .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 13_249 - .saturating_add(Weight::from_parts(9_813_360, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 3289).saturating_mul(k.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:25 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 24]`. - fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1921 + n * (88 ±0)` - // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 66_845_000 picoseconds. - Weight::from_parts(67_790_022, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 18_238 - .saturating_add(Weight::from_parts(3_739_950, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1671` - // Estimated: `6248` - // Minimum execution time: 59_727_000 picoseconds. - Weight::from_parts(61_591_000, 0) - .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn set_payee() -> Weight { - // Proof Size summary in bytes: - // Measured: `735` - // Estimated: `4556` - // Minimum execution time: 13_578_000 picoseconds. - Weight::from_parts(14_266_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:2) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - fn set_controller() -> Weight { - // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `8122` - // Minimum execution time: 21_128_000 picoseconds. - Weight::from_parts(21_739_000, 0) - .saturating_add(Weight::from_parts(0, 8122)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_validator_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_016_000 picoseconds. - Weight::from_parts(3_195_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_no_eras() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_431_000 picoseconds. - Weight::from_parts(9_624_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_new_era() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_322_000 picoseconds. - Weight::from_parts(9_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_new_era_always() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_209_000 picoseconds. - Weight::from_parts(9_772_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[0, 1000]`. - fn set_invulnerables(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_228_000 picoseconds. - Weight::from_parts(3_437_995, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 50 - .saturating_add(Weight::from_parts(12_179, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn force_unstake(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1947 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_567_000 picoseconds. - Weight::from_parts(93_537_408, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_840 - .saturating_add(Weight::from_parts(1_371_525, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(12)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1000]`. - fn cancel_deferred_slash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `66572` - // Estimated: `70037` - // Minimum execution time: 129_433_000 picoseconds. - Weight::from_parts(939_746_867, 0) - .saturating_add(Weight::from_parts(0, 70037)) - // Standard Error: 58_234 - .saturating_add(Weight::from_parts(4_851_875, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:513 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:513 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:513 w:513) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 512]`. - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `34175 + n * (149 ±0)` - // Estimated: `32387 + n * (2603 ±1)` - // Minimum execution time: 121_648_000 picoseconds. - Weight::from_parts(145_330_037, 0) - .saturating_add(Weight::from_parts(0, 32387)) - // Standard Error: 30_044 - .saturating_add(Weight::from_parts(35_396_961, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:513 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:513 w:513) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:513 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:513 w:513) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:513 w:513) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:513 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 512]`. - fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `58149 + n * (385 ±0)` - // Estimated: `53036 + n * (3774 ±2)` - // Minimum execution time: 159_726_000 picoseconds. - Weight::from_parts(163_012_000, 0) - .saturating_add(Weight::from_parts(0, 53036)) - // Standard Error: 96_376 - .saturating_add(Weight::from_parts(59_227_426, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// The range of component `l` is `[1, 32]`. - fn rebond(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1956 + l * (5 ±0)` - // Estimated: `8877` - // Minimum execution time: 88_119_000 picoseconds. - Weight::from_parts(91_343_026, 0) - .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 5_157 - .saturating_add(Weight::from_parts(38_885, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn reap_stash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2217 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 100_347_000 picoseconds. - Weight::from_parts(103_081_218, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_957 - .saturating_add(Weight::from_parts(1_403_417, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(11)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:166 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:110 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:110 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:11 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:110 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:110 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinimumValidatorCount (r:1 w:0) - /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:1) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:0 w:10) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:0 w:10) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:0 w:10) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasTotalStake (r:0 w:1) - /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:0 w:1) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 10]`. - /// The range of component `n` is `[0, 100]`. - fn new_era(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (714 ±0) + v * (3592 ±0)` - // Estimated: `425452 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 543_737_000 picoseconds. - Weight::from_parts(547_799_000, 0) - .saturating_add(Weight::from_parts(0, 425452)) - // Standard Error: 2_046_982 - .saturating_add(Weight::from_parts(66_708_000, 0).saturating_mul(v.into())) - // Standard Error: 203_970 - .saturating_add(Weight::from_parts(20_246_221, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(173)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:166 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2000 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:2000 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1000 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2000 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2000 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// The range of component `v` is `[500, 1000]`. - /// The range of component `n` is `[500, 1000]`. - fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `3151 + n * (1161 ±0) + v * (389 ±0)` - // Estimated: `425452 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 38_906_963_000 picoseconds. - Weight::from_parts(39_744_147_000, 0) - .saturating_add(Weight::from_parts(0, 425452)) - // Standard Error: 411_378 - .saturating_add(Weight::from_parts(3_691_522, 0).saturating_mul(v.into())) - // Standard Error: 411_378 - .saturating_add(Weight::from_parts(5_732_105, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(168)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) - } - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1001 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// The range of component `v` is `[500, 1000]`. - fn get_npos_targets(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `917 + v * (50 ±0)` - // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_614_613_000 picoseconds. - Weight::from_parts(127_976_836, 0) - .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 10_285 - .saturating_add(Weight::from_parts(5_101_327, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - fn set_staking_configs_all_set() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_533_000 picoseconds. - Weight::from_parts(6_797_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - fn set_staking_configs_all_remove() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_056_000 picoseconds. - Weight::from_parts(6_255_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(814), added: 3289, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:1 w:0) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `1794` - // Estimated: `6248` - // Minimum execution time: 71_915_000 picoseconds. - Weight::from_parts(73_500_000, 0) - .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - fn force_apply_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `627` - // Estimated: `3510` - // Minimum execution time: 12_994_000 picoseconds. - Weight::from_parts(13_452_000, 0) - .saturating_add(Weight::from_parts(0, 3510)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_191_000 picoseconds. - Weight::from_parts(3_315_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_timestamp.rs b/polkadot/runtime/kusama/src/weights/pallet_timestamp.rs deleted file mode 100644 index ab127fd9606466fc5a1ec0a8c6b5435c17115d26..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_timestamp.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_timestamp` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_timestamp -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_timestamp`. -pub struct WeightInfo(PhantomData); -impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: Timestamp Now (r:1 w:1) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - fn set() -> Weight { - // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `1493` - // Minimum execution time: 9_183_000 picoseconds. - Weight::from_parts(9_579_000, 0) - .saturating_add(Weight::from_parts(0, 1493)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn on_finalize() -> Weight { - // Proof Size summary in bytes: - // Measured: `94` - // Estimated: `0` - // Minimum execution time: 3_897_000 picoseconds. - Weight::from_parts(4_053_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_tips.rs b/polkadot/runtime/kusama/src/weights/pallet_tips.rs deleted file mode 100644 index 64729ed63039f53c5c3ae9a3317e4f976c29645b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_tips.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_tips` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, 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("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_tips -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_tips`. -pub struct WeightInfo(PhantomData); -impl pallet_tips::WeightInfo for WeightInfo { - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - fn report_awesome(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `6938` - // Minimum execution time: 23_689_000 picoseconds. - Weight::from_parts(24_837_709, 0) - .saturating_add(Weight::from_parts(0, 6938)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_449, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - fn retract_tip() -> Weight { - // Proof Size summary in bytes: - // Measured: `221` - // Estimated: `3907` - // Minimum execution time: 23_163_000 picoseconds. - Weight::from_parts(23_386_000, 0) - .saturating_add(Weight::from_parts(0, 3907)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:0 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - /// The range of component `t` is `[1, 19]`. - fn tip_new(r: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `108 + t * (64 ±0)` - // Estimated: `5274 + t * (192 ±0)` - // Minimum execution time: 18_945_000 picoseconds. - Weight::from_parts(17_578_665, 0) - .saturating_add(Weight::from_parts(0, 5274)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_320, 0).saturating_mul(r.into())) - // Standard Error: 5_480 - .saturating_add(Weight::from_parts(154_765, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `329 + t * (112 ±0)` - // Estimated: `5608 + t * (224 ±0)` - // Minimum execution time: 14_212_000 picoseconds. - Weight::from_parts(14_717_871, 0) - .saturating_add(Weight::from_parts(0, 5608)) - // Standard Error: 1_305 - .saturating_add(Weight::from_parts(135_786, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn close_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `368 + t * (112 ±0)` - // Estimated: `9620 + t * (336 ±0)` - // Minimum execution time: 41_550_000 picoseconds. - Weight::from_parts(43_011_989, 0) - .saturating_add(Weight::from_parts(0, 9620)) - // Standard Error: 5_482 - .saturating_add(Weight::from_parts(120_085, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn slash_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `4003` - // Minimum execution time: 13_897_000 picoseconds. - Weight::from_parts(14_435_129, 0) - .saturating_add(Weight::from_parts(0, 4003)) - // Standard Error: 1_409 - .saturating_add(Weight::from_parts(9_959, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_vesting.rs b/polkadot/runtime/kusama/src/weights/pallet_vesting.rs deleted file mode 100644 index b33a9174bce1163ac5a990bd0502433cbd28f0ed..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_vesting.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_vesting` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_vesting -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_vesting`. -pub struct WeightInfo(PhantomData); -impl pallet_vesting::WeightInfo for WeightInfo { - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_locked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `314 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 34_784_000 picoseconds. - Weight::from_parts(33_272_889, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_885 - .saturating_add(Weight::from_parts(59_791, 0).saturating_mul(l.into())) - // Standard Error: 3_354 - .saturating_add(Weight::from_parts(107_412, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_unlocked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `314 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 38_597_000 picoseconds. - Weight::from_parts(38_328_545, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_835 - .saturating_add(Weight::from_parts(30_108, 0).saturating_mul(l.into())) - // Standard Error: 3_265 - .saturating_add(Weight::from_parts(67_840, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `417 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 36_505_000 picoseconds. - Weight::from_parts(35_149_105, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_328 - .saturating_add(Weight::from_parts(59_063, 0).saturating_mul(l.into())) - // Standard Error: 2_363 - .saturating_add(Weight::from_parts(102_227, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `417 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 39_946_000 picoseconds. - Weight::from_parts(40_375_572, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_657 - .saturating_add(Weight::from_parts(36_203, 0).saturating_mul(l.into())) - // Standard Error: 2_948 - .saturating_add(Weight::from_parts(54_092, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[0, 27]`. - fn vested_transfer(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `488 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 73_800_000 picoseconds. - Weight::from_parts(76_190_149, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 3_306 - .saturating_add(Weight::from_parts(62_177, 0).saturating_mul(l.into())) - // Standard Error: 5_882 - .saturating_add(Weight::from_parts(142_130, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[0, 27]`. - fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `591 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `6196` - // Minimum execution time: 74_744_000 picoseconds. - Weight::from_parts(77_992_773, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 3_321 - .saturating_add(Weight::from_parts(66_392, 0).saturating_mul(l.into())) - // Standard Error: 5_910 - .saturating_add(Weight::from_parts(142_911, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[2, 28]`. - fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `415 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 37_626_000 picoseconds. - Weight::from_parts(36_213_370, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_056 - .saturating_add(Weight::from_parts(56_586, 0).saturating_mul(l.into())) - // Standard Error: 3_798 - .saturating_add(Weight::from_parts(111_413, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[2, 28]`. - fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `415 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 41_647_000 picoseconds. - Weight::from_parts(40_350_649, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_906 - .saturating_add(Weight::from_parts(59_779, 0).saturating_mul(l.into())) - // Standard Error: 3_521 - .saturating_add(Weight::from_parts(111_787, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_xcm.rs b/polkadot/runtime/kusama/src/weights/pallet_xcm.rs deleted file mode 100644 index 4b1a790a57a146641fd172b71d5248de500e108a..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_xcm -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=kusama-dev -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm`. -pub struct WeightInfo(PhantomData); -impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 36_359_000 picoseconds. - Weight::from_parts(37_262_000, 0) - .saturating_add(Weight::from_parts(0, 3676)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 22_115_000 picoseconds. - Weight::from_parts(22_381_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn reserve_transfer_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 21_978_000 picoseconds. - Weight::from_parts(22_407_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_620_000 picoseconds. - Weight::from_parts(10_061_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: XcmPallet SupportedVersion (r:0 w:1) - /// Proof Skipped: 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: 9_884_000 picoseconds. - Weight::from_parts(10_207_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn force_default_xcm_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_939_000 picoseconds. - Weight::from_parts(3_022_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: XcmPallet VersionNotifiers (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet QueryCounter (r:1 w:1) - /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - fn force_subscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 40_948_000 picoseconds. - Weight::from_parts(41_577_000, 0) - .saturating_add(Weight::from_parts(0, 3676)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: XcmPallet VersionNotifiers (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - fn force_unsubscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `538` - // Estimated: `4003` - // Minimum execution time: 45_857_000 picoseconds. - Weight::from_parts(47_289_000, 0) - .saturating_add(Weight::from_parts(0, 4003)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) - fn force_suspension() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_837_000 picoseconds. - Weight::from_parts(3_065_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: XcmPallet SupportedVersion (r:4 w:2) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - fn migrate_supported_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `229` - // Estimated: `11119` - // Minimum execution time: 17_125_000 picoseconds. - Weight::from_parts(17_582_000, 0) - .saturating_add(Weight::from_parts(0, 11119)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifiers (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifiers (max_values: None, max_size: None, mode: Measured) - fn migrate_version_notifiers() -> Weight { - // Proof Size summary in bytes: - // Measured: `233` - // Estimated: `11123` - // Minimum execution time: 16_834_000 picoseconds. - Weight::from_parts(17_412_000, 0) - .saturating_add(Weight::from_parts(0, 11123)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:5 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn already_notified_target() -> Weight { - // Proof Size summary in bytes: - // Measured: `243` - // Estimated: `13608` - // Minimum execution time: 18_784_000 picoseconds. - Weight::from_parts(19_184_000, 0) - .saturating_add(Weight::from_parts(0, 13608)) - .saturating_add(T::DbWeight::get().reads(5)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:2 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `6221` - // Minimum execution time: 38_232_000 picoseconds. - Weight::from_parts(39_125_000, 0) - .saturating_add(Weight::from_parts(0, 6221)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn notify_target_migration_fail() -> Weight { - // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `8687` - // Minimum execution time: 9_661_000 picoseconds. - Weight::from_parts(10_094_000, 0) - .saturating_add(Weight::from_parts(0, 8687)) - .saturating_add(T::DbWeight::get().reads(3)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn migrate_version_notify_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `240` - // Estimated: `11130` - // Minimum execution time: 17_593_000 picoseconds. - Weight::from_parts(18_158_000, 0) - .saturating_add(Weight::from_parts(0, 11130)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `285` - // Estimated: `11175` - // Minimum execution time: 45_525_000 picoseconds. - Weight::from_parts(46_583_000, 0) - .saturating_add(Weight::from_parts(0, 11175)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_common_auctions.rs b/polkadot/runtime/kusama/src/weights/runtime_common_auctions.rs deleted file mode 100644 index 2370f98f07037c03634ae549b5120ba64a50c8f7..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_common_auctions.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::auctions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::auctions -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_common_auctions.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::auctions`. -pub struct WeightInfo(PhantomData); -impl runtime_common::auctions::WeightInfo for WeightInfo { - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:1) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn new_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `1493` - // Minimum execution time: 12_713_000 picoseconds. - Weight::from_parts(13_211_000, 0) - .saturating_add(Weight::from_parts(0, 1493)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:2 w:2) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `661` - // Estimated: `6060` - // Minimum execution time: 98_648_000 picoseconds. - Weight::from_parts(106_823_000, 0) - .saturating_add(Weight::from_parts(0, 6060)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe NextRandomness (r:1 w:0) - /// Proof: Babe NextRandomness (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: Babe EpochStart (r:1 w:0) - /// Proof: Babe EpochStart (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:7 w:7) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `6947699` - // Estimated: `15822990` - // Minimum execution time: 7_936_854_000 picoseconds. - Weight::from_parts(8_091_086_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3688)) - .saturating_add(T::DbWeight::get().writes(3683)) - } - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:0 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - fn cancel_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `177732` - // Estimated: `15822990` - // Minimum execution time: 6_127_393_000 picoseconds. - Weight::from_parts(6_302_044_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3673)) - .saturating_add(T::DbWeight::get().writes(3673)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_common_claims.rs b/polkadot/runtime/kusama/src/weights/runtime_common_claims.rs deleted file mode 100644 index ecf29f0cdc1858fe21ed07c28cc1f81d607cf039..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_common_claims.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::claims` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::claims -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_common_claims.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::claims`. -pub struct WeightInfo(PhantomData); -impl runtime_common::claims::WeightInfo for WeightInfo { - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `620` - // Estimated: `4764` - // Minimum execution time: 213_980_000 picoseconds. - Weight::from_parts(229_096_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:0 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:0 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:0 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - fn mint_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `216` - // Estimated: `1701` - // Minimum execution time: 13_378_000 picoseconds. - Weight::from_parts(15_841_000, 0) - .saturating_add(Weight::from_parts(0, 1701)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn claim_attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `620` - // Estimated: `4764` - // Minimum execution time: 213_747_000 picoseconds. - Weight::from_parts(236_937_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `694` - // Estimated: `4764` - // Minimum execution time: 103_706_000 picoseconds. - Weight::from_parts(108_213_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Claims Claims (r:1 w:2) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:2) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:2) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - fn move_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `440` - // Estimated: `3905` - // Minimum execution time: 27_331_000 picoseconds. - Weight::from_parts(29_408_000, 0) - .saturating_add(Weight::from_parts(0, 3905)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_common_crowdloan.rs b/polkadot/runtime/kusama/src/weights/runtime_common_crowdloan.rs deleted file mode 100644 index 1785e0e5d38ba3748068fa9c083c7c5e318fb19e..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_common_crowdloan.rs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::crowdloan` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::crowdloan -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_common_crowdloan.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::crowdloan`. -pub struct WeightInfo(PhantomData); -impl runtime_common::crowdloan::WeightInfo for WeightInfo { - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NextFundIndex (r:1 w:1) - /// Proof Skipped: Crowdloan NextFundIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `415` - // Estimated: `3880` - // Minimum execution time: 67_350_000 picoseconds. - Weight::from_parts(70_662_000, 0) - .saturating_add(Weight::from_parts(0, 3880)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:0) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn contribute() -> Weight { - // Proof Size summary in bytes: - // Measured: `463` - // Estimated: `3928` - // Minimum execution time: 172_864_000 picoseconds. - Weight::from_parts(181_577_000, 0) - .saturating_add(Weight::from_parts(0, 3928)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - /// Proof Skipped: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - fn withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `690` - // Estimated: `6196` - // Minimum execution time: 92_816_000 picoseconds. - Weight::from_parts(102_956_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `k` is `[0, 1000]`. - fn refund(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `128 + k * (189 ±0)` - // Estimated: `141 + k * (189 ±0)` - // Minimum execution time: 67_361_000 picoseconds. - Weight::from_parts(73_320_000, 0) - .saturating_add(Weight::from_parts(0, 141)) - // Standard Error: 30_080 - .saturating_add(Weight::from_parts(43_879_049, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `515` - // Estimated: `6196` - // Minimum execution time: 56_194_000 picoseconds. - Weight::from_parts(63_604_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - fn edit() -> Weight { - // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3700` - // Minimum execution time: 27_093_000 picoseconds. - Weight::from_parts(32_181_000, 0) - .saturating_add(Weight::from_parts(0, 3700)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn add_memo() -> Weight { - // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `3877` - // Minimum execution time: 39_489_000 picoseconds. - Weight::from_parts(44_798_000, 0) - .saturating_add(Weight::from_parts(0, 3877)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - fn poke() -> Weight { - // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `3704` - // Minimum execution time: 26_147_000 picoseconds. - Weight::from_parts(30_760_000, 0) - .saturating_add(Weight::from_parts(0, 3704)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:1) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:100 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Paras ParaLifecycles (r:100 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:100 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:100 w:100) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:100 w:100) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[2, 100]`. - fn on_initialize(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `130 + n * (356 ±0)` - // Estimated: `5385 + n * (2832 ±0)` - // Minimum execution time: 163_693_000 picoseconds. - Weight::from_parts(22_145_813, 0) - .saturating_add(Weight::from_parts(0, 5385)) - // Standard Error: 47_670 - .saturating_add(Weight::from_parts(72_049_146, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2832).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_common_paras_registrar.rs b/polkadot/runtime/kusama/src/weights/runtime_common_paras_registrar.rs deleted file mode 100644 index 9426d667346b1b4f72e3776d3a2d766182553fab..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_common_paras_registrar.rs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::paras_registrar` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::paras_registrar -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_common_paras_registrar.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::paras_registrar`. -pub struct WeightInfo(PhantomData); -impl runtime_common::paras_registrar::WeightInfo for WeightInfo { - /// Storage: Registrar NextFreeParaId (r:1 w:1) - /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 30_262_000 picoseconds. - Weight::from_parts(30_881_000, 0) - .saturating_add(Weight::from_parts(0, 3535)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn register() -> Weight { - // Proof Size summary in bytes: - // Measured: `329` - // Estimated: `3794` - // Minimum execution time: 6_443_064_000 picoseconds. - Weight::from_parts(7_074_736_000, 0) - .saturating_add(Weight::from_parts(0, 3794)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn force_register() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `3684` - // Minimum execution time: 6_298_725_000 picoseconds. - Weight::from_parts(7_130_498_000, 0) - .saturating_add(Weight::from_parts(0, 3684)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: Registrar PendingSwap (r:0 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - fn deregister() -> Weight { - // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `3941` - // Minimum execution time: 60_696_000 picoseconds. - Weight::from_parts(65_976_000, 0) - .saturating_add(Weight::from_parts(0, 3941)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Registrar Paras (r:1 w:0) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:2 w:2) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar PendingSwap (r:1 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:2 w:2) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - fn swap() -> Weight { - // Proof Size summary in bytes: - // Measured: `713` - // Estimated: `6653` - // Minimum execution time: 72_165_000 picoseconds. - Weight::from_parts(80_369_000, 0) - .saturating_add(Weight::from_parts(0, 6653)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 3145728]`. - fn schedule_code_upgrade(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `3642` - // Minimum execution time: 40_883_000 picoseconds. - Weight::from_parts(41_276_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_552, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 1048576]`. - fn set_current_head(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_864_000 picoseconds. - Weight::from_parts(9_023_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(983, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_common_slots.rs b/polkadot/runtime/kusama/src/weights/runtime_common_slots.rs deleted file mode 100644 index 8c76ff2c693ae5b78b1d05ce5070e669e07c545c..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_common_slots.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::slots` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::slots -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_common_slots.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::slots`. -pub struct WeightInfo(PhantomData); -impl runtime_common::slots::WeightInfo for WeightInfo { - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_lease() -> Weight { - // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 30_513_000 picoseconds. - Weight::from_parts(31_238_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Slots Leases (r:101 w:100) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:200 w:200) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:100 w:100) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[0, 100]`. - /// The range of component `t` is `[0, 100]`. - fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `46 + c * (47 ±0) + t * (308 ±0)` - // Estimated: `2823 + c * (2526 ±0) + t * (2789 ±0)` - // Minimum execution time: 758_558_000 picoseconds. - Weight::from_parts(769_052_000, 0) - .saturating_add(Weight::from_parts(0, 2823)) - // Standard Error: 93_260 - .saturating_add(Weight::from_parts(3_338_461, 0).saturating_mul(c.into())) - // Standard Error: 93_260 - .saturating_add(Weight::from_parts(13_755_524, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2526).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2789).saturating_mul(t.into())) - } - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:8 w:8) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn clear_all_leases() -> Weight { - // Proof Size summary in bytes: - // Measured: `2692` - // Estimated: `21814` - // Minimum execution time: 155_205_000 picoseconds. - Weight::from_parts(162_036_000, 0) - .saturating_add(Weight::from_parts(0, 21814)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(9)) - } - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn trigger_onboard() -> Weight { - // Proof Size summary in bytes: - // Measured: `617` - // Estimated: `4082` - // Minimum execution time: 38_799_000 picoseconds. - Weight::from_parts(42_044_000, 0) - .saturating_add(Weight::from_parts(0, 4082)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_configuration.rs deleted file mode 100644 index 22609209c7333386874d23172b91e3ada94b8fab..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_configuration.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::configuration` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("kusama-dev")`, DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_parachains::configuration -// --chain=kusama-dev -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::configuration`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_block_number() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_186_000 picoseconds. - Weight::from_parts(9_567_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_u32() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_388_000 picoseconds. - Weight::from_parts(9_723_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_option_u32() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_264_000 picoseconds. - Weight::from_parts(9_477_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_hrmp_open_request_ttl() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_balance() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_282_000 picoseconds. - Weight::from_parts(9_641_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_executor_params() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_937_000 picoseconds. - Weight::from_parts(10_445_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_perbill() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_106_000 picoseconds. - Weight::from_parts(9_645_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes.rs deleted file mode 100644 index be78e3ac86b6ac2475df11c85d5afba9e5df396b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::disputes` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::disputes -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_disputes.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::disputes`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::disputes::WeightInfo for WeightInfo { - /// Storage: ParasDisputes Frozen (r:0 w:1) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - fn force_unfreeze() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_684_000 picoseconds. - Weight::from_parts(2_943_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes_slashing.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes_slashing.rs deleted file mode 100644 index bcde1ef418d8934df5855ab5331b631e040dda6a..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_disputes_slashing.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::disputes::slashing` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::disputes::slashing -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_disputes_slashing.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::disputes::slashing`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::disputes::slashing::WeightInfo for WeightInfo { - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Historical HistoricalSessions (r:1 w:0) - /// Proof: Historical HistoricalSessions (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: ParasSlashing UnappliedSlashes (r:1 w:1) - /// Proof Skipped: ParasSlashing UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:1 w:1) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session DisabledValidators (r:1 w:1) - /// Proof Skipped: Session DisabledValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[4, 1000]`. - fn report_dispute_lost(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `5325 + n * (184 ±0)` - // Estimated: `8537 + n * (188 ±0)` - // Minimum execution time: 117_607_000 picoseconds. - Weight::from_parts(165_902_178, 0) - .saturating_add(Weight::from_parts(0, 8537)) - // Standard Error: 3_310 - .saturating_add(Weight::from_parts(358_233, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(17)) - .saturating_add(T::DbWeight::get().writes(10)) - .saturating_add(Weight::from_parts(0, 188).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs deleted file mode 100644 index c13a8413e4102ac4fbedb64fab0c92fcb6dcf247..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_hrmp.rs +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::hrmp` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::hrmp -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_hrmp.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_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) - fn hrmp_init_open_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `350` - // Estimated: `6290` - // Minimum execution time: 37_901_000 picoseconds. - Weight::from_parts(38_728_000, 0) - .saturating_add(Weight::from_parts(0, 6290)) - .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) - fn hrmp_accept_open_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `582` - // Estimated: `4047` - // Minimum execution time: 37_634_000 picoseconds. - Weight::from_parts(38_332_000, 0) - .saturating_add(Weight::from_parts(0, 4047)) - .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) - fn hrmp_close_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `453` - // Estimated: `3918` - // Minimum execution time: 33_719_000 picoseconds. - Weight::from_parts(34_342_000, 0) - .saturating_add(Weight::from_parts(0, 3918)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) - /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannels (r:254 w:254) - /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:0 w:1) - /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelContents (r:0 w:254) - /// Proof Skipped: Hrmp HrmpChannelContents (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpOpenChannelRequestCount (r:0 w:1) - /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) - /// 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: `197 + e * (100 ±0) + i * (100 ±0)` - // Estimated: `3659 + e * (2575 ±0) + i * (2575 ±0)` - // Minimum execution time: 1_267_013_000 picoseconds. - Weight::from_parts(1_283_708_000, 0) - .saturating_add(Weight::from_parts(0, 3659)) - // Standard Error: 118_117 - .saturating_add(Weight::from_parts(3_722_255, 0).saturating_mul(i.into())) - // Standard Error: 118_117 - .saturating_add(Weight::from_parts(3_701_842, 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()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(e.into()))) - .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) - /// The range of component `c` is `[0, 128]`. - fn force_process_hrmp_open(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `425 + c * (136 ±0)` - // Estimated: `1880 + c * (5086 ±0)` - // Minimum execution time: 6_798_000 picoseconds. - Weight::from_parts(6_921_000, 0) - .saturating_add(Weight::from_parts(0, 1880)) - // Standard Error: 12_517 - .saturating_add(Weight::from_parts(21_683_294, 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) - /// The range of component `c` is `[0, 128]`. - fn force_process_hrmp_close(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `268 + c * (124 ±0)` - // Estimated: `1728 + c * (2600 ±0)` - // Minimum execution time: 5_695_000 picoseconds. - Weight::from_parts(5_776_000, 0) - .saturating_add(Weight::from_parts(0, 1728)) - // Standard Error: 11_189 - .saturating_add(Weight::from_parts(13_477_149, 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) - /// The range of component `c` is `[0, 128]`. - fn hrmp_cancel_open_request(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `959 + c * (13 ±0)` - // Estimated: `4228 + c * (15 ±0)` - // Minimum execution time: 21_141_000 picoseconds. - Weight::from_parts(29_731_969, 0) - .saturating_add(Weight::from_parts(0, 4228)) - // Standard Error: 3_263 - .saturating_add(Weight::from_parts(198_283, 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) - /// The range of component `c` is `[0, 128]`. - fn clean_open_channel_requests(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `176 + c * (63 ±0)` - // Estimated: `1655 + c * (2538 ±0)` - // Minimum execution time: 4_573_000 picoseconds. - Weight::from_parts(5_593_572, 0) - .saturating_add(Weight::from_parts(0, 1655)) - // Standard Error: 4_134 - .saturating_add(Weight::from_parts(3_565_821, 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 { - // Proof Size summary in bytes: - // Measured: `350` - // Estimated: `6290` - // Minimum execution time: 53_253_000 picoseconds. - Weight::from_parts(55_141_000, 0) - .saturating_add(Weight::from_parts(0, 6290)) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(8)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index 9ca4b2fe2a7e7353dc09bc9b7415c57f2b7807e8..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_inclusion.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::inclusion` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::inclusion -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_inclusion.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::inclusion`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:999) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// The range of component `i` is `[1, 1000]`. - fn receive_upward_messages(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `65761` - // Estimated: `69051` - // Minimum execution time: 119_471_000 picoseconds. - Weight::from_parts(120_105_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - // Standard Error: 42_037 - .saturating_add(Weight::from_parts(103_436_040, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_initializer.rs deleted file mode 100644 index 31878846d328126ac41cb71969c8d14a9108d9f4..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_initializer.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::initializer` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::initializer -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_initializer.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::initializer`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::initializer::WeightInfo for WeightInfo { - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `d` is `[0, 65536]`. - fn force_approve(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + d * (11 ±0)` - // Estimated: `1480 + d * (11 ±0)` - // Minimum execution time: 3_509_000 picoseconds. - Weight::from_parts(3_655_000, 0) - .saturating_add(Weight::from_parts(0, 1480)) - // Standard Error: 15 - .saturating_add(Weight::from_parts(2_861, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 11).saturating_mul(d.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_paras.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_paras.rs deleted file mode 100644 index 9e66592fbdfab1520b0267f4fbbeb6bde5809d22..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_paras.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::paras` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::paras -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_paras.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::paras`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::paras::WeightInfo for WeightInfo { - /// Storage: Paras CurrentCodeHash (r:1 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodeMeta (r:1 w:1) - /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodePruning (r:1 w:1) - /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PastCodeHash (r:0 w:1) - /// Proof Skipped: Paras PastCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_set_current_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8309` - // Estimated: `11774` - // Minimum execution time: 33_015_000 picoseconds. - Weight::from_parts(33_678_000, 0) - .saturating_add(Weight::from_parts(0, 11774)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_417, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_set_current_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_308_000 picoseconds. - Weight::from_parts(8_473_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(992, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Paras Heads (r:0 w:1) - fn force_set_most_recent_context() -> Weight { - Weight::from_parts(10_155_000, 0) - // Standard Error: 0 - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_schedule_code_upgrade(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8428` - // Estimated: `11893` - // Minimum execution time: 49_058_000 picoseconds. - Weight::from_parts(49_768_000, 0) - .saturating_add(Weight::from_parts(0, 11893)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(2_541, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_note_new_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `3560` - // Minimum execution time: 13_559_000 picoseconds. - Weight::from_parts(13_774_000, 0) - .saturating_add(Weight::from_parts(0, 3560)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_082, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn force_queue_action() -> Weight { - // Proof Size summary in bytes: - // Measured: `4288` - // Estimated: `7753` - // Minimum execution time: 20_213_000 picoseconds. - Weight::from_parts(20_576_000, 0) - .saturating_add(Weight::from_parts(0, 7753)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn add_trusted_validation_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `659` - // Estimated: `4124` - // Minimum execution time: 99_127_000 picoseconds. - Weight::from_parts(82_909_137, 0) - .saturating_add(Weight::from_parts(0, 4124)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_848, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Paras CodeByHashRefs (r:1 w:0) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - fn poke_unused_validation_code() -> Weight { - // Proof Size summary in bytes: - // Measured: `28` - // Estimated: `3493` - // Minimum execution time: 5_816_000 picoseconds. - Weight::from_parts(6_139_000, 0) - .saturating_add(Weight::from_parts(0, 3493)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 116_078_000 picoseconds. - Weight::from_parts(119_110_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras UpcomingUpgrades (r:1 w:1) - /// Proof Skipped: Paras UpcomingUpgrades (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:0 w:100) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `27236` - // Estimated: `30701` - // Minimum execution time: 934_879_000 picoseconds. - Weight::from_parts(946_892_000, 0) - .saturating_add(Weight::from_parts(0, 30701)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(104)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `27214` - // Estimated: `30679` - // Minimum execution time: 112_297_000 picoseconds. - Weight::from_parts(118_546_000, 0) - .saturating_add(Weight::from_parts(0, 30679)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `26704` - // Estimated: `30169` - // Minimum execution time: 723_534_000 picoseconds. - Weight::from_parts(746_144_000, 0) - .saturating_add(Weight::from_parts(0, 30169)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 110_352_000 picoseconds. - Weight::from_parts(115_568_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs deleted file mode 100644 index 9a9a3a3dffb5a1a1f364610cbb2dd8267adf8a97..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::paras_inherent` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_parachains::paras_inherent -// --chain=kusama-dev -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::paras_inherent`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaSessionInfo Sessions (r:1 w:0) - /// Proof Skipped: ParaSessionInfo Sessions (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:1) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes BackersOnDisputes (r:1 w:1) - /// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:1 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[10, 200]`. - fn enter_variable_disputes(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `50671` - // Estimated: `56611 + v * (23 ±0)` - // Minimum execution time: 1_008_586_000 picoseconds. - Weight::from_parts(471_892_709, 0) - .saturating_add(Weight::from_parts(0, 56611)) - // Standard Error: 15_634 - .saturating_add(Weight::from_parts(56_433_120, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(27)) - .saturating_add(T::DbWeight::get().writes(15)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) - /// Proof Skipped: ParaInclusion AvailabilityBitfields (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - fn enter_bitfields() -> Weight { - // Proof Size summary in bytes: - // Measured: `42504` - // Estimated: `48444` - // Minimum execution time: 469_409_000 picoseconds. - Weight::from_parts(487_865_000, 0) - .saturating_add(Weight::from_parts(0, 48444)) - .saturating_add(T::DbWeight::get().reads(25)) - .saturating_add(T::DbWeight::get().writes(16)) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[101, 200]`. - fn enter_backed_candidates_variable(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `42540` - // Estimated: `48480` - // Minimum execution time: 6_874_816_000 picoseconds. - Weight::from_parts(1_229_912_739, 0) - .saturating_add(Weight::from_parts(0, 48480)) - // Standard Error: 27_352 - .saturating_add(Weight::from_parts(56_137_302, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(15)) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:0) - /// Proof Skipped: Paras UpgradeRestrictionSignal (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: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - fn enter_backed_candidate_code_upgrade() -> Weight { - // Proof Size summary in bytes: - // Measured: `42567` - // Estimated: `48507` - // Minimum execution time: 41_075_073_000 picoseconds. - Weight::from_parts(43_753_587_000, 0) - .saturating_add(Weight::from_parts(0, 48507)) - .saturating_add(T::DbWeight::get().reads(30)) - .saturating_add(T::DbWeight::get().writes(15)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs deleted file mode 100644 index 07f3ccb48d9268275ef8d56d7240bddead0e9896..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-gghbxkbs-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_xcm_benchmarks::fungible -// --chain=kusama-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/kusama/src/weights/xcm/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm_benchmarks::fungible`. -pub struct WeightInfo(PhantomData); -impl WeightInfo { - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - pub(crate) fn withdraw_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 23_950_000 picoseconds. - Weight::from_parts(24_720_000, 3593) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - pub(crate) fn transfer_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `6196` - // Minimum execution time: 51_687_000 picoseconds. - Weight::from_parts(52_490_000, 6196) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - pub(crate) fn transfer_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `6196` - // Minimum execution time: 75_438_000 picoseconds. - Weight::from_parts(77_495_000, 6196) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - pub(crate) fn reserve_asset_deposited() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - pub(crate) fn initiate_reserve_withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 28_370_000 picoseconds. - Weight::from_parts(29_100_000, 3541) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - pub(crate) fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // Minimum execution time: 23_041_000 picoseconds. - Weight::from_parts(23_433_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`) - pub(crate) fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 25_386_000 picoseconds. - Weight::from_parts(25_904_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: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - pub(crate) fn deposit_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3593` - // Minimum execution time: 50_645_000 picoseconds. - Weight::from_parts(51_719_000, 3593) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - pub(crate) fn initiate_teleport() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3593` - // Minimum execution time: 53_055_000 picoseconds. - Weight::from_parts(54_214_000, 3593) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index fb0ca3c19f425643f2532a0f5241688c6d84a69b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::generic` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_xcm_benchmarks::generic -// --chain=kusama-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/kusama/src/weights/xcm/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm_benchmarks::generic`. -pub struct WeightInfo(PhantomData); -impl WeightInfo { - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn report_holding() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 32_102_000 picoseconds. - Weight::from_parts(33_749_000, 3676) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - pub(crate) fn buy_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_624_000 picoseconds. - Weight::from_parts(2_714_000, 0) - } - /// Storage: XcmPallet Queries (r:1 w:0) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - pub(crate) fn query_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 10_599_000 picoseconds. - Weight::from_parts(10_882_000, 3634) - .saturating_add(T::DbWeight::get().reads(1)) - } - pub(crate) fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_985_000 picoseconds. - Weight::from_parts(12_274_000, 0) - } - pub(crate) fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_739_000 picoseconds. - Weight::from_parts(2_862_000, 0) - } - pub(crate) fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_533_000 picoseconds. - Weight::from_parts(2_646_000, 0) - } - pub(crate) fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_563_000 picoseconds. - Weight::from_parts(2_647_000, 0) - } - pub(crate) fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_512_000 picoseconds. - Weight::from_parts(2_574_000, 0) - } - pub(crate) fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_307_000 picoseconds. - Weight::from_parts(3_448_000, 0) - } - pub(crate) fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(2_614_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn report_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 27_275_000 picoseconds. - Weight::from_parts(27_861_000, 3676) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: XcmPallet AssetTraps (r:1 w:1) - /// Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured) - pub(crate) fn claim_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `226` - // Estimated: `3691` - // Minimum execution time: 14_731_000 picoseconds. - Weight::from_parts(15_006_000, 3691) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - pub(crate) fn trap() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_446_000 picoseconds. - Weight::from_parts(2_581_000, 0) - } - /// Storage: XcmPallet VersionNotifyTargets (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn subscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 34_319_000 picoseconds. - Weight::from_parts(34_708_000, 3676) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:0 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - pub(crate) fn unsubscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_974_000 picoseconds. - Weight::from_parts(5_155_000, 0) - .saturating_add(T::DbWeight::get().writes(1)) - } - pub(crate) fn burn_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_059_000 picoseconds. - Weight::from_parts(4_125_000, 0) - } - pub(crate) fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_657_000 picoseconds. - Weight::from_parts(2_741_000, 0) - } - pub(crate) fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_585_000 picoseconds. - Weight::from_parts(2_653_000, 0) - } - pub(crate) fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_552_000 picoseconds. - Weight::from_parts(2_632_000, 0) - } - pub(crate) fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_682_000 picoseconds. - Weight::from_parts(2_763_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn query_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 34_316_000 picoseconds. - Weight::from_parts(34_682_000, 3676) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - pub(crate) fn expect_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_938_000 picoseconds. - Weight::from_parts(8_071_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn report_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `211` - // Estimated: `3676` - // Minimum execution time: 28_002_000 picoseconds. - Weight::from_parts(28_184_000, 3676) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - pub(crate) fn clear_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_520_000 picoseconds. - Weight::from_parts(2_617_000, 0) - } - pub(crate) fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_506_000 picoseconds. - Weight::from_parts(2_560_000, 0) - } - pub(crate) fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_503_000 picoseconds. - Weight::from_parts(2_605_000, 0) - } - pub(crate) fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_511_000 picoseconds. - Weight::from_parts(2_597_000, 0) - } - pub(crate) fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_617_000 picoseconds. - Weight::from_parts(2_715_000, 0) - } -} diff --git a/polkadot/runtime/kusama/src/xcm_config.rs b/polkadot/runtime/kusama/src/xcm_config.rs deleted file mode 100644 index 59ea937e11c133770cc78853d9a0dfc8c04c8b0b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/kusama/src/xcm_config.rs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! XCM configurations for the Kusama runtime. - -use super::{ - parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, Fellows, ParaId, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, TransactionByteFee, WeightToFee, - XcmPallet, -}; -use frame_support::{ - match_types, parameter_types, - traits::{Everything, Nothing}, - weights::Weight, -}; -use frame_system::EnsureRoot; -use kusama_runtime_constants::currency::CENTS; -use runtime_common::{ - xcm_sender::{ChildParachainRouter, ExponentialPrice}, - ToAuthor, -}; -use sp_core::ConstU32; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, - IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, -}; - -parameter_types! { - /// The location of the KSM token, from the context of this chain. Since this token is native to this - /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to - /// the context". - pub const TokenLocation: MultiLocation = Here.into_location(); - /// The Kusama network ID. This is named. - pub const ThisNetwork: NetworkId = Kusama; - /// Our XCM location ancestry - i.e. our location within the Consensus Universe. - /// - /// Since Kusama is a top-level relay-chain with its own consensus, it's just our network ID. - pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); - /// The check account, which holds any native assets that have been teleported out and not back in (yet). - pub CheckAccount: AccountId = XcmPallet::check_account(); - /// The check account that is allowed to mint assets locally. - pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); -} - -/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to -/// determine the sovereign account controlled by a location. -pub type SovereignAccountOf = ( - // We can convert a child parachain using the standard `AccountId` conversion. - ChildParachainConvertsVia, - // We can directly alias an `AccountId32` into a local account. - AccountId32Aliases, -); - -/// Our asset transactor. This is what allows us to interest with the runtime facilities from the -/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. -/// -/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. -pub type LocalAssetTransactor = XcmCurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // We can convert the MultiLocations with our converter above: - SovereignAccountOf, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We track our teleports in/out to keep total issuance correct. - LocalCheckAccount, ->; - -/// The means that we convert the XCM message origin location into a local dispatch origin. -type LocalOriginConverter = ( - // A `Signed` origin of the sovereign account that the original location controls. - SovereignSignedViaLocation, - // A child parachain, natively expressed, has the `Parachain` origin. - ChildParachainAsNative, - // The AccountId32 location type can be expressed natively as a `Signed` origin. - SignedAccountId32AsNative, -); - -parameter_types! { - /// The amount of weight an XCM operation takes. This is a safe overestimate. - pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); - /// Maximum number of instructions in a single XCM fragment. A sanity check against weight - /// calculations getting too crazy. - pub const MaxInstructions: u32 = 100; - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(TokenLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our -/// individual routers. -pub type XcmRouter = WithUniqueTopic<( - // Only one router so far - use DMP to communicate with child parachains. - ChildParachainRouter< - Runtime, - XcmPallet, - ExponentialPrice, - >, -)>; - -parameter_types! { - pub const Ksm: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); - pub const Statemine: MultiLocation = Parachain(1000).into_location(); - pub const Encointer: MultiLocation = Parachain(1001).into_location(); - pub const KsmForStatemine: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Statemine::get()); - pub const KsmForEncointer: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Encointer::get()); - pub const MaxAssetsIntoHolding: u32 = 64; -} -pub type TrustedTeleporters = - (xcm_builder::Case, xcm_builder::Case); - -match_types! { - pub type OnlyParachains: impl Contains = { - MultiLocation { parents: 0, interior: X1(Parachain(_)) } - }; -} - -/// The barriers one of which must be passed for an XCM message to be executed. -pub type Barrier = TrailingSetTopicAsId<( - // Weight that is paid for may be consumed. - TakeWeightCredit, - // Expected responses are OK. - AllowKnownQueryResponses, - WithComputedOrigin< - ( - // If the message is one that immediately attempts to pay for execution, then allow it. - AllowTopLevelPaidExecutionFrom, - // Messages coming from system parachains need not pay for execution. - AllowExplicitUnpaidExecutionFrom>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - ), - UniversalLocation, - ConstU32<8>, - >, -)>; - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = LocalOriginConverter; - type IsReserve = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::KusamaXcmWeight, - RuntimeCall, - MaxInstructions, - >; - // The weight trader piggybacks on the existing transaction-fee conversion logic. - type Trader = - UsingComponents>; - type ResponseHandler = XcmPallet; - type AssetTrap = XcmPallet; - type AssetLocker = (); - type AssetExchanger = (); - type AssetClaims = XcmPallet; - type SubscriptionService = XcmPallet; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); - // No bridges yet... - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; -} - -parameter_types! { - // StakingAdmin pluralistic body. - pub const StakingAdminBodyId: BodyId = BodyId::Defense; - // Fellows pluralistic body. - pub const FellowsBodyId: BodyId = BodyId::Technical; -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); -} - -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior -/// location of this chain. -pub type LocalOriginToLocation = ( - // And a usual Signed origin to be used in XCM as a corresponding AccountId32 - SignedToAccountId32, -); - -/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value. -pub type StakingAdminToPlurality = - OriginToPluralityVoice; - -/// Type to convert the Fellows origin to a Plurality `MultiLocation` value. -pub type FellowsToPlurality = OriginToPluralityVoice; - -/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an -/// interior location of this chain for a destination chain. -pub type LocalPalletOriginToLocation = ( - // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. - StakingAdminToPlurality, - // Fellows origin to be used in XCM as a corresponding Plurality `MultiLocation` value. - FellowsToPlurality, -); - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - // We only allow the root, fellows and the staking admin to send messages. - // This is basically safe to enable for everyone (safe the possibility of someone spamming the - // parachain if they're willing to pay the KSM to send from the Relay-chain), but it's useless - // until we bring in XCM v3 which will make `DescendOrigin` a bit more useful. - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = XcmRouter; - // Anyone can execute XCM messages locally. - type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = xcm_executor::XcmExecutor; - // Anyone is able to use teleportation regardless of who they are and what they want to - // teleport. - type XcmTeleportFilter = Everything; - // Anyone is able to use reserve transfers regardless of who they are and what they want to - // transfer. - type XcmReserveTransferFilter = Everything; - type Weigher = WeightInfoBounds< - crate::weights::xcm::KusamaXcmWeight, - RuntimeCall, - MaxInstructions, - >; - 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 = (); - type SovereignAccountOf = SovereignAccountOf; - type MaxLockers = ConstU32<8>; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; -} - -#[test] -fn karura_liquid_staking_xcm_has_sane_weight_upper_limt() { - use frame_support::dispatch::GetDispatchInfo; - use parity_scale_codec::Decode; - use xcm::VersionedXcm; - use xcm_executor::traits::WeightBounds; - - // should be [WithdrawAsset, BuyExecution, Transact, RefundSurplus, DepositAsset] - let blob = hex_literal::hex!("02140004000000000700e40b540213000000000700e40b54020006010700c817a804341801000006010b00c490bf4302140d010003ffffffff000100411f"); - let Ok(VersionedXcm::V2(old_xcm)) = VersionedXcm::::decode(&mut &blob[..]) - else { - panic!("can't decode XCM blob") - }; - let mut xcm: Xcm = - old_xcm.try_into().expect("conversion from v2 to v3 failed"); - let weight = ::Weigher::weight(&mut xcm) - .expect("weighing XCM failed"); - - // Test that the weigher gives us a sensible weight but don't exactly hard-code it, otherwise it - // will be out of date after each re-run. - assert!(weight.all_lte(Weight::from_parts(30_313_281_000, 72_722))); - - let Some(Transact { require_weight_at_most, call, .. }) = - xcm.inner_mut().into_iter().find(|inst| matches!(inst, Transact { .. })) - else { - panic!("no Transact instruction found") - }; - // should be pallet_utility.as_derivative { index: 0, call: pallet_staking::bond_extra { - // max_additional: 2490000000000 } } - let message_call = call.take_decoded().expect("can't decode Transact call"); - let call_weight = message_call.get_dispatch_info().weight; - // Ensure that the Transact instruction is giving a sensible `require_weight_at_most` value - assert!( - call_weight.all_lte(*require_weight_at_most), - "call weight ({:?}) was not less than or equal to require_weight_at_most ({:?})", - call_weight, - require_weight_at_most - ); -} diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs index fe9a4e52bd076e2698c9e153a770c0261f6349fe..d07964b691654b9de57b3f108b6439e2c720514f 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs @@ -28,7 +28,7 @@ use crate::{ }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use pallet_balances::Error as BalancesError; -use primitives::{v5::ValidationCode, BlockNumber, SessionIndex}; +use primitives::{BlockNumber, SessionIndex, ValidationCode}; use sp_std::collections::btree_map::BTreeMap; fn schedule_blank_para(id: ParaId, parakind: ParaKind) { diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 33039cd08ca4b90e58b2a1e415242402d81dad92..a65fda370488a5285e3c751a5a618a00a1c20ef1 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,8 +26,9 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, LEGACY_MIN_BACKING_VOTES, - MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, + LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; @@ -348,6 +349,8 @@ pub enum InconsistentError { MaxHrmpInboundChannelsExceeded, /// `minimum_backing_votes` is set to zero. ZeroMinimumBackingVotes, + /// `executor_params` are inconsistent. + InconsistentExecutorParams { inner: ExecutorParamError }, } impl HostConfiguration @@ -432,6 +435,10 @@ where return Err(ZeroMinimumBackingVotes) } + if let Err(inner) = self.executor_params.check_consistency() { + return Err(InconsistentExecutorParams { inner }) + } + Ok(()) } diff --git a/polkadot/runtime/parachains/src/configuration/migration/v6.rs b/polkadot/runtime/parachains/src/configuration/migration/v6.rs index beed54deaffa8ea6c9331948027ecf57766ce67d..19031a90bab45c5c4cf58e50f07111db547365a6 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v6.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v6.rs @@ -21,7 +21,7 @@ use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; use sp_std::vec::Vec; -use primitives::{vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; +use primitives::{AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; #[cfg(feature = "try-runtime")] use sp_std::prelude::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v7.rs b/polkadot/runtime/parachains/src/configuration/migration/v7.rs index 11365138120782c7b5909d320f2778401f0e2916..1754b78e0a1d3bd1d764f44352601fdf187b85b5 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v7.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v7.rs @@ -23,7 +23,7 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; +use primitives::{AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v8.rs b/polkadot/runtime/parachains/src/configuration/migration/v8.rs index 5c5b34821835ed2a3295b272ee0987f57584a480..d1bc9005112529d55749a82de78fe17ff28391f7 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v8.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v8.rs @@ -24,8 +24,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, - ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + AsyncBackingParams, Balance, ExecutorParams, SessionIndex, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; use sp_std::vec::Vec; diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index b27a7ab1ad734162e11f808825db46e59979b23b..9b2b7a48dc8b3ace0b4feea937b7efbe98e4950e 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -51,7 +51,7 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::slashing::{DisputeProof, DisputesTimeSlot, PendingSlashes, SlashingOffenceKind}, + slashing::{DisputeProof, DisputesTimeSlot, PendingSlashes, SlashingOffenceKind}, CandidateHash, SessionIndex, ValidatorId, ValidatorIndex, }; use scale_info::TypeInfo; diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 3ede1c908802558da7af09a7201d4e18a82f4dbc..f075ce5ca737d7597c4ed5d664050e08b9d28bf8 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -51,7 +51,7 @@ where use rand::{RngCore, SeedableRng}; let validator = T::Lookup::lookup(who).unwrap(); - let controller = pallet_staking::Pallet::::bonded(validator).unwrap(); + let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); let keys = { const SESSION_KEY_LEN: usize = 32; diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index cdb38ba6a8eaf855a6977d01c0c2fa9183cb6396..42592d9d9f1496c882e0dd2d98e53cf06fcefcc1 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -21,13 +21,16 @@ use crate::{ use frame_support::{pallet_prelude::*, traits::ReservableCurrency, DefaultNoBound}; use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; -use polkadot_parachain_primitives::primitives::HorizontalMessages; +use polkadot_parachain_primitives::primitives::{HorizontalMessages, IsSystem}; use primitives::{ Balance, Hash, HrmpChannelId, Id as ParaId, InboundHrmpMessage, OutboundHrmpMessage, SessionIndex, }; use scale_info::TypeInfo; -use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, UniqueSaturatedInto}; +use sp_runtime::{ + traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, UniqueSaturatedInto, Zero}, + ArithmeticError, +}; use sp_std::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, fmt, mem, @@ -60,6 +63,8 @@ pub trait WeightInfo { fn hrmp_cancel_open_request(c: u32) -> Weight; fn clean_open_channel_requests(c: u32) -> Weight; fn force_open_hrmp_channel(c: u32) -> Weight; + fn establish_system_channel() -> Weight; + fn poke_channel_deposits() -> Weight; } /// A weight info that is only suitable for testing. @@ -93,6 +98,12 @@ impl WeightInfo for TestWeightInfo { fn force_open_hrmp_channel(_: u32) -> Weight { Weight::MAX } + fn establish_system_channel() -> Weight { + Weight::MAX + } + fn poke_channel_deposits() -> Weight { + Weight::MAX + } } /// A description of a request to open an HRMP channel. @@ -267,18 +278,34 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Open HRMP channel requested. - /// `[sender, recipient, proposed_max_capacity, proposed_max_message_size]` - OpenChannelRequested(ParaId, ParaId, u32, u32), + OpenChannelRequested { + sender: ParaId, + recipient: ParaId, + proposed_max_capacity: u32, + proposed_max_message_size: u32, + }, /// An HRMP channel request sent by the receiver was canceled by either party. - /// `[by_parachain, channel_id]` - OpenChannelCanceled(ParaId, HrmpChannelId), - /// Open HRMP channel accepted. `[sender, recipient]` - OpenChannelAccepted(ParaId, ParaId), - /// HRMP channel closed. `[by_parachain, channel_id]` - ChannelClosed(ParaId, HrmpChannelId), + OpenChannelCanceled { by_parachain: ParaId, channel_id: HrmpChannelId }, + /// Open HRMP channel accepted. + OpenChannelAccepted { sender: ParaId, recipient: ParaId }, + /// HRMP channel closed. + ChannelClosed { by_parachain: ParaId, channel_id: HrmpChannelId }, /// An HRMP channel was opened via Root origin. - /// `[sender, recipient, proposed_max_capacity, proposed_max_message_size]` - HrmpChannelForceOpened(ParaId, ParaId, u32, u32), + HrmpChannelForceOpened { + sender: ParaId, + recipient: ParaId, + proposed_max_capacity: u32, + proposed_max_message_size: u32, + }, + /// An HRMP channel was opened between two system chains. + HrmpSystemChannelOpened { + sender: ParaId, + recipient: ParaId, + proposed_max_capacity: u32, + proposed_max_message_size: u32, + }, + /// An HRMP channel's deposits were updated. + OpenChannelDepositsUpdated { sender: ParaId, recipient: ParaId }, } #[pallet::error] @@ -321,6 +348,8 @@ pub mod pallet { OpenHrmpChannelAlreadyConfirmed, /// The provided witness data is wrong. WrongWitness, + /// The channel between these two chains cannot be authorized. + ChannelCreationNotAuthorized, } /// The set of pending HRMP open channel requests. @@ -480,12 +509,12 @@ pub mod pallet { proposed_max_capacity, proposed_max_message_size, )?; - Self::deposit_event(Event::OpenChannelRequested( - origin, + Self::deposit_event(Event::OpenChannelRequested { + sender: origin, recipient, proposed_max_capacity, proposed_max_message_size, - )); + }); Ok(()) } @@ -497,7 +526,7 @@ pub mod pallet { pub fn hrmp_accept_open_channel(origin: OriginFor, sender: ParaId) -> DispatchResult { let origin = ensure_parachain(::RuntimeOrigin::from(origin))?; Self::accept_open_channel(origin, sender)?; - Self::deposit_event(Event::OpenChannelAccepted(sender, origin)); + Self::deposit_event(Event::OpenChannelAccepted { sender, recipient: origin }); Ok(()) } @@ -513,7 +542,7 @@ pub mod pallet { ) -> DispatchResult { let origin = ensure_parachain(::RuntimeOrigin::from(origin))?; Self::close_channel(origin, channel_id.clone())?; - Self::deposit_event(Event::ChannelClosed(origin, channel_id)); + Self::deposit_event(Event::ChannelClosed { by_parachain: origin, channel_id }); Ok(()) } @@ -525,14 +554,26 @@ pub mod pallet { /// /// Origin must be the `ChannelManager`. #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::force_clean_hrmp(*_inbound, *_outbound))] + #[pallet::weight(::WeightInfo::force_clean_hrmp(*num_inbound, *num_outbound))] pub fn force_clean_hrmp( origin: OriginFor, para: ParaId, - _inbound: u32, - _outbound: u32, + num_inbound: u32, + num_outbound: u32, ) -> DispatchResult { T::ChannelManager::ensure_origin(origin)?; + + ensure!( + HrmpIngressChannelsIndex::::decode_len(para).unwrap_or_default() <= + num_inbound as usize, + Error::::WrongWitness + ); + ensure!( + HrmpEgressChannelsIndex::::decode_len(para).unwrap_or_default() <= + num_outbound as usize, + Error::::WrongWitness + ); + Self::clean_hrmp_after_outgoing(¶); Ok(()) } @@ -546,9 +587,16 @@ pub mod pallet { /// /// Origin must be the `ChannelManager`. #[pallet::call_index(4)] - #[pallet::weight(::WeightInfo::force_process_hrmp_open(*_channels))] - pub fn force_process_hrmp_open(origin: OriginFor, _channels: u32) -> DispatchResult { + #[pallet::weight(::WeightInfo::force_process_hrmp_open(*channels))] + pub fn force_process_hrmp_open(origin: OriginFor, channels: u32) -> DispatchResult { T::ChannelManager::ensure_origin(origin)?; + + ensure!( + HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32 <= + channels, + Error::::WrongWitness + ); + let host_config = configuration::Pallet::::config(); Self::process_hrmp_open_channel_requests(&host_config); Ok(()) @@ -563,9 +611,16 @@ pub mod pallet { /// /// Origin must be the `ChannelManager`. #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::force_process_hrmp_close(*_channels))] - pub fn force_process_hrmp_close(origin: OriginFor, _channels: u32) -> DispatchResult { + #[pallet::weight(::WeightInfo::force_process_hrmp_close(*channels))] + pub fn force_process_hrmp_close(origin: OriginFor, channels: u32) -> DispatchResult { T::ChannelManager::ensure_origin(origin)?; + + ensure!( + HrmpCloseChannelRequestsList::::decode_len().unwrap_or_default() as u32 <= + channels, + Error::::WrongWitness + ); + Self::process_hrmp_close_channel_requests(); Ok(()) } @@ -592,7 +647,7 @@ pub mod pallet { Error::::WrongWitness ); Self::cancel_open_request(origin, channel_id.clone())?; - Self::deposit_event(Event::OpenChannelCanceled(origin, channel_id)); + Self::deposit_event(Event::OpenChannelCanceled { by_parachain: origin, channel_id }); Ok(()) } @@ -600,8 +655,8 @@ pub mod pallet { /// the `max_capacity` and `max_message_size` are still subject to the Relay Chain's /// configured limits. /// - /// Expected use is when one of the `ParaId`s involved in the channel is governed by the - /// Relay Chain, e.g. a system parachain. + /// Expected use is when one (and only one) of the `ParaId`s involved in the channel is + /// governed by the system, e.g. a system parachain. /// /// Origin must be the `ChannelManager`. #[pallet::call_index(7)] @@ -628,18 +683,159 @@ pub mod pallet { 0 }; - // Now we proceed with normal init/accept. + // Now we proceed with normal init/accept, except that we set `no_deposit` to true such + // that it will not require deposits from either member. Self::init_open_channel(sender, recipient, max_capacity, max_message_size)?; Self::accept_open_channel(recipient, sender)?; - Self::deposit_event(Event::HrmpChannelForceOpened( + Self::deposit_event(Event::HrmpChannelForceOpened { sender, recipient, - max_capacity, - max_message_size, - )); + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size, + }); Ok(Some(::WeightInfo::force_open_hrmp_channel(cancel_request)).into()) } + + /// Establish an HRMP channel between two system chains. If the channel does not already + /// exist, the transaction fees will be refunded to the caller. The system does not take + /// deposits for channels between system chains, and automatically sets the message number + /// and size limits to the maximum allowed by the network's configuration. + /// + /// Arguments: + /// + /// - `sender`: A system chain, `ParaId`. + /// - `recipient`: A system chain, `ParaId`. + /// + /// Any signed origin can call this function, but _both_ inputs MUST be system chains. If + /// the channel does not exist yet, there is no fee. + #[pallet::call_index(8)] + #[pallet::weight(::WeightInfo::establish_system_channel())] + pub fn establish_system_channel( + origin: OriginFor, + sender: ParaId, + recipient: ParaId, + ) -> DispatchResultWithPostInfo { + let _caller = ensure_signed(origin)?; + + // both chains must be system + ensure!( + sender.is_system() && recipient.is_system(), + Error::::ChannelCreationNotAuthorized + ); + + let config = >::config(); + let max_message_size = config.hrmp_channel_max_message_size; + let max_capacity = config.hrmp_channel_max_capacity; + + Self::init_open_channel(sender, recipient, max_capacity, max_message_size)?; + Self::accept_open_channel(recipient, sender)?; + + Self::deposit_event(Event::HrmpSystemChannelOpened { + sender, + recipient, + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size, + }); + + Ok(Pays::No.into()) + } + + /// Update the deposits held for an HRMP channel to the latest `Configuration`. Channels + /// with system chains do not require a deposit. + /// + /// Arguments: + /// + /// - `sender`: A chain, `ParaId`. + /// - `recipient`: A chain, `ParaId`. + /// + /// Any signed origin can call this function. + #[pallet::call_index(9)] + #[pallet::weight(::WeightInfo::poke_channel_deposits())] + pub fn poke_channel_deposits( + origin: OriginFor, + sender: ParaId, + recipient: ParaId, + ) -> DispatchResult { + let _caller = ensure_signed(origin)?; + let channel_id = HrmpChannelId { sender, recipient }; + let is_system = sender.is_system() || recipient.is_system(); + + let config = >::config(); + + // Channels with and amongst the system do not require a deposit. + let (new_sender_deposit, new_recipient_deposit) = if is_system { + (0, 0) + } else { + (config.hrmp_sender_deposit, config.hrmp_recipient_deposit) + }; + + let _ = HrmpChannels::::mutate(&channel_id, |channel| -> DispatchResult { + if let Some(ref mut channel) = channel { + let current_sender_deposit = channel.sender_deposit; + let current_recipient_deposit = channel.recipient_deposit; + + // nothing to update + if current_sender_deposit == new_sender_deposit && + current_recipient_deposit == new_recipient_deposit + { + return Ok(()) + } + + // sender + if current_sender_deposit > new_sender_deposit { + // Can never underflow, but be paranoid. + let amount = current_sender_deposit + .checked_sub(new_sender_deposit) + .ok_or(ArithmeticError::Underflow)?; + T::Currency::unreserve( + &channel_id.sender.into_account_truncating(), + // The difference should always be convertable into `Balance`, but be + // paranoid and do nothing in case. + amount.try_into().unwrap_or(Zero::zero()), + ); + } else if current_sender_deposit < new_sender_deposit { + let amount = new_sender_deposit + .checked_sub(current_sender_deposit) + .ok_or(ArithmeticError::Underflow)?; + T::Currency::reserve( + &channel_id.sender.into_account_truncating(), + amount.try_into().unwrap_or(Zero::zero()), + )?; + } + + // recipient + if current_recipient_deposit > new_recipient_deposit { + let amount = current_recipient_deposit + .checked_sub(new_recipient_deposit) + .ok_or(ArithmeticError::Underflow)?; + T::Currency::unreserve( + &channel_id.recipient.into_account_truncating(), + amount.try_into().unwrap_or(Zero::zero()), + ); + } else if current_recipient_deposit < new_recipient_deposit { + let amount = new_recipient_deposit + .checked_sub(current_recipient_deposit) + .ok_or(ArithmeticError::Underflow)?; + T::Currency::reserve( + &channel_id.recipient.into_account_truncating(), + amount.try_into().unwrap_or(Zero::zero()), + )?; + } + + // update storage + channel.sender_deposit = new_sender_deposit; + channel.recipient_deposit = new_recipient_deposit; + } else { + return Err(Error::::OpenHrmpChannelDoesntExist.into()) + } + Ok(()) + })?; + + Self::deposit_event(Event::OpenChannelDepositsUpdated { sender, recipient }); + + Ok(()) + } } } @@ -817,6 +1013,10 @@ impl Pallet { "can't be `None` due to the invariant that the list contains the same items as the set; qed", ); + let system_channel = channel_id.sender.is_system() || channel_id.recipient.is_system(); + let sender_deposit = request.sender_deposit; + let recipient_deposit = if system_channel { 0 } else { config.hrmp_recipient_deposit }; + if request.confirmed { if >::is_valid_para(channel_id.sender) && >::is_valid_para(channel_id.recipient) @@ -824,8 +1024,8 @@ impl Pallet { HrmpChannels::::insert( &channel_id, HrmpChannel { - sender_deposit: request.sender_deposit, - recipient_deposit: config.hrmp_recipient_deposit, + sender_deposit, + recipient_deposit, max_capacity: request.max_capacity, max_total_size: request.max_total_size, max_message_size: request.max_message_size, @@ -1173,7 +1373,9 @@ impl Pallet { } /// Initiate opening a channel from a parachain to a given recipient with given channel - /// parameters. + /// parameters. If neither chain is part of the system, then a deposit from the `Configuration` + /// will be required for `origin` (the sender) upon opening the request and the `recipient` upon + /// accepting it. /// /// Basically the same as [`hrmp_init_open_channel`](Pallet::hrmp_init_open_channel) but /// intended for calling directly from other pallets rather than dispatched. @@ -1219,10 +1421,15 @@ impl Pallet { Error::::OpenHrmpChannelLimitExceeded, ); - T::Currency::reserve( - &origin.into_account_truncating(), - config.hrmp_sender_deposit.unique_saturated_into(), - )?; + // Do not require deposits for channels with or amongst the system. + let is_system = origin.is_system() || recipient.is_system(); + let deposit = if is_system { 0 } else { config.hrmp_sender_deposit }; + if !deposit.is_zero() { + T::Currency::reserve( + &origin.into_account_truncating(), + deposit.unique_saturated_into(), + )?; + } // mutating storage directly now -- shall not bail henceforth. @@ -1232,7 +1439,7 @@ impl Pallet { HrmpOpenChannelRequest { confirmed: false, _age: 0, - sender_deposit: config.hrmp_sender_deposit, + sender_deposit: deposit, max_capacity: proposed_max_capacity, max_message_size: proposed_max_message_size, max_total_size: config.hrmp_channel_max_total_size, @@ -1254,7 +1461,7 @@ impl Pallet { if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) = >::queue_downward_message(&config, recipient, notification_bytes) { - // this should never happen unless the max downward message size is configured to an + // this should never happen unless the max downward message size is configured to a // jokingly small number. log::error!( target: "runtime::hrmp", @@ -1287,10 +1494,15 @@ impl Pallet { Error::::AcceptHrmpChannelLimitExceeded, ); - T::Currency::reserve( - &origin.into_account_truncating(), - config.hrmp_recipient_deposit.unique_saturated_into(), - )?; + // Do not require deposits for channels with or amongst the system. + let is_system = origin.is_system() || sender.is_system(); + let deposit = if is_system { 0 } else { config.hrmp_recipient_deposit }; + if !deposit.is_zero() { + T::Currency::reserve( + &origin.into_account_truncating(), + deposit.unique_saturated_into(), + )?; + } // persist the updated open channel request and then increment the number of accepted // channels. diff --git a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs index 3fe347a7bcbaf054b23afa67ecaa7bb20d9100b0..2cb49c88d437cb3e0a4c01a40d343a179316ec9d 100644 --- a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs +++ b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs @@ -14,12 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +#![cfg(feature = "runtime-benchmarks")] + use crate::{ configuration::Pallet as Configuration, hrmp::{Pallet as Hrmp, *}, paras::{Pallet as Paras, ParaKind, ParachainsCache}, shared::Pallet as Shared, }; +use frame_benchmarking::{impl_benchmark_test_suite, v2::*, whitelisted_caller}; use frame_support::{assert_ok, traits::Currency}; type BalanceOf = @@ -138,10 +141,12 @@ static_assertions::const_assert!(MAX_UNIQUE_CHANNELS < PREFIX_0); static_assertions::const_assert!(HRMP_MAX_INBOUND_CHANNELS_BOUND < PREFIX_0); static_assertions::const_assert!(HRMP_MAX_OUTBOUND_CHANNELS_BOUND < PREFIX_0); -frame_benchmarking::benchmarks! { - where_clause { where ::RuntimeOrigin: From } +#[benchmarks(where ::RuntimeOrigin: From)] +mod benchmarks { + use super::*; - hrmp_init_open_channel { + #[benchmark] + fn hrmp_init_open_channel() { let sender_id: ParaId = 1u32.into(); let sender_origin: crate::Origin = 1u32.into(); @@ -149,51 +154,75 @@ frame_benchmarking::benchmarks! { // make sure para is registered, and has enough balance. let ed = T::Currency::minimum_balance(); - let deposit: BalanceOf = Configuration::::config().hrmp_sender_deposit.unique_saturated_into(); + let deposit: BalanceOf = + Configuration::::config().hrmp_sender_deposit.unique_saturated_into(); register_parachain_with_balance::(sender_id, deposit + ed); register_parachain_with_balance::(recipient_id, deposit + ed); let capacity = Configuration::::config().hrmp_channel_max_capacity; let message_size = Configuration::::config().hrmp_channel_max_message_size; - }: _(sender_origin, recipient_id, capacity, message_size) - verify { + + #[extrinsic_call] + _(sender_origin, recipient_id, capacity, message_size); + assert_last_event::( - Event::::OpenChannelRequested(sender_id, recipient_id, capacity, message_size).into() + Event::::OpenChannelRequested { + sender: sender_id, + recipient: recipient_id, + proposed_max_capacity: capacity, + proposed_max_message_size: message_size, + } + .into(), ); } - hrmp_accept_open_channel { + #[benchmark] + fn hrmp_accept_open_channel() { let [(sender, _), (recipient, recipient_origin)] = establish_para_connection::(1, 2, ParachainSetupStep::Requested); - }: _(recipient_origin, sender) - verify { - assert_last_event::(Event::::OpenChannelAccepted(sender, recipient).into()); + + #[extrinsic_call] + _(recipient_origin, sender); + + assert_last_event::(Event::::OpenChannelAccepted { sender, recipient }.into()); } - hrmp_close_channel { + #[benchmark] + fn hrmp_close_channel() { let [(sender, sender_origin), (recipient, _)] = establish_para_connection::(1, 2, ParachainSetupStep::Established); let channel_id = HrmpChannelId { sender, recipient }; - }: _(sender_origin, channel_id.clone()) - verify { - assert_last_event::(Event::::ChannelClosed(sender, channel_id).into()); + + #[extrinsic_call] + _(sender_origin, channel_id.clone()); + + assert_last_event::( + Event::::ChannelClosed { by_parachain: sender, channel_id }.into(), + ); } // NOTE: a single parachain should have the maximum number of allowed ingress and egress // channels. - force_clean_hrmp { + #[benchmark] + fn force_clean_hrmp( // ingress channels to a single leaving parachain that need to be closed. - let i in 0 .. (HRMP_MAX_INBOUND_CHANNELS_BOUND - 1); + i: Linear<0, { HRMP_MAX_INBOUND_CHANNELS_BOUND - 1 }>, // egress channels to a single leaving parachain that need to be closed. - let e in 0 .. (HRMP_MAX_OUTBOUND_CHANNELS_BOUND - 1); - + e: Linear<0, { HRMP_MAX_OUTBOUND_CHANNELS_BOUND - 1 }>, + ) { // first, update the configs to support this many open channels... - assert_ok!( - Configuration::::set_hrmp_max_parachain_outbound_channels(frame_system::RawOrigin::Root.into(), e + 1) - ); - assert_ok!( - Configuration::::set_hrmp_max_parachain_inbound_channels(frame_system::RawOrigin::Root.into(), i + 1) - ); + assert_ok!(Configuration::::set_hrmp_max_parachain_outbound_channels( + frame_system::RawOrigin::Root.into(), + e + 1 + )); + assert_ok!(Configuration::::set_hrmp_max_parachain_inbound_channels( + frame_system::RawOrigin::Root.into(), + i + 1 + )); + assert_ok!(Configuration::::set_max_downward_message_size( + frame_system::RawOrigin::Root.into(), + 1024 + )); // .. and enact it. Configuration::::initializer_on_new_session(&Shared::::scheduled_session()); @@ -201,14 +230,17 @@ frame_benchmarking::benchmarks! { let deposit: BalanceOf = config.hrmp_sender_deposit.unique_saturated_into(); let para: ParaId = 1u32.into(); - let para_origin: crate::Origin = 1u32.into(); register_parachain_with_balance::(para, deposit); T::Currency::make_free_balance_be(¶.into_account_truncating(), deposit * 256u32.into()); for ingress_para_id in 0..i { // establish ingress channels to `para`. let ingress_para_id = ingress_para_id + PREFIX_0; - let _ = establish_para_connection::(ingress_para_id, para.into(), ParachainSetupStep::Established); + let _ = establish_para_connection::( + ingress_para_id, + para.into(), + ParachainSetupStep::Established, + ); } // nothing should be left unprocessed. @@ -217,7 +249,11 @@ frame_benchmarking::benchmarks! { for egress_para_id in 0..e { // establish egress channels to `para`. let egress_para_id = egress_para_id + PREFIX_1; - let _ = establish_para_connection::(para.into(), egress_para_id, ParachainSetupStep::Established); + let _ = establish_para_connection::( + para.into(), + egress_para_id, + ParachainSetupStep::Established, + ); } // nothing should be left unprocessed. @@ -225,7 +261,10 @@ frame_benchmarking::benchmarks! { // all in all, we have created this many channels. assert_eq!(HrmpChannels::::iter().count() as u32, i + e); - }: _(frame_system::Origin::::Root, para, i, e) verify { + + #[extrinsic_call] + _(frame_system::Origin::::Root, para, i, e); + // all in all, all of them must be gone by now. assert_eq!(HrmpChannels::::iter().count() as u32, 0); // borrow this function from the tests to make sure state is clear, given that we do a lot @@ -233,128 +272,250 @@ frame_benchmarking::benchmarks! { Hrmp::::assert_storage_consistency_exhaustive(); } - force_process_hrmp_open { + #[benchmark] + fn force_process_hrmp_open( // number of channels that need to be processed. Worse case is an N-M relation: unique // sender and recipients for all channels. - let c in 0 .. MAX_UNIQUE_CHANNELS; - - for id in 0 .. c { - let _ = establish_para_connection::(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Accepted); + c: Linear<0, MAX_UNIQUE_CHANNELS>, + ) { + for id in 0..c { + let _ = establish_para_connection::( + PREFIX_0 + id, + PREFIX_1 + id, + ParachainSetupStep::Accepted, + ); } assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, c); - }: _(frame_system::Origin::::Root, c) - verify { + + #[extrinsic_call] + _(frame_system::Origin::::Root, c); + assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, 0); } - force_process_hrmp_close { + #[benchmark] + fn force_process_hrmp_close( // number of channels that need to be processed. Worse case is an N-M relation: unique // sender and recipients for all channels. - let c in 0 .. MAX_UNIQUE_CHANNELS; - - for id in 0 .. c { - let _ = establish_para_connection::(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::CloseRequested); + c: Linear<0, MAX_UNIQUE_CHANNELS>, + ) { + for id in 0..c { + let _ = establish_para_connection::( + PREFIX_0 + id, + PREFIX_1 + id, + ParachainSetupStep::CloseRequested, + ); } assert_eq!(HrmpCloseChannelRequestsList::::decode_len().unwrap_or_default() as u32, c); - }: _(frame_system::Origin::::Root, c) - verify { + + #[extrinsic_call] + _(frame_system::Origin::::Root, c); + assert_eq!(HrmpCloseChannelRequestsList::::decode_len().unwrap_or_default() as u32, 0); } - hrmp_cancel_open_request { + #[benchmark] + fn hrmp_cancel_open_request( // number of items already existing in the `HrmpOpenChannelRequestsList`, other than the // one that we remove. - let c in 0 .. MAX_UNIQUE_CHANNELS; - - for id in 0 .. c { - let _ = establish_para_connection::(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Requested); + c: Linear<0, MAX_UNIQUE_CHANNELS>, + ) { + for id in 0..c { + let _ = establish_para_connection::( + PREFIX_0 + id, + PREFIX_1 + id, + ParachainSetupStep::Requested, + ); } let [(sender, sender_origin), (recipient, _)] = establish_para_connection::(1, 2, ParachainSetupStep::Requested); - assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, c + 1); + assert_eq!( + HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, + c + 1 + ); let channel_id = HrmpChannelId { sender, recipient }; - }: _(sender_origin, channel_id, c + 1) - verify { + + #[extrinsic_call] + _(sender_origin, channel_id, c + 1); + assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, c); } // worse case will be `n` parachain channel requests, where in all of them either the sender or // the recipient need to be cleaned. This enforces the deposit of at least one to be processed. // No code path for triggering two deposit process exists. - clean_open_channel_requests { - let c in 0 .. MAX_UNIQUE_CHANNELS; - - for id in 0 .. c { - let _ = establish_para_connection::(PREFIX_0 + id, PREFIX_1 + id, ParachainSetupStep::Requested); + #[benchmark] + fn clean_open_channel_requests(c: Linear<0, MAX_UNIQUE_CHANNELS>) { + for id in 0..c { + let _ = establish_para_connection::( + PREFIX_0 + id, + PREFIX_1 + id, + ParachainSetupStep::Requested, + ); } assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, c); let outgoing = (0..c).map(|id| (id + PREFIX_1).into()).collect::>(); let config = Configuration::::config(); - }: { - Hrmp::::clean_open_channel_requests(&config, &outgoing); - } verify { + + #[block] + { + Hrmp::::clean_open_channel_requests(&config, &outgoing); + } + assert_eq!(HrmpOpenChannelRequestsList::::decode_len().unwrap_or_default() as u32, 0); } - force_open_hrmp_channel { + #[benchmark] + fn force_open_hrmp_channel( + // Weight parameter only accepts `u32`, `0` and `1` used to represent `false` and `true`, + // respectively. + c: Linear<0, 1>, + ) { let sender_id: ParaId = 1u32.into(); let sender_origin: crate::Origin = 1u32.into(); let recipient_id: ParaId = 2u32.into(); - // make sure para is registered, and has enough balance. + // Make sure para is registered. The sender does actually need the normal deposit because it + // is first going the "init" route. let ed = T::Currency::minimum_balance(); let sender_deposit: BalanceOf = Configuration::::config().hrmp_sender_deposit.unique_saturated_into(); - let recipient_deposit: BalanceOf = - Configuration::::config().hrmp_recipient_deposit.unique_saturated_into(); register_parachain_with_balance::(sender_id, sender_deposit + ed); - register_parachain_with_balance::(recipient_id, recipient_deposit + ed); + register_parachain_with_balance::(recipient_id, Zero::zero()); let capacity = Configuration::::config().hrmp_channel_max_capacity; let message_size = Configuration::::config().hrmp_channel_max_message_size; - // Weight parameter only accepts `u32`, `0` and `1` used to represent `false` and `true`, - // respectively. - let c = [0, 1]; let channel_id = HrmpChannelId { sender: sender_id, recipient: recipient_id }; - for channels_to_close in c { - if channels_to_close == 1 { - // this will consume more weight if a channel _request_ already exists, because it - // will need to clear the request. - assert_ok!(Hrmp::::hrmp_init_open_channel( + if c == 1 { + // this will consume more weight if a channel _request_ already exists, because it + // will need to clear the request. + assert_ok!(Hrmp::::hrmp_init_open_channel( + sender_origin.clone().into(), + recipient_id, + capacity, + message_size + )); + assert!(HrmpOpenChannelRequests::::get(&channel_id).is_some()); + } else { + if HrmpOpenChannelRequests::::get(&channel_id).is_some() { + assert_ok!(Hrmp::::hrmp_cancel_open_request( sender_origin.clone().into(), - recipient_id, - capacity, - message_size + channel_id.clone(), + MAX_UNIQUE_CHANNELS, )); - assert!(HrmpOpenChannelRequests::::get(&channel_id).is_some()); - } else { - if HrmpOpenChannelRequests::::get(&channel_id).is_some() { - assert_ok!(Hrmp::::hrmp_cancel_open_request( - sender_origin.clone().into(), - channel_id.clone(), - MAX_UNIQUE_CHANNELS, - )); - } - assert!(HrmpOpenChannelRequests::::get(&channel_id).is_none()); } + assert!(HrmpOpenChannelRequests::::get(&channel_id).is_none()); } // but the _channel_ should not exist assert!(HrmpChannels::::get(&channel_id).is_none()); - }: _(frame_system::Origin::::Root, sender_id, recipient_id, capacity, message_size) - verify { + + #[extrinsic_call] + _(frame_system::Origin::::Root, sender_id, recipient_id, capacity, message_size); + assert_last_event::( - Event::::HrmpChannelForceOpened(sender_id, recipient_id, capacity, message_size).into() + Event::::HrmpChannelForceOpened { + sender: sender_id, + recipient: recipient_id, + proposed_max_capacity: capacity, + proposed_max_message_size: message_size, + } + .into(), ); } -} -frame_benchmarking::impl_benchmark_test_suite!( - Hrmp, - crate::mock::new_test_ext(crate::hrmp::tests::GenesisConfigBuilder::default().build()), - crate::mock::Test -); + #[benchmark] + fn establish_system_channel() { + let sender_id: ParaId = 1u32.into(); + let recipient_id: ParaId = 2u32.into(); + + let caller: T::AccountId = whitelisted_caller(); + let config = Configuration::::config(); + + // make sure para is registered, and has zero balance. + register_parachain_with_balance::(sender_id, Zero::zero()); + register_parachain_with_balance::(recipient_id, Zero::zero()); + + let capacity = config.hrmp_channel_max_capacity; + let message_size = config.hrmp_channel_max_message_size; + + #[extrinsic_call] + _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); + + assert_last_event::( + Event::::HrmpSystemChannelOpened { + sender: sender_id, + recipient: recipient_id, + proposed_max_capacity: capacity, + proposed_max_message_size: message_size, + } + .into(), + ); + } + + #[benchmark] + fn poke_channel_deposits() { + let sender_id: ParaId = 1u32.into(); + let recipient_id: ParaId = 2u32.into(); + let channel_id = HrmpChannelId { sender: sender_id, recipient: recipient_id }; + + let caller: T::AccountId = whitelisted_caller(); + let config = Configuration::::config(); + + // make sure para is registered, and has balance to reserve. + let ed = T::Currency::minimum_balance(); + let sender_deposit: BalanceOf = config.hrmp_sender_deposit.unique_saturated_into(); + let recipient_deposit: BalanceOf = config.hrmp_recipient_deposit.unique_saturated_into(); + register_parachain_with_balance::(sender_id, ed + sender_deposit); + register_parachain_with_balance::(recipient_id, ed + recipient_deposit); + + // Our normal establishment won't actually reserve deposits, so just insert them directly. + HrmpChannels::::insert( + &channel_id, + HrmpChannel { + sender_deposit: config.hrmp_sender_deposit, + recipient_deposit: config.hrmp_recipient_deposit, + max_capacity: config.hrmp_channel_max_capacity, + max_total_size: config.hrmp_channel_max_total_size, + max_message_size: config.hrmp_channel_max_message_size, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + // Actually reserve the deposits. + let _ = T::Currency::reserve(&sender_id.into_account_truncating(), sender_deposit); + let _ = T::Currency::reserve(&recipient_id.into_account_truncating(), recipient_deposit); + + #[extrinsic_call] + _(frame_system::RawOrigin::Signed(caller), sender_id, recipient_id); + + assert_last_event::( + Event::::OpenChannelDepositsUpdated { sender: sender_id, recipient: recipient_id } + .into(), + ); + let channel = HrmpChannels::::get(&channel_id).unwrap(); + // Check that the deposit was updated in the channel state. + assert_eq!(channel.sender_deposit, 0); + assert_eq!(channel.recipient_deposit, 0); + // And that the funds were unreserved. + assert_eq!( + T::Currency::reserved_balance(&sender_id.into_account_truncating()), + 0u128.unique_saturated_into() + ); + assert_eq!( + T::Currency::reserved_balance(&recipient_id.into_account_truncating()), + 0u128.unique_saturated_into() + ); + } + + impl_benchmark_test_suite!( + Hrmp, + crate::mock::new_test_ext(crate::hrmp::tests::GenesisConfigBuilder::default().build()), + crate::mock::Test + ); +} diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 8cfaf48d10ef7f688ef37a4fb3a12182a7e06c13..4fc0b0b448a50658758d4f76e46c7034d2edce01 100644 --- a/polkadot/runtime/parachains/src/hrmp/tests.rs +++ b/polkadot/runtime/parachains/src/hrmp/tests.rs @@ -14,13 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +// NOTE: System chains, identified by ParaId < 2000, are treated as special in HRMP channel +// initialization. Namely, they do not require a deposit if even one ParaId is a system para. If +// both paras are system chains, then they are also configured to the system's max configuration. + use super::*; use crate::mock::{ deregister_parachain, new_test_ext, register_parachain, register_parachain_with_balance, Configuration, Hrmp, MockGenesisConfig, Paras, ParasShared, RuntimeEvent as MockEvent, RuntimeOrigin, System, Test, }; -use frame_support::assert_noop; +use frame_support::{assert_noop, assert_ok}; use primitives::BlockNumber; use std::collections::BTreeMap; @@ -133,10 +137,10 @@ fn empty_state_consistent_state() { #[test] fn open_channel_works() { - let para_a = 1.into(); - let para_a_origin: crate::Origin = 1.into(); - let para_b = 3.into(); - let para_b_origin: crate::Origin = 3.into(); + 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. @@ -147,14 +151,17 @@ fn open_channel_works() { Hrmp::hrmp_init_open_channel(para_a_origin.into(), para_b, 2, 8).unwrap(); Hrmp::assert_storage_consistency_exhaustive(); assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8)))); + MockEvent::Hrmp(Event::OpenChannelRequested { + sender: para_a, + recipient: para_b, + proposed_max_capacity: 2, + proposed_max_message_size: 8 + }))); Hrmp::hrmp_accept_open_channel(para_b_origin.into(), para_a).unwrap(); Hrmp::assert_storage_consistency_exhaustive(); - assert!(System::events() - .iter() - .any(|record| record.event == - MockEvent::Hrmp(Event::OpenChannelAccepted(para_a, para_b)))); + assert!(System::events().iter().any(|record| record.event == + MockEvent::Hrmp(Event::OpenChannelAccepted { sender: para_a, recipient: para_b }))); // Advance to a block 6, but without session change. That means that the channel has // not been created yet. @@ -171,18 +178,26 @@ fn open_channel_works() { #[test] fn force_open_channel_works() { let para_a = 1.into(); - let para_b = 3.into(); + let para_b = 2003.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { // We need both A & B to be registered and live parachains. register_parachain(para_a); register_parachain(para_b); + let para_b_free_balance = + ::Currency::free_balance(¶_b.into_account_truncating()); + run_to_block(5, Some(vec![4, 5])); Hrmp::force_open_hrmp_channel(RuntimeOrigin::root(), para_a, para_b, 2, 8).unwrap(); Hrmp::assert_storage_consistency_exhaustive(); assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::HrmpChannelForceOpened(para_a, para_b, 2, 8)))); + MockEvent::Hrmp(Event::HrmpChannelForceOpened { + sender: para_a, + recipient: para_b, + proposed_max_capacity: 2, + proposed_max_message_size: 8 + }))); // Advance to a block 6, but without session change. That means that the channel has // not been created yet. @@ -193,14 +208,19 @@ fn force_open_channel_works() { // Now let the session change happen and thus open the channel. run_to_block(8, Some(vec![8])); assert!(channel_exists(para_a, para_b)); + // Because para_a is a system chain, para_b's free balance should not have changed. + assert_eq!( + ::Currency::free_balance(¶_b.into_account_truncating()), + para_b_free_balance + ); }); } #[test] fn force_open_channel_works_with_existing_request() { - let para_a = 1.into(); - let para_a_origin: crate::Origin = 1.into(); - let para_b = 3.into(); + let para_a = 2001.into(); + let para_a_origin: crate::Origin = 2001.into(); + let para_b = 2003.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { // We need both A & B to be registered and live parachains. @@ -212,7 +232,12 @@ fn force_open_channel_works_with_existing_request() { Hrmp::hrmp_init_open_channel(para_a_origin.into(), para_b, 2, 8).unwrap(); Hrmp::assert_storage_consistency_exhaustive(); assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8)))); + MockEvent::Hrmp(Event::OpenChannelRequested { + sender: para_a, + recipient: para_b, + proposed_max_capacity: 2, + proposed_max_message_size: 8 + }))); run_to_block(5, Some(vec![4, 5])); // the request exists, but no channel. @@ -226,7 +251,12 @@ fn force_open_channel_works_with_existing_request() { Hrmp::force_open_hrmp_channel(RuntimeOrigin::root(), para_a, para_b, 2, 8).unwrap(); Hrmp::assert_storage_consistency_exhaustive(); assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::HrmpChannelForceOpened(para_a, para_b, 2, 8)))); + MockEvent::Hrmp(Event::HrmpChannelForceOpened { + sender: para_a, + recipient: para_b, + proposed_max_capacity: 2, + proposed_max_message_size: 8 + }))); // Advance to a block 6, but without session change. That means that the channel has // not been created yet. @@ -240,11 +270,132 @@ fn force_open_channel_works_with_existing_request() { }); } +#[test] +fn open_system_channel_works() { + let para_a = 1.into(); + let para_b = 3.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and live parachains. + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + Hrmp::establish_system_channel(RuntimeOrigin::signed(1), para_a, para_b).unwrap(); + Hrmp::assert_storage_consistency_exhaustive(); + assert!(System::events().iter().any(|record| record.event == + MockEvent::Hrmp(Event::HrmpSystemChannelOpened { + sender: para_a, + recipient: para_b, + proposed_max_capacity: 2, + proposed_max_message_size: 8 + }))); + + // Advance to a block 6, but without session change. That means that the channel has + // not been created yet. + run_to_block(6, None); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + + // Now let the session change happen and thus open the channel. + run_to_block(8, Some(vec![8])); + assert!(channel_exists(para_a, para_b)); + }); +} + +#[test] +fn open_system_channel_does_not_work_for_non_system_chains() { + let para_a = 2001.into(); + let para_b = 2003.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and live parachains. + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + assert_noop!( + Hrmp::establish_system_channel(RuntimeOrigin::signed(1), para_a, para_b), + Error::::ChannelCreationNotAuthorized + ); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn open_system_channel_does_not_work_with_one_non_system_chain() { + let para_a = 1.into(); + let para_b = 2003.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and live parachains. + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + assert_noop!( + Hrmp::establish_system_channel(RuntimeOrigin::signed(1), para_a, para_b), + Error::::ChannelCreationNotAuthorized + ); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn poke_deposits_works() { + let para_a = 1.into(); + let para_b = 2001.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and live parachains. + register_parachain_with_balance(para_a, 200); + register_parachain_with_balance(para_b, 200); + + let config = Configuration::config(); + let channel_id = HrmpChannelId { sender: para_a, recipient: para_b }; + + // Our normal establishment won't actually reserve deposits, so just insert them directly. + HrmpChannels::::insert( + &channel_id, + HrmpChannel { + sender_deposit: config.hrmp_sender_deposit, + recipient_deposit: config.hrmp_recipient_deposit, + max_capacity: config.hrmp_channel_max_capacity, + max_total_size: config.hrmp_channel_max_total_size, + max_message_size: config.hrmp_channel_max_message_size, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + // reserve funds + assert_ok!(::Currency::reserve( + ¶_a.into_account_truncating(), + config.hrmp_sender_deposit + )); + assert_ok!(::Currency::reserve( + ¶_b.into_account_truncating(), + config.hrmp_recipient_deposit + )); + + assert_ok!(Hrmp::poke_channel_deposits(RuntimeOrigin::signed(1), para_a, para_b)); + + assert_eq!( + ::Currency::reserved_balance(¶_a.into_account_truncating()), + 0 + ); + assert_eq!( + ::Currency::reserved_balance(¶_b.into_account_truncating()), + 0 + ); + }); +} + #[test] fn close_channel_works() { - let para_a = 5.into(); - let para_b = 2.into(); - let para_b_origin: crate::Origin = 2.into(); + let para_a = 2005.into(); + let para_b = 2002.into(); + let para_b_origin: crate::Origin = 2002.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { register_parachain(para_a); @@ -269,14 +420,17 @@ fn close_channel_works() { assert!(!channel_exists(para_a, para_b)); Hrmp::assert_storage_consistency_exhaustive(); assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::ChannelClosed(para_b, channel_id.clone())))); + MockEvent::Hrmp(Event::ChannelClosed { + by_parachain: para_b, + channel_id: channel_id.clone() + }))); }); } #[test] fn send_recv_messages() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_channel_max_message_size = 20; @@ -358,8 +512,8 @@ fn hrmp_mqc_head_fixture() { #[test] fn accept_incoming_request_and_offboard() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { register_parachain(para_a); @@ -380,9 +534,9 @@ fn accept_incoming_request_and_offboard() { #[test] fn check_sent_messages() { - let para_a = 32.into(); - let para_b = 64.into(); - let para_c = 97.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); + let para_c = 2097.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { register_parachain(para_a); @@ -444,8 +598,8 @@ fn check_sent_messages() { fn verify_externally_accessible() { use primitives::{well_known_keys, AbridgedHrmpChannel}; - let para_a = 20.into(); - let para_b = 21.into(); + let para_a = 2020.into(); + let para_b = 2021.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { // Register two parachains, wait until a session change, then initiate channel open @@ -502,8 +656,8 @@ fn verify_externally_accessible() { #[test] fn charging_deposits() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { register_parachain_with_balance(para_a, 0); @@ -532,8 +686,8 @@ fn charging_deposits() { #[test] fn refund_deposit_on_normal_closure() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_sender_deposit = 20; @@ -565,8 +719,8 @@ fn refund_deposit_on_normal_closure() { #[test] fn refund_deposit_on_offboarding() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_sender_deposit = 20; @@ -605,8 +759,8 @@ fn refund_deposit_on_offboarding() { #[test] fn no_dangling_open_requests() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_sender_deposit = 20; @@ -643,8 +797,8 @@ fn no_dangling_open_requests() { #[test] fn cancel_pending_open_channel_request() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_sender_deposit = 20; @@ -675,8 +829,8 @@ fn cancel_pending_open_channel_request() { #[test] fn watermark_maxed_out_at_relay_parent() { - let para_a = 32.into(); - let para_b = 64.into(); + let para_a = 2032.into(); + let para_b = 2064.into(); let mut genesis = GenesisConfigBuilder::default(); genesis.hrmp_channel_max_message_size = 20; diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index bb16c804150dc7ca35aecaa2ee5b6c16cff98e28..e34286d750ac1c89d83f1c33e606e08947f6002c 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -21,7 +21,8 @@ use crate::{ configuration::{self, HostConfiguration}, - disputes, dmp, hrmp, paras, + disputes, dmp, hrmp, + paras::{self, SetGoAhead}, scheduler::{self, AvailabilityTimeoutStatus}, shared::{self, AllowedRelayParentsTracker}, }; @@ -448,8 +449,9 @@ impl fmt::Debug for UmpAcceptanceCheckErr { "the ump queue would have grown past the max size permitted by config ({} > {})", total_size, limit, ), - UmpAcceptanceCheckErr::IsOffboarding => - write!(fmt, "upward message rejected because the para is off-boarding",), + UmpAcceptanceCheckErr::IsOffboarding => { + write!(fmt, "upward message rejected because the para is off-boarding") + }, } } } @@ -885,6 +887,7 @@ impl Pallet { new_code, now, &config, + SetGoAhead::Yes, )); } diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 7677108d73decf816d62b8ea5491e058dcfac126..6bb731671f6f8afbb350dff2a2821f6ab31da5a0 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -1255,7 +1255,13 @@ fn candidate_checks() { let cfg = Configuration::config(); let expected_at = 10 + cfg.validation_upgrade_delay; assert_eq!(expected_at, 12); - Paras::schedule_code_upgrade(chain_a, vec![1, 2, 3, 4].into(), expected_at, &cfg); + Paras::schedule_code_upgrade( + chain_a, + vec![1, 2, 3, 4].into(), + expected_at, + &cfg, + SetGoAhead::Yes, + ); } assert_noop!( @@ -2235,7 +2241,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let cause = &active_vote_state.causes()[0]; // Upgrade block is the block of inclusion, not candidate's parent. assert_matches!(cause, - paras::PvfCheckCause::Upgrade { id, included_at } + paras::PvfCheckCause::Upgrade { id, included_at, set_go_ahead: SetGoAhead::Yes } if id == &chain_a && included_at == &7 ); }); diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index 64365f17b7e8b83ce0aef13c00ccdbd1a8b5f744..e0ace86d3794a2dc4aee09ca10aa321abce1d42b 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -53,7 +53,7 @@ mod mock; mod ump_tests; pub use origin::{ensure_parachain, Origin}; -pub use paras::ParaLifecycle; +pub use paras::{ParaLifecycle, SetGoAhead}; use primitives::{HeadData, Id as ParaId, ValidationCode}; use sp_runtime::{DispatchResult, FixedU128}; @@ -89,8 +89,9 @@ pub fn schedule_parachain_downgrade(id: ParaId) -> Result<(), pub fn schedule_code_upgrade( id: ParaId, new_code: ValidationCode, + set_go_ahead: SetGoAhead, ) -> DispatchResult { - paras::Pallet::::schedule_code_upgrade_external(id, new_code) + paras::Pallet::::schedule_code_upgrade_external(id, new_code, set_go_ahead) } /// Sets the current parachain head with the given id. diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 5c060547601f5869a671856b3bf3ceebf49ee812..554f0c15af24ff632e6e5ae9da34baf43aa0975e 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -124,7 +124,13 @@ benchmarks! { let expired = frame_system::Pallet::::block_number().saturating_sub(One::one()); let config = HostConfiguration::>::default(); generate_disordered_pruning::(); - Pallet::::schedule_code_upgrade(para_id, ValidationCode(vec![0]), expired, &config); + Pallet::::schedule_code_upgrade( + para_id, + ValidationCode(vec![0]), + expired, + &config, + SetGoAhead::Yes, + ); }: _(RawOrigin::Root, para_id, new_head) verify { assert_last_event::(Event::NewHeadNoted(para_id).into()); diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs index ab5e13124436d076018b6e30dc2cc8a13162d5a1..05c4c9c37b4d9241a64539c13a1960f93c80d7c1 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs @@ -177,6 +177,7 @@ where validation_code, /* relay_parent_number */ 1u32.into(), &configuration::Pallet::::config(), + SetGoAhead::Yes, ); } else { let r = Pallet::::schedule_para_initialize( diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 2f370b5bfe472a3994a4aabf6df9e8245d7b4f88..cd73d23bdadb398d8e852b71fce3c09f5b97d94e 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -386,9 +386,18 @@ pub(crate) enum PvfCheckCause { /// /// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation. included_at: BlockNumber, + /// Whether or not the given para should be sent the `GoAhead` signal. + set_go_ahead: SetGoAhead, }, } +/// Should the `GoAhead` signal be set after a successful check of the new wasm binary? +#[derive(Debug, Copy, Clone, PartialEq, TypeInfo, Decode, Encode)] +pub enum SetGoAhead { + Yes, + No, +} + impl PvfCheckCause { /// Returns the ID of the para that initiated or subscribed to the pre-checking vote. fn para_id(&self) -> ParaId { @@ -888,7 +897,13 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; let config = configuration::Pallet::::config(); - Self::schedule_code_upgrade(para, new_code, relay_parent_number, &config); + Self::schedule_code_upgrade( + para, + new_code, + relay_parent_number, + &config, + SetGoAhead::No, + ); Self::deposit_event(Event::CodeUpgradeScheduled(para)); Ok(()) } @@ -1186,6 +1201,7 @@ impl Pallet { pub(crate) fn schedule_code_upgrade_external( id: ParaId, new_code: ValidationCode, + set_go_ahead: SetGoAhead, ) -> DispatchResult { // Check that we can schedule an upgrade at all. ensure!(Self::can_upgrade_validation_code(id), Error::::CannotUpgradeCode); @@ -1193,7 +1209,7 @@ impl Pallet { let current_block = frame_system::Pallet::::block_number(); // Schedule the upgrade with a delay just like if a parachain triggered the upgrade. let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay); - Self::schedule_code_upgrade(id, new_code, upgrade_block, &config); + Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, set_go_ahead); Self::deposit_event(Event::CodeUpgradeScheduled(id)); Ok(()) } @@ -1534,8 +1550,15 @@ impl Pallet { PvfCheckCause::Onboarding(id) => { weight += Self::proceed_with_onboarding(*id, sessions_observed); }, - PvfCheckCause::Upgrade { id, included_at } => { - weight += Self::proceed_with_upgrade(*id, code_hash, now, *included_at, cfg); + PvfCheckCause::Upgrade { id, included_at, set_go_ahead } => { + weight += Self::proceed_with_upgrade( + *id, + code_hash, + now, + *included_at, + cfg, + *set_go_ahead, + ); }, } } @@ -1568,6 +1591,7 @@ impl Pallet { now: BlockNumberFor, relay_parent_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, + set_go_ahead: SetGoAhead, ) -> Weight { let mut weight = Weight::zero(); @@ -1591,12 +1615,15 @@ impl Pallet { weight += T::DbWeight::get().reads_writes(1, 4); FutureCodeUpgrades::::insert(&id, expected_at); - UpcomingUpgrades::::mutate(|upcoming_upgrades| { - let insert_idx = upcoming_upgrades - .binary_search_by_key(&expected_at, |&(_, b)| b) - .unwrap_or_else(|idx| idx); - upcoming_upgrades.insert(insert_idx, (id, expected_at)); - }); + // Only set an upcoming upgrade if `GoAhead` signal should be set for the respective para. + if set_go_ahead == SetGoAhead::Yes { + UpcomingUpgrades::::mutate(|upcoming_upgrades| { + let insert_idx = upcoming_upgrades + .binary_search_by_key(&expected_at, |&(_, b)| b) + .unwrap_or_else(|idx| idx); + upcoming_upgrades.insert(insert_idx, (id, expected_at)); + }); + } let expected_at = expected_at.saturated_into(); let log = ConsensusLog::ParaScheduleUpgradeCode(id, *code_hash, expected_at); @@ -1835,6 +1862,7 @@ impl Pallet { new_code: ValidationCode, inclusion_block_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, + set_go_ahead: SetGoAhead, ) -> Weight { let mut weight = T::DbWeight::get().reads(1); @@ -1884,7 +1912,7 @@ impl Pallet { }); weight += Self::kick_off_pvf_check( - PvfCheckCause::Upgrade { id, included_at: inclusion_block_number }, + PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, set_go_ahead }, code_hash, new_code, cfg, diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index c511c65d473304b230897b036c73d63daca52024..cca200c2765e361120b4c5ea8db3dfc7c82bdc13 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -436,7 +436,13 @@ fn code_upgrade_applied_after_delay() { // this parablock is in the context of block 1. let expected_at = 1 + validation_upgrade_delay; let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; - Paras::schedule_code_upgrade(para_id, new_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -504,6 +510,127 @@ fn code_upgrade_applied_after_delay() { }); } +#[test] +fn code_upgrade_applied_without_setting_go_ahead_signal() { + let code_retention_period = 10; + let validation_upgrade_delay = 5; + let validation_upgrade_cooldown = 10; + + let original_code = ValidationCode(vec![1, 2, 3]); + let paras = vec![( + 0u32.into(), + ParaGenesisArgs { + para_kind: ParaKind::Parachain, + genesis_head: dummy_head_data(), + validation_code: original_code.clone(), + }, + )]; + + let genesis_config = MockGenesisConfig { + paras: GenesisConfig { paras, ..Default::default() }, + configuration: crate::configuration::GenesisConfig { + config: HostConfiguration { + code_retention_period, + validation_upgrade_delay, + validation_upgrade_cooldown, + ..Default::default() + }, + }, + ..Default::default() + }; + + new_test_ext(genesis_config).execute_with(|| { + check_code_is_stored(&original_code); + + let para_id = ParaId::from(0); + let new_code = ValidationCode(vec![4, 5, 6]); + + // Wait for at least one session change to set active validators. + const EXPECTED_SESSION: SessionIndex = 1; + run_to_block(2, Some(vec![1])); + assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); + + let (expected_at, next_possible_upgrade_at) = { + // this parablock is in the context of block 1. + let expected_at = 1 + validation_upgrade_delay; + let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; + // `set_go_ahead` parameter set to `false` which prevents signaling the parachain + // with the `GoAhead` signal. + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::No, + ); + // Include votes for super-majority. + submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); + + Paras::note_new_head(para_id, Default::default(), 1); + + assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); + assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); + assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); + assert_eq!(UpcomingUpgrades::::get(), vec![]); + assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); + assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); + check_code_is_stored(&original_code); + check_code_is_stored(&new_code); + + (expected_at, next_possible_upgrade_at) + }; + + run_to_block(expected_at, None); + + // the candidate is in the context of the parent of `expected_at`, + // thus does not trigger the code upgrade. However, now the `UpgradeGoAheadSignal` + // should not be set. + { + Paras::note_new_head(para_id, Default::default(), expected_at - 1); + + assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); + assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); + assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); + assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); + assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); + check_code_is_stored(&original_code); + check_code_is_stored(&new_code); + } + + run_to_block(expected_at + 1, None); + + // the candidate is in the context of `expected_at`, and triggers + // the upgrade. + { + Paras::note_new_head(para_id, Default::default(), expected_at); + + assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at)); + assert_eq!( + PastCodeHash::::get(&(para_id, expected_at)), + Some(original_code.hash()), + ); + assert!(FutureCodeUpgrades::::get(¶_id).is_none()); + assert!(FutureCodeHash::::get(¶_id).is_none()); + assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); + assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); + assert_eq!( + UpgradeRestrictionSignal::::get(¶_id), + Some(UpgradeRestriction::Present), + ); + assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); + check_code_is_stored(&original_code); + check_code_is_stored(&new_code); + } + + run_to_block(next_possible_upgrade_at + 1, None); + + { + assert!(UpgradeRestrictionSignal::::get(¶_id).is_none()); + assert!(UpgradeCooldowns::::get().is_empty()); + } + }); +} + #[test] fn code_upgrade_applied_after_delay_even_when_late() { let code_retention_period = 10; @@ -546,7 +673,13 @@ fn code_upgrade_applied_after_delay_even_when_late() { // this parablock is in the context of block 1. let expected_at = 1 + validation_upgrade_delay; let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; - Paras::schedule_code_upgrade(para_id, new_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -624,7 +757,13 @@ fn submit_code_change_when_not_allowed_is_err() { const EXPECTED_SESSION: SessionIndex = 1; run_to_block(1, Some(vec![1])); - Paras::schedule_code_upgrade(para_id, new_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -636,7 +775,13 @@ fn submit_code_change_when_not_allowed_is_err() { // ignore it. Note that this is only true from perspective of this module. run_to_block(2, None); assert!(!Paras::can_upgrade_validation_code(para_id)); - Paras::schedule_code_upgrade(para_id, newer_code.clone(), 2, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + newer_code.clone(), + 2, + &Configuration::config(), + SetGoAhead::Yes, + ); assert_eq!( FutureCodeUpgrades::::get(¶_id), Some(1 + validation_upgrade_delay), /* did not change since the same assertion from @@ -694,7 +839,13 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { const EXPECTED_SESSION: SessionIndex = 1; run_to_block(1, Some(vec![1])); - Paras::schedule_code_upgrade(para_id, new_code.clone(), 0, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 0, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -713,7 +864,13 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { assert!(!Paras::can_upgrade_validation_code(para_id)); // And scheduling another upgrade does not do anything. `expected_at` is still the same. - Paras::schedule_code_upgrade(para_id, newer_code.clone(), 30, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + newer_code.clone(), + 30, + &Configuration::config(), + SetGoAhead::Yes, + ); assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(0 + validation_upgrade_delay)); }); } @@ -765,7 +922,13 @@ fn full_parachain_cleanup_storage() { let expected_at = { // this parablock is in the context of block 1. let expected_at = 1 + validation_upgrade_delay; - Paras::schedule_code_upgrade(para_id, new_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -860,6 +1023,7 @@ fn cannot_offboard_ongoing_pvf_check() { new_code.clone(), RELAY_PARENT, &Configuration::config(), + SetGoAhead::Yes, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1012,7 +1176,13 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { let para_id = ParaId::from(0); let old_code: ValidationCode = vec![1, 2, 3].into(); let new_code: ValidationCode = vec![4, 5, 6].into(); - Paras::schedule_code_upgrade(para_id, new_code.clone(), 0, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 0, + &Configuration::config(), + SetGoAhead::Yes, + ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -1120,6 +1290,7 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { validation_code.clone(), RELAY_PARENT, &Configuration::config(), + SetGoAhead::Yes, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1224,7 +1395,13 @@ fn pvf_check_upgrade_reject() { // Expected current session index. const EXPECTED_SESSION: SessionIndex = 1; - Paras::schedule_code_upgrade(a, new_code.clone(), RELAY_PARENT, &Configuration::config()); + Paras::schedule_code_upgrade( + a, + new_code.clone(), + RELAY_PARENT, + &Configuration::config(), + SetGoAhead::Yes, + ); check_code_is_stored(&new_code); // 1/3 of validators vote against `new_code`. PVF should not be rejected yet. @@ -1404,7 +1581,13 @@ fn include_pvf_check_statement_refunds_weight() { // Expected current session index. const EXPECTED_SESSION: SessionIndex = 1; - Paras::schedule_code_upgrade(a, new_code.clone(), RELAY_PARENT, &Configuration::config()); + Paras::schedule_code_upgrade( + a, + new_code.clone(), + RELAY_PARENT, + &Configuration::config(), + SetGoAhead::Yes, + ); let mut stmts = IntoIterator::into_iter([0, 1, 2, 3]) .map(|i| { @@ -1499,7 +1682,13 @@ fn poke_unused_validation_code_doesnt_remove_code_with_users() { // Then we add a user to the code, say by upgrading. run_to_block(2, None); - Paras::schedule_code_upgrade(para_id, validation_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + validation_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); Paras::note_new_head(para_id, HeadData::default(), 1); // Finally we poke the code, which should not remove it from the storage. @@ -1564,7 +1753,13 @@ fn add_trusted_validation_code_insta_approval() { // Then some parachain upgrades it's code with the relay-parent 1. run_to_block(2, None); - Paras::schedule_code_upgrade(para_id, validation_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + validation_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); Paras::note_new_head(para_id, HeadData::default(), 1); // Verify that the code upgrade has `expected_at` set to `26`. @@ -1600,7 +1795,13 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() { new_test_ext(genesis_config).execute_with(|| { // First, some parachain upgrades it's code with the relay-parent 1. run_to_block(2, None); - Paras::schedule_code_upgrade(para_id, validation_code.clone(), 1, &Configuration::config()); + Paras::schedule_code_upgrade( + para_id, + validation_code.clone(), + 1, + &Configuration::config(), + SetGoAhead::Yes, + ); Paras::note_new_head(para_id, HeadData::default(), 1); // No upgrade should be scheduled at this point. PVF pre-checking vote should run for diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index e066ad825a3300545a4ecf7840084ecbfc838223..ba74e488cd3b7aac66fb4e62938235b491cce839 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs @@ -25,5 +25,6 @@ //! 1. Bump the version of the stable module (e.g. `v2` becomes `v3`) //! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from //! `vstaging` tagged with the new version number (e.g. all `v3` methods). -pub mod v5; + +pub mod v7; pub mod vstaging; diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs similarity index 79% rename from polkadot/runtime/parachains/src/runtime_api_impl/v5.rs rename to polkadot/runtime/parachains/src/runtime_api_impl/v7.rs index 46a609e0368dd65224fb24376245c4883c97e4c9..35d92f71084fe64f1890f29d1ee840606e944beb 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs @@ -18,12 +18,16 @@ //! functions. use crate::{ - disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, + configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler::{self, CoreOccupied}, session_info, shared, }; use frame_system::pallet_prelude::*; use primitives::{ + async_backing::{ + AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, + InboundHrmpLimitations, OutboundHrmpChannelLimitations, + }, slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, @@ -395,3 +399,100 @@ pub fn submit_unsigned_slashing_report( key_ownership_proof, ) } + +/// Return the min backing votes threshold from the configuration. +pub fn minimum_backing_votes() -> u32 { + >::config().minimum_backing_votes +} + +/// Implementation for `ParaBackingState` function from the runtime API +pub fn backing_state( + para_id: ParaId, +) -> Option>> { + let config = >::config(); + // Async backing is only expected to be enabled with a tracker capacity of 1. + // Subsequent configuration update gets applied on new session, which always + // clears the buffer. + // + // Thus, minimum relay parent is ensured to have asynchronous backing enabled. + let now = >::block_number(); + let min_relay_parent_number = >::allowed_relay_parents() + .hypothetical_earliest_block_number(now, config.async_backing_params.allowed_ancestry_len); + + let required_parent = >::para_head(para_id)?; + let validation_code_hash = >::current_code_hash(para_id)?; + + let upgrade_restriction = >::upgrade_restriction_signal(para_id); + let future_validation_code = + >::future_code_upgrade_at(para_id).and_then(|block_num| { + // Only read the storage if there's a pending upgrade. + Some(block_num).zip(>::future_code_hash(para_id)) + }); + + let (ump_msg_count, ump_total_bytes) = + >::relay_dispatch_queue_size(para_id); + let ump_remaining = config.max_upward_queue_count - ump_msg_count; + let ump_remaining_bytes = config.max_upward_queue_size - ump_total_bytes; + + let dmp_remaining_messages = >::dmq_contents(para_id) + .into_iter() + .map(|msg| msg.sent_at) + .collect(); + + let valid_watermarks = >::valid_watermarks(para_id); + let hrmp_inbound = InboundHrmpLimitations { valid_watermarks }; + let hrmp_channels_out = >::outbound_remaining_capacity(para_id) + .into_iter() + .map(|(para, (messages_remaining, bytes_remaining))| { + (para, OutboundHrmpChannelLimitations { messages_remaining, bytes_remaining }) + }) + .collect(); + + let constraints = Constraints { + min_relay_parent_number, + max_pov_size: config.max_pov_size, + max_code_size: config.max_code_size, + ump_remaining, + ump_remaining_bytes, + max_ump_num_per_candidate: config.max_upward_message_num_per_candidate, + dmp_remaining_messages, + hrmp_inbound, + hrmp_channels_out, + max_hrmp_num_per_candidate: config.hrmp_max_message_num_per_candidate, + required_parent, + validation_code_hash, + upgrade_restriction, + future_validation_code, + }; + + let pending_availability = { + // Note: the API deals with a `Vec` as it is future-proof for cases + // where there may be multiple candidates pending availability at a time. + // But at the moment only one candidate can be pending availability per + // parachain. + crate::inclusion::PendingAvailability::::get(¶_id) + .and_then(|pending| { + let commitments = + crate::inclusion::PendingAvailabilityCommitments::::get(¶_id); + commitments.map(move |c| (pending, c)) + }) + .map(|(pending, commitments)| { + CandidatePendingAvailability { + candidate_hash: pending.candidate_hash(), + descriptor: pending.candidate_descriptor().clone(), + commitments, + relay_parent_number: pending.relay_parent_number(), + max_pov_size: constraints.max_pov_size, // assume always same in session. + } + }) + .into_iter() + .collect() + }; + + Some(BackingState { constraints, pending_availability }) +} + +/// Implementation for `AsyncBackingParams` function from the runtime API +pub fn async_backing_params() -> AsyncBackingParams { + >::config().async_backing_params +} diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index deef19d9071071fa86ec7a79341191a8d6737a70..24a076f3a44310990d61ad0076db39f4deb8f9e5 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -16,110 +16,29 @@ //! Put implementations of functions from staging APIs here. -use crate::{configuration, dmp, hrmp, inclusion, initializer, paras, shared}; -use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{ - vstaging::{ - AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, - InboundHrmpLimitations, OutboundHrmpChannelLimitations, - }, - Id as ParaId, -}; -use sp_std::prelude::*; - -/// Implementation for `StagingParaBackingState` function from the runtime API -pub fn backing_state( - para_id: ParaId, -) -> Option>> { - let config = >::config(); - // Async backing is only expected to be enabled with a tracker capacity of 1. - // Subsequent configuration update gets applied on new session, which always - // clears the buffer. - // - // Thus, minimum relay parent is ensured to have asynchronous backing enabled. - let now = >::block_number(); - let min_relay_parent_number = >::allowed_relay_parents() - .hypothetical_earliest_block_number(now, config.async_backing_params.allowed_ancestry_len); - - let required_parent = >::para_head(para_id)?; - let validation_code_hash = >::current_code_hash(para_id)?; - - let upgrade_restriction = >::upgrade_restriction_signal(para_id); - let future_validation_code = - >::future_code_upgrade_at(para_id).and_then(|block_num| { - // Only read the storage if there's a pending upgrade. - Some(block_num).zip(>::future_code_hash(para_id)) - }); - - let (ump_msg_count, ump_total_bytes) = - >::relay_dispatch_queue_size(para_id); - let ump_remaining = config.max_upward_queue_count - ump_msg_count; - let ump_remaining_bytes = config.max_upward_queue_size - ump_total_bytes; - - let dmp_remaining_messages = >::dmq_contents(para_id) - .into_iter() - .map(|msg| msg.sent_at) - .collect(); - - let valid_watermarks = >::valid_watermarks(para_id); - let hrmp_inbound = InboundHrmpLimitations { valid_watermarks }; - let hrmp_channels_out = >::outbound_remaining_capacity(para_id) - .into_iter() - .map(|(para, (messages_remaining, bytes_remaining))| { - (para, OutboundHrmpChannelLimitations { messages_remaining, bytes_remaining }) - }) - .collect(); - - let constraints = Constraints { - min_relay_parent_number, - max_pov_size: config.max_pov_size, - max_code_size: config.max_code_size, - ump_remaining, - ump_remaining_bytes, - max_ump_num_per_candidate: config.max_upward_message_num_per_candidate, - dmp_remaining_messages, - hrmp_inbound, - hrmp_channels_out, - max_hrmp_num_per_candidate: config.hrmp_max_message_num_per_candidate, - required_parent, - validation_code_hash, - upgrade_restriction, - future_validation_code, - }; - - let pending_availability = { - // Note: the API deals with a `Vec` as it is future-proof for cases - // where there may be multiple candidates pending availability at a time. - // But at the moment only one candidate can be pending availability per - // parachain. - crate::inclusion::PendingAvailability::::get(¶_id) - .and_then(|pending| { - let commitments = - crate::inclusion::PendingAvailabilityCommitments::::get(¶_id); - commitments.map(move |c| (pending, c)) - }) - .map(|(pending, commitments)| { - CandidatePendingAvailability { - candidate_hash: pending.candidate_hash(), - descriptor: pending.candidate_descriptor().clone(), - commitments, - relay_parent_number: pending.relay_parent_number(), - max_pov_size: constraints.max_pov_size, // assume always same in session. - } - }) - .into_iter() - .collect() - }; - - Some(BackingState { constraints, pending_availability }) -} - -/// Implementation for `StagingAsyncBackingParams` function from the runtime API -pub fn async_backing_params() -> AsyncBackingParams { - >::config().async_backing_params -} - -/// Return the min backing votes threshold from the configuration. -pub fn minimum_backing_votes() -> u32 { - >::config().minimum_backing_votes +use crate::shared; +use primitives::ValidatorIndex; +use sp_std::{collections::btree_map::BTreeMap, prelude::Vec}; + +/// Implementation for `DisabledValidators` +// CAVEAT: this should only be called on the node side +// as it might produce incorrect results on session boundaries +pub fn disabled_validators() -> Vec +where + T: pallet_session::Config + shared::Config, +{ + let shuffled_indices = >::active_validator_indices(); + // mapping from raw validator index to `ValidatorIndex` + // this computation is the same within a session, but should be cheap + let reverse_index = shuffled_indices + .iter() + .enumerate() + .map(|(i, v)| (v.0, ValidatorIndex(i as u32))) + .collect::>(); + + // we might have disabled validators who are not parachain validators + >::disabled_validators() + .iter() + .filter_map(|v| reverse_index.get(v).cloned()) + .collect() } diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index accff7016ed1e37e585b8433b5cdfd37378e4fe3..c1ce95b10e3cb6841cde20017c8944df9021c200 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -18,7 +18,8 @@ use super::*; use frame_support::{ - pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, + migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, + traits::OnRuntimeUpgrade, weights::Weight, }; mod v0 { @@ -83,22 +84,26 @@ mod v0 { pub mod v1 { use super::*; use crate::scheduler; - use frame_support::traits::StorageVersion; - pub struct MigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { + #[allow(deprecated)] + pub type MigrateToV1 = VersionedMigration< + 0, + 1, + UncheckedMigrateToV1, + Pallet, + ::DbWeight, + >; + + #[deprecated(note = "Use MigrateToV1 instead")] + pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); + #[allow(deprecated)] + impl OnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { - if StorageVersion::get::>() == 0 { - let weight_consumed = migrate_to_v1::(); + let weight_consumed = migrate_to_v1::(); - log::info!(target: scheduler::LOG_TARGET, "Migrating para scheduler storage to v1"); - StorageVersion::new(1).put::>(); + log::info!(target: scheduler::LOG_TARGET, "Migrating para scheduler storage to v1"); - weight_consumed - } else { - log::warn!(target: scheduler::LOG_TARGET, "Para scheduler v1 migration should be removed."); - T::DbWeight::get().reads(1) - } + weight_consumed } #[cfg(feature = "try-runtime")] @@ -117,10 +122,7 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); - ensure!( - StorageVersion::get::>() >= 1, - "Storage version should be at least `1` after the migration" - ); + ensure!( v0::Scheduled::::get().len() == 0, "Scheduled should be empty after the migration" diff --git a/polkadot/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index 0043851be0f22ef50cabb1b5f9f9fd51e9b5e188..9e1b3d05842fd7b35f87de5c297958f5f3f36bf3 100644 --- a/polkadot/runtime/parachains/src/session_info.rs +++ b/polkadot/runtime/parachains/src/session_info.rs @@ -17,8 +17,9 @@ //! The session info pallet provides information about validator sets //! from prior sessions needed for approvals and disputes. //! -//! See . - +//! See the documentation on [session info][session-info-page] in the implementers' guide. +//! +//! [session-info-page]: https://paritytech.github.io/polkadot-sdk/book/runtime/session_info.html use crate::{ configuration, paras, scheduler, shared, util::{take_active_subset, take_active_subset_and_inactive}, diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml deleted file mode 100644 index a659a4553220cd782d62b1b4db2b58030294077a..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/Cargo.toml +++ /dev/null @@ -1,319 +0,0 @@ -[package] -name = "polkadot-runtime" -build = "build.rs" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.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"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -log = { version = "0.4.17", default-features = false } -rustc-hex = { version = "2.1.0", default-features = false } -serde = { version = "1.0.188", default-features = false } -serde_derive = { version = "1.0.117", optional = true } -static_assertions = "1.1.0" -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 } -beefy-primitives = { package = "sp-consensus-beefy", path = "../../../substrate/primitives/consensus/beefy", default-features = false } -block-builder-api = { package = "sp-block-builder", path = "../../../substrate/primitives/block-builder", default-features = false } -inherents = { package = "sp-inherents", path = "../../../substrate/primitives/inherents", default-features = false } -offchain-primitives = { package = "sp-offchain", path = "../../../substrate/primitives/offchain", default-features = false } -tx-pool-api = { package = "sp-transaction-pool", path = "../../../substrate/primitives/transaction-pool", default-features = false } -sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } -sp-api = { path = "../../../substrate/primitives/api", default-features = false } -sp-std = { path = "../../../substrate/primitives/std", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } -sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } -sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-session = { path = "../../../substrate/primitives/session", default-features = false } -sp-storage = { path = "../../../substrate/primitives/storage", default-features = false } -sp-version = { path = "../../../substrate/primitives/version", default-features = false } -sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", default-features = false } - -pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } -pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } -pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } -pallet-bags-list = { path = "../../../substrate/frame/bags-list", default-features = false } -pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } -pallet-bounties = { path = "../../../substrate/frame/bounties", default-features = false } -pallet-child-bounties = { path = "../../../substrate/frame/child-bounties", 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 } -pallet-collective = { path = "../../../substrate/frame/collective", default-features = false } -pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } -pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false } -pallet-elections-phragmen = { path = "../../../substrate/frame/elections-phragmen", default-features = false } -pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false } -pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } -frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } -pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } -pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } -pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } -pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } -pallet-multisig = { path = "../../../substrate/frame/multisig", default-features = false } -pallet-nomination-pools = { path = "../../../substrate/frame/nomination-pools", default-features = false } -pallet-nomination-pools-runtime-api = { path = "../../../substrate/frame/nomination-pools/runtime-api", default-features = false } -pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } -pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } -pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } -pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } -pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } -pallet-session = { path = "../../../substrate/frame/session", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } -pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } -pallet-staking-reward-curve = { path = "../../../substrate/frame/staking/reward-curve" } -pallet-staking-runtime-api = { path = "../../../substrate/frame/staking/runtime-api", default-features = false } -frame-system = { path = "../../../substrate/frame/system", default-features = false } -frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -polkadot-runtime-constants = { package = "polkadot-runtime-constants", path = "constants", default-features = false } -pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } -pallet-tips = { path = "../../../substrate/frame/tips", default-features = false } -pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } -pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } -pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } -pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } -frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } -pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } - -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } -frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } -frame-system-benchmarking = { path = "../../../substrate/frame/system/benchmarking", default-features = false, optional = true } -pallet-election-provider-support-benchmarking = { path = "../../../substrate/frame/election-provider-support/benchmarking", default-features = false, optional = true } -pallet-offences-benchmarking = { path = "../../../substrate/frame/offences/benchmarking", default-features = false, optional = true } -pallet-session-benchmarking = { path = "../../../substrate/frame/session/benchmarking", default-features = false, optional = true } -pallet-nomination-pools-benchmarking = { path = "../../../substrate/frame/nomination-pools/benchmarking", default-features = false, optional = true } -hex-literal = { version = "0.4.1", optional = true } - -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } -runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } -primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } - -xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } -xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } -xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } - -[dev-dependencies] -hex-literal = "0.4.1" -tiny-keccak = { version = "2.0.2", features = ["keccak"] } -keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } -sp-trie = { path = "../../../substrate/primitives/trie" } -serde_json = "1.0.107" -separator = "0.4.1" -remote-externalities = { package = "frame-remote-externalities" , path = "../../../substrate/utils/frame/remote-externalities" } -tokio = { version = "1.24.2", features = ["macros"] } -sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } - -[build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } - -[features] -default = [ "std" ] -no_std = [] -only-staking = [] -std = [ - "authority-discovery-primitives/std", - "babe-primitives/std", - "beefy-primitives/std", - "bitvec/std", - "block-builder-api/std", - "frame-benchmarking?/std", - "frame-election-provider-support/std", - "frame-executive/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime/std", - "inherents/std", - "log/std", - "offchain-primitives/std", - "pallet-authority-discovery/std", - "pallet-authorship/std", - "pallet-babe/std", - "pallet-bags-list/std", - "pallet-balances/std", - "pallet-bounties/std", - "pallet-child-bounties/std", - "pallet-collective/std", - "pallet-conviction-voting/std", - "pallet-democracy/std", - "pallet-election-provider-multi-phase/std", - "pallet-election-provider-support-benchmarking?/std", - "pallet-elections-phragmen/std", - "pallet-fast-unstake/std", - "pallet-grandpa/std", - "pallet-identity/std", - "pallet-im-online/std", - "pallet-indices/std", - "pallet-membership/std", - "pallet-message-queue/std", - "pallet-multisig/std", - "pallet-nomination-pools-benchmarking?/std", - "pallet-nomination-pools-runtime-api/std", - "pallet-nomination-pools/std", - "pallet-offences-benchmarking?/std", - "pallet-offences/std", - "pallet-preimage/std", - "pallet-proxy/std", - "pallet-referenda/std", - "pallet-scheduler/std", - "pallet-session-benchmarking?/std", - "pallet-session/std", - "pallet-staking-runtime-api/std", - "pallet-staking/std", - "pallet-timestamp/std", - "pallet-tips/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-treasury/std", - "pallet-utility/std", - "pallet-vesting/std", - "pallet-whitelist/std", - "pallet-xcm-benchmarks?/std", - "pallet-xcm/std", - "parity-scale-codec/std", - "polkadot-runtime-constants/std", - "primitives/std", - "runtime-common/std", - "runtime-parachains/std", - "rustc-hex/std", - "scale-info/std", - "serde/std", - "serde_derive", - "sp-api/std", - "sp-arithmetic/std", - "sp-core/std", - "sp-io/std", - "sp-mmr-primitives/std", - "sp-npos-elections/std", - "sp-runtime/std", - "sp-session/std", - "sp-staking/std", - "sp-std/std", - "sp-storage/std", - "sp-tracing/std", - "sp-version/std", - "tx-pool-api/std", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "hex-literal", - "pallet-babe/runtime-benchmarks", - "pallet-bags-list/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-bounties/runtime-benchmarks", - "pallet-child-bounties/runtime-benchmarks", - "pallet-collective/runtime-benchmarks", - "pallet-conviction-voting/runtime-benchmarks", - "pallet-democracy/runtime-benchmarks", - "pallet-election-provider-multi-phase/runtime-benchmarks", - "pallet-election-provider-support-benchmarking/runtime-benchmarks", - "pallet-elections-phragmen/runtime-benchmarks", - "pallet-fast-unstake/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", - "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", - "pallet-indices/runtime-benchmarks", - "pallet-membership/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "pallet-multisig/runtime-benchmarks", - "pallet-nomination-pools-benchmarking/runtime-benchmarks", - "pallet-nomination-pools/runtime-benchmarks", - "pallet-offences-benchmarking/runtime-benchmarks", - "pallet-offences/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", - "pallet-referenda/runtime-benchmarks", - "pallet-scheduler/runtime-benchmarks", - "pallet-session-benchmarking/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-tips/runtime-benchmarks", - "pallet-treasury/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", - "pallet-vesting/runtime-benchmarks", - "pallet-whitelist/runtime-benchmarks", - "pallet-xcm-benchmarks/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "primitives/runtime-benchmarks", - "runtime-common/runtime-benchmarks", - "runtime-parachains/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "sp-staking/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", -] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime", - "frame-try-runtime/try-runtime", - "pallet-authority-discovery/try-runtime", - "pallet-authorship/try-runtime", - "pallet-babe/try-runtime", - "pallet-bags-list/try-runtime", - "pallet-balances/try-runtime", - "pallet-bounties/try-runtime", - "pallet-child-bounties/try-runtime", - "pallet-collective/try-runtime", - "pallet-conviction-voting/try-runtime", - "pallet-democracy/try-runtime", - "pallet-election-provider-multi-phase/try-runtime", - "pallet-elections-phragmen/try-runtime", - "pallet-fast-unstake/try-runtime", - "pallet-grandpa/try-runtime", - "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", - "pallet-indices/try-runtime", - "pallet-membership/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-multisig/try-runtime", - "pallet-nomination-pools/try-runtime", - "pallet-offences/try-runtime", - "pallet-preimage/try-runtime", - "pallet-proxy/try-runtime", - "pallet-referenda/try-runtime", - "pallet-scheduler/try-runtime", - "pallet-session/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-tips/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-treasury/try-runtime", - "pallet-utility/try-runtime", - "pallet-vesting/try-runtime", - "pallet-whitelist/try-runtime", - "pallet-xcm/try-runtime", - "runtime-common/try-runtime", - "runtime-parachains/try-runtime", - "sp-runtime/try-runtime", -] - -# A feature that should be enabled when the runtime should be build for on-chain -# deployment. This will disable stuff that shouldn't be part of the on-chain wasm -# to make it smaller like logging for example. -on-chain-release-build = [ "sp-api/disable-logging" ] - -# Set timing constants (e.g. session period) to faster versions to speed up testing. -fast-runtime = [] - -runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] diff --git a/polkadot/runtime/polkadot/build.rs b/polkadot/runtime/polkadot/build.rs deleted file mode 100644 index 428c971bc132a5c7e856e6485246c4fd2ff57822..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/build.rs +++ /dev/null @@ -1,25 +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. - -// 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 . - -use substrate_wasm_builder::WasmBuilder; - -fn main() { - WasmBuilder::new() - .with_current_project() - .import_memory() - .export_heap_base() - .build() -} diff --git a/polkadot/runtime/polkadot/constants/Cargo.toml b/polkadot/runtime/polkadot/constants/Cargo.toml deleted file mode 100644 index 554b72f23179f41cc9acb5f8ce755b49ffa72f8d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "polkadot-runtime-constants" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license.workspace = true - -[dependencies] -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/polkadot/constants/src/lib.rs b/polkadot/runtime/polkadot/constants/src/lib.rs deleted file mode 100644 index 304d86d1dd7c572531006d76c9aab844daa19a62..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/lib.rs +++ /dev/null @@ -1,150 +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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod weights; - -pub use self::currency::DOLLARS; - -/// Money matters. -pub mod currency { - use primitives::Balance; - - /// The existential deposit. - pub const EXISTENTIAL_DEPOSIT: Balance = 100 * CENTS; - - pub const UNITS: Balance = 10_000_000_000; - pub const DOLLARS: Balance = UNITS; // 10_000_000_000 - pub const GRAND: Balance = DOLLARS * 1_000; // 10_000_000_000_000 - pub const CENTS: Balance = DOLLARS / 100; // 100_000_000 - pub const MILLICENTS: Balance = CENTS / 1_000; // 100_000 - - pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 20 * DOLLARS + (bytes as Balance) * 100 * MILLICENTS - } -} - -/// Time and blocks. -pub mod time { - use primitives::{BlockNumber, Moment}; - use runtime_common::prod_or_fast; - pub const MILLISECS_PER_BLOCK: Moment = 6000; - pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; - pub const EPOCH_DURATION_IN_SLOTS: BlockNumber = prod_or_fast!(4 * HOURS, 1 * MINUTES); - - // These time units are defined in number of blocks. - pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); - pub const HOURS: BlockNumber = MINUTES * 60; - pub const DAYS: BlockNumber = HOURS * 24; - pub const WEEKS: BlockNumber = DAYS * 7; - - // 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); -} - -/// Fee-related. -pub mod fee { - use crate::weights::ExtrinsicBaseWeight; - use frame_support::weights::{ - WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, - }; - use primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// The block saturation level. Fees will be updates based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); - - /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the - /// node's balance type. - /// - /// This should typically create a mapping between the following ranges: - /// - [0, `MAXIMUM_BLOCK_WEIGHT`] - /// - [Balance::min, Balance::max] - /// - /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: - /// - Setting it to `0` will essentially disable the weight fee. - /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. - pub struct WeightToFee; - impl WeightToFeePolynomial for WeightToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - let p = super::currency::CENTS; - let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// XCM protocol related constants. -pub mod xcm { - /// Pluralistic bodies existing within the consensus. - pub mod body { - // Preallocated for the Root body. - #[allow(dead_code)] - const ROOT_INDEX: u32 = 0; - // The bodies corresponding to the Polkadot OpenGov Origins. - pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; - } -} - -/// System Parachains. -pub mod system_parachain { - /// Statemint parachain ID. - pub const STATEMINT_ID: u32 = 1000; - /// Collectives parachain ID. - pub const COLLECTIVES_ID: u32 = 1001; -} - -#[cfg(test)] -mod tests { - use super::{ - currency::{CENTS, DOLLARS, MILLICENTS}, - fee::WeightToFee, - }; - use crate::weights::ExtrinsicBaseWeight; - use frame_support::weights::WeightToFee as WeightToFeeT; - use runtime_common::MAXIMUM_BLOCK_WEIGHT; - - #[test] - // Test that the fee for `MAXIMUM_BLOCK_WEIGHT` of weight has sane bounds. - fn full_block_fee_is_correct() { - // A full block should cost between 10 and 100 DOLLARS. - let full_block = WeightToFee::weight_to_fee(&MAXIMUM_BLOCK_WEIGHT); - assert!(full_block >= 10 * DOLLARS); - assert!(full_block <= 100 * DOLLARS); - } - - #[test] - // This function tests that the fee for `ExtrinsicBaseWeight` of weight is correct - fn extrinsic_base_fee_is_correct() { - // `ExtrinsicBaseWeight` should cost 1/10 of a CENT - println!("Base: {}", ExtrinsicBaseWeight::get()); - let x = WeightToFee::weight_to_fee(&ExtrinsicBaseWeight::get()); - let y = CENTS / 10; - assert!(x.max(y) - x.min(y) < MILLICENTS); - } -} diff --git a/polkadot/runtime/polkadot/constants/src/weights/block_weights.rs b/polkadot/runtime/polkadot/constants/src/weights/block_weights.rs deleted file mode 100644 index 9608fd534069de346bf98e95b46e6f1c5170d025..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/weights/block_weights.rs +++ /dev/null @@ -1,81 +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 . - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! -//! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` -//! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/polkadot/constants/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark -// overhead -// --chain=polkadot-dev -// --execution=wasm -// --wasm-execution=compiled -// --weight-path=runtime/polkadot/constants/src/weights/ -// --warmup=10 -// --repeat=100 -// --header=./file_header.txt - -use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; - -parameter_types! { - /// Time to execute an empty block. - /// Calculated by multiplying the *Average* with `1.0` and adding `0`. - /// - /// Stats nanoseconds: - /// Min, Max: 13_546_462, 14_258_156 - /// Average: 13_806_190 - /// Median: 13_798_575 - /// Std-Dev: 141568.11 - /// - /// Percentiles nanoseconds: - /// 99th: 14_144_016 - /// 95th: 14_039_432 - /// 75th: 13_904_965 - pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(13_806_190), 0); -} - -#[cfg(test)] -mod test_weights { - use sp_weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::BlockExecutionWeight::get(); - - // At least 100 µs. - assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 100 µs." - ); - // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); - } -} diff --git a/polkadot/runtime/polkadot/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/polkadot/constants/src/weights/extrinsic_weights.rs deleted file mode 100644 index fac87924821f5d98b9c552f016935b45617adfb8..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,81 +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 . - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18 (Y/M/D) -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! -//! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` -//! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/polkadot/constants/src/weights/` -//! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark -// overhead -// --chain=polkadot-dev -// --execution=wasm -// --wasm-execution=compiled -// --weight-path=runtime/polkadot/constants/src/weights/ -// --warmup=10 -// --repeat=100 -// --header=./file_header.txt - -use sp_core::parameter_types; -use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; - -parameter_types! { - /// Time to execute a NO-OP extrinsic, for example `System::remark`. - /// Calculated by multiplying the *Average* with `1.0` and adding `0`. - /// - /// Stats nanoseconds: - /// Min, Max: 125_467, 127_402 - /// Average: 126_045 - /// Median: 126_039 - /// Std-Dev: 310.96 - /// - /// Percentiles nanoseconds: - /// 99th: 126_699 - /// 95th: 126_620 - /// 75th: 126_207 - pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(126_045), 0); -} - -#[cfg(test)] -mod test_weights { - use sp_weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::ExtrinsicBaseWeight::get(); - - // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); - // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); - } -} diff --git a/polkadot/runtime/polkadot/constants/src/weights/mod.rs b/polkadot/runtime/polkadot/constants/src/weights/mod.rs deleted file mode 100644 index 23812ce7ed0528c394f84042fb9842eb617a834b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/weights/mod.rs +++ /dev/null @@ -1,28 +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. - -//! Expose the auto generated weight files. - -pub mod block_weights; -pub mod extrinsic_weights; -pub mod paritydb_weights; -pub mod rocksdb_weights; - -pub use block_weights::BlockExecutionWeight; -pub use extrinsic_weights::ExtrinsicBaseWeight; -pub use paritydb_weights::constants::ParityDbWeight; -pub use rocksdb_weights::constants::RocksDbWeight; diff --git a/polkadot/runtime/polkadot/constants/src/weights/paritydb_weights.rs b/polkadot/runtime/polkadot/constants/src/weights/paritydb_weights.rs deleted file mode 100644 index ae7bedc394f8cd485de9ee72064f351d787450e3..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,109 +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. - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-30 (Y/M/D) -//! -//! DATABASE: `ParityDb`, RUNTIME: `Polkadot` -//! BLOCK-NUM: `BlockId::Number(9653477)` -//! SKIP-WRITE: `false`, SKIP-READ: `false`, WARMUPS: `1` -//! STATE-VERSION: `V0`, STATE-CACHE-SIZE: `0` -//! WEIGHT-PATH: `runtime/polkadot/constants/src/weights/` -//! METRIC: `Average`, WEIGHT-MUL: `1.1`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark-storage -// --db=paritydb -// --state-version=0 -// --mul=1.1 -// --weight-path=runtime/polkadot/constants/src/weights/ - -/// Storage DB weights for the `Polkadot` runtime and `ParityDb`. -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights - /// are available for brave runtime engineers who may want to try this out as default. - pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - /// Time to read one storage item. - /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. - /// - /// Stats [NS]: - /// Min, Max: 4_611, 13_478_005 - /// Average: 10_750 - /// Median: 10_655 - /// Std-Dev: 12214.49 - /// - /// Percentiles [NS]: - /// 99th: 14_451 - /// 95th: 12_588 - /// 75th: 11_200 - read: 11_826 * constants::WEIGHT_REF_TIME_PER_NANOS, - - /// Time to write one storage item. - /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. - /// - /// Stats [NS]: - /// Min, Max: 8_023, 47_367_740 - /// Average: 34_592 - /// Median: 32_703 - /// Std-Dev: 49417.24 - /// - /// Percentiles [NS]: - /// 99th: 69_379 - /// 95th: 47_168 - /// 75th: 35_252 - write: 38_052 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use super::constants::ParityDbWeight as W; - use frame_support::weights::constants; - - /// Checks that all weights exist and have sane values. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn bound() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/polkadot/runtime/polkadot/constants/src/weights/rocksdb_weights.rs b/polkadot/runtime/polkadot/constants/src/weights/rocksdb_weights.rs deleted file mode 100644 index 029f892b01dc247c7906f90441b63e6da5903297..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/constants/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,108 +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. - -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-03-29 (Y/M/D) -//! -//! DATABASE: `RocksDb`, RUNTIME: `Polkadot` -//! BLOCK-NUM: `BlockId::Number(9643856)` -//! SKIP-WRITE: `false`, SKIP-READ: `false`, WARMUPS: `1` -//! STATE-VERSION: `V0`, STATE-CACHE-SIZE: `0` -//! WEIGHT-PATH: `runtime/polkadot/constants/src/weights/` -//! METRIC: `Average`, WEIGHT-MUL: `1.1`, WEIGHT-ADD: `0` - -// Executed Command: -// ./target/production/polkadot -// benchmark-storage -// --state-version=0 -// --mul=1.1 -// --weight-path=runtime/polkadot/constants/src/weights/ - -/// Storage DB weights for the `Polkadot` runtime and `RocksDb`. -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout - /// the runtime. - pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - /// Time to read one storage item. - /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. - /// - /// Stats [NS]: - /// Min, Max: 5_015, 1_441_022 - /// Average: 18_635 - /// Median: 17_795 - /// Std-Dev: 4829.75 - /// - /// Percentiles [NS]: - /// 99th: 32_074 - /// 95th: 26_658 - /// 75th: 19_363 - read: 20_499 * constants::WEIGHT_REF_TIME_PER_NANOS, - - /// Time to write one storage item. - /// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. - /// - /// Stats [NS]: - /// Min, Max: 16_368, 34_500_937 - /// Average: 75_882 - /// Median: 74_236 - /// Std-Dev: 64706.41 - /// - /// Percentiles [NS]: - /// 99th: 111_151 - /// 95th: 92_666 - /// 75th: 80_297 - write: 83_471 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use super::constants::RocksDbWeight as W; - use frame_support::weights::constants; - - /// Checks that all weights exist and have sane values. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn bound() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/polkadot/runtime/polkadot/src/bag_thresholds.rs b/polkadot/runtime/polkadot/src/bag_thresholds.rs deleted file mode 100644 index 56c764f7a6985424f06e9bc289126b2b68be3aa2..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/bag_thresholds.rs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated bag thresholds. -//! -//! Generated on 2021-10-14T08:36:33.156699497+00:00 -//! for the polkadot runtime. - -/// Existential weight for this runtime. -#[cfg(any(test, feature = "std"))] -#[allow(unused)] -pub const EXISTENTIAL_WEIGHT: u64 = 10_000_000_000; - -/// Constant ratio between bags for this runtime. -#[cfg(any(test, feature = "std"))] -#[allow(unused)] -pub const CONSTANT_RATIO: f64 = 1.1131723507077667; - -/// Upper thresholds delimiting the bag list. -pub const THRESHOLDS: [u64; 200] = [ - 10_000_000_000, - 11_131_723_507, - 12_391_526_824, - 13_793_905_044, - 15_354_993_703, - 17_092_754_435, - 19_027_181_634, - 21_180_532_507, - 23_577_583_160, - 26_245_913_670, - 29_216_225_417, - 32_522_694_326, - 36_203_364_094, - 40_300_583_912, - 44_861_495_728, - 49_938_576_656, - 55_590_242_767, - 61_881_521_217, - 68_884_798_439, - 76_680_653_006, - 85_358_782_760, - 95_019_036_859, - 105_772_564_622, - 117_743_094_401, - 131_068_357_174, - 145_901_671_259, - 162_413_706_368, - 180_794_447_305, - 201_255_379_901, - 224_031_924_337, - 249_386_143_848, - 277_609_759_981, - 309_027_509_097, - 344_000_878_735, - 382_932_266_827, - 426_269_611_626, - 474_511_545_609, - 528_213_132_664, - 587_992_254_562, - 654_536_720_209, - 728_612_179_460, - 811_070_932_564, - 902_861_736_593, - 1_005_040_721_687, - 1_118_783_542_717, - 1_245_398_906_179, - 1_386_343_627_960, - 1_543_239_395_225, - 1_717_891_425_287, - 1_912_309_236_147, - 2_128_729_767_682, - 2_369_643_119_512, - 2_637_821_201_686, - 2_936_349_627_828, - 3_268_663_217_709, - 3_638_585_517_729, - 4_050_372_794_022, - 4_508_763_004_364, - 5_019_030_312_352, - 5_587_045_771_074, - 6_219_344_874_498, - 6_923_202_753_807, - 7_706_717_883_882, - 8_578_905_263_043, - 9_549_800_138_161, - 10_630_573_468_586, - 11_833_660_457_397, - 13_172_903_628_838, - 14_663_712_098_160, - 16_323_238_866_411, - 18_170_578_180_087, - 20_226_985_226_447, - 22_516_120_692_255, - 25_064_322_999_817, - 27_900_911_352_605, - 31_058_523_077_268, - 34_573_489_143_434, - 38_486_252_181_966, - 42_841_831_811_331, - 47_690_342_626_046, - 53_087_570_807_094, - 59_095_615_988_698, - 65_783_605_766_662, - 73_228_491_069_308, - 81_515_931_542_404, - 90_741_281_135_191, - 101_010_685_227_495, - 112_442_301_921_293, - 125_167_661_548_718, - 139_333_180_038_781, - 155_101_843_555_358, - 172_655_083_789_626, - 192_194_865_483_744, - 213_946_010_204_502, - 238_158_783_103_893, - 265_111_772_429_462, - 295_115_094_915_607, - 328_513_963_936_552, - 365_692_661_475_578, - 407_078_959_611_349, - 453_149_042_394_237, - 504_432_984_742_966, - 561_520_851_400_862, - 625_069_486_125_324, - 695_810_069_225_823, - 774_556_530_406_243, - 862_214_913_708_369, - 959_793_802_308_039, - 1_068_415_923_109_985, - 1_189_331_064_661_951, - 1_323_930_457_019_515, - 1_473_762_779_014_021, - 1_640_551_977_100_649, - 1_826_217_100_807_404, - 2_032_894_383_008_501, - 2_262_961_819_074_188, - 2_519_066_527_700_738, - 2_804_155_208_229_882, - 3_121_508_044_894_685, - 3_474_776_448_088_622, - 3_868_025_066_902_796, - 4_305_778_556_320_752, - 4_793_073_637_166_665, - 5_335_517_047_800_242, - 5_939_350_054_341_159, - 6_611_520_261_667_250, - 7_359_761_551_432_161, - 8_192_683_066_856_378, - 9_119_868_268_136_230, - 10_151_985_198_186_376, - 11_300_909_227_415_580, - 12_579_859_689_817_292, - 14_003_551_982_487_792, - 15_588_366_878_604_342, - 17_352_539_001_951_086, - 19_316_366_631_550_092, - 21_502_445_250_375_680, - 23_935_927_525_325_748, - 26_644_812_709_737_600, - 29_660_268_798_266_784, - 33_016_991_140_790_860, - 36_753_601_641_491_664, - 40_913_093_136_236_104, - 45_543_324_061_189_736, - 50_697_569_104_240_168, - 56_435_132_174_936_472, - 62_822_028_745_677_552, - 69_931_745_415_056_768, - 77_846_085_432_775_824, - 86_656_109_914_600_688, - 96_463_185_576_826_656, - 107_380_151_045_315_664, - 119_532_615_158_469_088, - 133_060_402_202_199_856, - 148_119_160_705_543_712, - 164_882_154_307_451_552, - 183_542_255_300_186_560, - 204_314_163_786_713_728, - 227_436_877_985_347_776, - 253_176_444_104_585_088, - 281_829_017_427_734_464, - 313_724_269_827_691_328, - 349_229_182_918_168_832, - 388_752_270_484_770_624, - 432_748_278_778_513_664, - 481_723_418_752_617_984, - 536_241_190_443_833_600, - 596_928_866_512_693_376, - 664_484_709_541_257_600, - 739_686_006_129_409_280, - 823_398_010_228_713_984, - 916_583_898_614_395_264, - 1_020_315_853_041_475_584, - 1_135_787_396_594_579_584, - 1_264_327_126_171_442_688, - 1_407_413_999_103_859_968, - 1_566_694_349_801_462_272, - 1_744_000_832_209_069_824, - 1_941_373_506_026_471_680, - 2_161_083_309_305_266_176, - 2_405_658_187_494_662_656, - 2_677_912_179_572_818_944, - 2_980_977_795_924_034_048, - 3_318_342_060_496_414_208, - 3_693_886_631_935_247_360, - 4_111_932_465_319_354_368, - 4_577_289_528_371_127_808, - 5_095_312_144_166_932_480, - 5_671_960_597_112_134_656, - 6_313_869_711_009_142_784, - 7_028_425_188_266_614_784, - 7_823_848_588_596_424_704, - 8_709_291_924_949_524_480, - 9_694_942_965_096_232_960, - 10_792_142_450_433_898_496, - 12_013_514_580_722_579_456, - 13_373_112_266_084_982_784, - 14_886_578_817_516_689_408, - 16_571_327_936_291_497_984, - 18_446_744_073_709_551_615, -]; diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs deleted file mode 100644 index da27771af4007601f53b34e18bdf0a193f67abd4..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/lib.rs +++ /dev/null @@ -1,2609 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! The Polkadot runtime. This can be compiled with `#[no_std]`, ready for Wasm. - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "512"] - -use pallet_transaction_payment::CurrencyAdapter; -use runtime_common::{ - auctions, claims, crowdloan, impl_runtime_weights, impls::DealWithFees, paras_registrar, - prod_or_fast, slots, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, -}; - -use runtime_parachains::{ - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, - dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, - inclusion::{AggregateMessageOrigin, UmpQueueId}, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, - runtime_api_impl::v5 as parachains_runtime_api_impl, - scheduler as parachains_scheduler, session_info as parachains_session_info, - shared as parachains_shared, -}; - -use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; -use frame_election_provider_support::{ - bounds::ElectionBoundsBuilder, generate_solution_type, onchain, SequentialPhragmen, -}; -use frame_support::{ - construct_runtime, parameter_types, - traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, - WithdrawReasons, - }, - weights::{ConstantMultiplier, WeightMeter}, - PalletId, -}; -use frame_system::EnsureRoot; -use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use pallet_session::historical as session_historical; -use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use primitives::{ - slashing, AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionInfo, Signature, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, LOWEST_PUBLIC_ID, - PARACHAIN_KEY_TYPE_ID, -}; -use sp_core::OpaqueMetadata; -use sp_mmr_primitives as mmr; -use sp_runtime::{ - create_runtime_str, - curve::PiecewiseLinear, - generic, impl_opaque_keys, - traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, - OpaqueKeys, SaturatedConversion, Verify, - }, - transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, -}; -use sp_staking::SessionIndex; -use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; -#[cfg(any(feature = "std", test))] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; -use xcm::latest::Junction; - -pub use frame_system::Call as SystemCall; -pub use pallet_balances::Call as BalancesCall; -pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; -#[cfg(feature = "std")] -pub use pallet_staking::StakerStatus; -use pallet_staking::UseValidatorsMap; -pub use pallet_timestamp::Call as TimestampCall; -use sp_runtime::traits::Get; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; - -/// Constant values used within the runtime. -use polkadot_runtime_constants::{currency::*, fee::*, time::*}; - -// Weights used in the runtime. -mod weights; - -mod bag_thresholds; - -// Governance configurations. -pub mod governance; -use governance::{ - pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, StakingAdmin, - Treasurer, TreasurySpender, -}; - -pub mod xcm_config; - -impl_runtime_weights!(polkadot_runtime_constants); - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -// Polkadot version identifier; -/// Runtime version (Polkadot). -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("polkadot"), - impl_name: create_runtime_str!("parity-polkadot"), - authoring_version: 0, - spec_version: 9430, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 24, - state_version: 0, -}; - -/// The BABE epoch configuration at genesis. -pub const BABE_GENESIS_EPOCH_CONFIG: babe_primitives::BabeEpochConfiguration = - babe_primitives::BabeEpochConfiguration { - c: PRIMARY_PROBABILITY, - allowed_slots: babe_primitives::AllowedSlots::PrimaryAndSecondaryVRFSlots, - }; - -/// Native version. -#[cfg(any(feature = "std", test))] -pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } -} - -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - pub const SS58Prefix: u8 = 0; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = BlockLength; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = Nonce; - type Hash = Hash; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = AccountIdLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = RocksDbWeight; - type Version = Version; - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = weights::frame_system::WeightInfo; - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * - BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; - pub const NoPreimagePostponement: Option = Some(10); -} - -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; - -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { - if left == right { - return Some(Ordering::Equal) - } - - match (left, right) { - // Root is greater than anything. - (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), - // For every other origin we don't care, as they are not used for `ScheduleOrigin`. - _ => None, - } - } -} - -impl pallet_scheduler::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of - // OpenGov to schedule periodic auctions. - // Also allow Treasurer to schedule recurring payments. - type ScheduleOrigin = EitherOf, AuctionAdmin>, Treasurer>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = weights::pallet_scheduler::WeightInfo; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type Preimages = Preimage; -} - -parameter_types! { - pub const PreimageBaseDeposit: Balance = deposit(2, 64); - pub const PreimageByteDeposit: Balance = deposit(0, 1); - pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); -} - -impl pallet_preimage::Config for Runtime { - type WeightInfo = weights::pallet_preimage::WeightInfo; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ManagerOrigin = EnsureRoot; - type Consideration = HoldConsideration< - AccountId, - Balances, - PreimageHoldReason, - LinearStoragePrice, - >; -} - -parameter_types! { - pub EpochDuration: u64 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS as u64, - 2 * MINUTES as u64, - "DOT_EPOCH_DURATION" - ); - pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; - pub ReportLongevity: u64 = - BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); -} - -impl pallet_babe::Config for Runtime { - type EpochDuration = EpochDuration; - type ExpectedBlockTime = ExpectedBlockTime; - - // session module is the trigger - type EpochChangeTrigger = pallet_babe::ExternalTrigger; - - type DisabledValidators = Session; - - type WeightInfo = (); - - type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; - - type KeyOwnerProof = - >::Proof; - - type EquivocationReportSystem = - pallet_babe::EquivocationReportSystem; -} - -parameter_types! { - pub const IndexDeposit: Balance = 10 * DOLLARS; -} - -impl pallet_indices::Config for Runtime { - type AccountIndex = AccountIndex; - type Currency = Balances; - type Deposit = IndexDeposit; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_indices::WeightInfo; -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = weights::pallet_balances::WeightInfo; - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - pub const TransactionByteFee: Balance = 10 * MILLICENTS; - /// This value increases the priority of `Operational` transactions by adding - /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`. - pub const OperationalFeeMultiplier: u8 = 5; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter>; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; -} - -parameter_types! { - pub const MinimumPeriod: u64 = SLOT_DURATION / 2; -} -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = Babe; - type MinimumPeriod = MinimumPeriod; - type WeightInfo = weights::pallet_timestamp::WeightInfo; -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (Staking, ImOnline); -} - -impl_opaque_keys! { - pub struct SessionKeys { - pub grandpa: Grandpa, - pub babe: Babe, - pub im_online: ImOnline, - pub para_validator: Initializer, - pub para_assignment: ParaSessionInfo, - pub authority_discovery: AuthorityDiscovery, - } -} - -impl pallet_session::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = AccountId; - type ValidatorIdOf = pallet_staking::StashOf; - type ShouldEndSession = Babe; - type NextSessionRotation = Babe; - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - type WeightInfo = weights::pallet_session::WeightInfo; -} - -impl pallet_session::historical::Config for Runtime { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -parameter_types! { - // phase durations. 1/4 of the last session for each. - // in testing: 1min or half of the session for each - pub SignedPhase: u32 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS / 4, - (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2), - "DOT_SIGNED_PHASE" - ); - pub UnsignedPhase: u32 = prod_or_fast!( - EPOCH_DURATION_IN_SLOTS / 4, - (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2), - "DOT_UNSIGNED_PHASE" - ); - - // signed config - pub const SignedMaxSubmissions: u32 = 16; - pub const SignedMaxRefunds: u32 = 16 / 4; - pub const SignedFixedDeposit: Balance = deposit(2, 0); - pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); - // 40 DOTs fixed deposit.. - pub const SignedDepositBase: Balance = deposit(2, 0); - // 0.01 DOT per KB of solution data. - pub const SignedDepositByte: Balance = deposit(0, 10) / 1024; - // Each good submission will get 1 DOT as reward - pub SignedRewardBase: Balance = 1 * UNITS; - pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(5u32, 10_000); - - // 4 hour session, 1 hour unsigned phase, 32 offchain executions. - pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32; - - pub const MaxElectingVoters: u32 = 22_500; - /// We take the top 22500 nominators as electing voters and all of the validators as electable - /// targets. Whilst this is the case, we cannot and shall not increase the size of the - /// validator intentions. - pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = - ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); - /// Setup election pallet to support maximum winners upto 1200. This will mean Staking Pallet - /// cannot have active validators higher than this count. - pub const MaxActiveValidators: u32 = 1200; -} - -generate_solution_type!( - #[compact] - pub struct NposCompactSolution16::< - VoterIndex = u32, - TargetIndex = u16, - Accuracy = sp_runtime::PerU16, - MaxVoters = MaxElectingVoters, - >(16) -); - -pub struct OnChainSeqPhragmen; -impl onchain::Config for OnChainSeqPhragmen { - type System = Runtime; - type Solver = SequentialPhragmen; - type DataProvider = Staking; - type WeightInfo = weights::frame_election_provider_support::WeightInfo; - type MaxWinners = MaxActiveValidators; - type Bounds = ElectionBounds; -} - -impl pallet_election_provider_multi_phase::MinerConfig for Runtime { - type AccountId = AccountId; - type MaxLength = OffchainSolutionLengthLimit; - type MaxWeight = OffchainSolutionWeightLimit; - type Solution = NposCompactSolution16; - type MaxVotesPerVoter = < - ::DataProvider - as - frame_election_provider_support::ElectionDataProvider - >::MaxVotesPerVoter; - type MaxWinners = MaxActiveValidators; - - // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their - // weight estimate function is wired to this call's weight. - fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { - < - ::WeightInfo - as - pallet_election_provider_multi_phase::WeightInfo - >::submit_unsigned(v, t, a, d) - } -} - -impl pallet_election_provider_multi_phase::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EstimateCallFee = TransactionPayment; - type SignedPhase = SignedPhase; - type UnsignedPhase = UnsignedPhase; - type SignedMaxSubmissions = SignedMaxSubmissions; - type SignedMaxRefunds = SignedMaxRefunds; - type SignedRewardBase = SignedRewardBase; - type SignedDepositBase = - GeometricDepositBase; - type SignedDepositByte = SignedDepositByte; - type SignedDepositWeight = (); - type SignedMaxWeight = - ::MaxWeight; - type MinerConfig = Self; - type SlashHandler = (); // burn slashes - type RewardHandler = (); // nothing to do upon rewards - type BetterUnsignedThreshold = BetterUnsignedThreshold; - type BetterSignedThreshold = (); - type OffchainRepeat = OffchainRepeat; - type MinerTxPriority = NposSolutionPriority; - type DataProvider = Staking; - #[cfg(any(feature = "fast-runtime", feature = "runtime-benchmarks"))] - type Fallback = onchain::OnChainExecution; - #[cfg(not(any(feature = "fast-runtime", feature = "runtime-benchmarks")))] - type Fallback = frame_election_provider_support::NoElection<( - AccountId, - BlockNumber, - Staking, - MaxActiveValidators, - )>; - type GovernanceFallback = onchain::OnChainExecution; - type Solver = SequentialPhragmen< - AccountId, - pallet_election_provider_multi_phase::SolutionAccuracyOf, - (), - >; - type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; - type ForceOrigin = EitherOf, StakingAdmin>; - type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxWinners = MaxActiveValidators; - type ElectionBounds = ElectionBounds; -} - -parameter_types! { - pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS; -} - -type VoterBagsListInstance = pallet_bags_list::Instance1; -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ScoreProvider = Staking; - type WeightInfo = weights::pallet_bags_list::WeightInfo; - type BagThresholds = BagThresholds; - type Score = sp_npos_elections::VoteWeight; -} - -// TODO #6469: This shouldn't be static, but a lazily cached value, not built unless needed, and -// re-built in case input parameters have changed. The `ideal_stake` should be determined by the -// amount of parachain slots being bid on: this should be around `(75 - 25.min(slots / 4))%`. -pallet_staking_reward_curve::build! { - const REWARD_CURVE: PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - // 3:2:1 staked : parachains : float. - // while there's no parachains, then this is 75% staked : 25% float. - ideal_stake: 0_750_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} - -parameter_types! { - // Six sessions in an era (24 hours). - pub const SessionsPerEra: SessionIndex = prod_or_fast!(6, 1); - - // 28 eras for unbonding (28 days). - pub BondingDuration: sp_staking::EraIndex = prod_or_fast!( - 28, - 28, - "DOT_BONDING_DURATION" - ); - pub SlashDeferDuration: sp_staking::EraIndex = prod_or_fast!( - 27, - 27, - "DOT_SLASH_DEFER_DURATION" - ); - pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 512; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); - // 16 - pub const MaxNominations: u32 = ::LIMIT as u32; -} - -pub struct EraPayout; -impl pallet_staking::EraPayout for EraPayout { - fn era_payout( - total_staked: Balance, - total_issuance: Balance, - era_duration_millis: u64, - ) -> (Balance, Balance) { - // all para-ids that are not active. - let auctioned_slots = Paras::parachains() - .into_iter() - // all active para-ids that do not belong to a system chain is the number - // of parachains that we should take into account for inflation. - .filter(|i| *i >= LOWEST_PUBLIC_ID) - .count() as u64; - - const MAX_ANNUAL_INFLATION: Perquintill = Perquintill::from_percent(10); - const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; - - runtime_common::impls::era_payout( - total_staked, - total_issuance, - MAX_ANNUAL_INFLATION, - Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR), - auctioned_slots, - ) - } -} - -impl pallet_staking::Config for Runtime { - type Currency = Balances; - type CurrencyBalance = Balance; - type UnixTime = Timestamp; - type CurrencyToVote = CurrencyToVote; - type RewardRemainder = Treasury; - type RuntimeEvent = RuntimeEvent; - type Slash = Treasury; - type Reward = (); - type SessionsPerEra = SessionsPerEra; - type BondingDuration = BondingDuration; - type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = EitherOf, StakingAdmin>; - type SessionInterface = Self; - type EraPayout = EraPayout; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; - type NextNewSession = Session; - type ElectionProvider = ElectionProviderMultiPhase; - type GenesisElectionProvider = onchain::OnChainExecution; - type VoterList = VoterList; - type TargetList = UseValidatorsMap; - type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; - type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; - type HistoryDepth = frame_support::traits::ConstU32<84>; - type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; - type EventListeners = NominationPools; - type WeightInfo = weights::pallet_staking::WeightInfo; -} - -impl pallet_fast_unstake::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BatchSize = frame_support::traits::ConstU32<16>; - type Deposit = frame_support::traits::ConstU128<{ UNITS }>; - type ControlOrigin = EnsureRoot; - type Staking = Staking; - type MaxErasToCheckPerBlock = ConstU32<1>; - #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; - type WeightInfo = weights::pallet_fast_unstake::WeightInfo; -} - -parameter_types! { - // Minimum 4 CENTS/byte - pub const BasicDeposit: Balance = deposit(1, 258); - pub const FieldDeposit: Balance = deposit(0, 66); - pub const SubAccountDeposit: Balance = deposit(1, 53); - pub const MaxSubAccounts: u32 = 100; - pub const MaxAdditionalFields: u32 = 100; - pub const MaxRegistrars: u32 = 20; -} - -impl pallet_identity::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BasicDeposit = BasicDeposit; - type FieldDeposit = FieldDeposit; - type SubAccountDeposit = SubAccountDeposit; - type MaxSubAccounts = MaxSubAccounts; - type MaxAdditionalFields = MaxAdditionalFields; - type MaxRegistrars = MaxRegistrars; - type Slashed = Treasury; - type ForceOrigin = EitherOf, GeneralAdmin>; - type RegistrarOrigin = EitherOf, GeneralAdmin>; - type WeightInfo = weights::pallet_identity::WeightInfo; -} - -parameter_types! { - pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: Balance = 100 * DOLLARS; - pub const ProposalBondMaximum: Balance = 500 * DOLLARS; - pub const SpendPeriod: BlockNumber = 24 * DAYS; - pub const Burn: Permill = Permill::from_percent(1); - pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - - pub const TipCountdown: BlockNumber = 1 * DAYS; - pub const TipFindersFee: Percent = Percent::from_percent(20); - pub const TipReportDepositBase: Balance = 1 * DOLLARS; - pub const DataDepositPerByte: Balance = 1 * CENTS; - pub const MaxApprovals: u32 = 100; - pub const MaxAuthorities: u32 = 100_000; - pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; - pub const RootSpendOriginMaxAmount: Balance = Balance::MAX; - pub const CouncilSpendOriginMaxAmount: Balance = Balance::MAX; -} - -impl pallet_treasury::Config for Runtime { - type PalletId = TreasuryPalletId; - type Currency = Balances; - type ApproveOrigin = EitherOfDiverse, Treasurer>; - type RejectOrigin = EitherOfDiverse, Treasurer>; - type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; - type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type ProposalBondMaximum = ProposalBondMaximum; - type SpendPeriod = SpendPeriod; - type Burn = Burn; - type BurnDestination = (); - type SpendFunds = Bounties; - type MaxApprovals = MaxApprovals; - type WeightInfo = weights::pallet_treasury::WeightInfo; - type SpendOrigin = TreasurySpender; -} - -parameter_types! { - pub const BountyDepositBase: Balance = 1 * DOLLARS; - pub const BountyDepositPayoutDelay: BlockNumber = 8 * DAYS; - pub const BountyUpdatePeriod: BlockNumber = 90 * DAYS; - pub const MaximumReasonLength: u32 = 16384; - pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); - pub const CuratorDepositMin: Balance = 10 * DOLLARS; - pub const CuratorDepositMax: Balance = 200 * DOLLARS; - pub const BountyValueMinimum: Balance = 10 * DOLLARS; -} - -impl pallet_bounties::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BountyDepositBase = BountyDepositBase; - type BountyDepositPayoutDelay = BountyDepositPayoutDelay; - type BountyUpdatePeriod = BountyUpdatePeriod; - type CuratorDepositMultiplier = CuratorDepositMultiplier; - type CuratorDepositMin = CuratorDepositMin; - type CuratorDepositMax = CuratorDepositMax; - type BountyValueMinimum = BountyValueMinimum; - type ChildBountyManager = ChildBounties; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; - type WeightInfo = weights::pallet_bounties::WeightInfo; -} - -parameter_types! { - pub const MaxActiveChildBountyCount: u32 = 100; - pub const ChildBountyValueMinimum: Balance = BountyValueMinimum::get() / 10; -} - -impl pallet_child_bounties::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type MaxActiveChildBountyCount = MaxActiveChildBountyCount; - type ChildBountyValueMinimum = ChildBountyValueMinimum; - type WeightInfo = weights::pallet_child_bounties::WeightInfo; -} - -impl pallet_offences::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type IdentificationTuple = pallet_session::historical::IdentificationTuple; - type OnOffenceHandler = Staking; -} - -impl pallet_authority_discovery::Config for Runtime { - type MaxAuthorities = MaxAuthorities; -} - -parameter_types! { - pub NposSolutionPriority: TransactionPriority = - Perbill::from_percent(90) * TransactionPriority::max_value(); - pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); -} - -impl pallet_im_online::Config for Runtime { - type AuthorityId = ImOnlineId; - type RuntimeEvent = RuntimeEvent; - type ValidatorSet = Historical; - type NextSessionRotation = Babe; - type ReportUnresponsiveness = Offences; - type UnsignedPriority = ImOnlineUnsignedPriority; - type WeightInfo = weights::pallet_im_online::WeightInfo; - type MaxKeys = MaxKeys; - type MaxPeerInHeartbeats = MaxPeerInHeartbeats; -} - -parameter_types! { - pub MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); -} - -impl pallet_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - - type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; - type MaxNominators = MaxNominatorRewardedPerValidator; - type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - - type KeyOwnerProof = >::Proof; - - type EquivocationReportSystem = - pallet_grandpa::EquivocationReportSystem; -} - -/// Submits a transaction with the node's public and signature type. Adheres to the signed extension -/// format of the chain. -impl frame_system::offchain::CreateSignedTransaction for Runtime -where - RuntimeCall: From, -{ - fn create_transaction>( - call: RuntimeCall, - public: ::Signer, - account: AccountId, - nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { - use sp_runtime::traits::StaticLookup; - // take the biggest period possible. - let period = - BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; - - let current_block = System::block_number() - .saturated_into::() - // The `System::block_number` is initialized with `n+1`, - // so the actual block number is `n`. - .saturating_sub(1); - let tip = 0; - let extra: SignedExtra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(generic::Era::mortal( - period, - current_block, - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - claims::PrevalidateAttests::::new(), - ); - let raw_payload = SignedPayload::new(call, extra) - .map_err(|e| { - log::warn!("Unable to create signed payload: {:?}", e); - }) - .ok()?; - let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); - let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) - } -} - -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; -} - -impl frame_system::offchain::SendTransactionTypes for Runtime -where - RuntimeCall: From, -{ - type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; -} - -parameter_types! { - // Deposit for a parathread (on-demand parachain) - pub const ParathreadDeposit: Balance = 500 * DOLLARS; - pub const MaxRetries: u32 = 3; -} - -parameter_types! { - pub Prefix: &'static [u8] = b"Pay DOTs to the Polkadot account:"; -} - -impl claims::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type VestingSchedule = Vesting; - type Prefix = Prefix; - /// Only Root can move a claim. - type MoveClaimOrigin = EnsureRoot; - type WeightInfo = weights::runtime_common_claims::WeightInfo; -} - -parameter_types! { - pub const MinVestedTransfer: Balance = 1 * DOLLARS; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); -} - -impl pallet_vesting::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BlockNumberToBalance = ConvertInto; - type MinVestedTransfer = MinVestedTransfer; - type WeightInfo = weights::pallet_vesting::WeightInfo; - type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - const MAX_VESTING_SCHEDULES: u32 = 28; -} - -impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = weights::pallet_utility::WeightInfo; -} - -parameter_types! { - // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. - pub const DepositBase: Balance = deposit(1, 88); - // Additional storage item size of 32 bytes. - pub const DepositFactor: Balance = deposit(0, 32); - pub const MaxSignatories: u32 = 100; -} - -impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = MaxSignatories; - type WeightInfo = weights::pallet_multisig::WeightInfo; -} - -parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 8); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 32; - pub const AnnouncementDepositBase: Balance = deposit(1, 8); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 32; -} - -/// The type used to represent the kinds of proxying allowed. -#[derive( - Copy, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - MaxEncodedLen, - scale_info::TypeInfo, -)] -pub enum ProxyType { - Any = 0, - NonTransfer = 1, - Governance = 2, - Staking = 3, - // Skip 4 as it is now removed (was SudoBalances) - IdentityJudgement = 5, - CancelProxy = 6, - Auction = 7, - NominationPools = 8, -} - -#[cfg(test)] -mod proxy_type_tests { - use super::*; - - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug)] - pub enum OldProxyType { - Any, - NonTransfer, - Governance, - Staking, - SudoBalances, - IdentityJudgement, - } - - #[test] - fn proxy_type_decodes_correctly() { - for (i, j) in vec![ - (OldProxyType::Any, ProxyType::Any), - (OldProxyType::NonTransfer, ProxyType::NonTransfer), - (OldProxyType::Governance, ProxyType::Governance), - (OldProxyType::Staking, ProxyType::Staking), - (OldProxyType::IdentityJudgement, ProxyType::IdentityJudgement), - ] - .into_iter() - { - assert_eq!(i.encode(), j.encode()); - } - assert!(ProxyType::decode(&mut &OldProxyType::SudoBalances.encode()[..]).is_err()); - } -} - -impl Default for ProxyType { - fn default() -> Self { - Self::Any - } -} -impl InstanceFilter for ProxyType { - fn filter(&self, c: &RuntimeCall) -> bool { - match self { - ProxyType::Any => true, - ProxyType::NonTransfer => matches!( - c, - RuntimeCall::System(..) | - RuntimeCall::Scheduler(..) | - RuntimeCall::Babe(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Indices(pallet_indices::Call::claim{..}) | - RuntimeCall::Indices(pallet_indices::Call::free{..}) | - RuntimeCall::Indices(pallet_indices::Call::freeze{..}) | - // Specifically omitting Indices `transfer`, `force_transfer` - // Specifically omitting the entire Balances pallet - RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | - RuntimeCall::Grandpa(..) | - RuntimeCall::ImOnline(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda(..) | - RuntimeCall::Whitelist(..) | - RuntimeCall::Claims(..) | - RuntimeCall::Vesting(pallet_vesting::Call::vest{..}) | - RuntimeCall::Vesting(pallet_vesting::Call::vest_other{..}) | - // Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer` - RuntimeCall::Utility(..) | - RuntimeCall::Identity(..) | - RuntimeCall::Proxy(..) | - RuntimeCall::Multisig(..) | - RuntimeCall::Registrar(paras_registrar::Call::register {..}) | - RuntimeCall::Registrar(paras_registrar::Call::deregister {..}) | - // Specifically omitting Registrar `swap` - RuntimeCall::Registrar(paras_registrar::Call::reserve {..}) | - RuntimeCall::Crowdloan(..) | - RuntimeCall::Slots(..) | - RuntimeCall::Auctions(..) | // Specifically omitting the entire XCM Pallet - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools(..) | - RuntimeCall::FastUnstake(..) - ), - ProxyType::Governance => matches!( - c, - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::Utility(..) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda(..) | - RuntimeCall::Whitelist(..) - ), - ProxyType::Staking => { - matches!( - c, - RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | - RuntimeCall::FastUnstake(..) | - RuntimeCall::VoterList(..) | - RuntimeCall::NominationPools(..) - ) - }, - ProxyType::NominationPools => { - matches!(c, RuntimeCall::NominationPools(..) | RuntimeCall::Utility(..)) - }, - ProxyType::IdentityJudgement => matches!( - c, - RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | - RuntimeCall::Utility(..) - ), - ProxyType::CancelProxy => { - matches!(c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })) - }, - ProxyType::Auction => matches!( - c, - RuntimeCall::Auctions(..) | - RuntimeCall::Crowdloan(..) | - RuntimeCall::Registrar(..) | - RuntimeCall::Slots(..) - ), - } - } - fn is_superset(&self, o: &Self) -> bool { - match (self, o) { - (x, y) if x == y => true, - (ProxyType::Any, _) => true, - (_, ProxyType::Any) => false, - (ProxyType::NonTransfer, _) => true, - _ => false, - } - } -} - -impl pallet_proxy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type ProxyType = ProxyType; - type ProxyDepositBase = ProxyDepositBase; - type ProxyDepositFactor = ProxyDepositFactor; - type MaxProxies = MaxProxies; - type WeightInfo = weights::pallet_proxy::WeightInfo; - type MaxPending = MaxPending; - type CallHasher = BlakeTwo256; - type AnnouncementDepositBase = AnnouncementDepositBase; - type AnnouncementDepositFactor = AnnouncementDepositFactor; -} - -impl parachains_origin::Config for Runtime {} - -impl parachains_configuration::Config for Runtime { - type WeightInfo = weights::runtime_parachains_configuration::WeightInfo; -} - -impl parachains_shared::Config for Runtime {} - -impl parachains_session_info::Config for Runtime { - type ValidatorSet = Historical; -} - -impl parachains_inclusion::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type DisputesHandler = ParasDisputes; - type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; - type MessageQueue = MessageQueue; - type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo; -} - -parameter_types! { - pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); -} - -impl parachains_paras::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::runtime_parachains_paras::WeightInfo; - type UnsignedPriority = ParasUnsignedPriority; - type QueueFootprinter = ParaInclusion; - type NextSessionRotation = Babe; - type OnNewHead = Registrar; -} - -parameter_types! { - /// Amount of weight that can be spent per block to service messages. - /// - /// # WARNING - /// - /// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight. - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block; - pub const MessageQueueHeapSize: u32 = 65_536; - pub const MessageQueueMaxStale: u32 = 8; -} - -/// 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; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = MessageProcessor; - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = - pallet_message_queue::mock_helpers::NoopMessageProcessor; - type QueueChangeHandler = ParaInclusion; - type QueuePausedQuery = (); - type WeightInfo = weights::pallet_message_queue::WeightInfo; -} - -impl parachains_dmp::Config for Runtime {} - -impl parachains_hrmp::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type ChannelManager = EitherOf, GeneralAdmin>; - type Currency = Balances; - type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; -} - -impl parachains_paras_inherent::Config for Runtime { - type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; -} - -impl parachains_scheduler::Config for Runtime { - type AssignmentProvider = ParaAssignmentProvider; -} - -impl parachains_assigner_parachains::Config for Runtime {} - -impl parachains_initializer::Config for Runtime { - type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type ForceOrigin = EnsureRoot; - type WeightInfo = weights::runtime_parachains_initializer::WeightInfo; -} - -impl parachains_disputes::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; - type SlashingHandler = parachains_slashing::SlashValidatorsForDisputes; - type WeightInfo = weights::runtime_parachains_disputes::WeightInfo; -} - -impl parachains_slashing::Config for Runtime { - type KeyOwnerProofSystem = Historical; - type KeyOwnerProof = - >::Proof; - type KeyOwnerIdentification = >::IdentificationTuple; - type HandleReports = parachains_slashing::SlashingReportHandler< - Self::KeyOwnerIdentification, - Offences, - ReportLongevity, - >; - type WeightInfo = weights::runtime_parachains_disputes_slashing::WeightInfo; - type BenchmarkingConfig = parachains_slashing::BenchConfig<1000>; -} - -parameter_types! { - // Mostly arbitrary deposit price, but should provide an adequate incentive not to spam reserve - // `ParaId`s. - pub const ParaDeposit: Balance = 100 * DOLLARS; - pub const ParaDataByteDeposit: Balance = deposit(0, 1); -} - -impl paras_registrar::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type OnSwap = (Crowdloan, Slots); - type ParaDeposit = ParaDeposit; - type DataDepositPerByte = ParaDataByteDeposit; - type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; -} - -parameter_types! { - // 12 weeks = 3 months per lease period -> 8 lease periods ~ 2 years - pub LeasePeriod: BlockNumber = prod_or_fast!(12 * WEEKS, 12 * WEEKS, "DOT_LEASE_PERIOD"); - // Polkadot Genesis was on May 26, 2020. - // Target Parachain Onboarding Date: Dec 15, 2021. - // Difference is 568 days. - // We want a lease period to start on the target onboarding date. - // 568 % (12 * 7) = 64 day offset - pub LeaseOffset: BlockNumber = prod_or_fast!(64 * DAYS, 0, "DOT_LEASE_OFFSET"); -} - -impl slots::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type Registrar = Registrar; - type LeasePeriod = LeasePeriod; - type LeaseOffset = LeaseOffset; - type ForceOrigin = EitherOf, LeaseAdmin>; - type WeightInfo = weights::runtime_common_slots::WeightInfo; -} - -parameter_types! { - pub const CrowdloanId: PalletId = PalletId(*b"py/cfund"); - // Accounts for 10_000 contributions, each using 48 bytes (16 bytes for balance, and 32 bytes - // for a memo). - pub const SubmissionDeposit: Balance = deposit(1, 480_000); - // The minimum crowdloan contribution. - pub const MinContribution: Balance = 5 * DOLLARS; - pub const RemoveKeysLimit: u32 = 1000; - // Allow 32 bytes for an additional memo to a crowdloan. - pub const MaxMemoLength: u8 = 32; -} - -impl crowdloan::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletId = CrowdloanId; - type SubmissionDeposit = SubmissionDeposit; - type MinContribution = MinContribution; - type RemoveKeysLimit = RemoveKeysLimit; - type Registrar = Registrar; - type Auctioneer = Auctions; - type MaxMemoLength = MaxMemoLength; - type WeightInfo = weights::runtime_common_crowdloan::WeightInfo; -} - -parameter_types! { - // The average auction is 7 days long, so this will be 70% for ending period. - // 5 Days = 72000 Blocks @ 6 sec per block - pub const EndingPeriod: BlockNumber = 5 * DAYS; - // ~ 1000 samples per day -> ~ 20 blocks per sample -> 2 minute samples - pub const SampleLength: BlockNumber = 2 * MINUTES; -} - -impl auctions::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Leaser = Slots; - type Registrar = Registrar; - type EndingPeriod = EndingPeriod; - type SampleLength = SampleLength; - type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type InitiateOrigin = EitherOf, AuctionAdmin>; - type WeightInfo = weights::runtime_common_auctions::WeightInfo; -} - -parameter_types! { - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - // Allow pools that got slashed up to 90% to remain operational. - pub const MaxPointsToBalance: u8 = 10; -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type RewardCounter = FixedU128; - type BalanceToU256 = runtime_common::BalanceToU256; - type U256ToBalance = runtime_common::U256ToBalance; - type Staking = Staking; - type PostUnbondingPoolsWindow = frame_support::traits::ConstU32<4>; - type MaxMetadataLen = frame_support::traits::ConstU32<256>; - // we use the same number of allowed unlocking chunks as with staking. - type MaxUnbonding = ::MaxUnlockingChunks; - type PalletId = PoolsPalletId; - type MaxPointsToBalance = MaxPointsToBalance; - type WeightInfo = weights::pallet_nomination_pools::WeightInfo; -} - -pub struct InitiateNominationPools; -impl frame_support::traits::OnRuntimeUpgrade for InitiateNominationPools { - fn on_runtime_upgrade() -> frame_support::weights::Weight { - // we use one as an indicator if this has already been set. - if pallet_nomination_pools::MaxPools::::get().is_none() { - // 5 DOT to join a pool. - pallet_nomination_pools::MinJoinBond::::put(5 * UNITS); - // 100 DOT to create a pool. - pallet_nomination_pools::MinCreateBond::::put(100 * UNITS); - - // Initialize with limits for now. - pallet_nomination_pools::MaxPools::::put(0); - pallet_nomination_pools::MaxPoolMembersPerPool::::put(0); - pallet_nomination_pools::MaxPoolMembers::::put(0); - - log::info!(target: "runtime::polkadot", "pools config initiated 🎉"); - ::DbWeight::get().reads_writes(1, 5) - } else { - log::info!(target: "runtime::polkadot", "pools config already initiated 😏"); - ::DbWeight::get().reads(1) - } - } -} - -construct_runtime! { - pub enum Runtime - { - // Basic stuff; balances is uncallable initially. - System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 1, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 10, - - // Babe must be before session. - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2, - - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, - Indices: pallet_indices::{Pallet, Call, Storage, Config, Event} = 4, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 5, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event} = 32, - - // Consensus support. - // Authorship must be before session in order to note author in the correct session and era - // for im-online and staking. - Authorship: pallet_authorship::{Pallet, Storage} = 6, - Staking: pallet_staking::{Pallet, Call, Storage, Config, Event} = 7, - Offences: pallet_offences::{Pallet, Storage, Event} = 8, - Historical: session_historical::{Pallet} = 33, - Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 9, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 11, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 12, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 13, - - // OpenGov stuff. - Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 19, - ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 20, - Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 21, - Origins: pallet_custom_origins::{Origin} = 22, - Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 23, - - // Claims. Usable initially. - Claims: claims::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 24, - // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config} = 25, - // Cunning utilities. Usable initially. - Utility: pallet_utility::{Pallet, Call, Event} = 26, - - // Identity. Late addition. - Identity: pallet_identity::{Pallet, Call, Storage, Event} = 28, - - // Proxy module. Late addition. - Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 29, - - // Multisig dispatch. Late addition. - Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 30, - - // Bounties modules. - Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 34, - ChildBounties: pallet_child_bounties = 38, - - // Election pallet. Only works with staking, but placed here to maintain indices. - ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 36, - - // Provides a semi-sorted list of nominators for staking. - VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 37, - - // Nomination pools: extension to staking. - NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event, Config} = 39, - - // Fast unstake pallet: extension to staking. - FastUnstake: pallet_fast_unstake = 40, - - // Parachains pallets. Start indices at 50 to leave room. - ParachainsOrigin: parachains_origin::{Pallet, Origin} = 50, - Configuration: parachains_configuration::{Pallet, Call, Storage, Config} = 51, - ParasShared: parachains_shared::{Pallet, Call, Storage} = 52, - ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event} = 53, - ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 54, - ParaScheduler: parachains_scheduler::{Pallet, Storage} = 55, - Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56, - Initializer: parachains_initializer::{Pallet, Call, Storage} = 57, - Dmp: parachains_dmp::{Pallet, Storage} = 58, - // Ump 59 - Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event, Config} = 60, - ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, - ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 62, - ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, - ParaAssignmentProvider: parachains_assigner_parachains::{Pallet} = 64, - - // Parachain Onboarding Pallets. Start indices at 70 to leave room. - Registrar: paras_registrar::{Pallet, Call, Storage, Event} = 70, - Slots: slots::{Pallet, Call, Storage, Event} = 71, - Auctions: auctions::{Pallet, Call, Storage, Event} = 72, - Crowdloan: crowdloan::{Pallet, Call, Storage, Event} = 73, - - // Pallet for sending XCM. - XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, - - // Generalized message queue - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 100, - } -} - -/// The address format for describing accounts. -pub type Address = sp_runtime::MultiAddress; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// `BlockId` type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckMortality, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, - claims::PrevalidateAttests, -); - -pub struct NominationPoolsMigrationV4OldPallet; -impl Get for NominationPoolsMigrationV4OldPallet { - fn get() -> Perbill { - Perbill::zero() - } -} - -/// All migrations that will run on the next runtime upgrade. -/// -/// This contains the combined migrations of the last 10 releases. It allows to skip runtime -/// upgrades in case governance decides to do so. THE ORDER IS IMPORTANT. -pub type Migrations = migrations::Unreleased; - -/// The runtime migrations per release. -#[allow(deprecated, missing_docs)] -pub mod migrations { - use super::*; - use frame_support::traits::LockIdentifier; - use frame_system::pallet_prelude::BlockNumberFor; - - parameter_types! { - pub const DemocracyPalletName: &'static str = "Democracy"; - pub const CouncilPalletName: &'static str = "Council"; - pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; - pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; - pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; - pub const TipsPalletName: &'static str = "Tips"; - pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; - } - - // Special Config for Gov V1 pallets, allowing us to run migrations for them without - // implementing their configs on [`Runtime`]. - pub struct UnlockConfig; - impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { - type Currency = Balances; - type MaxVotes = ConstU32<100>; - type MaxDeposits = ConstU32<100>; - type AccountId = AccountId; - type BlockNumber = BlockNumberFor; - type DbWeight = ::DbWeight; - type PalletName = DemocracyPalletName; - } - impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig - for UnlockConfig - { - type Currency = Balances; - type MaxVotesPerVoter = ConstU32<16>; - type PalletId = PhragmenElectionPalletId; - type AccountId = AccountId; - type DbWeight = ::DbWeight; - type PalletName = PhragmenElectionPalletName; - } - impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { - type Currency = Balances; - type Hash = Hash; - type DataDepositPerByte = DataDepositPerByte; - type TipReportDepositBase = TipReportDepositBase; - type AccountId = AccountId; - type BlockNumber = BlockNumberFor; - type DbWeight = ::DbWeight; - type PalletName = TipsPalletName; - } - - pub struct ParachainsToUnlock; - impl Contains for ParachainsToUnlock { - fn contains(id: &ParaId) -> bool { - let id: u32 = (*id).into(); - // polkadot parachains/parathreads that are locked and never produced block - match id { - 2003 | 2015 | 2017 | 2018 | 2025 | 2028 | 2036 | 2038 | 2053 | 2055 | 2090 | - 2097 | 2106 | 3336 | 3338 | 3342 => true, - _ => false, - } - } - } - - /// Unreleased migrations. Add new ones here: - pub type Unreleased = ( - pallet_im_online::migration::v1::Migration, - parachains_configuration::migration::v7::MigrateToV7, - parachains_scheduler::migration::v1::MigrateToV1, - parachains_configuration::migration::v8::MigrateToV8, - - // Gov v1 storage migrations - // https://github.com/paritytech/polkadot/issues/6749 - pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, - - // Delete all Gov v1 pallet storage key/values. - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - frame_support::migrations::RemovePallet::DbWeight>, - - parachains_configuration::migration::v9::MigrateToV9, - // Migrate parachain info format - paras_registrar::migration::VersionCheckedMigrateToV1, - ); -} - -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, - Migrations, ->; - -/// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; - -#[cfg(feature = "runtime-benchmarks")] -mod benches { - frame_benchmarking::define_benchmarks!( - // Polkadot - // NOTE: Make sure to prefix these with `runtime_common::` so - // the that path resolves correctly in the generated file. - [runtime_common::auctions, Auctions] - [runtime_common::claims, Claims] - [runtime_common::crowdloan, Crowdloan] - [runtime_common::slots, Slots] - [runtime_common::paras_registrar, Registrar] - [runtime_parachains::configuration, Configuration] - [runtime_parachains::disputes, ParasDisputes] - [runtime_parachains::disputes::slashing, ParasSlashing] - [runtime_parachains::hrmp, Hrmp] - [runtime_parachains::inclusion, ParaInclusion] - [runtime_parachains::initializer, Initializer] - [runtime_parachains::paras, Paras] - [runtime_parachains::paras_inherent, ParaInherent] - // Substrate - [pallet_bags_list, VoterList] - [pallet_balances, Balances] - [frame_benchmarking::baseline, Baseline::] - [pallet_bounties, Bounties] - [pallet_child_bounties, ChildBounties] - [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] - [frame_election_provider_support, ElectionProviderBench::] - [pallet_fast_unstake, FastUnstake] - [pallet_identity, Identity] - [pallet_im_online, ImOnline] - [pallet_indices, Indices] - [pallet_message_queue, MessageQueue] - [pallet_multisig, Multisig] - [pallet_nomination_pools, NominationPoolsBench::] - [pallet_offences, OffencesBench::] - [pallet_preimage, Preimage] - [pallet_proxy, Proxy] - [pallet_scheduler, Scheduler] - [pallet_session, SessionBench::] - [pallet_staking, Staking] - [frame_system, SystemBench::] - [pallet_timestamp, Timestamp] - [pallet_treasury, Treasury] - [pallet_utility, Utility] - [pallet_vesting, Vesting] - [pallet_conviction_voting, ConvictionVoting] - [pallet_referenda, Referenda] - [pallet_whitelist, Whitelist] - // XCM - [pallet_xcm, XcmPallet] - [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] - [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::] - ); -} - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block); - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> sp_std::vec::Vec { - Runtime::metadata_versions() - } - } - - impl block_builder_api::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: inherents::InherentData, - ) -> inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl pallet_nomination_pools_runtime_api::NominationPoolsApi< - Block, - AccountId, - Balance, - > for Runtime { - fn pending_rewards(member: AccountId) -> Balance { - NominationPools::api_pending_rewards(member).unwrap_or_default() - } - - fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { - NominationPools::api_points_to_balance(pool_id, points) - } - - fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { - NominationPools::api_balance_to_points(pool_id, new_funds) - } - } - - impl pallet_staking_runtime_api::StakingApi for Runtime { - fn nominations_quota(balance: Balance) -> u32 { - Staking::api_nominations_quota(balance) - } - } - - impl tx_pool_api::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl offchain_primitives::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl primitives::runtime_api::ParachainHost for Runtime { - fn validators() -> Vec { - parachains_runtime_api_impl::validators::() - } - - fn validator_groups() -> (Vec>, GroupRotationInfo) { - parachains_runtime_api_impl::validator_groups::() - } - - fn availability_cores() -> Vec> { - parachains_runtime_api_impl::availability_cores::() - } - - fn persisted_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option> { - parachains_runtime_api_impl::persisted_validation_data::(para_id, assumption) - } - - fn assumed_validation_data( - para_id: ParaId, - expected_persisted_validation_data_hash: Hash, - ) -> Option<(PersistedValidationData, ValidationCodeHash)> { - parachains_runtime_api_impl::assumed_validation_data::( - para_id, - expected_persisted_validation_data_hash, - ) - } - - fn check_validation_outputs( - para_id: ParaId, - outputs: primitives::CandidateCommitments, - ) -> bool { - parachains_runtime_api_impl::check_validation_outputs::(para_id, outputs) - } - - fn session_index_for_child() -> SessionIndex { - parachains_runtime_api_impl::session_index_for_child::() - } - - fn validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option { - parachains_runtime_api_impl::validation_code::(para_id, assumption) - } - - fn candidate_pending_availability(para_id: ParaId) -> Option> { - parachains_runtime_api_impl::candidate_pending_availability::(para_id) - } - - fn candidate_events() -> Vec> { - parachains_runtime_api_impl::candidate_events::(|ev| { - match ev { - RuntimeEvent::ParaInclusion(ev) => { - Some(ev) - } - _ => None, - } - }) - } - - fn session_info(index: SessionIndex) -> Option { - parachains_runtime_api_impl::session_info::(index) - } - - fn session_executor_params(session_index: SessionIndex) -> Option { - parachains_runtime_api_impl::session_executor_params::(session_index) - } - - fn dmq_contents(recipient: ParaId) -> Vec> { - parachains_runtime_api_impl::dmq_contents::(recipient) - } - - fn inbound_hrmp_channels_contents( - recipient: ParaId - ) -> BTreeMap>> { - parachains_runtime_api_impl::inbound_hrmp_channels_contents::(recipient) - } - - fn validation_code_by_hash(hash: ValidationCodeHash) -> Option { - parachains_runtime_api_impl::validation_code_by_hash::(hash) - } - - fn on_chain_votes() -> Option> { - parachains_runtime_api_impl::on_chain_votes::() - } - - fn submit_pvf_check_statement( - stmt: primitives::PvfCheckStatement, - signature: primitives::ValidatorSignature, - ) { - parachains_runtime_api_impl::submit_pvf_check_statement::(stmt, signature) - } - - fn pvfs_require_precheck() -> Vec { - parachains_runtime_api_impl::pvfs_require_precheck::() - } - - fn validation_code_hash(para_id: ParaId, assumption: OccupiedCoreAssumption) - -> Option - { - parachains_runtime_api_impl::validation_code_hash::(para_id, assumption) - } - - fn disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState)> { - parachains_runtime_api_impl::get_session_disputes::() - } - - fn unapplied_slashes( - ) -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)> { - parachains_runtime_api_impl::unapplied_slashes::() - } - - fn key_ownership_proof( - validator_id: ValidatorId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((PARACHAIN_KEY_TYPE_ID, validator_id)) - .map(|p| p.encode()) - .map(slashing::OpaqueKeyOwnershipProof::new) - } - - fn submit_report_dispute_lost( - dispute_proof: slashing::DisputeProof, - key_ownership_proof: slashing::OpaqueKeyOwnershipProof, - ) -> Option<()> { - parachains_runtime_api_impl::submit_unsigned_slashing_report::( - dispute_proof, - key_ownership_proof, - ) - } - } - - impl beefy_primitives::BeefyApi for Runtime { - fn beefy_genesis() -> Option { - // dummy implementation due to lack of BEEFY pallet. - None - } - - fn validator_set() -> Option> { - // dummy implementation due to lack of BEEFY pallet. - None - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: beefy_primitives::EquivocationProof< - BlockNumber, - BeefyId, - BeefySignature, - >, - _key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _set_id: beefy_primitives::ValidatorSetId, - _authority_id: BeefyId, - ) -> Option { - None - } - } - - impl mmr::MmrApi for Runtime { - fn mmr_root() -> Result { - Err(mmr::Error::PalletNotIncluded) - } - - fn mmr_leaf_count() -> Result { - Err(mmr::Error::PalletNotIncluded) - } - - fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) - } - - fn verify_proof(_leaves: Vec, _proof: mmr::Proof) - -> Result<(), mmr::Error> - { - Err(mmr::Error::PalletNotIncluded) - } - - fn verify_proof_stateless( - _root: Hash, - _leaves: Vec, - _proof: mmr::Proof - ) -> Result<(), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) - } - } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> Vec<(GrandpaId, u64)> { - Grandpa::grandpa_authorities() - } - - fn current_set_id() -> fg_primitives::SetId { - Grandpa::current_set_id() - } - - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: fg_primitives::EquivocationProof< - ::Hash, - sp_runtime::traits::NumberFor, - >, - key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - let key_owner_proof = key_owner_proof.decode()?; - - Grandpa::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - } - - fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, - authority_id: fg_primitives::AuthorityId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((fg_primitives::KEY_TYPE, authority_id)) - .map(|p| p.encode()) - .map(fg_primitives::OpaqueKeyOwnershipProof::new) - } - } - - impl babe_primitives::BabeApi for Runtime { - fn configuration() -> babe_primitives::BabeConfiguration { - let epoch_config = Babe::epoch_config().unwrap_or(BABE_GENESIS_EPOCH_CONFIG); - babe_primitives::BabeConfiguration { - slot_duration: Babe::slot_duration(), - epoch_length: EpochDuration::get(), - c: epoch_config.c, - authorities: Babe::authorities().to_vec(), - randomness: Babe::randomness(), - allowed_slots: epoch_config.allowed_slots, - } - } - - fn current_epoch_start() -> babe_primitives::Slot { - Babe::current_epoch_start() - } - - fn current_epoch() -> babe_primitives::Epoch { - Babe::current_epoch() - } - - fn next_epoch() -> babe_primitives::Epoch { - Babe::next_epoch() - } - - fn generate_key_ownership_proof( - _slot: babe_primitives::Slot, - authority_id: babe_primitives::AuthorityId, - ) -> Option { - use parity_scale_codec::Encode; - - Historical::prove((babe_primitives::KEY_TYPE, authority_id)) - .map(|p| p.encode()) - .map(babe_primitives::OpaqueKeyOwnershipProof::new) - } - - fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: babe_primitives::EquivocationProof<::Header>, - key_owner_proof: babe_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - let key_owner_proof = key_owner_proof.decode()?; - - Babe::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - } - } - - impl authority_discovery_primitives::AuthorityDiscoveryApi for Runtime { - fn authorities() -> Vec { - parachains_runtime_api_impl::relevant_authority_ids::() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, sp_core::crypto::KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Nonce { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< - Block, - Balance, - > for Runtime { - fn query_info(uxt: ::Extrinsic, len: u32) -> RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - log::info!("try-runtime::on_runtime_upgrade polkadot."); - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, BlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - - use pallet_session_benchmarking::Pallet as SessionBench; - use pallet_offences_benchmarking::Pallet as OffencesBench; - use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; - use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; - use frame_system_benchmarking::Pallet as SystemBench; - use frame_benchmarking::baseline::Pallet as Baseline; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - return (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result< - Vec, - sp_runtime::RuntimeString, - > { - use frame_support::traits::WhitelistedStorageKeys; - use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; - use sp_storage::TrackedStorageKey; - // Trying to add benchmarks directly to some pallets caused cyclic dependency issues. - // To get around that, we separated the benchmarks into its own crate. - use pallet_session_benchmarking::Pallet as SessionBench; - use pallet_offences_benchmarking::Pallet as OffencesBench; - use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; - use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; - use frame_system_benchmarking::Pallet as SystemBench; - use frame_benchmarking::baseline::Pallet as Baseline; - use xcm::latest::prelude::*; - use xcm_config::{XcmConfig, StatemintLocation, TokenLocation, LocalCheckAccount, SovereignAccountOf}; - - impl pallet_session_benchmarking::Config for Runtime {} - impl pallet_offences_benchmarking::Config for Runtime {} - impl pallet_election_provider_support_benchmarking::Config for Runtime {} - impl frame_system_benchmarking::Config for Runtime {} - impl frame_benchmarking::baseline::Config for Runtime {} - impl pallet_nomination_pools_benchmarking::Config for Runtime {} - impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} - - let mut whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); - let treasury_key = frame_system::Account::::hashed_key_for(Treasury::account_id()); - whitelist.push(treasury_key.to_vec().into()); - - impl pallet_xcm_benchmarks::Config for Runtime { - type XcmConfig = XcmConfig; - type AccountIdConverter = SovereignAccountOf; - fn valid_destination() -> Result { - Ok(StatemintLocation::get()) - } - fn worst_case_holding(_depositable_count: u32) -> MultiAssets { - // Polkadot only knows about DOT - vec![MultiAsset { id: Concrete(TokenLocation::get()), fun: Fungible(1_000_000 * UNITS) }].into() - } - } - - parameter_types! { - pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - StatemintLocation::get(), - MultiAsset { id: Concrete(TokenLocation::get()), fun: Fungible(1 * UNITS) } - )); - pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; - } - - impl pallet_xcm_benchmarks::fungible::Config for Runtime { - type TransactAsset = Balances; - - type CheckedAccount = LocalCheckAccount; - type TrustedTeleporter = TrustedTeleporter; - type TrustedReserve = TrustedReserve; - - fn get_multi_asset() -> MultiAsset { - MultiAsset { - id: Concrete(TokenLocation::get()), - fun: Fungible(1 * UNITS) - } - } - } - - impl pallet_xcm_benchmarks::generic::Config for Runtime { - type RuntimeCall = RuntimeCall; - - fn worst_case_response() -> (u64, Response) { - (0u64, Response::Version(Default::default())) - } - - fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> { - // Polkadot doesn't support asset exchanges - Err(BenchmarkError::Skip) - } - - fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { - // The XCM executor of Polkadot doesn't have a configured `UniversalAliases` - Err(BenchmarkError::Skip) - } - - fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((StatemintLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) - } - - fn subscribe_origin() -> Result { - Ok(StatemintLocation::get()) - } - - fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = StatemintLocation::get(); - let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); - let ticket = MultiLocation { parents: 0, interior: Here }; - Ok((origin, ticket, assets)) - } - - fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> { - // Polkadot doesn't support asset locking - Err(BenchmarkError::Skip) - } - - fn export_message_origin_and_destination( - ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - // Polkadot doesn't support exporting messages - Err(BenchmarkError::Skip) - } - - fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { - // The XCM executor of Polkadot doesn't have a configured `Aliasers` - Err(BenchmarkError::Skip) - } - } - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - - add_benchmarks!(params, batches); - - Ok(batches) - } - } -} - -#[cfg(test)] -mod test_fees { - use super::*; - use frame_support::{dispatch::GetDispatchInfo, weights::WeightToFee as WeightToFeeT}; - use keyring::Sr25519Keyring::{Alice, Charlie}; - use pallet_transaction_payment::Multiplier; - use runtime_common::MinimumMultiplier; - use separator::Separatable; - use sp_runtime::{assert_eq_error_rate, FixedPointNumber, MultiAddress, MultiSignature}; - - #[test] - fn payout_weight_portion() { - use pallet_staking::WeightInfo; - let payout_weight = - ::WeightInfo::payout_stakers_alive_staked( - MaxNominatorRewardedPerValidator::get(), - ) - .ref_time() as f64; - let block_weight = BlockWeights::get().max_block.ref_time() as f64; - - println!( - "a full payout takes {:.2} of the block weight [{} / {}]", - payout_weight / block_weight, - payout_weight, - block_weight - ); - assert!(payout_weight * 2f64 < block_weight); - } - - #[test] - fn block_cost() { - let max_block_weight = BlockWeights::get().max_block; - let raw_fee = WeightToFee::weight_to_fee(&max_block_weight); - - let fee_with_multiplier = |m: Multiplier| { - println!( - "Full Block weight == {} // multiplier: {:?} // WeightToFee(full_block) == {} plank", - max_block_weight, - m, - m.saturating_mul_int(raw_fee).separated_string(), - ); - }; - fee_with_multiplier(MinimumMultiplier::get()); - fee_with_multiplier(Multiplier::from_rational(1, 2)); - fee_with_multiplier(Multiplier::from_u32(1)); - fee_with_multiplier(Multiplier::from_u32(2)); - } - - #[test] - fn transfer_cost_min_multiplier() { - let min_multiplier = MinimumMultiplier::get(); - let call = pallet_balances::Call::::transfer_keep_alive { - dest: Charlie.to_account_id().into(), - value: Default::default(), - }; - let info = call.get_dispatch_info(); - println!("call = {:?} / info = {:?}", call, info); - // convert to runtime call. - let call = RuntimeCall::Balances(call); - let extra: SignedExtra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckMortality::::from(generic::Era::immortal()), - frame_system::CheckNonce::::from(1), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(0), - claims::PrevalidateAttests::::new(), - ); - let uxt = UncheckedExtrinsic { - function: call, - signature: Some(( - MultiAddress::Id(Alice.to_account_id()), - MultiSignature::Sr25519(Alice.sign(b"foo")), - extra, - )), - }; - let len = uxt.encoded_size(); - - let mut ext = sp_io::TestExternalities::new_empty(); - let mut test_with_multiplier = |m: Multiplier| { - ext.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::put(m); - let fee = TransactionPayment::query_fee_details(uxt.clone(), len as u32); - println!( - "multiplier = {:?} // fee details = {:?} // final fee = {:?}", - pallet_transaction_payment::NextFeeMultiplier::::get(), - fee, - fee.final_fee().separated_string(), - ); - }); - }; - - test_with_multiplier(min_multiplier); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_0u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_00u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000_000u128)); - } - - #[test] - fn nominator_limit() { - use pallet_election_provider_multi_phase::WeightInfo; - // starting point of the nominators. - let target_voters: u32 = 50_000; - - // assuming we want around 5k candidates and 1k active validators. (March 31, 2021) - let all_targets: u32 = 5_000; - let desired: u32 = 1_000; - let weight_with = |active| { - ::WeightInfo::submit_unsigned( - active, - all_targets, - active, - desired, - ) - }; - - let mut active = target_voters; - while weight_with(active).all_lte(OffchainSolutionWeightLimit::get()) || - active == target_voters - { - active += 1; - } - - println!("can support {} nominators to yield a weight of {}", active, weight_with(active)); - assert!(active > target_voters, "we need to reevaluate the weight of the election system"); - } - - #[test] - fn signed_deposit_is_sensible() { - // ensure this number does not change, or that it is checked after each change. - // a 1 MB solution should take (40 + 10) DOTs of deposit. - let deposit = SignedFixedDeposit::get() + (SignedDepositByte::get() * 1024 * 1024); - assert_eq_error_rate!(deposit, 50 * DOLLARS, DOLLARS); - } -} - -#[cfg(test)] -mod test { - use std::collections::HashSet; - - use super::*; - use frame_support::traits::WhitelistedStorageKeys; - use sp_core::hexdisplay::HexDisplay; - - #[test] - fn call_size() { - RuntimeCall::assert_size_under(230); - } - - #[test] - fn check_whitelist() { - let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() - .iter() - .map(|e| HexDisplay::from(&e.key).to_string()) - .collect(); - - // Block number - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") - ); - // Total issuance - assert!( - whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") - ); - // Execution phase - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") - ); - // Event count - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") - ); - // System events - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") - ); - // XcmPallet VersionDiscoveryQueue - assert!( - whitelist.contains("1405f2411d0af5a7ff397e7c9dc68d194a222ba0333561192e474c59ed8e30e1") - ); - // XcmPallet SafeXcmVersion - assert!( - whitelist.contains("1405f2411d0af5a7ff397e7c9dc68d196323ae84c43568be0d1394d5d0d522c4") - ); - } -} - -#[cfg(test)] -mod multiplier_tests { - use super::*; - use frame_support::{dispatch::DispatchInfo, traits::OnFinalize}; - use runtime_common::{MinimumMultiplier, TargetBlockFullness}; - use separator::Separatable; - use sp_runtime::traits::Convert; - - fn run_with_system_weight(w: Weight, mut assertions: F) - where - F: FnMut() -> (), - { - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - t.execute_with(|| { - System::set_block_consumed_resources(w, 0); - assertions() - }); - } - - #[test] - fn multiplier_can_grow_from_zero() { - let minimum_multiplier = MinimumMultiplier::get(); - let target = TargetBlockFullness::get() * - BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); - // if the min is too small, then this will not change, and we are doomed forever. - // the weight is 1/100th bigger than target. - run_with_system_weight(target.saturating_mul(101) / 100, || { - let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); - assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); - }) - } - - #[test] - fn fast_unstake_estimate() { - use pallet_fast_unstake::WeightInfo; - let block_time = BlockWeights::get().max_block.ref_time() as f32; - let on_idle = weights::pallet_fast_unstake::WeightInfo::::on_idle_check( - 300, - ::BatchSize::get(), - ) - .ref_time() as f32; - println!("ratio of block weight for full batch fast-unstake {}", on_idle / block_time); - assert!(on_idle / block_time <= 0.5f32) - } - - #[test] - #[ignore] - fn multiplier_growth_simulator() { - // assume the multiplier is initially set to its minimum. We update it with values twice the - //target (target is 25%, thus 50%) and we see at which point it reaches 1. - let mut multiplier = MinimumMultiplier::get(); - let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); - let mut blocks = 0; - let mut fees_paid = 0; - - frame_system::Pallet::::set_block_consumed_resources(Weight::MAX, 0); - let info = DispatchInfo { weight: Weight::MAX, ..Default::default() }; - - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - // set the minimum - t.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::set(MinimumMultiplier::get()); - }); - - while multiplier <= Multiplier::from_u32(1) { - t.execute_with(|| { - // imagine this tx was called. - let fee = TransactionPayment::compute_fee(0, &info, 0); - fees_paid += fee; - - // this will update the multiplier. - System::set_block_consumed_resources(block_weight, 0); - TransactionPayment::on_finalize(1); - let next = TransactionPayment::next_fee_multiplier(); - - assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); - multiplier = next; - - println!( - "block = {} / multiplier {:?} / fee = {:?} / fess so far {:?}", - blocks, - multiplier, - fee.separated_string(), - fees_paid.separated_string() - ); - }); - blocks += 1; - } - } - - #[test] - #[ignore] - fn multiplier_cool_down_simulator() { - // assume the multiplier is initially set to its minimum. We update it with values twice the - //target (target is 25%, thus 50%) and we see at which point it reaches 1. - let mut multiplier = Multiplier::from_u32(2); - let mut blocks = 0; - - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap() - .into(); - // set the minimum - t.execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); - }); - - while multiplier > Multiplier::from_u32(0) { - t.execute_with(|| { - // this will update the multiplier. - TransactionPayment::on_finalize(1); - let next = TransactionPayment::next_fee_multiplier(); - - assert!(next < multiplier, "{:?} !>= {:?}", next, multiplier); - multiplier = next; - - println!("block = {} / multiplier {:?}", blocks, multiplier); - }); - blocks += 1; - } - } -} - -#[cfg(all(test, feature = "try-runtime"))] -mod remote_tests { - use super::*; - use frame_try_runtime::{runtime_decl_for_try_runtime::TryRuntime, UpgradeCheckSelect}; - use remote_externalities::{ - Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport, - }; - use std::env::var; - - #[tokio::test] - async fn run_migrations() { - if var("RUN_MIGRATION_TESTS").is_err() { - return - } - - sp_tracing::try_init_simple(); - let transport: Transport = - var("WS").unwrap_or("wss://rpc.polkadot.io:443".to_string()).into(); - let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); - let mut ext = Builder::::default() - .mode(if let Some(state_snapshot) = maybe_state_snapshot { - Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - ..Default::default() - }, - ) - } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) - }) - .build() - .await - .unwrap(); - ext.execute_with(|| Runtime::on_runtime_upgrade(UpgradeCheckSelect::PreAndPost)); - } - - #[tokio::test] - #[ignore = "this test is meant to be executed manually"] - async fn try_fast_unstake_all() { - sp_tracing::try_init_simple(); - let transport: Transport = - var("WS").unwrap_or("wss://rpc.polkadot.io:443".to_string()).into(); - let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); - let mut ext = Builder::::default() - .mode(if let Some(state_snapshot) = maybe_state_snapshot { - Mode::OfflineOrElseOnline( - OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - ..Default::default() - }, - ) - } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) - }) - .build() - .await - .unwrap(); - ext.execute_with(|| { - pallet_fast_unstake::ErasToCheckPerBlock::::put(1); - runtime_common::try_runtime::migrate_all_inactive_nominators::() - }); - } -} diff --git a/polkadot/runtime/polkadot/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/polkadot/src/weights/frame_benchmarking_baseline.rs deleted file mode 100644 index bb27fdc880ca46c2f05e368a51b7da77e23b7a10..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/frame_benchmarking_baseline.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_benchmarking::baseline` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_benchmarking::baseline -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/frame_benchmarking_baseline.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_benchmarking::baseline`. -pub struct WeightInfo(PhantomData); -impl frame_benchmarking::baseline::WeightInfo for WeightInfo { - /// The range of component `i` is `[0, 1000000]`. - fn addition(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 163_000 picoseconds. - Weight::from_parts(209_370, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn subtraction(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 159_000 picoseconds. - Weight::from_parts(203_916, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn multiplication(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 163_000 picoseconds. - Weight::from_parts(211_152, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 1000000]`. - fn division(_i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 165_000 picoseconds. - Weight::from_parts(205_618, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn hashing() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 22_794_873_000 picoseconds. - Weight::from_parts(22_858_244_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `i` is `[0, 100]`. - fn sr25519_verification(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 218_000 picoseconds. - Weight::from_parts(2_663_311, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_556 - .saturating_add(Weight::from_parts(55_473_775, 0).saturating_mul(i.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/frame_election_provider_support.rs b/polkadot/runtime/polkadot/src/weights/frame_election_provider_support.rs deleted file mode 100644 index 109c82884214d9a5012ad9ed05367c45f8913c79..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/frame_election_provider_support.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_election_provider_support` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_election_provider_support -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_election_provider_support`. -pub struct WeightInfo(PhantomData); -impl frame_election_provider_support::WeightInfo for WeightInfo { - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_659_138_000 picoseconds. - Weight::from_parts(6_742_669_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 134_896 - .saturating_add(Weight::from_parts(5_872_242, 0).saturating_mul(v.into())) - // Standard Error: 13_791_372 - .saturating_add(Weight::from_parts(1_417_540_796, 0).saturating_mul(d.into())) - } - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_614_958_000 picoseconds. - Weight::from_parts(4_655_159_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 121_610 - .saturating_add(Weight::from_parts(4_875_919, 0).saturating_mul(v.into())) - // Standard Error: 12_432_980 - .saturating_add(Weight::from_parts(1_332_850_451, 0).saturating_mul(d.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/frame_system.rs b/polkadot/runtime/polkadot/src/weights/frame_system.rs deleted file mode 100644 index e6ece50fc8e0f1244b4286ee644ef12a9ca9ad48..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/frame_system.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_system` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_system -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system`. -pub struct WeightInfo(PhantomData); -impl frame_system::WeightInfo for WeightInfo { - /// The range of component `b` is `[0, 3932160]`. - fn remark(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_933_000 picoseconds. - Weight::from_parts(2_016_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(469, 0).saturating_mul(b.into())) - } - /// The range of component `b` is `[0, 3932160]`. - fn remark_with_event(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_415_000 picoseconds. - Weight::from_parts(7_513_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_834, 0).saturating_mul(b.into())) - } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) - /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) - fn set_heap_pages() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 3_680_000 picoseconds. - Weight::from_parts(3_889_000, 0) - .saturating_add(Weight::from_parts(0, 1485)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a636f6465` (r:0 w:1) - /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) - fn set_code() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 92_505_621_000 picoseconds. - Weight::from_parts(96_677_957_000, 0) - .saturating_add(Weight::from_parts(0, 1485)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1000]`. - fn set_storage(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_080_000 picoseconds. - Weight::from_parts(2_160_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_639 - .saturating_add(Weight::from_parts(731_622, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1000]`. - fn kill_storage(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_135_000 picoseconds. - Weight::from_parts(2_184_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 976 - .saturating_add(Weight::from_parts(554_293, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[0, 1000]`. - fn kill_prefix(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `132 + p * (69 ±0)` - // Estimated: `128 + p * (70 ±0)` - // Minimum execution time: 3_851_000 picoseconds. - Weight::from_parts(4_039_000, 0) - .saturating_add(Weight::from_parts(0, 128)) - // Standard Error: 1_612 - .saturating_add(Weight::from_parts(1_220_557, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/mod.rs b/polkadot/runtime/polkadot/src/weights/mod.rs deleted file mode 100644 index 596b594c93707388d8c2a36bd2531a616dffd3b3..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/mod.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A list of the different weight modules for our runtime. - -pub mod frame_election_provider_support; -pub mod frame_system; -pub mod pallet_bags_list; -pub mod pallet_balances; -pub mod pallet_bounties; -pub mod pallet_child_bounties; -pub mod pallet_collective_council; -pub mod pallet_collective_technical_committee; -pub mod pallet_conviction_voting; -pub mod pallet_democracy; -pub mod pallet_election_provider_multi_phase; -pub mod pallet_elections_phragmen; -pub mod pallet_fast_unstake; -pub mod pallet_identity; -pub mod pallet_im_online; -pub mod pallet_indices; -pub mod pallet_membership; -pub mod pallet_message_queue; -pub mod pallet_multisig; -pub mod pallet_nomination_pools; -pub mod pallet_preimage; -pub mod pallet_proxy; -pub mod pallet_referenda; -pub mod pallet_scheduler; -pub mod pallet_session; -pub mod pallet_staking; -pub mod pallet_timestamp; -pub mod pallet_tips; -pub mod pallet_treasury; -pub mod pallet_utility; -pub mod pallet_vesting; -pub mod pallet_whitelist; -pub mod pallet_xcm; -pub mod runtime_common_auctions; -pub mod runtime_common_claims; -pub mod runtime_common_crowdloan; -pub mod runtime_common_paras_registrar; -pub mod runtime_common_slots; -pub mod runtime_parachains_configuration; -pub mod runtime_parachains_disputes; -pub mod runtime_parachains_disputes_slashing; -pub mod runtime_parachains_hrmp; -pub mod runtime_parachains_inclusion; -pub mod runtime_parachains_initializer; -pub mod runtime_parachains_paras; -pub mod runtime_parachains_paras_inherent; -pub mod xcm; diff --git a/polkadot/runtime/polkadot/src/weights/pallet_bags_list.rs b/polkadot/runtime/polkadot/src/weights/pallet_bags_list.rs deleted file mode 100644 index 47decc88d73e0a80db09b776fd4c0b0a8eed2a22..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_bags_list.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_bags_list` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_bags_list -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_bags_list`. -pub struct WeightInfo(PhantomData); -impl pallet_bags_list::WeightInfo for WeightInfo { - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn rebag_non_terminal() -> Weight { - // Proof Size summary in bytes: - // Measured: `1622` - // Estimated: `11506` - // Minimum execution time: 61_742_000 picoseconds. - Weight::from_parts(63_696_000, 0) - .saturating_add(Weight::from_parts(0, 11506)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn rebag_terminal() -> Weight { - // Proof Size summary in bytes: - // Measured: `1516` - // Estimated: `8877` - // Minimum execution time: 60_247_000 picoseconds. - Weight::from_parts(62_096_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: VoterList ListNodes (r:4 w:4) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn put_in_front_of() -> Weight { - // Proof Size summary in bytes: - // Measured: `1827` - // Estimated: `11506` - // Minimum execution time: 67_049_000 picoseconds. - Weight::from_parts(68_704_000, 0) - .saturating_add(Weight::from_parts(0, 11506)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(6)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_bounties.rs b/polkadot/runtime/polkadot/src/weights/pallet_bounties.rs deleted file mode 100644 index 62a417832901954a01306579dba58bd5b7019c62..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_bounties.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_bounties` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_bounties -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_bounties`. -pub struct WeightInfo(PhantomData); -impl pallet_bounties::WeightInfo for WeightInfo { - /// Storage: Bounties BountyCount (r:1 w:1) - /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:0 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// The range of component `d` is `[0, 16384]`. - fn propose_bounty(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `3593` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_021_890, 0) - .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(757, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - fn approve_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3642` - // Minimum execution time: 11_055_000 picoseconds. - Weight::from_parts(11_875_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - fn propose_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `3642` - // Minimum execution time: 10_266_000 picoseconds. - Weight::from_parts(10_581_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn unassign_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `3642` - // Minimum execution time: 43_566_000 picoseconds. - Weight::from_parts(44_671_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn accept_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `461` - // Estimated: `3642` - // Minimum execution time: 28_400_000 picoseconds. - Weight::from_parts(29_259_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - fn award_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `439` - // Estimated: `3642` - // Minimum execution time: 20_071_000 picoseconds. - Weight::from_parts(20_662_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn claim_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `803` - // Estimated: `8799` - // Minimum execution time: 119_806_000 picoseconds. - Weight::from_parts(122_217_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_bounty_proposed() -> Weight { - // Proof Size summary in bytes: - // Measured: `483` - // Estimated: `3642` - // Minimum execution time: 48_528_000 picoseconds. - Weight::from_parts(49_592_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_bounty_active() -> Weight { - // Proof Size summary in bytes: - // Measured: `719` - // Estimated: `6196` - // Minimum execution time: 79_963_000 picoseconds. - Weight::from_parts(81_894_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - fn extend_bounty_expiry() -> Weight { - // Proof Size summary in bytes: - // Measured: `325` - // Estimated: `3642` - // Minimum execution time: 15_794_000 picoseconds. - Weight::from_parts(16_237_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:100 w:100) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:200 w:200) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `b` is `[0, 100]`. - fn spend_funds(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + b * (297 ±0)` - // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 5_312_000 picoseconds. - Weight::from_parts(5_480_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 12_652 - .saturating_add(Weight::from_parts(45_246_882, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_child_bounties.rs b/polkadot/runtime/polkadot/src/weights/pallet_child_bounties.rs deleted file mode 100644 index 0e885883f093c739892944729ba8b1a1ec545ca5..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_child_bounties.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_child_bounties` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_child_bounties -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_child_bounties`. -pub struct WeightInfo(PhantomData); -impl pallet_child_bounties::WeightInfo for WeightInfo { - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyCount (r:1 w:1) - /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:0 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// The range of component `d` is `[0, 16384]`. - fn add_child_bounty(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `579` - // Estimated: `6196` - // Minimum execution time: 71_357_000 picoseconds. - Weight::from_parts(73_240_027, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(830, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - fn propose_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `633` - // Estimated: `3642` - // Minimum execution time: 18_405_000 picoseconds. - Weight::from_parts(19_111_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn accept_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `779` - // Estimated: `3642` - // Minimum execution time: 33_467_000 picoseconds. - Weight::from_parts(34_246_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn unassign_curator() -> Weight { - // Proof Size summary in bytes: - // Measured: `779` - // Estimated: `3642` - // Minimum execution time: 49_658_000 picoseconds. - Weight::from_parts(50_457_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - fn award_child_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `676` - // Estimated: `3642` - // Minimum execution time: 22_723_000 picoseconds. - Weight::from_parts(23_232_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn claim_child_bounty() -> Weight { - // Proof Size summary in bytes: - // Measured: `648` - // Estimated: `8799` - // Minimum execution time: 119_809_000 picoseconds. - Weight::from_parts(120_890_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_child_bounty_added() -> Weight { - // Proof Size summary in bytes: - // Measured: `879` - // Estimated: `6196` - // Minimum execution time: 77_381_000 picoseconds. - Weight::from_parts(78_284_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Bounties Bounties (r:1 w:0) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBounties (r:1 w:1) - /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) - /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:1) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) - /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - fn close_child_bounty_active() -> Weight { - // Proof Size summary in bytes: - // Measured: `1066` - // Estimated: `8799` - // Minimum execution time: 95_032_000 picoseconds. - Weight::from_parts(96_932_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_collective_council.rs b/polkadot/runtime/polkadot/src/weights/pallet_collective_council.rs deleted file mode 100644 index 0d75865bf2e9e519516f473ae172598db8b4bbfe..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_collective_council.rs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: Council Members (r:1 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:100 w:100) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15762 + m * (1967 ±16) + p * (4332 ±16)` - // Minimum execution time: 17_563_000 picoseconds. - Weight::from_parts(17_790_000, 0) - .saturating_add(Weight::from_parts(0, 15762)) - // Standard Error: 43_106 - .saturating_add(Weight::from_parts(4_715_053, 0).saturating_mul(m.into())) - // Standard Error: 43_106 - .saturating_add(Weight::from_parts(8_200_250, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `103 + m * (32 ±0)` - // Estimated: `1589 + m * (32 ±0)` - // Minimum execution time: 16_175_000 picoseconds. - Weight::from_parts(15_361_457, 0) - .saturating_add(Weight::from_parts(0, 1589)) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_795, 0).saturating_mul(b.into())) - // Standard Error: 184 - .saturating_add(Weight::from_parts(14_177, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:0) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `103 + m * (32 ±0)` - // Estimated: `3569 + m * (32 ±0)` - // Minimum execution time: 18_948_000 picoseconds. - Weight::from_parts(18_240_525, 0) - .saturating_add(Weight::from_parts(0, 3569)) - // Standard Error: 21 - .saturating_add(Weight::from_parts(1_603, 0).saturating_mul(b.into())) - // Standard Error: 224 - .saturating_add(Weight::from_parts(22_805, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalCount (r:1 w:1) - /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `393 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3785 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 25_762_000 picoseconds. - Weight::from_parts(24_727_354, 0) - .saturating_add(Weight::from_parts(0, 3785)) - // Standard Error: 87 - .saturating_add(Weight::from_parts(3_653, 0).saturating_mul(b.into())) - // Standard Error: 908 - .saturating_add(Weight::from_parts(28_147, 0).saturating_mul(m.into())) - // Standard Error: 897 - .saturating_add(Weight::from_parts(198_752, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `842 + m * (64 ±0)` - // Estimated: `4306 + m * (64 ±0)` - // Minimum execution time: 26_644_000 picoseconds. - Weight::from_parts(27_694_655, 0) - .saturating_add(Weight::from_parts(0, 4306)) - // Standard Error: 624 - .saturating_add(Weight::from_parts(54_184, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `431 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3876 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_742_000 picoseconds. - Weight::from_parts(27_892_765, 0) - .saturating_add(Weight::from_parts(0, 3876)) - // Standard Error: 666 - .saturating_add(Weight::from_parts(35_102, 0).saturating_mul(m.into())) - // Standard Error: 649 - .saturating_add(Weight::from_parts(190_180, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `733 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4050 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 39_283_000 picoseconds. - Weight::from_parts(40_633_810, 0) - .saturating_add(Weight::from_parts(0, 4050)) - // Standard Error: 144 - .saturating_add(Weight::from_parts(3_292, 0).saturating_mul(b.into())) - // Standard Error: 1_524 - .saturating_add(Weight::from_parts(9_562, 0).saturating_mul(m.into())) - // Standard Error: 1_485 - .saturating_add(Weight::from_parts(237_159, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `451 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3896 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 30_417_000 picoseconds. - Weight::from_parts(30_840_007, 0) - .saturating_add(Weight::from_parts(0, 3896)) - // Standard Error: 662 - .saturating_add(Weight::from_parts(37_877, 0).saturating_mul(m.into())) - // Standard Error: 645 - .saturating_add(Weight::from_parts(189_312, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `753 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4070 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 41_630_000 picoseconds. - Weight::from_parts(42_847_316, 0) - .saturating_add(Weight::from_parts(0, 4070)) - // Standard Error: 134 - .saturating_add(Weight::from_parts(3_962, 0).saturating_mul(b.into())) - // Standard Error: 1_423 - .saturating_add(Weight::from_parts(22_489, 0).saturating_mul(m.into())) - // Standard Error: 1_387 - .saturating_add(Weight::from_parts(244_543, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `260 + p * (32 ±0)` - // Estimated: `1745 + p * (32 ±0)` - // Minimum execution time: 15_754_000 picoseconds. - Weight::from_parts(17_477_133, 0) - .saturating_add(Weight::from_parts(0, 1745)) - // Standard Error: 608 - .saturating_add(Weight::from_parts(178_320, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_collective_technical_committee.rs b/polkadot/runtime/polkadot/src/weights/pallet_collective_technical_committee.rs deleted file mode 100644 index 07fb1209b0a17b1a8990a0f71f81804d2d13314b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_collective_technical_committee.rs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: TechnicalCommittee Members (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:100 w:100) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15800 + m * (1967 ±16) + p * (4332 ±16)` - // Minimum execution time: 18_203_000 picoseconds. - Weight::from_parts(18_473_000, 0) - .saturating_add(Weight::from_parts(0, 15800)) - // Standard Error: 43_603 - .saturating_add(Weight::from_parts(4_734_955, 0).saturating_mul(m.into())) - // Standard Error: 43_603 - .saturating_add(Weight::from_parts(8_291_611, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `141 + m * (32 ±0)` - // Estimated: `1627 + m * (32 ±0)` - // Minimum execution time: 17_071_000 picoseconds. - Weight::from_parts(16_315_595, 0) - .saturating_add(Weight::from_parts(0, 1627)) - // Standard Error: 14 - .saturating_add(Weight::from_parts(1_706, 0).saturating_mul(b.into())) - // Standard Error: 146 - .saturating_add(Weight::from_parts(13_626, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:0) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `141 + m * (32 ±0)` - // Estimated: `3607 + m * (32 ±0)` - // Minimum execution time: 19_983_000 picoseconds. - Weight::from_parts(18_925_239, 0) - .saturating_add(Weight::from_parts(0, 3607)) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_664, 0).saturating_mul(b.into())) - // Standard Error: 176 - .saturating_add(Weight::from_parts(23_169, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalCount (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `431 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3823 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 26_490_000 picoseconds. - Weight::from_parts(25_739_853, 0) - .saturating_add(Weight::from_parts(0, 3823)) - // Standard Error: 77 - .saturating_add(Weight::from_parts(3_479, 0).saturating_mul(b.into())) - // Standard Error: 807 - .saturating_add(Weight::from_parts(28_438, 0).saturating_mul(m.into())) - // Standard Error: 796 - .saturating_add(Weight::from_parts(199_864, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `880 + m * (64 ±0)` - // Estimated: `4344 + m * (64 ±0)` - // Minimum execution time: 27_693_000 picoseconds. - Weight::from_parts(28_461_881, 0) - .saturating_add(Weight::from_parts(0, 4344)) - // Standard Error: 592 - .saturating_add(Weight::from_parts(55_442, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3914 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 28_958_000 picoseconds. - Weight::from_parts(28_772_598, 0) - .saturating_add(Weight::from_parts(0, 3914)) - // Standard Error: 673 - .saturating_add(Weight::from_parts(36_736, 0).saturating_mul(m.into())) - // Standard Error: 657 - .saturating_add(Weight::from_parts(191_282, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `771 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4088 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_599_000 picoseconds. - Weight::from_parts(40_617_733, 0) - .saturating_add(Weight::from_parts(0, 4088)) - // Standard Error: 122 - .saturating_add(Weight::from_parts(3_479, 0).saturating_mul(b.into())) - // Standard Error: 1_296 - .saturating_add(Weight::from_parts(34_407, 0).saturating_mul(m.into())) - // Standard Error: 1_263 - .saturating_add(Weight::from_parts(236_766, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `489 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3934 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 32_265_000 picoseconds. - Weight::from_parts(31_660_039, 0) - .saturating_add(Weight::from_parts(0, 3934)) - // Standard Error: 689 - .saturating_add(Weight::from_parts(39_118, 0).saturating_mul(m.into())) - // Standard Error: 672 - .saturating_add(Weight::from_parts(192_797, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `791 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4108 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 42_456_000 picoseconds. - Weight::from_parts(43_760_828, 0) - .saturating_add(Weight::from_parts(0, 4108)) - // Standard Error: 132 - .saturating_add(Weight::from_parts(3_531, 0).saturating_mul(b.into())) - // Standard Error: 1_397 - .saturating_add(Weight::from_parts(28_101, 0).saturating_mul(m.into())) - // Standard Error: 1_362 - .saturating_add(Weight::from_parts(248_244, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `298 + p * (32 ±0)` - // Estimated: `1783 + p * (32 ±0)` - // Minimum execution time: 16_506_000 picoseconds. - Weight::from_parts(18_127_000, 0) - .saturating_add(Weight::from_parts(0, 1783)) - // Standard Error: 616 - .saturating_add(Weight::from_parts(175_889, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/polkadot/src/weights/pallet_conviction_voting.rs deleted file mode 100644 index ce42464c292f742e6fcbcfb23f661961fc90fe19..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_conviction_voting.rs +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_conviction_voting` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_conviction_voting -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_conviction_voting`. -pub struct WeightInfo(PhantomData); -impl pallet_conviction_voting::WeightInfo for WeightInfo { - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn vote_new() -> Weight { - // Proof Size summary in bytes: - // Measured: `13551` - // Estimated: `42428` - // Minimum execution time: 154_104_000 picoseconds. - Weight::from_parts(162_701_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn vote_existing() -> Weight { - // Proof Size summary in bytes: - // Measured: `14272` - // Estimated: `83866` - // Minimum execution time: 241_839_000 picoseconds. - Weight::from_parts(251_787_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn remove_vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `14024` - // Estimated: `83866` - // Minimum execution time: 198_871_000 picoseconds. - Weight::from_parts(208_410_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - fn remove_other_vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `13110` - // Estimated: `30706` - // Minimum execution time: 86_480_000 picoseconds. - Weight::from_parts(90_343_000, 0) - .saturating_add(Weight::from_parts(0, 30706)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 512]`. - fn delegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `29746 + r * (365 ±0)` - // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 82_384_000 picoseconds. - Weight::from_parts(1_967_705_239, 0) - .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 169_648 - .saturating_add(Weight::from_parts(46_550_419, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) - } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 512]`. - fn undelegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `29661 + r * (365 ±0)` - // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 50_266_000 picoseconds. - Weight::from_parts(1_956_854_151, 0) - .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 172_335 - .saturating_add(Weight::from_parts(46_688_704, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) - } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn unlock() -> Weight { - // Proof Size summary in bytes: - // Measured: `12323` - // Estimated: `30706` - // Minimum execution time: 114_930_000 picoseconds. - Weight::from_parts(122_209_000, 0) - .saturating_add(Weight::from_parts(0, 30706)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_democracy.rs b/polkadot/runtime/polkadot/src/weights/pallet_democracy.rs deleted file mode 100644 index 069b10a2bcc5ad1949cb26120766334e8ed4a729..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_democracy.rs +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_democracy` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_democracy -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_democracy`. -pub struct WeightInfo(PhantomData); -impl pallet_democracy::WeightInfo for WeightInfo { - /// Storage: Democracy PublicPropCount (r:1 w:1) - /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:0 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `4768` - // Estimated: `18187` - // Minimum execution time: 47_165_000 picoseconds. - Weight::from_parts(48_488_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn second() -> Weight { - // Proof Size summary in bytes: - // Measured: `3523` - // Estimated: `6695` - // Minimum execution time: 41_328_000 picoseconds. - Weight::from_parts(42_526_000, 0) - .saturating_add(Weight::from_parts(0, 6695)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn vote_new() -> Weight { - // Proof Size summary in bytes: - // Measured: `3437` - // Estimated: `7260` - // Minimum execution time: 57_941_000 picoseconds. - Weight::from_parts(59_547_000, 0) - .saturating_add(Weight::from_parts(0, 7260)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn vote_existing() -> Weight { - // Proof Size summary in bytes: - // Measured: `3459` - // Estimated: `7260` - // Minimum execution time: 63_933_000 picoseconds. - Weight::from_parts(65_560_000, 0) - .saturating_add(Weight::from_parts(0, 7260)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Cancellations (r:1 w:1) - /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn emergency_cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `3666` - // Minimum execution time: 26_501_000 picoseconds. - Weight::from_parts(26_882_000, 0) - .saturating_add(Weight::from_parts(0, 3666)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:3 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:0 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn blacklist() -> Weight { - // Proof Size summary in bytes: - // Measured: `5877` - // Estimated: `18187` - // Minimum execution time: 111_868_000 picoseconds. - Weight::from_parts(116_733_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn external_propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `3383` - // Estimated: `6703` - // Minimum execution time: 13_786_000 picoseconds. - Weight::from_parts(14_280_000, 0) - .saturating_add(Weight::from_parts(0, 6703)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_majority() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_320_000 picoseconds. - Weight::from_parts(3_467_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_default() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_540_000 picoseconds. - Weight::from_parts(3_681_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:1) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:2) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn fast_track() -> Weight { - // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `3518` - // Minimum execution time: 28_074_000 picoseconds. - Weight::from_parts(28_980_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn veto_external() -> Weight { - // Proof Size summary in bytes: - // Measured: `3486` - // Estimated: `6703` - // Minimum execution time: 32_243_000 picoseconds. - Weight::from_parts(32_604_000, 0) - .saturating_add(Weight::from_parts(0, 6703)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn cancel_proposal() -> Weight { - // Proof Size summary in bytes: - // Measured: `5788` - // Estimated: `18187` - // Minimum execution time: 93_410_000 picoseconds. - Weight::from_parts(95_323_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn cancel_referendum() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3518` - // Minimum execution time: 20_185_000 picoseconds. - Weight::from_parts(20_661_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `211 + r * (86 ±0)` - // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 7_484_000 picoseconds. - Weight::from_parts(8_532_503, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 6_320 - .saturating_add(Weight::from_parts(3_176_208, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy LastTabledWasExternal (r:1 w:0) - /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `211 + r * (86 ±0)` - // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 10_406_000 picoseconds. - Weight::from_parts(11_689_093, 0) - .saturating_add(Weight::from_parts(0, 18187)) - // Standard Error: 7_450 - .saturating_add(Weight::from_parts(3_172_162, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:3 w:3) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn delegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `797 + r * (108 ±0)` - // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 42_210_000 picoseconds. - Weight::from_parts(47_151_756, 0) - .saturating_add(Weight::from_parts(0, 19800)) - // Standard Error: 9_095 - .saturating_add(Weight::from_parts(4_553_285, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:2 w:2) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn undelegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `460 + r * (108 ±0)` - // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 21_815_000 picoseconds. - Weight::from_parts(21_914_769, 0) - .saturating_add(Weight::from_parts(0, 13530)) - // Standard Error: 7_866 - .saturating_add(Weight::from_parts(4_497_036, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy PublicProps (r:0 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - fn clear_public_proposals() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_315_000 picoseconds. - Weight::from_parts(3_525_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_remove(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `7260` - // Minimum execution time: 25_326_000 picoseconds. - Weight::from_parts(40_406_995, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 3_775 - .saturating_add(Weight::from_parts(111_536, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_set(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `531 + r * (22 ±0)` - // Estimated: `7260` - // Minimum execution time: 35_263_000 picoseconds. - Weight::from_parts(39_034_189, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 2_263 - .saturating_add(Weight::from_parts(143_605, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `695 + r * (26 ±0)` - // Estimated: `7260` - // Minimum execution time: 15_880_000 picoseconds. - Weight::from_parts(19_395_916, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 1_616 - .saturating_add(Weight::from_parts(144_889, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_other_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `695 + r * (26 ±0)` - // Estimated: `7260` - // Minimum execution time: 16_157_000 picoseconds. - Weight::from_parts(19_671_561, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 1_803 - .saturating_add(Weight::from_parts(143_214, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `323` - // Estimated: `3556` - // Minimum execution time: 18_768_000 picoseconds. - Weight::from_parts(19_420_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `3518` - // Minimum execution time: 17_184_000 picoseconds. - Weight::from_parts(17_768_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4855` - // Estimated: `18187` - // Minimum execution time: 40_295_000 picoseconds. - Weight::from_parts(41_356_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4789` - // Estimated: `18187` - // Minimum execution time: 37_215_000 picoseconds. - Weight::from_parts(38_297_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 14_960_000 picoseconds. - Weight::from_parts(15_339_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3666` - // Minimum execution time: 19_182_000 picoseconds. - Weight::from_parts(19_788_000, 0) - .saturating_add(Weight::from_parts(0, 3666)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_election_provider_multi_phase.rs b/polkadot/runtime/polkadot/src/weights/pallet_election_provider_multi_phase.rs deleted file mode 100644 index f16da40e8eceb02293ac6d6149c6bc1bba2ecaab..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_election_provider_multi_phase.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_election_provider_multi_phase` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_election_provider_multi_phase -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_election_provider_multi_phase`. -pub struct WeightInfo(PhantomData); -impl pallet_election_provider_multi_phase::WeightInfo for WeightInfo { - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentPlannedSession (r:1 w:0) - /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Babe EpochIndex (r:1 w:0) - /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe GenesisSlot (r:1 w:0) - /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Staking ForceEra (r:1 w:0) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_nothing() -> Weight { - // Proof Size summary in bytes: - // Measured: `993` - // Estimated: `3481` - // Minimum execution time: 19_675_000 picoseconds. - Weight::from_parts(20_310_000, 0) - .saturating_add(Weight::from_parts(0, 3481)) - .saturating_add(T::DbWeight::get().reads(8)) - } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_open_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `1599` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_730_000, 0) - .saturating_add(Weight::from_parts(0, 1599)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - fn on_initialize_open_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `1599` - // Minimum execution time: 13_456_000 picoseconds. - Weight::from_parts(13_787_000, 0) - .saturating_add(Weight::from_parts(0, 1599)) - .saturating_add(T::DbWeight::get().reads(2)) - .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: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - fn finalize_signed_phase_accept_solution() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 33_871_000 picoseconds. - Weight::from_parts(34_289_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .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) - fn finalize_signed_phase_reject_solution() -> Weight { - // Proof Size summary in bytes: - // Measured: `174` - // Estimated: `3593` - // Minimum execution time: 22_897_000 picoseconds. - Weight::from_parts(23_307_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 556_279_000 picoseconds. - Weight::from_parts(581_580_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_088 - .saturating_add(Weight::from_parts(312_241, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn elect_queued(a: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `338 + a * (768 ±0) + d * (48 ±0)` - // Estimated: `3890 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 420_334_000 picoseconds. - Weight::from_parts(18_023_312, 0) - .saturating_add(Weight::from_parts(0, 3890)) - // Standard Error: 7_565 - .saturating_add(Weight::from_parts(659_974, 0).saturating_mul(a.into())) - // Standard Error: 11_339 - .saturating_add(Weight::from_parts(287_336, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(9)) - .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) - } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) - /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) - /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) - fn submit() -> Weight { - // Proof Size summary in bytes: - // Measured: `1204` - // Estimated: `2689` - // Minimum execution time: 49_669_000 picoseconds. - Weight::from_parts(52_076_000, 0) - .saturating_add(Weight::from_parts(0, 2689)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `219 + t * (32 ±0) + v * (553 ±0)` - // Estimated: `1704 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_966_688_000 picoseconds. - Weight::from_parts(6_129_265_000, 0) - .saturating_add(Weight::from_parts(0, 1704)) - // Standard Error: 20_174 - .saturating_add(Weight::from_parts(154_243, 0).saturating_mul(v.into())) - // Standard Error: 59_786 - .saturating_add(Weight::from_parts(5_709_666, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) - } - /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `a` is `[500, 800]`. - /// The range of component `d` is `[200, 400]`. - fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `194 + t * (32 ±0) + v * (553 ±0)` - // Estimated: `1679 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_058_457_000 picoseconds. - Weight::from_parts(5_216_393_000, 0) - .saturating_add(Weight::from_parts(0, 1679)) - // Standard Error: 15_829 - .saturating_add(Weight::from_parts(278_945, 0).saturating_mul(v.into())) - // Standard Error: 46_908 - .saturating_add(Weight::from_parts(3_239_889, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_elections_phragmen.rs b/polkadot/runtime/polkadot/src/weights/pallet_elections_phragmen.rs deleted file mode 100644 index e93de0c14c1c2190bfba6cdce9b1f9680ffb5ba4..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_elections_phragmen.rs +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_elections_phragmen` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_elections_phragmen -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_elections_phragmen`. -pub struct WeightInfo(PhantomData); -impl pallet_elections_phragmen::WeightInfo for WeightInfo { - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 16]`. - fn vote_equal(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `369 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 32_711_000 picoseconds. - Weight::from_parts(33_843_954, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 3_332 - .saturating_add(Weight::from_parts(148_060, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_more(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `337 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 46_078_000 picoseconds. - Weight::from_parts(46_574_818, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 3_834 - .saturating_add(Weight::from_parts(182_895, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_less(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `369 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 45_677_000 picoseconds. - Weight::from_parts(46_613_391, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 4_271 - .saturating_add(Weight::from_parts(180_095, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn remove_voter() -> Weight { - // Proof Size summary in bytes: - // Measured: `891` - // Estimated: `4764` - // Minimum execution time: 47_963_000 picoseconds. - Weight::from_parts(48_833_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn submit_candidacy(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2358 + c * (48 ±0)` - // Estimated: `3841 + c * (48 ±0)` - // Minimum execution time: 39_368_000 picoseconds. - Weight::from_parts(28_568_416, 0) - .saturating_add(Weight::from_parts(0, 3841)) - // Standard Error: 1_416 - .saturating_add(Weight::from_parts(131_107, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `250 + c * (48 ±0)` - // Estimated: `1722 + c * (48 ±0)` - // Minimum execution time: 34_977_000 picoseconds. - Weight::from_parts(24_677_388, 0) - .saturating_add(Weight::from_parts(0, 1722)) - // Standard Error: 1_498 - .saturating_add(Weight::from_parts(100_855, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_members() -> Weight { - // Proof Size summary in bytes: - // Measured: `2599` - // Estimated: `4084` - // Minimum execution time: 52_891_000 picoseconds. - Weight::from_parts(53_852_000, 0) - .saturating_add(Weight::from_parts(0, 4084)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_runners_up() -> Weight { - // Proof Size summary in bytes: - // Measured: `1711` - // Estimated: `3196` - // Minimum execution time: 36_514_000 picoseconds. - Weight::from_parts(37_441_000, 0) - .saturating_add(Weight::from_parts(0, 3196)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn remove_member_without_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn remove_member_with_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `2599` - // Estimated: `4084` - // Minimum execution time: 73_160_000 picoseconds. - Weight::from_parts(74_548_000, 0) - .saturating_add(Weight::from_parts(0, 4084)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: PhragmenElection Voting (r:10001 w:10000) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:10000 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `36028 + v * (808 ±0)` - // Estimated: `39768 + v * (3774 ±0)` - // Minimum execution time: 434_369_619_000 picoseconds. - Weight::from_parts(436_606_328_000, 0) - .saturating_add(Weight::from_parts(0, 39768)) - // Standard Error: 365_744 - .saturating_add(Weight::from_parts(53_633_149, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:10001 w:0) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:967 w:967) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection ElectionRounds (r:1 w:1) - /// Proof Skipped: PhragmenElection ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + e * (28 ±0) + v * (607 ±0)` - // Estimated: `2771984 + c * (2560 ±0) + e * (16 ±0) + v * (2744 ±4)` - // Minimum execution time: 39_817_678_000 picoseconds. - Weight::from_parts(40_023_537_000, 0) - .saturating_add(Weight::from_parts(0, 2771984)) - // Standard Error: 411_583 - .saturating_add(Weight::from_parts(34_005_169, 0).saturating_mul(v.into())) - // Standard Error: 26_412 - .saturating_add(Weight::from_parts(1_743_887, 0).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(269)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 2560).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 16).saturating_mul(e.into())) - .saturating_add(Weight::from_parts(0, 2744).saturating_mul(v.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_fast_unstake.rs b/polkadot/runtime/polkadot/src/weights/pallet_fast_unstake.rs deleted file mode 100644 index 38771e04cb5738a51f77d9565fa5bbf3fdef7fb6..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_fast_unstake.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_fast_unstake` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_fast_unstake -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_fast_unstake`. -pub struct WeightInfo(PhantomData); -impl pallet_fast_unstake::WeightInfo for WeightInfo { - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(886), added: 1381, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:16 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Bonded (r:16 w:16) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:16 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:16 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:16 w:16) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:16 w:16) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:16 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:16) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:16) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// The range of component `b` is `[1, 16]`. - fn on_idle_unstake(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1057 + b * (359 ±0)` - // Estimated: `2542 + b * (3774 ±0)` - // Minimum execution time: 89_149_000 picoseconds. - Weight::from_parts(41_025_862, 0) - .saturating_add(Weight::from_parts(0, 2542)) - // Standard Error: 41_892 - .saturating_add(Weight::from_parts(56_756_404, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:1) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(886), added: 1381, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:0) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:257 w:0) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[1, 256]`. - /// The range of component `b` is `[1, 16]`. - fn on_idle_check(v: u32, b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1411 + b * (48 ±0) + v * (19511 ±0)` - // Estimated: `4726 + b * (52 ±0) + v * (21987 ±0)` - // Minimum execution time: 645_357_000 picoseconds. - Weight::from_parts(650_793_000, 0) - .saturating_add(Weight::from_parts(0, 4726)) - // Standard Error: 5_811_859 - .saturating_add(Weight::from_parts(194_264_130, 0).saturating_mul(v.into())) - // Standard Error: 93_262_882 - .saturating_add(Weight::from_parts(2_905_419_408, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 52).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 21987).saturating_mul(v.into())) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(886), added: 1381, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn register_fast_unstake() -> Weight { - // Proof Size summary in bytes: - // Measured: `1919` - // Estimated: `6248` - // Minimum execution time: 128_072_000 picoseconds. - Weight::from_parts(133_183_000, 0) - .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(10)) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: FastUnstake Queue (r:1 w:1) - /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// Storage: FastUnstake Head (r:1 w:0) - /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(886), added: 1381, mode: MaxEncodedLen) - /// Storage: FastUnstake CounterForQueue (r:1 w:1) - /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn deregister() -> Weight { - // Proof Size summary in bytes: - // Measured: `1118` - // Estimated: `4556` - // Minimum execution time: 40_801_000 picoseconds. - Weight::from_parts(42_396_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) - /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn control() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_531_000 picoseconds. - Weight::from_parts(2_706_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_identity.rs b/polkadot/runtime/polkadot/src/weights/pallet_identity.rs deleted file mode 100644 index 8ec244ea127c10baafd7d2646b66dea919a83833..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_identity.rs +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_identity` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_identity -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_identity`. -pub struct WeightInfo(PhantomData); -impl pallet_identity::WeightInfo for WeightInfo { - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn add_registrar(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 12_135_000 picoseconds. - Weight::from_parts(12_609_967, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 2_052 - .saturating_add(Weight::from_parts(100_719, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn set_identity(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `442 + r * (5 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_888_000 picoseconds. - Weight::from_parts(30_128_985, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_003 - .saturating_add(Weight::from_parts(185_434, 0).saturating_mul(r.into())) - // Standard Error: 976 - .saturating_add(Weight::from_parts(470_886, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:100 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn set_subs_new(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `11003 + s * (2589 ±0)` - // Minimum execution time: 8_780_000 picoseconds. - Weight::from_parts(21_992_489, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 3_846 - .saturating_add(Weight::from_parts(3_111_150, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. - fn set_subs_old(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `194 + p * (32 ±0)` - // Estimated: `11003` - // Minimum execution time: 8_828_000 picoseconds. - Weight::from_parts(22_708_063, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 3_578 - .saturating_add(Weight::from_parts(1_303_160, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[0, 100]`. - /// The range of component `x` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 56_805_000 picoseconds. - Weight::from_parts(32_595_150, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 9_806 - .saturating_add(Weight::from_parts(148_154, 0).saturating_mul(r.into())) - // Standard Error: 1_915 - .saturating_add(Weight::from_parts(1_305_241, 0).saturating_mul(s.into())) - // Standard Error: 1_915 - .saturating_add(Weight::from_parts(253_271, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn request_judgement(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_747_000 picoseconds. - Weight::from_parts(30_894_600, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 3_575 - .saturating_add(Weight::from_parts(173_522, 0).saturating_mul(r.into())) - // Standard Error: 697 - .saturating_add(Weight::from_parts(484_893, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `398 + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_601_000 picoseconds. - Weight::from_parts(28_786_367, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 4_460 - .saturating_add(Weight::from_parts(120_240, 0).saturating_mul(r.into())) - // Standard Error: 870 - .saturating_add(Weight::from_parts(484_414, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_fee(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_562_000 picoseconds. - Weight::from_parts(8_106_958, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_945 - .saturating_add(Weight::from_parts(75_862, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_account_id(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_437_000 picoseconds. - Weight::from_parts(7_970_108, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_497 - .saturating_add(Weight::from_parts(93_785, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - fn set_fields(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `89 + r * (57 ±0)` - // Estimated: `2626` - // Minimum execution time: 7_337_000 picoseconds. - Weight::from_parts(7_782_268, 0) - .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_272 - .saturating_add(Weight::from_parts(97_602, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 19]`. - /// The range of component `x` is `[0, 100]`. - fn provide_judgement(r: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 22_825_000 picoseconds. - Weight::from_parts(21_046_708, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 5_012 - .saturating_add(Weight::from_parts(180_118, 0).saturating_mul(r.into())) - // Standard Error: 927 - .saturating_add(Weight::from_parts(788_617, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 20]`. - /// The range of component `s` is `[0, 100]`. - /// The range of component `x` is `[0, 100]`. - fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 75_635_000 picoseconds. - Weight::from_parts(47_274_783, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 11_632 - .saturating_add(Weight::from_parts(230_554, 0).saturating_mul(r.into())) - // Standard Error: 2_271 - .saturating_add(Weight::from_parts(1_333_461, 0).saturating_mul(s.into())) - // Standard Error: 2_271 - .saturating_add(Weight::from_parts(276_612, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 99]`. - fn add_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `475 + s * (36 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_374_000 picoseconds. - Weight::from_parts(33_426_262, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_171 - .saturating_add(Weight::from_parts(101_531, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn rename_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `591 + s * (3 ±0)` - // Estimated: `11003` - // Minimum execution time: 12_449_000 picoseconds. - Weight::from_parts(13_803_167, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 492 - .saturating_add(Weight::from_parts(39_985, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn remove_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `638 + s * (35 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_962_000 picoseconds. - Weight::from_parts(35_538_881, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_052 - .saturating_add(Weight::from_parts(96_317, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 99]`. - fn quit_sub(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `704 + s * (37 ±0)` - // Estimated: `6723` - // Minimum execution time: 25_233_000 picoseconds. - Weight::from_parts(27_271_178, 0) - .saturating_add(Weight::from_parts(0, 6723)) - // Standard Error: 897 - .saturating_add(Weight::from_parts(92_723, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_im_online.rs b/polkadot/runtime/polkadot/src/weights/pallet_im_online.rs deleted file mode 100644 index 93264c0c6991ec04e723ae3da29eebd5130e7117..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_im_online.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_im_online` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_im_online -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_im_online`. -pub struct WeightInfo(PhantomData); -impl pallet_im_online::WeightInfo for WeightInfo { - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ImOnline Keys (r:1 w:0) - /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) - /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) - /// Storage: ImOnline AuthoredBlocks (r:1 w:0) - /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 1000]`. - fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `361 + k * (32 ±0)` - // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 83_488_000 picoseconds. - Weight::from_parts(99_862_268, 0) - .saturating_add(Weight::from_parts(0, 321487)) - // Standard Error: 567 - .saturating_add(Weight::from_parts(35_207, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_indices.rs b/polkadot/runtime/polkadot/src/weights/pallet_indices.rs deleted file mode 100644 index 94f2285efc25e0d345b823277432f4235a7668cf..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_indices.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_indices` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_indices -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_indices`. -pub struct WeightInfo(PhantomData); -impl pallet_indices::WeightInfo for WeightInfo { - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `3534` - // Minimum execution time: 24_795_000 picoseconds. - Weight::from_parts(25_532_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `341` - // Estimated: `3593` - // Minimum execution time: 35_879_000 picoseconds. - Weight::from_parts(36_559_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn free() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3534` - // Minimum execution time: 25_628_000 picoseconds. - Weight::from_parts(26_584_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `341` - // Estimated: `3593` - // Minimum execution time: 28_963_000 picoseconds. - Weight::from_parts(29_722_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - fn freeze() -> Weight { - // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3534` - // Minimum execution time: 27_596_000 picoseconds. - Weight::from_parts(28_182_000, 0) - .saturating_add(Weight::from_parts(0, 3534)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_membership.rs b/polkadot/runtime/polkadot/src/weights/pallet_membership.rs deleted file mode 100644 index a4e5ce4a7bbb8f6b05f2c3934820f1628174984b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_membership.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_membership` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_membership -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_membership`. -pub struct WeightInfo(PhantomData); -impl pallet_membership::WeightInfo for WeightInfo { - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 99]`. - fn add_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `174 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 17_443_000 picoseconds. - Weight::from_parts(18_272_399, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 376 - .saturating_add(Weight::from_parts(33_633, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn remove_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `278 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_826_000 picoseconds. - Weight::from_parts(20_859_732, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 667 - .saturating_add(Weight::from_parts(33_155, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn swap_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `278 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_151_000 picoseconds. - Weight::from_parts(20_774_114, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 447 - .saturating_add(Weight::from_parts(44_052, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn reset_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `278 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_846_000 picoseconds. - Weight::from_parts(20_903_563, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 865 - .saturating_add(Weight::from_parts(149_306, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn change_key(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `278 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_523_000 picoseconds. - Weight::from_parts(21_705_085, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 948 - .saturating_add(Weight::from_parts(44_568, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:0) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn set_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 8_032_000 picoseconds. - Weight::from_parts(8_386_682, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 190 - .saturating_add(Weight::from_parts(9_724, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_061_000 picoseconds. - Weight::from_parts(3_304_217, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 80 - .saturating_add(Weight::from_parts(273, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_message_queue.rs b/polkadot/runtime/polkadot/src/weights/pallet_message_queue.rs deleted file mode 100644 index b0b9776b0114d95fc5cca0634c4ff7eaaa0ff1e6..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_message_queue.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_message_queue` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_message_queue -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_message_queue`. -pub struct WeightInfo(PhantomData); -impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn ready_ring_knit() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `6050` - // Minimum execution time: 12_778_000 picoseconds. - Weight::from_parts(13_167_000, 0) - .saturating_add(Weight::from_parts(0, 6050)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - fn ready_ring_unknit() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `6050` - // Minimum execution time: 11_910_000 picoseconds. - Weight::from_parts(12_318_000, 0) - .saturating_add(Weight::from_parts(0, 6050)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn service_queue_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `3520` - // Minimum execution time: 5_070_000 picoseconds. - Weight::from_parts(5_266_000, 0) - .saturating_add(Weight::from_parts(0, 3520)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - fn service_page_base_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `69051` - // Minimum execution time: 6_812_000 picoseconds. - Weight::from_parts(7_085_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - fn service_page_base_no_completion() -> Weight { - // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `69051` - // Minimum execution time: 7_136_000 picoseconds. - Weight::from_parts(7_392_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_page_item() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 92_069_000 picoseconds. - Weight::from_parts(92_769_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - fn bump_service_head() -> Weight { - // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `3520` - // Minimum execution time: 7_443_000 picoseconds. - Weight::from_parts(7_670_000, 0) - .saturating_add(Weight::from_parts(0, 3520)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn reap_page() -> Weight { - // Proof Size summary in bytes: - // Measured: `66030` - // Estimated: `69051` - // Minimum execution time: 67_176_000 picoseconds. - Weight::from_parts(68_406_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn execute_overweight_page_removed() -> Weight { - // Proof Size summary in bytes: - // Measured: `66030` - // Estimated: `69051` - // Minimum execution time: 83_156_000 picoseconds. - Weight::from_parts(85_134_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - fn execute_overweight_page_updated() -> Weight { - // Proof Size summary in bytes: - // Measured: `66030` - // Estimated: `69051` - // Minimum execution time: 125_205_000 picoseconds. - Weight::from_parts(127_325_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_multisig.rs b/polkadot/runtime/polkadot/src/weights/pallet_multisig.rs deleted file mode 100644 index 70df8a78d4f11b6605994a095daaeb842f89d304..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_multisig.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_multisig` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_multisig -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_multisig`. -pub struct WeightInfo(PhantomData); -impl pallet_multisig::WeightInfo for WeightInfo { - /// The range of component `z` is `[0, 10000]`. - fn as_multi_threshold_1(z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 13_729_000 picoseconds. - Weight::from_parts(14_236_505, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(610, 0).saturating_mul(z.into())) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// The range of component `s` is `[2, 100]`. - /// The range of component `z` is `[0, 10000]`. - fn as_multi_create(s: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `267 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 45_550_000 picoseconds. - Weight::from_parts(34_831_496, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 772 - .saturating_add(Weight::from_parts(120_012, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_567, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// The range of component `s` is `[3, 100]`. - /// The range of component `z` is `[0, 10000]`. - fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `286` - // Estimated: `6811` - // Minimum execution time: 29_794_000 picoseconds. - Weight::from_parts(20_091_975, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 775 - .saturating_add(Weight::from_parts(111_349, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_553, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `s` is `[2, 100]`. - /// The range of component `z` is `[0, 10000]`. - fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `392 + s * (33 ±0)` - // Estimated: `6811` - // Minimum execution time: 51_181_000 picoseconds. - Weight::from_parts(38_235_268, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 973 - .saturating_add(Weight::from_parts(145_449, 0).saturating_mul(s.into())) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_618, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// The range of component `s` is `[2, 100]`. - fn approve_as_multi_create(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `267 + s * (2 ±0)` - // Estimated: `6811` - // Minimum execution time: 33_278_000 picoseconds. - Weight::from_parts(33_697_154, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 863 - .saturating_add(Weight::from_parts(122_174, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// The range of component `s` is `[2, 100]`. - fn approve_as_multi_approve(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `286` - // Estimated: `6811` - // Minimum execution time: 18_541_000 picoseconds. - Weight::from_parts(19_007_991, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 847 - .saturating_add(Weight::from_parts(106_382, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// The range of component `s` is `[2, 100]`. - fn cancel_as_multi(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `458 + s * (1 ±0)` - // Estimated: `6811` - // Minimum execution time: 34_373_000 picoseconds. - Weight::from_parts(35_062_021, 0) - .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 770 - .saturating_add(Weight::from_parts(113_576, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_nomination_pools.rs b/polkadot/runtime/polkadot/src/weights/pallet_nomination_pools.rs deleted file mode 100644 index 7273389a08055be1d61a617b9e19b1d19f34a11d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_nomination_pools.rs +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_nomination_pools` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_nomination_pools -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_nomination_pools`. -pub struct WeightInfo(PhantomData); -impl pallet_nomination_pools::WeightInfo for WeightInfo { - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn join() -> Weight { - // Proof Size summary in bytes: - // Measured: `3195` - // Estimated: `8877` - // Minimum execution time: 191_933_000 picoseconds. - Weight::from_parts(199_790_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().writes(12)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `3205` - // Estimated: `8877` - // Minimum execution time: 189_630_000 picoseconds. - Weight::from_parts(195_241_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(12)) - } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `3152` - // Estimated: `8799` - // Minimum execution time: 220_371_000 picoseconds. - Weight::from_parts(224_963_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(12)) - } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn claim_payout() -> Weight { - // Proof Size summary in bytes: - // Measured: `1137` - // Estimated: `4182` - // Minimum execution time: 81_050_000 picoseconds. - Weight::from_parts(82_523_000, 0) - .saturating_add(Weight::from_parts(0, 4182)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `3475` - // Estimated: `8877` - // Minimum execution time: 174_402_000 picoseconds. - Weight::from_parts(180_701_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(20)) - .saturating_add(T::DbWeight::get().writes(13)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn pool_withdraw_unbonded(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1580` - // Estimated: `4764` - // Minimum execution time: 63_246_000 picoseconds. - Weight::from_parts(65_760_934, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_105 - .saturating_add(Weight::from_parts(61_621, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2008` - // Estimated: `4764` - // Minimum execution time: 133_264_000 picoseconds. - Weight::from_parts(137_557_538, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_409 - .saturating_add(Weight::from_parts(71_667, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(1197), added: 3672, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2364` - // Estimated: `6196` - // Minimum execution time: 223_680_000 picoseconds. - Weight::from_parts(232_248_103, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(21)) - .saturating_add(T::DbWeight::get().writes(18)) - } - /// Storage: NominationPools LastPoolId (r:1 w:1) - /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:1 w:0) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:1 w:0) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `1188` - // Estimated: `6196` - // Minimum execution time: 195_007_000 picoseconds. - Weight::from_parts(199_781_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(22)) - .saturating_add(T::DbWeight::get().writes(15)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 16]`. - fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1745` - // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 68_155_000 picoseconds. - Weight::from_parts(68_982_265, 0) - .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 9_798 - .saturating_add(Weight::from_parts(1_483_835, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - fn set_state() -> Weight { - // Proof Size summary in bytes: - // Measured: `1333` - // Estimated: `4556` - // Minimum execution time: 34_246_000 picoseconds. - Weight::from_parts(35_523_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForMetadata (r:1 w:1) - /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 256]`. - fn set_metadata(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3735` - // Minimum execution time: 14_742_000 picoseconds. - Weight::from_parts(15_414_886, 0) - .saturating_add(Weight::from_parts(0, 3735)) - // Standard Error: 140 - .saturating_add(Weight::from_parts(1_641, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools MinJoinBond (r:0 w:1) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:0 w:1) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:0 w:1) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:0 w:1) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_configs() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_186_000 picoseconds. - Weight::from_parts(6_325_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn update_roles() -> Weight { - // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3685` - // Minimum execution time: 20_194_000 picoseconds. - Weight::from_parts(21_006_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1908` - // Estimated: `4556` - // Minimum execution time: 66_180_000 picoseconds. - Weight::from_parts(68_446_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `736` - // Estimated: `3685` - // Minimum execution time: 32_843_000 picoseconds. - Weight::from_parts(33_862_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn set_commission_max() -> Weight { - // Proof Size summary in bytes: - // Measured: `537` - // Estimated: `3685` - // Minimum execution time: 19_565_000 picoseconds. - Weight::from_parts(20_103_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - fn set_commission_change_rate() -> Weight { - // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3685` - // Minimum execution time: 19_957_000 picoseconds. - Weight::from_parts(20_927_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools PoolMembers (r:1 w:0) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:1 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - fn set_claim_permission() -> Weight { - // Proof Size summary in bytes: - // Measured: `508` - // Estimated: `4182` - // Minimum execution time: 15_092_000 picoseconds. - Weight::from_parts(15_507_000, 0) - .saturating_add(Weight::from_parts(0, 4182)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn claim_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `934` - // Estimated: `3685` - // Minimum execution time: 63_775_000 picoseconds. - Weight::from_parts(65_498_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_offences.rs b/polkadot/runtime/polkadot/src/weights/pallet_offences.rs deleted file mode 100644 index 1233133dfa3916465ecc2e087558745ecd13910c..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_offences.rs +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_offences` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_offences -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_offences`. -pub struct WeightInfo(PhantomData); -impl pallet_offences::WeightInfo for WeightInfo { - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:100 w:100) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:100 w:100) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1700 w:1700) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:1700 w:1700) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:100 w:100) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:299 w:299) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:100 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:1600 w:1600) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[1, 100]`. - /// The range of component `o` is `[2, 100]`. - /// The range of component `n` is `[0, 16]`. - fn report_offence_im_online(_r: u32, o: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (3454 ±0) + o * (1042 ±0)` - // Estimated: `88614 + n * (157019 ±1_888) + o * (26384 ±310)` - // Minimum execution time: 528_759_000 picoseconds. - Weight::from_parts(538_714_000, 0) - .saturating_add(Weight::from_parts(0, 88614)) - // Standard Error: 3_704_868 - .saturating_add(Weight::from_parts(378_188_057, 0).saturating_mul(o.into())) - // Standard Error: 22_512_446 - .saturating_add(Weight::from_parts(389_244_693, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(124)) - .saturating_add(T::DbWeight::get().reads((37_u64).saturating_mul(o.into()))) - .saturating_add(T::DbWeight::get().reads((187_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(117)) - .saturating_add(T::DbWeight::get().writes((36_u64).saturating_mul(o.into()))) - .saturating_add(T::DbWeight::get().writes((187_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 157019).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 26384).saturating_mul(o.into())) - } - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:17 w:17) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:17 w:17) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:16 w:16) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 16]`. - fn report_offence_grandpa(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1709 + n * (66 ±0)` - // Estimated: `5520 + n * (2551 ±0)` - // Minimum execution time: 92_527_000 picoseconds. - Weight::from_parts(104_194_764, 0) - .saturating_add(Weight::from_parts(0, 5520)) - // Standard Error: 32_501 - .saturating_add(Weight::from_parts(11_219_757, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(13)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2551).saturating_mul(n.into())) - } - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:17 w:17) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:17 w:17) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking NominatorSlashInEra (r:16 w:16) - /// Proof: Staking NominatorSlashInEra (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 16]`. - fn report_offence_babe(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1709 + n * (66 ±0)` - // Estimated: `5520 + n * (2551 ±0)` - // Minimum execution time: 93_431_000 picoseconds. - Weight::from_parts(104_636_499, 0) - .saturating_add(Weight::from_parts(0, 5520)) - // Standard Error: 31_475 - .saturating_add(Weight::from_parts(11_183_248, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(19)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(13)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2551).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs b/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs deleted file mode 100644 index a283f09eae5f8224189bee22e461ee0d3eec6ab5..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_preimage.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_preimage` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_preimage -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_preimage`. -pub struct WeightInfo(PhantomData); -impl pallet_preimage::WeightInfo for WeightInfo { - fn ensure_updated(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(2_000_000, 3593) - // Standard Error: 13_720 - .saturating_add(Weight::from_parts(17_309_199, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) - } - - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `143` - // Estimated: `3556` - // Minimum execution time: 31_712_000 picoseconds. - Weight::from_parts(32_014_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_433, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_requested_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 16_935_000 picoseconds. - Weight::from_parts(17_306_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(2_448, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 4194304]`. - fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 16_600_000 picoseconds. - Weight::from_parts(16_837_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(2_424, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unnote_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `3556` - // Minimum execution time: 50_349_000 picoseconds. - Weight::from_parts(55_322_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unnote_no_deposit_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 32_867_000 picoseconds. - Weight::from_parts(36_581_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `188` - // Estimated: `3556` - // Minimum execution time: 27_810_000 picoseconds. - Weight::from_parts(30_821_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_no_deposit_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 17_455_000 picoseconds. - Weight::from_parts(19_842_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_unnoted_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `3556` - // Minimum execution time: 19_593_000 picoseconds. - Weight::from_parts(22_947_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn request_requested_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 11_066_000 picoseconds. - Weight::from_parts(12_720_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) - fn unrequest_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `3556` - // Minimum execution time: 28_739_000 picoseconds. - Weight::from_parts(31_484_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn unrequest_unnoted_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 10_424_000 picoseconds. - Weight::from_parts(11_233_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn unrequest_multi_referenced_preimage() -> Weight { - // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3556` - // Minimum execution time: 11_087_000 picoseconds. - Weight::from_parts(12_055_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_proxy.rs b/polkadot/runtime/polkadot/src/weights/pallet_proxy.rs deleted file mode 100644 index 662b610f86ba845a8df8b336d5258b6cf448c403..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_proxy.rs +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_proxy` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_proxy -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_proxy`. -pub struct WeightInfo(PhantomData); -impl pallet_proxy::WeightInfo for WeightInfo { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 15_142_000 picoseconds. - Weight::from_parts(15_809_707, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 889 - .saturating_add(Weight::from_parts(29_639, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `554 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 38_116_000 picoseconds. - Weight::from_parts(38_591_703, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 2_336 - .saturating_add(Weight::from_parts(169_558, 0).saturating_mul(a.into())) - // Standard Error: 2_414 - .saturating_add(Weight::from_parts(25_502, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, _p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_792_000 picoseconds. - Weight::from_parts(26_160_353, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_738 - .saturating_add(Weight::from_parts(157_640, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, _p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 24_905_000 picoseconds. - Weight::from_parts(26_368_411, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_895 - .saturating_add(Weight::from_parts(155_491, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. - fn announce(a: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `486 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 34_820_000 picoseconds. - Weight::from_parts(35_236_824, 0) - .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_574 - .saturating_add(Weight::from_parts(166_722, 0).saturating_mul(a.into())) - // Standard Error: 1_626 - .saturating_add(Weight::from_parts(25_405, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn add_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_820_000 picoseconds. - Weight::from_parts(27_003_669, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_555 - .saturating_add(Weight::from_parts(65_038, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxy(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 26_328_000 picoseconds. - Weight::from_parts(27_336_521, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_703 - .saturating_add(Weight::from_parts(57_107, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn remove_proxies(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_016_000 picoseconds. - Weight::from_parts(23_867_116, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_227 - .saturating_add(Weight::from_parts(38_349, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `4706` - // Minimum execution time: 27_525_000 picoseconds. - Weight::from_parts(28_670_720, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_869 - .saturating_add(Weight::from_parts(16_659, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 30]`. - fn kill_pure(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `264 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_877_000 picoseconds. - Weight::from_parts(24_530_683, 0) - .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_569 - .saturating_add(Weight::from_parts(49_912, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_referenda.rs b/polkadot/runtime/polkadot/src/weights/pallet_referenda.rs deleted file mode 100644 index 7f6fb0419c76b54ca933dea5baf457266eeaae41..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_referenda.rs +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_referenda` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_referenda -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_referenda`. -pub struct WeightInfo(PhantomData); -impl pallet_referenda::WeightInfo for WeightInfo { - /// Storage: Referenda ReferendumCount (r:1 w:1) - /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:0 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - fn submit() -> Weight { - // Proof Size summary in bytes: - // Measured: `291` - // Estimated: `42428` - // Minimum execution time: 40_432_000 picoseconds. - Weight::from_parts(41_423_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `544` - // Estimated: `83866` - // Minimum execution time: 52_009_000 picoseconds. - Weight::from_parts(54_126_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `3331` - // Estimated: `42428` - // Minimum execution time: 69_077_000 picoseconds. - Weight::from_parts(71_533_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `3351` - // Estimated: `42428` - // Minimum execution time: 68_115_000 picoseconds. - Weight::from_parts(70_485_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `544` - // Estimated: `83866` - // Minimum execution time: 64_860_000 picoseconds. - Weight::from_parts(66_772_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `544` - // Estimated: `83866` - // Minimum execution time: 63_403_000 picoseconds. - Weight::from_parts(64_420_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - fn refund_decision_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `384` - // Estimated: `4401` - // Minimum execution time: 31_560_000 picoseconds. - Weight::from_parts(32_111_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - fn refund_submission_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `374` - // Estimated: `4401` - // Minimum execution time: 31_536_000 picoseconds. - Weight::from_parts(32_118_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `83866` - // Minimum execution time: 39_132_000 picoseconds. - Weight::from_parts(39_878_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:0) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn kill() -> Weight { - // Proof Size summary in bytes: - // Measured: `693` - // Estimated: `83866` - // Minimum execution time: 105_261_000 picoseconds. - Weight::from_parts(106_923_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda TrackQueue (r:1 w:0) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - fn one_fewer_deciding_queue_empty() -> Weight { - // Proof Size summary in bytes: - // Measured: `207` - // Estimated: `5477` - // Minimum execution time: 9_171_000 picoseconds. - Weight::from_parts(9_585_000, 0) - .saturating_add(Weight::from_parts(0, 5477)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `3221` - // Estimated: `42428` - // Minimum execution time: 49_135_000 picoseconds. - Weight::from_parts(50_860_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `3221` - // Estimated: `42428` - // Minimum execution time: 53_279_000 picoseconds. - Weight::from_parts(54_069_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - fn nudge_referendum_requeued_insertion() -> Weight { - // Proof Size summary in bytes: - // Measured: `3044` - // Estimated: `5477` - // Minimum execution time: 22_537_000 picoseconds. - Weight::from_parts(23_853_000, 0) - .saturating_add(Weight::from_parts(0, 5477)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - fn nudge_referendum_requeued_slide() -> Weight { - // Proof Size summary in bytes: - // Measured: `3044` - // Estimated: `5477` - // Minimum execution time: 22_686_000 picoseconds. - Weight::from_parts(23_947_000, 0) - .saturating_add(Weight::from_parts(0, 5477)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - fn nudge_referendum_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `3048` - // Estimated: `5477` - // Minimum execution time: 28_373_000 picoseconds. - Weight::from_parts(29_033_000, 0) - .saturating_add(Weight::from_parts(0, 5477)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:0) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Referenda TrackQueue (r:1 w:1) - /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) - fn nudge_referendum_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `3068` - // Estimated: `5477` - // Minimum execution time: 28_137_000 picoseconds. - Weight::from_parts(28_716_000, 0) - .saturating_add(Weight::from_parts(0, 5477)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_no_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `404` - // Estimated: `42428` - // Minimum execution time: 25_880_000 picoseconds. - Weight::from_parts(26_405_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `42428` - // Minimum execution time: 26_349_000 picoseconds. - Weight::from_parts(27_181_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - fn nudge_referendum_timed_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `4401` - // Minimum execution time: 17_735_000 picoseconds. - Weight::from_parts(18_130_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `42428` - // Minimum execution time: 36_244_000 picoseconds. - Weight::from_parts(37_174_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda DecidingCount (r:1 w:1) - /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `452` - // Estimated: `42428` - // Minimum execution time: 38_250_000 picoseconds. - Weight::from_parts(38_771_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `42428` - // Minimum execution time: 31_177_000 picoseconds. - Weight::from_parts(31_886_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_end_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `488` - // Estimated: `42428` - // Minimum execution time: 31_826_000 picoseconds. - Weight::from_parts(32_664_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_not_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `42428` - // Minimum execution time: 28_957_000 picoseconds. - Weight::from_parts(29_810_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `509` - // Estimated: `42428` - // Minimum execution time: 28_002_000 picoseconds. - Weight::from_parts(28_440_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - fn nudge_referendum_approved() -> Weight { - // Proof Size summary in bytes: - // Measured: `509` - // Estimated: `83866` - // Minimum execution time: 43_527_000 picoseconds. - Weight::from_parts(44_536_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_rejected() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `42428` - // Minimum execution time: 31_767_000 picoseconds. - Weight::from_parts(32_407_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:0 w:1) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn set_some_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `455` - // Estimated: `4401` - // Minimum execution time: 21_013_000 picoseconds. - Weight::from_parts(21_503_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Referenda MetadataOf (r:1 w:1) - /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn clear_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `4401` - // Minimum execution time: 18_535_000 picoseconds. - Weight::from_parts(19_056_000, 0) - .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_scheduler.rs b/polkadot/runtime/polkadot/src/weights/pallet_scheduler.rs deleted file mode 100644 index 79ad62954ec66bea85994112976fa9966d991f7e..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_scheduler.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_scheduler` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_scheduler -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_scheduler`. -pub struct WeightInfo(PhantomData); -impl pallet_scheduler::WeightInfo for WeightInfo { - /// Storage: Scheduler IncompleteSince (r:1 w:1) - /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn service_agendas_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1489` - // Minimum execution time: 5_003_000 picoseconds. - Weight::from_parts(5_239_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 50]`. - fn service_agenda_base(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 4_577_000 picoseconds. - Weight::from_parts(7_388_958, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_944 - .saturating_add(Weight::from_parts(898_872, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_base() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_430_000 picoseconds. - Weight::from_parts(5_696_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: Preimage PreimageFor (r:1 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// The range of component `s` is `[128, 4194304]`. - fn service_task_fetched(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `179 + s * (1 ±0)` - // Estimated: `3644 + s * (1 ±0)` - // Minimum execution time: 20_567_000 picoseconds. - Weight::from_parts(20_856_000, 0) - .saturating_add(Weight::from_parts(0, 3644)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) - } - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - fn service_task_named() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_013_000 picoseconds. - Weight::from_parts(7_231_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn service_task_periodic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_486_000 picoseconds. - Weight::from_parts(5_656_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_532_000 picoseconds. - Weight::from_parts(2_635_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_dispatch_unsigned() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_502_000 picoseconds. - Weight::from_parts(2_615_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 49]`. - fn schedule(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 14_011_000 picoseconds. - Weight::from_parts(16_753_097, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_751 - .saturating_add(Weight::from_parts(908_905, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:0 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 50]`. - fn cancel(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `116 + s * (177 ±0)` - // Estimated: `42428` - // Minimum execution time: 18_326_000 picoseconds. - Weight::from_parts(17_114_477, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_468 - .saturating_add(Weight::from_parts(1_642_647, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 49]`. - fn schedule_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `293 + s * (185 ±0)` - // Estimated: `42428` - // Minimum execution time: 16_885_000 picoseconds. - Weight::from_parts(20_432_099, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_865 - .saturating_add(Weight::from_parts(954_709, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 50]`. - fn cancel_named(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `319 + s * (185 ±0)` - // Estimated: `42428` - // Minimum execution time: 19_988_000 picoseconds. - Weight::from_parts(19_533_754, 0) - .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 3_226 - .saturating_add(Weight::from_parts(1_671_811, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_session.rs b/polkadot/runtime/polkadot/src/weights/pallet_session.rs deleted file mode 100644 index 53f470ef5340b10b9ef51dd3ed4696780112c86e..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_session.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_session` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_session -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_session`. -pub struct WeightInfo(PhantomData); -impl pallet_session::WeightInfo for WeightInfo { - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:6 w:6) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - fn set_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `1920` - // Estimated: `17760` - // Minimum execution time: 59_408_000 picoseconds. - Weight::from_parts(60_600_000, 0) - .saturating_add(Weight::from_parts(0, 17760)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session KeyOwner (r:0 w:6) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - fn purge_keys() -> Weight { - // Proof Size summary in bytes: - // Measured: `1784` - // Estimated: `5249` - // Minimum execution time: 42_078_000 picoseconds. - Weight::from_parts(43_200_000, 0) - .saturating_add(Weight::from_parts(0, 5249)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_staking.rs b/polkadot/runtime/polkadot/src/weights/pallet_staking.rs deleted file mode 100644 index 80a60467eda137aeda6ee08460537679af4b40f9..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_staking.rs +++ /dev/null @@ -1,796 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_staking` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_staking -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_staking`. -pub struct WeightInfo(PhantomData); -impl pallet_staking::WeightInfo for WeightInfo { - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn bond() -> Weight { - // Proof Size summary in bytes: - // Measured: `980` - // Estimated: `4764` - // Minimum execution time: 52_344_000 picoseconds. - Weight::from_parts(53_469_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra() -> Weight { - // Proof Size summary in bytes: - // Measured: `1925` - // Estimated: `8877` - // Minimum execution time: 96_497_000 picoseconds. - Weight::from_parts(98_479_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `2132` - // Estimated: `8877` - // Minimum execution time: 98_872_000 picoseconds. - Weight::from_parts(101_630_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `947` - // Estimated: `4764` - // Minimum execution time: 42_427_000 picoseconds. - Weight::from_parts(44_370_898, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_286 - .saturating_add(Weight::from_parts(49_383, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2185 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 95_067_000 picoseconds. - Weight::from_parts(101_507_625, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_419 - .saturating_add(Weight::from_parts(1_387_390, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:1 w:0) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:1 w:0) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn validate() -> Weight { - // Proof Size summary in bytes: - // Measured: `1309` - // Estimated: `4556` - // Minimum execution time: 58_106_000 picoseconds. - Weight::from_parts(59_755_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:128 w:128) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// The range of component `k` is `[1, 128]`. - fn kick(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1214 + k * (569 ±0)` - // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 30_053_000 picoseconds. - Weight::from_parts(30_456_129, 0) - .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 8_026 - .saturating_add(Weight::from_parts(9_197_360, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 16]`. - fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1805 + n * (102 ±0)` - // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_438_000 picoseconds. - Weight::from_parts(65_922_031, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 13_125 - .saturating_add(Weight::from_parts(4_057_833, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1639` - // Estimated: `6248` - // Minimum execution time: 61_082_000 picoseconds. - Weight::from_parts(62_694_000, 0) - .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - fn set_payee() -> Weight { - // Proof Size summary in bytes: - // Measured: `737` - // Estimated: `4556` - // Minimum execution time: 14_638_000 picoseconds. - Weight::from_parts(15_251_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:2) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - fn set_controller() -> Weight { - // Proof Size summary in bytes: - // Measured: `836` - // Estimated: `8122` - // Minimum execution time: 21_077_000 picoseconds. - Weight::from_parts(21_635_000, 0) - .saturating_add(Weight::from_parts(0, 8122)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_validator_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_006_000 picoseconds. - Weight::from_parts(3_176_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_no_eras() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_462_000 picoseconds. - Weight::from_parts(9_740_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_new_era() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_279_000 picoseconds. - Weight::from_parts(9_662_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - fn force_new_era_always() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 9_346_000 picoseconds. - Weight::from_parts(9_708_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `v` is `[0, 1000]`. - fn set_invulnerables(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_120_000 picoseconds. - Weight::from_parts(3_442_453, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 40 - .saturating_add(Weight::from_parts(12_464, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[0, 100]`. - fn force_unstake(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1911 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_885_000 picoseconds. - Weight::from_parts(92_726_876, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_614 - .saturating_add(Weight::from_parts(1_393_582, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(12)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1000]`. - fn cancel_deferred_slash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `66572` - // Estimated: `70037` - // Minimum execution time: 131_927_000 picoseconds. - Weight::from_parts(933_717_768, 0) - .saturating_add(Weight::from_parts(0, 70037)) - // Standard Error: 57_864 - .saturating_add(Weight::from_parts(4_834_464, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:513 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:513 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:513 w:513) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 512]`. - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `34179 + n * (150 ±0)` - // Estimated: `32391 + n * (2603 ±0)` - // Minimum execution time: 118_319_000 picoseconds. - Weight::from_parts(150_596_293, 0) - .saturating_add(Weight::from_parts(0, 32391)) - // Standard Error: 18_978 - .saturating_add(Weight::from_parts(34_357_240, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:513 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:513 w:513) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:513 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:513 w:513) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:513 w:513) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:513 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 512]`. - fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `58153 + n * (388 ±0)` - // Estimated: `53040 + n * (3774 ±0)` - // Minimum execution time: 140_238_000 picoseconds. - Weight::from_parts(80_637_879, 0) - .saturating_add(Weight::from_parts(0, 53040)) - // Standard Error: 53_109 - .saturating_add(Weight::from_parts(55_488_791, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// The range of component `l` is `[1, 32]`. - fn rebond(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1926 + l * (5 ±0)` - // Estimated: `8877` - // Minimum execution time: 89_764_000 picoseconds. - Weight::from_parts(92_966_007, 0) - .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 4_077 - .saturating_add(Weight::from_parts(44_963, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// The range of component `s` is `[1, 100]`. - fn reap_stash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2185 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 102_828_000 picoseconds. - Weight::from_parts(104_295_311, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_221 - .saturating_add(Weight::from_parts(1_380_506, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(11)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:178 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:110 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:110 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:11 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:110 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:110 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinimumValidatorCount (r:1 w:0) - /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:1) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:0 w:10) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:0 w:10) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:0 w:10) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasTotalStake (r:0 w:1) - /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:0 w:1) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 10]`. - /// The range of component `n` is `[0, 100]`. - fn new_era(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±3) + v * (3566 ±38)` - // Minimum execution time: 543_692_000 picoseconds. - Weight::from_parts(548_108_000, 0) - .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_062_056 - .saturating_add(Weight::from_parts(64_901_773, 0).saturating_mul(v.into())) - // Standard Error: 205_472 - .saturating_add(Weight::from_parts(18_855_795, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(185)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(5)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:178 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2000 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:2000 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1000 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2000 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2000 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// The range of component `v` is `[500, 1000]`. - /// The range of component `n` is `[500, 1000]`. - fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `3117 + n * (907 ±0) + v * (391 ±0)` - // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 36_757_500_000 picoseconds. - Weight::from_parts(37_291_052_000, 0) - .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 408_866 - .saturating_add(Weight::from_parts(5_324_689, 0).saturating_mul(v.into())) - // Standard Error: 408_866 - .saturating_add(Weight::from_parts(4_075_058, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(180)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) - } - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1001 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: System BlockWeight (r:1 w:1) - /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) - /// The range of component `v` is `[500, 1000]`. - fn get_npos_targets(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `917 + v * (50 ±0)` - // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_558_883_000 picoseconds. - Weight::from_parts(85_901_228, 0) - .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 7_392 - .saturating_add(Weight::from_parts(5_071_697, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - fn set_staking_configs_all_set() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_298_000 picoseconds. - Weight::from_parts(6_596_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - fn set_staking_configs_all_remove() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_901_000 picoseconds. - Weight::from_parts(6_092_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:1 w:0) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn chill_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `1762` - // Estimated: `6248` - // Minimum execution time: 72_549_000 picoseconds. - Weight::from_parts(74_685_000, 0) - .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - fn force_apply_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `627` - // Estimated: `3510` - // Minimum execution time: 13_882_000 picoseconds. - Weight::from_parts(14_453_000, 0) - .saturating_add(Weight::from_parts(0, 3510)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn set_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_998_000 picoseconds. - Weight::from_parts(3_175_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_tips.rs b/polkadot/runtime/polkadot/src/weights/pallet_tips.rs deleted file mode 100644 index 62e08e017a877e7e9026590839c4e06981b20883..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_tips.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_tips` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_tips -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_tips`. -pub struct WeightInfo(PhantomData); -impl pallet_tips::WeightInfo for WeightInfo { - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - fn report_awesome(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3469` - // Minimum execution time: 28_332_000 picoseconds. - Weight::from_parts(29_229_064, 0) - .saturating_add(Weight::from_parts(0, 3469)) - // Standard Error: 20 - .saturating_add(Weight::from_parts(1_717, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - fn retract_tip() -> Weight { - // Proof Size summary in bytes: - // Measured: `221` - // Estimated: `3686` - // Minimum execution time: 28_421_000 picoseconds. - Weight::from_parts(29_235_000, 0) - .saturating_add(Weight::from_parts(0, 3686)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:0 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - /// The range of component `t` is `[1, 13]`. - fn tip_new(r: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `74 + t * (64 ±0)` - // Estimated: `3539 + t * (64 ±0)` - // Minimum execution time: 19_215_000 picoseconds. - Weight::from_parts(18_521_677, 0) - .saturating_add(Weight::from_parts(0, 3539)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_600, 0).saturating_mul(r.into())) - // Standard Error: 5_637 - .saturating_add(Weight::from_parts(171_000, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 13]`. - fn tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `295 + t * (112 ±0)` - // Estimated: `3760 + t * (112 ±0)` - // Minimum execution time: 15_664_000 picoseconds. - Weight::from_parts(16_047_212, 0) - .saturating_add(Weight::from_parts(0, 3760)) - // Standard Error: 1_859 - .saturating_add(Weight::from_parts(133_685, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 13]`. - fn close_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `334 + t * (112 ±0)` - // Estimated: `3790 + t * (112 ±0)` - // Minimum execution time: 61_465_000 picoseconds. - Weight::from_parts(62_876_205, 0) - .saturating_add(Weight::from_parts(0, 3790)) - // Standard Error: 6_840 - .saturating_add(Weight::from_parts(133_654, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 13]`. - fn slash_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3734` - // Minimum execution time: 14_539_000 picoseconds. - Weight::from_parts(15_138_065, 0) - .saturating_add(Weight::from_parts(0, 3734)) - // Standard Error: 1_577 - .saturating_add(Weight::from_parts(6_176, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_treasury.rs b/polkadot/runtime/polkadot/src/weights/pallet_treasury.rs deleted file mode 100644 index 669bfdeb7cfd4f831d39ac11e8a90fc66d5c5d42..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_treasury.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_treasury` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_treasury -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_treasury`. -pub struct WeightInfo(PhantomData); -impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend() -> Weight { - // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `1887` - // Minimum execution time: 14_843_000 picoseconds. - Weight::from_parts(15_346_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn propose_spend() -> Weight { - // Proof Size summary in bytes: - // Measured: `107` - // Estimated: `1489` - // Minimum execution time: 27_443_000 picoseconds. - Weight::from_parts(28_046_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Treasury Proposals (r:1 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn reject_proposal() -> Weight { - // Proof Size summary in bytes: - // Measured: `265` - // Estimated: `3593` - // Minimum execution time: 42_227_000 picoseconds. - Weight::from_parts(44_158_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Treasury Proposals (r:1 w:0) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 99]`. - fn approve_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `433 + p * (8 ±0)` - // Estimated: `3573` - // Minimum execution time: 9_538_000 picoseconds. - Weight::from_parts(11_238_300, 0) - .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 1_300 - .saturating_add(Weight::from_parts(72_785, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `90` - // Estimated: `1887` - // Minimum execution time: 7_582_000 picoseconds. - Weight::from_parts(7_778_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Treasury Deactivated (r:1 w:1) - /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:100 w:100) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:200 w:200) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. - fn on_initialize_proposals(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `251 + p * (251 ±0)` - // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 45_157_000 picoseconds. - Weight::from_parts(40_228_554, 0) - .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 17_245 - .saturating_add(Weight::from_parts(43_213_942, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_utility.rs b/polkadot/runtime/polkadot/src/weights/pallet_utility.rs deleted file mode 100644 index 1315ad6f8c44787ba936d49474034889bb67d073..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_utility.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_utility` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_utility -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_utility`. -pub struct WeightInfo(PhantomData); -impl pallet_utility::WeightInfo for WeightInfo { - /// The range of component `c` is `[0, 1000]`. - fn batch(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_489_000 picoseconds. - Weight::from_parts(13_259_019, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_263 - .saturating_add(Weight::from_parts(5_239_842, 0).saturating_mul(c.into())) - } - fn as_derivative() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_128_000 picoseconds. - Weight::from_parts(5_402_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `c` is `[0, 1000]`. - fn batch_all(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_609_000 picoseconds. - Weight::from_parts(9_345_211, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_018 - .saturating_add(Weight::from_parts(5_550_153, 0).saturating_mul(c.into())) - } - fn dispatch_as() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_803_000 picoseconds. - Weight::from_parts(9_123_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `c` is `[0, 1000]`. - fn force_batch(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_630_000 picoseconds. - Weight::from_parts(8_158_486, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_533 - .saturating_add(Weight::from_parts(5_246_137, 0).saturating_mul(c.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_vesting.rs b/polkadot/runtime/polkadot/src/weights/pallet_vesting.rs deleted file mode 100644 index 916ca4bf6b9c7cc4f90e26ea3b38a76b105d10ce..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_vesting.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_vesting` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_vesting -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_vesting`. -pub struct WeightInfo(PhantomData); -impl pallet_vesting::WeightInfo for WeightInfo { - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_locked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `314 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 34_121_000 picoseconds. - Weight::from_parts(33_874_584, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_001 - .saturating_add(Weight::from_parts(43_368, 0).saturating_mul(l.into())) - // Standard Error: 3_560 - .saturating_add(Weight::from_parts(80_668, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_unlocked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `314 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 37_615_000 picoseconds. - Weight::from_parts(37_040_523, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_513 - .saturating_add(Weight::from_parts(44_043, 0).saturating_mul(l.into())) - // Standard Error: 2_692 - .saturating_add(Weight::from_parts(76_579, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `417 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 36_953_000 picoseconds. - Weight::from_parts(35_679_094, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_788 - .saturating_add(Weight::from_parts(55_569, 0).saturating_mul(l.into())) - // Standard Error: 3_182 - .saturating_add(Weight::from_parts(95_878, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[1, 28]`. - fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `417 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 39_817_000 picoseconds. - Weight::from_parts(40_592_159, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_675 - .saturating_add(Weight::from_parts(34_692, 0).saturating_mul(l.into())) - // Standard Error: 4_760 - .saturating_add(Weight::from_parts(65_300, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[0, 27]`. - fn vested_transfer(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `488 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 72_258_000 picoseconds. - Weight::from_parts(74_062_243, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 3_135 - .saturating_add(Weight::from_parts(50_768, 0).saturating_mul(l.into())) - // Standard Error: 5_578 - .saturating_add(Weight::from_parts(83_913, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[0, 27]`. - fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `591 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `6196` - // Minimum execution time: 75_260_000 picoseconds. - Weight::from_parts(75_838_762, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 2_742 - .saturating_add(Weight::from_parts(57_676, 0).saturating_mul(l.into())) - // Standard Error: 4_879 - .saturating_add(Weight::from_parts(106_745, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[2, 28]`. - fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `415 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 37_553_000 picoseconds. - Weight::from_parts(36_199_505, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_594 - .saturating_add(Weight::from_parts(60_107, 0).saturating_mul(l.into())) - // Standard Error: 2_945 - .saturating_add(Weight::from_parts(104_552, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[2, 28]`. - fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `415 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 41_939_000 picoseconds. - Weight::from_parts(42_113_365, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_119 - .saturating_add(Weight::from_parts(44_822, 0).saturating_mul(l.into())) - // Standard Error: 3_914 - .saturating_add(Weight::from_parts(73_401, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_whitelist.rs b/polkadot/runtime/polkadot/src/weights/pallet_whitelist.rs deleted file mode 100644 index fd3831a3ef5943288496d87b38b73bcaed2332b9..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_whitelist.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_whitelist` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_whitelist -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/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_whitelist`. -pub struct WeightInfo(PhantomData); -impl pallet_whitelist::WeightInfo for WeightInfo { - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn whitelist_call() -> Weight { - // Proof Size summary in bytes: - // Measured: `118` - // Estimated: `3556` - // Minimum execution time: 20_665_000 picoseconds. - Weight::from_parts(21_174_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - fn remove_whitelisted_call() -> Weight { - // Proof Size summary in bytes: - // Measured: `247` - // Estimated: `3556` - // Minimum execution time: 18_337_000 picoseconds. - Weight::from_parts(18_705_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:1 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 4194294]`. - fn dispatch_whitelisted_call(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `323 + n * (1 ±0)` - // Estimated: `3787 + n * (1 ±0)` - // Minimum execution time: 30_433_000 picoseconds. - Weight::from_parts(30_800_000, 0) - .saturating_add(Weight::from_parts(0, 3787)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_558, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) - } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// The range of component `n` is `[1, 10000]`. - fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `247` - // Estimated: `3556` - // Minimum execution time: 22_062_000 picoseconds. - Weight::from_parts(22_797_644, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_493, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/pallet_xcm.rs b/polkadot/runtime/polkadot/src/weights/pallet_xcm.rs deleted file mode 100644 index abbd5b1f2b9624d99a7fdaa6ad3f2cbde84355bc..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/pallet_xcm.rs +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_xcm -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=polkadot-dev -// --header=./file_header.txt -// --output=./runtime/polkadot/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_xcm`. -pub struct WeightInfo(PhantomData); -impl pallet_xcm::WeightInfo for WeightInfo { - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn send() -> Weight { - // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `3992` - // Minimum execution time: 38_390_000 picoseconds. - Weight::from_parts(38_885_000, 0) - .saturating_add(Weight::from_parts(0, 3992)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) - } - fn teleport_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 23_170_000 picoseconds. - Weight::from_parts(23_644_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn reserve_transfer_assets() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 22_672_000 picoseconds. - Weight::from_parts(23_138_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - 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: XcmPallet SupportedVersion (r:0 w:1) - /// Proof Skipped: 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: 9_462_000 picoseconds. - Weight::from_parts(9_853_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn force_default_xcm_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_769_000 picoseconds. - Weight::from_parts(3_001_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: XcmPallet VersionNotifiers (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifiers (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet QueryCounter (r:1 w:1) - /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - fn force_subscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `3992` - // Minimum execution time: 41_707_000 picoseconds. - Weight::from_parts(42_742_000, 0) - .saturating_add(Weight::from_parts(0, 3992)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: XcmPallet VersionNotifiers (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifiers (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: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - fn force_unsubscribe_version_notify() -> Weight { - // Proof Size summary in bytes: - // Measured: `799` - // Estimated: `4264` - // Minimum execution time: 46_077_000 picoseconds. - Weight::from_parts(46_504_000, 0) - .saturating_add(Weight::from_parts(0, 4264)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) - /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) - fn force_suspension() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_849_000 picoseconds. - Weight::from_parts(3_018_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: XcmPallet SupportedVersion (r:4 w:2) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - fn migrate_supported_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `229` - // Estimated: `11119` - // Minimum execution time: 17_729_000 picoseconds. - Weight::from_parts(18_210_000, 0) - .saturating_add(Weight::from_parts(0, 11119)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifiers (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifiers (max_values: None, max_size: None, mode: Measured) - fn migrate_version_notifiers() -> Weight { - // Proof Size summary in bytes: - // Measured: `233` - // Estimated: `11123` - // Minimum execution time: 17_615_000 picoseconds. - Weight::from_parts(18_157_000, 0) - .saturating_add(Weight::from_parts(0, 11123)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:5 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn already_notified_target() -> Weight { - // Proof Size summary in bytes: - // Measured: `243` - // Estimated: `13608` - // Minimum execution time: 19_112_000 picoseconds. - Weight::from_parts(19_512_000, 0) - .saturating_add(Weight::from_parts(0, 13608)) - .saturating_add(T::DbWeight::get().reads(5)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:2 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (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: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn notify_current_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `597` - // Estimated: `6537` - // Minimum execution time: 38_643_000 picoseconds. - Weight::from_parts(39_380_000, 0) - .saturating_add(Weight::from_parts(0, 6537)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:3 w:0) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn notify_target_migration_fail() -> Weight { - // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `8687` - // Minimum execution time: 9_326_000 picoseconds. - Weight::from_parts(9_772_000, 0) - .saturating_add(Weight::from_parts(0, 8687)) - .saturating_add(T::DbWeight::get().reads(3)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - fn migrate_version_notify_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `240` - // Estimated: `11130` - // Minimum execution time: 18_184_000 picoseconds. - Weight::from_parts(18_487_000, 0) - .saturating_add(Weight::from_parts(0, 11130)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: XcmPallet VersionNotifyTargets (r:4 w:2) - /// Proof Skipped: XcmPallet VersionNotifyTargets (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: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: 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) - fn migrate_and_notify_old_targets() -> Weight { - // Proof Size summary in bytes: - // Measured: `601` - // Estimated: `11491` - // Minimum execution time: 45_891_000 picoseconds. - Weight::from_parts(47_130_000, 0) - .saturating_add(Weight::from_parts(0, 11491)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_common_auctions.rs b/polkadot/runtime/polkadot/src/weights/runtime_common_auctions.rs deleted file mode 100644 index 8fdac1990620c754b9c0d694aa5ed32987da4d2f..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_common_auctions.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::auctions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::auctions -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_common_auctions.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::auctions`. -pub struct WeightInfo(PhantomData); -impl runtime_common::auctions::WeightInfo for WeightInfo { - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:1) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn new_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `1493` - // Minimum execution time: 13_598_000 picoseconds. - Weight::from_parts(14_292_000, 0) - .saturating_add(Weight::from_parts(0, 1493)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:2 w:2) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `661` - // Estimated: `6060` - // Minimum execution time: 93_532_000 picoseconds. - Weight::from_parts(99_534_000, 0) - .saturating_add(Weight::from_parts(0, 6060)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe NextRandomness (r:1 w:0) - /// Proof: Babe NextRandomness (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: Babe EpochStart (r:1 w:0) - /// Proof: Babe EpochStart (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:7 w:7) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `6947699` - // Estimated: `15822990` - // Minimum execution time: 7_832_854_000 picoseconds. - Weight::from_parts(8_120_980_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3688)) - .saturating_add(T::DbWeight::get().writes(3683)) - } - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:0 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - fn cancel_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `177732` - // Estimated: `15822990` - // Minimum execution time: 6_046_611_000 picoseconds. - Weight::from_parts(6_137_707_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3673)) - .saturating_add(T::DbWeight::get().writes(3673)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_common_claims.rs b/polkadot/runtime/polkadot/src/weights/runtime_common_claims.rs deleted file mode 100644 index b16ed97bc3ba5e74fc66a41cc26ae3dbfe5f65b1..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_common_claims.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::claims` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::claims -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_common_claims.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::claims`. -pub struct WeightInfo(PhantomData); -impl runtime_common::claims::WeightInfo for WeightInfo { - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `586` - // Estimated: `4764` - // Minimum execution time: 192_126_000 picoseconds. - Weight::from_parts(210_300_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:0 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:0 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:0 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - fn mint_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `182` - // Estimated: `1667` - // Minimum execution time: 15_323_000 picoseconds. - Weight::from_parts(16_648_000, 0) - .saturating_add(Weight::from_parts(0, 1667)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn claim_attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `586` - // Estimated: `4764` - // Minimum execution time: 198_285_000 picoseconds. - Weight::from_parts(211_990_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - fn attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `660` - // Estimated: `4764` - // Minimum execution time: 98_860_000 picoseconds. - Weight::from_parts(110_990_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Claims Claims (r:1 w:2) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:2) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:2) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - fn move_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `406` - // Estimated: `3871` - // Minimum execution time: 27_962_000 picoseconds. - Weight::from_parts(30_903_000, 0) - .saturating_add(Weight::from_parts(0, 3871)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_common_crowdloan.rs b/polkadot/runtime/polkadot/src/weights/runtime_common_crowdloan.rs deleted file mode 100644 index f9b84ff2f3e241d3aced50c22c2a6580bfa9d8aa..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_common_crowdloan.rs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::crowdloan` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::crowdloan -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_common_crowdloan.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::crowdloan`. -pub struct WeightInfo(PhantomData); -impl runtime_common::crowdloan::WeightInfo for WeightInfo { - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NextFundIndex (r:1 w:1) - /// Proof Skipped: Crowdloan NextFundIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `415` - // Estimated: `3880` - // Minimum execution time: 67_401_000 picoseconds. - Weight::from_parts(73_047_000, 0) - .saturating_add(Weight::from_parts(0, 3880)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:0) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn contribute() -> Weight { - // Proof Size summary in bytes: - // Measured: `463` - // Estimated: `3928` - // Minimum execution time: 158_577_000 picoseconds. - Weight::from_parts(163_468_000, 0) - .saturating_add(Weight::from_parts(0, 3928)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - /// Proof Skipped: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - fn withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `690` - // Estimated: `6196` - // Minimum execution time: 86_038_000 picoseconds. - Weight::from_parts(93_214_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `k` is `[0, 1000]`. - fn refund(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `128 + k * (189 ±0)` - // Estimated: `141 + k * (189 ±0)` - // Minimum execution time: 63_322_000 picoseconds. - Weight::from_parts(65_003_000, 0) - .saturating_add(Weight::from_parts(0, 141)) - // Standard Error: 27_401 - .saturating_add(Weight::from_parts(45_003_555, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `515` - // Estimated: `6196` - // Minimum execution time: 49_151_000 picoseconds. - Weight::from_parts(55_069_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - fn edit() -> Weight { - // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3700` - // Minimum execution time: 26_691_000 picoseconds. - Weight::from_parts(28_891_000, 0) - .saturating_add(Weight::from_parts(0, 3700)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn add_memo() -> Weight { - // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `3877` - // Minimum execution time: 46_088_000 picoseconds. - Weight::from_parts(49_781_000, 0) - .saturating_add(Weight::from_parts(0, 3877)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - fn poke() -> Weight { - // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `3704` - // Minimum execution time: 25_350_000 picoseconds. - Weight::from_parts(29_241_000, 0) - .saturating_add(Weight::from_parts(0, 3704)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:1) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:100 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Paras ParaLifecycles (r:100 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:100 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:100 w:100) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:100 w:100) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[2, 100]`. - fn on_initialize(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `130 + n * (356 ±0)` - // Estimated: `5385 + n * (2832 ±0)` - // Minimum execution time: 154_247_000 picoseconds. - Weight::from_parts(18_164_126, 0) - .saturating_add(Weight::from_parts(0, 5385)) - // Standard Error: 71_727 - .saturating_add(Weight::from_parts(72_599_775, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2832).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs b/polkadot/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs deleted file mode 100644 index d176b83a648b84fc89a0e10dcc58fea1096d5cce..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::paras_registrar` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::paras_registrar -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_common_paras_registrar.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::paras_registrar`. -pub struct WeightInfo(PhantomData); -impl runtime_common::paras_registrar::WeightInfo for WeightInfo { - /// Storage: Registrar NextFreeParaId (r:1 w:1) - /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 30_388_000 picoseconds. - Weight::from_parts(30_995_000, 0) - .saturating_add(Weight::from_parts(0, 3535)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn register() -> Weight { - // Proof Size summary in bytes: - // Measured: `645` - // Estimated: `4110` - // Minimum execution time: 6_371_660_000 picoseconds. - Weight::from_parts(6_872_164_000, 0) - .saturating_add(Weight::from_parts(0, 4110)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn force_register() -> Weight { - // Proof Size summary in bytes: - // Measured: `535` - // Estimated: `4000` - // Minimum execution time: 6_530_996_000 picoseconds. - Weight::from_parts(7_099_049_000, 0) - .saturating_add(Weight::from_parts(0, 4000)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: Registrar PendingSwap (r:0 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - fn deregister() -> Weight { - // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `3941` - // Minimum execution time: 61_803_000 picoseconds. - Weight::from_parts(65_036_000, 0) - .saturating_add(Weight::from_parts(0, 3941)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Registrar Paras (r:1 w:0) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:2 w:2) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar PendingSwap (r:1 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:2 w:2) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - fn swap() -> Weight { - // Proof Size summary in bytes: - // Measured: `713` - // Estimated: `6653` - // Minimum execution time: 67_847_000 picoseconds. - Weight::from_parts(71_909_000, 0) - .saturating_add(Weight::from_parts(0, 6653)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 3145728]`. - fn schedule_code_upgrade(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `493` - // Estimated: `3958` - // Minimum execution time: 44_170_000 picoseconds. - Weight::from_parts(44_955_000, 0) - .saturating_add(Weight::from_parts(0, 3958)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(2_501, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 1048576]`. - fn set_current_head(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_735_000 picoseconds. - Weight::from_parts(8_851_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_044, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_common_slots.rs b/polkadot/runtime/polkadot/src/weights/runtime_common_slots.rs deleted file mode 100644 index 7197c8721d8e43b1579dbeeda025008551e9e540..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_common_slots.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::slots` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::slots -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_common_slots.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::slots`. -pub struct WeightInfo(PhantomData); -impl runtime_common::slots::WeightInfo for WeightInfo { - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn force_lease() -> Weight { - // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `3685` - // Minimum execution time: 30_634_000 picoseconds. - Weight::from_parts(31_305_000, 0) - .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Slots Leases (r:101 w:100) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:200 w:200) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:100 w:100) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[0, 100]`. - /// The range of component `t` is `[0, 100]`. - fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12 + c * (47 ±0) + t * (308 ±0)` - // Estimated: `2789 + c * (2526 ±0) + t * (2789 ±0)` - // Minimum execution time: 752_614_000 picoseconds. - Weight::from_parts(775_359_000, 0) - .saturating_add(Weight::from_parts(0, 2789)) - // Standard Error: 95_470 - .saturating_add(Weight::from_parts(3_269_112, 0).saturating_mul(c.into())) - // Standard Error: 95_470 - .saturating_add(Weight::from_parts(13_826_144, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2526).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2789).saturating_mul(t.into())) - } - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:8 w:8) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn clear_all_leases() -> Weight { - // Proof Size summary in bytes: - // Measured: `2692` - // Estimated: `21814` - // Minimum execution time: 155_965_000 picoseconds. - Weight::from_parts(162_544_000, 0) - .saturating_add(Weight::from_parts(0, 21814)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(9)) - } - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn trigger_onboard() -> Weight { - // Proof Size summary in bytes: - // Measured: `617` - // Estimated: `4082` - // Minimum execution time: 34_811_000 picoseconds. - Weight::from_parts(39_327_000, 0) - .saturating_add(Weight::from_parts(0, 4082)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_configuration.rs deleted file mode 100644 index 39b0d893edbb54b20778afb3e4b6693f0855f168..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_configuration.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::configuration` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("polkadot-dev")`, DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_parachains::configuration -// --chain=polkadot-dev -// --header=./file_header.txt -// --output=./runtime/polkadot/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 `runtime_parachains::configuration`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_block_number() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_330_000 picoseconds. - Weight::from_parts(9_663_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_u32() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_155_000 picoseconds. - Weight::from_parts(9_554_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_option_u32() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_299_000 picoseconds. - Weight::from_parts(9_663_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_hrmp_open_request_ttl() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_balance() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_130_000 picoseconds. - Weight::from_parts(9_554_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_executor_params() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 10_177_000 picoseconds. - Weight::from_parts(10_632_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn set_config_with_perbill() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1612` - // Minimum execution time: 9_136_000 picoseconds. - Weight::from_parts(9_487_000, 0) - .saturating_add(Weight::from_parts(0, 1612)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes.rs deleted file mode 100644 index 2746924dc87b9fc206279903ff310e9dbbf085c1..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::disputes` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::disputes -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_disputes.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::disputes`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::disputes::WeightInfo for WeightInfo { - /// Storage: ParasDisputes Frozen (r:0 w:1) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - fn force_unfreeze() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_674_000 picoseconds. - Weight::from_parts(2_822_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes_slashing.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes_slashing.rs deleted file mode 100644 index eda2f14214b11f68c8a08625a99e6a0cc562c194..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_disputes_slashing.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::disputes::slashing` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::disputes::slashing -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_disputes_slashing.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::disputes::slashing`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::disputes::slashing::WeightInfo for WeightInfo { - /// Storage: Session CurrentIndex (r:1 w:0) - /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Historical HistoricalSessions (r:1 w:0) - /// Proof: Historical HistoricalSessions (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: ParasSlashing UnappliedSlashes (r:1 w:1) - /// Proof Skipped: ParasSlashing UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences ConcurrentReportsIndex (r:1 w:1) - /// Proof Skipped: Offences ConcurrentReportsIndex (max_values: None, max_size: None, mode: Measured) - /// Storage: Offences Reports (r:1 w:1) - /// Proof Skipped: Offences Reports (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SlashRewardFraction (r:1 w:0) - /// Proof: Staking SlashRewardFraction (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:1 w:0) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking Invulnerables (r:1 w:0) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ValidatorSlashInEra (r:1 w:1) - /// Proof: Staking ValidatorSlashInEra (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking SpanSlash (r:1 w:1) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) - /// Storage: Staking OffendingValidators (r:1 w:1) - /// Proof Skipped: Staking OffendingValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session DisabledValidators (r:1 w:1) - /// Proof Skipped: Session DisabledValidators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[4, 1000]`. - fn report_dispute_lost(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `5392 + n * (185 ±0)` - // Estimated: `8618 + n * (188 ±0)` - // Minimum execution time: 123_913_000 picoseconds. - Weight::from_parts(158_003_304, 0) - .saturating_add(Weight::from_parts(0, 8618)) - // Standard Error: 3_048 - .saturating_add(Weight::from_parts(361_664, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(17)) - .saturating_add(T::DbWeight::get().writes(10)) - .saturating_add(Weight::from_parts(0, 188).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs deleted file mode 100644 index 82d8c30bacad485ba137614a3417547723f27bf3..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_hrmp.rs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::hrmp` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-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/polkadot/src/weights/runtime_parachains_hrmp.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_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) - fn hrmp_init_open_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `6606` - // Minimum execution time: 41_092_000 picoseconds. - Weight::from_parts(43_188_000, 0) - .saturating_add(Weight::from_parts(0, 6606)) - .saturating_add(T::DbWeight::get().reads(10)) - .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) - fn hrmp_accept_open_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `898` - // Estimated: `4363` - // Minimum execution time: 43_872_000 picoseconds. - Weight::from_parts(45_130_000, 0) - .saturating_add(Weight::from_parts(0, 4363)) - .saturating_add(T::DbWeight::get().reads(7)) - .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) - fn hrmp_close_channel() -> Weight { - // Proof Size summary in bytes: - // Measured: `769` - // Estimated: `4234` - // Minimum execution time: 36_749_000 picoseconds. - Weight::from_parts(37_721_000, 0) - .saturating_add(Weight::from_parts(0, 4234)) - .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) - /// 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: `197 + e * (100 ±0) + i * (100 ±0)` - // Estimated: `3659 + e * (2575 ±0) + i * (2575 ±0)` - // Minimum execution time: 1_241_128_000 picoseconds. - Weight::from_parts(1_249_625_000, 0) - .saturating_add(Weight::from_parts(0, 3659)) - // Standard Error: 114_117 - .saturating_add(Weight::from_parts(3_676_253, 0).saturating_mul(i.into())) - // Standard Error: 114_117 - .saturating_add(Weight::from_parts(3_657_525, 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()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(e.into()))) - .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) - /// The range of component `c` is `[0, 128]`. - fn force_process_hrmp_open(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `741 + c * (136 ±0)` - // Estimated: `2196 + c * (5086 ±0)` - // Minimum execution time: 10_559_000 picoseconds. - Weight::from_parts(7_421_722, 0) - .saturating_add(Weight::from_parts(0, 2196)) - // Standard Error: 17_031 - .saturating_add(Weight::from_parts(21_174_297, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .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) - /// The range of component `c` is `[0, 128]`. - fn force_process_hrmp_close(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `268 + c * (124 ±0)` - // Estimated: `1728 + c * (2600 ±0)` - // Minimum execution time: 6_657_000 picoseconds. - Weight::from_parts(2_696_128, 0) - .saturating_add(Weight::from_parts(0, 1728)) - // Standard Error: 13_124 - .saturating_add(Weight::from_parts(13_190_422, 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) - /// The range of component `c` is `[0, 128]`. - fn hrmp_cancel_open_request(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `959 + c * (13 ±0)` - // Estimated: `4228 + c * (15 ±0)` - // Minimum execution time: 22_102_000 picoseconds. - Weight::from_parts(29_549_361, 0) - .saturating_add(Weight::from_parts(0, 4228)) - // Standard Error: 2_209 - .saturating_add(Weight::from_parts(132_354, 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) - /// The range of component `c` is `[0, 128]`. - fn clean_open_channel_requests(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `176 + c * (63 ±0)` - // Estimated: `1655 + c * (2538 ±0)` - // Minimum execution time: 5_362_000 picoseconds. - Weight::from_parts(5_817_072, 0) - .saturating_add(Weight::from_parts(0, 1655)) - // Standard Error: 4_287 - .saturating_add(Weight::from_parts(3_550_045, 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 { - // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `6606` - // Minimum execution time: 56_136_000 picoseconds. - Weight::from_parts(57_227_000, 0) - .saturating_add(Weight::from_parts(0, 6606)) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().writes(8)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index c1e89a1ea9889828ae2d773f81484eb425a1e243..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_inclusion.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::inclusion` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::inclusion -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_inclusion.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::inclusion`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:999) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65586), added: 68061, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// The range of component `i` is `[1, 1000]`. - fn receive_upward_messages(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `66077` - // Estimated: `69051` - // Minimum execution time: 124_710_000 picoseconds. - Weight::from_parts(126_824_000, 0) - .saturating_add(Weight::from_parts(0, 69051)) - // Standard Error: 127_283 - .saturating_add(Weight::from_parts(110_113_768, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_initializer.rs deleted file mode 100644 index 87e60aaeb24db96c1adf465524557769d60b5ebb..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_initializer.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::initializer` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::initializer -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_initializer.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::initializer`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::initializer::WeightInfo for WeightInfo { - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `d` is `[0, 65536]`. - fn force_approve(d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + d * (11 ±0)` - // Estimated: `1480 + d * (11 ±0)` - // Minimum execution time: 3_619_000 picoseconds. - Weight::from_parts(3_743_000, 0) - .saturating_add(Weight::from_parts(0, 1480)) - // Standard Error: 17 - .saturating_add(Weight::from_parts(3_045, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 11).saturating_mul(d.into())) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras.rs deleted file mode 100644 index 06f67211eade4180c956a7d5abc8c07b09395baf..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras.rs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::paras` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=polkadot-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::paras -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_paras.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_parachains::paras`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::paras::WeightInfo for WeightInfo { - /// Storage: Paras CurrentCodeHash (r:1 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodeMeta (r:1 w:1) - /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodePruning (r:1 w:1) - /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PastCodeHash (r:0 w:1) - /// Proof Skipped: Paras PastCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_set_current_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8309` - // Estimated: `11774` - // Minimum execution time: 33_840_000 picoseconds. - Weight::from_parts(34_093_000, 0) - .saturating_add(Weight::from_parts(0, 11774)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_436, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_set_current_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_922_000 picoseconds. - Weight::from_parts(8_254_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_040, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Paras Heads (r:0 w:1) - fn force_set_most_recent_context() -> Weight { - Weight::from_parts(10_155_000, 0) - // Standard Error: 0 - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_schedule_code_upgrade(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8744` - // Estimated: `12209` - // Minimum execution time: 52_554_000 picoseconds. - Weight::from_parts(53_345_000, 0) - .saturating_add(Weight::from_parts(0, 12209)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(2_405, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_note_new_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `3560` - // Minimum execution time: 14_465_000 picoseconds. - Weight::from_parts(20_861_569, 0) - .saturating_add(Weight::from_parts(0, 3560)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_002, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn force_queue_action() -> Weight { - // Proof Size summary in bytes: - // Measured: `4288` - // Estimated: `7753` - // Minimum execution time: 21_354_000 picoseconds. - Weight::from_parts(21_865_000, 0) - .saturating_add(Weight::from_parts(0, 7753)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn add_trusted_validation_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `4440` - // Minimum execution time: 102_448_000 picoseconds. - Weight::from_parts(101_036_531, 0) - .saturating_add(Weight::from_parts(0, 4440)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_850, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Paras CodeByHashRefs (r:1 w:0) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - fn poke_unused_validation_code() -> Weight { - // Proof Size summary in bytes: - // Measured: `28` - // Estimated: `3493` - // Minimum execution time: 6_803_000 picoseconds. - Weight::from_parts(7_013_000, 0) - .saturating_add(Weight::from_parts(0, 3493)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 121_645_000 picoseconds. - Weight::from_parts(125_576_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras UpcomingUpgrades (r:1 w:1) - /// Proof Skipped: Paras UpcomingUpgrades (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:0 w:100) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `27552` - // Estimated: `31017` - // Minimum execution time: 956_753_000 picoseconds. - Weight::from_parts(978_268_000, 0) - .saturating_add(Weight::from_parts(0, 31017)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(104)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `27214` - // Estimated: `30679` - // Minimum execution time: 112_500_000 picoseconds. - Weight::from_parts(120_090_000, 0) - .saturating_add(Weight::from_parts(0, 30679)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `27020` - // Estimated: `30485` - // Minimum execution time: 760_189_000 picoseconds. - Weight::from_parts(776_400_000, 0) - .saturating_add(Weight::from_parts(0, 30485)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 113_010_000 picoseconds. - Weight::from_parts(118_335_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras_inherent.rs deleted file mode 100644 index 70eb764305e4097ca02805a74b3d78aed98c7f78..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/runtime_parachains_paras_inherent.rs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_parachains::paras_inherent` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_parachains::paras_inherent -// --chain=polkadot-dev -// --header=./file_header.txt -// --output=./runtime/polkadot/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 `runtime_parachains::paras_inherent`. -pub struct WeightInfo(PhantomData); -impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaSessionInfo Sessions (r:1 w:0) - /// Proof Skipped: ParaSessionInfo Sessions (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:1) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes BackersOnDisputes (r:1 w:1) - /// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:1 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[10, 200]`. - fn enter_variable_disputes(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `50915` - // Estimated: `56855 + v * (23 ±0)` - // Minimum execution time: 999_704_000 picoseconds. - Weight::from_parts(455_751_887, 0) - .saturating_add(Weight::from_parts(0, 56855)) - // Standard Error: 14_301 - .saturating_add(Weight::from_parts(57_084_663, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(15)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) - /// Proof Skipped: ParaInclusion AvailabilityBitfields (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - fn enter_bitfields() -> Weight { - // Proof Size summary in bytes: - // Measured: `42748` - // Estimated: `48688` - // Minimum execution time: 485_153_000 picoseconds. - Weight::from_parts(504_774_000, 0) - .saturating_add(Weight::from_parts(0, 48688)) - .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(16)) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `v` is `[101, 200]`. - fn enter_backed_candidates_variable(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `42784` - // Estimated: `48724` - // Minimum execution time: 6_906_795_000 picoseconds. - Weight::from_parts(1_315_944_667, 0) - .saturating_add(Weight::from_parts(0, 48724)) - // Standard Error: 31_132 - .saturating_add(Weight::from_parts(55_792_755, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(29)) - .saturating_add(T::DbWeight::get().writes(15)) - } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (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 DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:0) - /// Proof Skipped: Paras UpgradeRestrictionSignal (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: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - fn enter_backed_candidate_code_upgrade() -> Weight { - // Proof Size summary in bytes: - // Measured: `42811` - // Estimated: `48751` - // Minimum execution time: 44_487_810_000 picoseconds. - Weight::from_parts(46_317_208_000, 0) - .saturating_add(Weight::from_parts(0, 48751)) - .saturating_add(T::DbWeight::get().reads(31)) - .saturating_add(T::DbWeight::get().writes(15)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/xcm/mod.rs b/polkadot/runtime/polkadot/src/weights/xcm/mod.rs deleted file mode 100644 index acef102b446f13835e04fd66fc64e778f4b28a52..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/xcm/mod.rs +++ /dev/null @@ -1,290 +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 . - -mod pallet_xcm_benchmarks_fungible; -mod pallet_xcm_benchmarks_generic; - -use crate::Runtime; -use frame_support::weights::Weight; -use sp_std::prelude::*; -use xcm::{latest::prelude::*, DoubleEncoded}; - -use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; -use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; - -/// Types of asset supported by the Polkadot runtime. -pub enum AssetTypes { - /// An asset backed by `pallet-balances`. - Balances, - /// Unknown asset. - Unknown, -} - -impl From<&MultiAsset> for AssetTypes { - fn from(asset: &MultiAsset) -> Self { - match asset { - MultiAsset { id: Concrete(MultiLocation { parents: 0, interior: Here }), .. } => - AssetTypes::Balances, - _ => AssetTypes::Unknown, - } - } -} - -trait WeighMultiAssets { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight; -} - -// Polkadot only knows about one asset, the balances pallet. -const MAX_ASSETS: u64 = 1; - -impl WeighMultiAssets for MultiAssetFilter { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { - match self { - Self::Definite(assets) => assets - .inner() - .into_iter() - .map(From::from) - .map(|t| match t { - AssetTypes::Balances => balances_weight, - AssetTypes::Unknown => Weight::MAX, - }) - .fold(Weight::zero(), |acc, x| acc.saturating_add(x)), - // We don't support any NFTs on Polkadot, so these two variants will always match - // only 1 kind of fungible asset. - Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight, - Self::Wild(AllCounted(count)) => - balances_weight.saturating_mul(MAX_ASSETS.min(*count as u64)), - Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS), - } - } -} - -impl WeighMultiAssets for MultiAssets { - fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { - self.inner() - .into_iter() - .map(|m| >::from(m)) - .map(|t| match t { - AssetTypes::Balances => balances_weight, - AssetTypes::Unknown => Weight::MAX, - }) - .fold(Weight::zero(), |acc, x| acc.saturating_add(x)) - } -} - -pub struct PolkadotXcmWeight(core::marker::PhantomData); -impl XcmWeightInfo for PolkadotXcmWeight { - fn withdraw_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::withdraw_asset()) - } - fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { - // Polkadot doesn't support ReserveAssetDeposited, so this benchmark has a default weight - assets.weigh_multi_assets(XcmBalancesWeight::::reserve_asset_deposited()) - } - fn receive_teleported_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::receive_teleported_asset()) - } - fn query_response( - _query_id: &u64, - _response: &Response, - _max_weight: &Weight, - _querier: &Option, - ) -> Weight { - XcmGeneric::::query_response() - } - fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::transfer_asset()) - } - fn transfer_reserve_asset( - assets: &MultiAssets, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::transfer_reserve_asset()) - } - fn transact( - _origin_kind: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { - XcmGeneric::::transact() - } - fn hrmp_new_channel_open_request( - _sender: &u32, - _max_message_size: &u32, - _max_capacity: &u32, - ) -> Weight { - // XCM Executor does not currently support HRMP channel operations - Weight::MAX - } - fn hrmp_channel_accepted(_recipient: &u32) -> Weight { - // XCM Executor does not currently support HRMP channel operations - Weight::MAX - } - fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> Weight { - // XCM Executor does not currently support HRMP channel operations - Weight::MAX - } - fn clear_origin() -> Weight { - XcmGeneric::::clear_origin() - } - fn descend_origin(_who: &InteriorMultiLocation) -> Weight { - XcmGeneric::::descend_origin() - } - fn report_error(_query_response_info: &QueryResponseInfo) -> Weight { - XcmGeneric::::report_error() - } - - fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::deposit_asset()) - } - fn deposit_reserve_asset( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::deposit_reserve_asset()) - } - fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight { - // Polkadot does not currently support exchange asset operations - Weight::MAX - } - fn initiate_reserve_withdraw( - assets: &MultiAssetFilter, - _reserve: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::initiate_reserve_withdraw()) - } - fn initiate_teleport( - assets: &MultiAssetFilter, - _dest: &MultiLocation, - _xcm: &Xcm<()>, - ) -> Weight { - assets.weigh_multi_assets(XcmBalancesWeight::::initiate_teleport()) - } - fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight { - XcmGeneric::::report_holding() - } - fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> Weight { - XcmGeneric::::buy_execution() - } - fn refund_surplus() -> Weight { - XcmGeneric::::refund_surplus() - } - fn set_error_handler(_xcm: &Xcm) -> Weight { - XcmGeneric::::set_error_handler() - } - fn set_appendix(_xcm: &Xcm) -> Weight { - XcmGeneric::::set_appendix() - } - fn clear_error() -> Weight { - XcmGeneric::::clear_error() - } - fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> Weight { - XcmGeneric::::claim_asset() - } - fn trap(_code: &u64) -> Weight { - XcmGeneric::::trap() - } - fn subscribe_version(_query_id: &QueryId, _max_response_weight: &Weight) -> Weight { - XcmGeneric::::subscribe_version() - } - fn unsubscribe_version() -> Weight { - XcmGeneric::::unsubscribe_version() - } - fn burn_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmGeneric::::burn_asset()) - } - fn expect_asset(assets: &MultiAssets) -> Weight { - assets.weigh_multi_assets(XcmGeneric::::expect_asset()) - } - fn expect_origin(_origin: &Option) -> Weight { - XcmGeneric::::expect_origin() - } - fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight { - XcmGeneric::::expect_error() - } - fn expect_transact_status(_transact_status: &MaybeErrorCode) -> Weight { - XcmGeneric::::expect_transact_status() - } - fn query_pallet(_module_name: &Vec, _response_info: &QueryResponseInfo) -> Weight { - XcmGeneric::::query_pallet() - } - fn expect_pallet( - _index: &u32, - _name: &Vec, - _module_name: &Vec, - _crate_major: &u32, - _min_crate_minor: &u32, - ) -> Weight { - XcmGeneric::::expect_pallet() - } - fn report_transact_status(_response_info: &QueryResponseInfo) -> Weight { - XcmGeneric::::report_transact_status() - } - fn clear_transact_status() -> Weight { - XcmGeneric::::clear_transact_status() - } - fn universal_origin(_: &Junction) -> Weight { - // Polkadot does not currently support universal origin operations - Weight::MAX - } - fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight { - // Polkadot relay should not support export message operations - Weight::MAX - } - fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Polkadot does not currently support asset locking operations - Weight::MAX - } - fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Polkadot does not currently support asset locking operations - Weight::MAX - } - fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Polkadot does not currently support asset locking operations - Weight::MAX - } - fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight { - // Polkadot does not currently support asset locking operations - Weight::MAX - } - fn set_fees_mode(_: &bool) -> Weight { - XcmGeneric::::set_fees_mode() - } - fn set_topic(_topic: &[u8; 32]) -> Weight { - XcmGeneric::::set_topic() - } - fn clear_topic() -> Weight { - XcmGeneric::::clear_topic() - } - fn alias_origin(_: &MultiLocation) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX - } - fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { - XcmGeneric::::unpaid_execution() - } -} - -#[test] -fn all_counted_has_a_sane_weight_upper_limit() { - let assets = MultiAssetFilter::Wild(AllCounted(4294967295)); - let weight = Weight::from_parts(1000, 1000); - - assert_eq!(assets.weigh_multi_assets(weight), weight * MAX_ASSETS); -} diff --git a/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs deleted file mode 100644 index 038e9f17361b0637755662337b2139c2e1bcc10d..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_xcm_benchmarks::fungible -// --chain=polkadot-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/polkadot/src/weights/xcm/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm_benchmarks::fungible`. -pub struct WeightInfo(PhantomData); -impl WeightInfo { - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - pub(crate) fn withdraw_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 24_801_000 picoseconds. - Weight::from_parts(25_567_000, 3593) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - pub(crate) fn transfer_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `6196` - // Minimum execution time: 53_090_000 picoseconds. - Weight::from_parts(54_157_000, 6196) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn transfer_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `628` - // Estimated: `6196` - // Minimum execution time: 80_084_000 picoseconds. - Weight::from_parts(81_110_000, 6196) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - pub(crate) fn reserve_asset_deposited() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - } - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn initiate_reserve_withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `3992` - // Minimum execution time: 32_535_000 picoseconds. - Weight::from_parts(33_276_000, 3992) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - pub(crate) fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // Minimum execution time: 24_283_000 picoseconds. - Weight::from_parts(25_042_000, 3593) - .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) - pub(crate) fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 25_002_000 picoseconds. - Weight::from_parts(25_816_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: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn deposit_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `3992` - // Minimum execution time: 55_355_000 picoseconds. - Weight::from_parts(56_410_000, 3992) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub(crate) fn initiate_teleport() -> Weight { - // Proof Size summary in bytes: - // Measured: `527` - // Estimated: `3992` - // Minimum execution time: 57_258_000 picoseconds. - Weight::from_parts(58_205_000, 3992) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} diff --git a/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index 0b61e7cd8d1f8ad45e19fd73ddda2edb629d93c6..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::generic` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --pallet=pallet_xcm_benchmarks::generic -// --chain=polkadot-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/polkadot/src/weights/xcm/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weights for `pallet_xcm_benchmarks::generic`. -pub struct WeightInfo(PhantomData); -impl WeightInfo { - // Storage: Configuration ActiveConfig (r:1 w:0) - // Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SupportedVersion (r:1 w:0) - // Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SafeXcmVersion (r:1 w:0) - // Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub fn report_holding() -> Weight { - // Proof Size summary in bytes: - // Measured: `514` - // Estimated: `17934` - // Minimum execution time: 33_813_000 picoseconds. - Weight::from_parts(34_357_000, 17934) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - pub fn buy_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_067_000 picoseconds. - Weight::from_parts(3_153_000, 0) - } - // Storage: XcmPallet Queries (r:1 w:0) - // Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) - pub fn query_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 12_236_000 picoseconds. - Weight::from_parts(12_725_000, 3634) - .saturating_add(T::DbWeight::get().reads(1)) - } - pub fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 13_193_000 picoseconds. - Weight::from_parts(13_427_000, 0) - } - pub fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_393_000 picoseconds. - Weight::from_parts(3_464_000, 0) - } - pub fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_955_000 picoseconds. - Weight::from_parts(3_068_000, 0) - } - pub fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_004_000 picoseconds. - Weight::from_parts(3_107_000, 0) - } - pub fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_981_000 picoseconds. - Weight::from_parts(3_039_000, 0) - } - pub fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_814_000 picoseconds. - Weight::from_parts(3_897_000, 0) - } - pub fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_921_000 picoseconds. - Weight::from_parts(3_010_000, 0) - } - // Storage: Configuration ActiveConfig (r:1 w:0) - // Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SupportedVersion (r:1 w:0) - // Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SafeXcmVersion (r:1 w:0) - // Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub fn report_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `514` - // Estimated: `17934` - // Minimum execution time: 28_324_000 picoseconds. - Weight::from_parts(28_690_000, 17934) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: XcmPallet AssetTraps (r:1 w:1) - // Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured) - pub fn claim_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `226` - // Estimated: `3691` - // Minimum execution time: 16_430_000 picoseconds. - Weight::from_parts(16_774_000, 3691) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - pub fn trap() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_916_000 picoseconds. - Weight::from_parts(3_035_000, 0) - } - // Storage: XcmPallet VersionNotifyTargets (r:1 w:1) - // Proof Skipped: XcmPallet VersionNotifyTargets (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: XcmPallet SupportedVersion (r:1 w:0) - // Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SafeXcmVersion (r:1 w:0) - // Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub fn subscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `514` - // Estimated: `21913` - // Minimum execution time: 35_915_000 picoseconds. - Weight::from_parts(36_519_000, 21913) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: XcmPallet VersionNotifyTargets (r:0 w:1) - // Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - pub fn unsubscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_344_000 picoseconds. - Weight::from_parts(5_487_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: 4_684_000 picoseconds. - Weight::from_parts(4_801_000, 0) - } - pub fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_228_000 picoseconds. - Weight::from_parts(3_325_000, 0) - } - pub fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_059_000 picoseconds. - Weight::from_parts(3_153_000, 0) - } - pub fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_037_000 picoseconds. - Weight::from_parts(3_128_000, 0) - } - pub fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_287_000 picoseconds. - Weight::from_parts(3_360_000, 0) - } - // Storage: Configuration ActiveConfig (r:1 w:0) - // Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SupportedVersion (r:1 w:0) - // Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SafeXcmVersion (r:1 w:0) - // Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub fn query_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `514` - // Estimated: `17934` - // Minimum execution time: 35_467_000 picoseconds. - Weight::from_parts(36_011_000, 17934) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - pub fn expect_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_630_000 picoseconds. - Weight::from_parts(8_870_000, 0) - } - // Storage: Configuration ActiveConfig (r:1 w:0) - // Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SupportedVersion (r:1 w:0) - // Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmPallet SafeXcmVersion (r:1 w:0) - // Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - // Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - pub fn report_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `514` - // Estimated: `17934` - // Minimum execution time: 28_630_000 picoseconds. - Weight::from_parts(29_085_000, 17934) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - pub fn clear_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_997_000 picoseconds. - Weight::from_parts(3_096_000, 0) - } - pub fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_984_000 picoseconds. - Weight::from_parts(3_059_000, 0) - } - pub fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_969_000 picoseconds. - Weight::from_parts(3_006_000, 0) - } - pub fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_045_000 picoseconds. - Weight::from_parts(3_087_000, 0) - } - pub fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_141_000 picoseconds. - Weight::from_parts(3_251_000, 0) - } -} diff --git a/polkadot/runtime/polkadot/src/xcm_config.rs b/polkadot/runtime/polkadot/src/xcm_config.rs deleted file mode 100644 index c7b15f7256ba784d4e626cbc73ca920b645d67ad..0000000000000000000000000000000000000000 --- a/polkadot/runtime/polkadot/src/xcm_config.rs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! XCM configuration for Polkadot. - -use super::{ - parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin, - GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, - TransactionByteFee, WeightToFee, XcmPallet, -}; -use frame_support::{ - match_types, parameter_types, - traits::{Everything, Nothing}, - weights::Weight, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use polkadot_runtime_constants::{ - currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, -}; -use runtime_common::{ - xcm_sender::{ChildParachainRouter, ExponentialPrice}, - ToAuthor, -}; -use sp_core::ConstU32; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, MintLocation, - OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, -}; - -parameter_types! { - /// The location of the DOT token, from the context of this chain. Since this token is native to this - /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to - /// the context". - pub const TokenLocation: MultiLocation = Here.into_location(); - /// The Polkadot network ID. This is named. - pub const ThisNetwork: NetworkId = NetworkId::Polkadot; - /// Our location in the universe of consensus systems. - pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get())); - /// The Checking Account, which holds any native assets that have been teleported out and not back in (yet). - pub CheckAccount: AccountId = XcmPallet::check_account(); - /// The Checking Account along with the indication that the local chain is able to mint tokens. - pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); -} - -/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to -/// determine the sovereign account controlled by a location. -pub type SovereignAccountOf = ( - // We can convert a child parachain using the standard `AccountId` conversion. - ChildParachainConvertsVia, - // We can directly alias an `AccountId32` into a local account. - AccountId32Aliases, -); - -/// Our asset transactor. This is what allows us to interact with the runtime assets from the point -/// of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. -/// -/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. -pub type LocalAssetTransactor = XcmCurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // We can convert the MultiLocations with our converter above: - SovereignAccountOf, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We track our teleports in/out to keep total issuance correct. - LocalCheckAccount, ->; - -/// The means that we convert an XCM origin `MultiLocation` into the runtime's `Origin` type for -/// local dispatch. This is a conversion function from an `OriginKind` type along with the -/// `MultiLocation` value and returns an `Origin` value or an error. -type LocalOriginConverter = ( - // If the origin kind is `Sovereign`, then return a `Signed` origin with the account determined - // by the `SovereignAccountOf` converter. - SovereignSignedViaLocation, - // If the origin kind is `Native` and the XCM origin is a child parachain, then we can express - // it with the special `parachains_origin::Origin` origin variant. - ChildParachainAsNative, - // If the origin kind is `Native` and the XCM origin is the `AccountId32` location, then it can - // be expressed using the `Signed` origin variant. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -parameter_types! { - /// The amount of weight an XCM operation takes. This is a safe overestimate. - pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 1024); - /// Maximum number of instructions in a single XCM fragment. A sanity check against weight - /// calculations getting too crazy. - pub const MaxInstructions: u32 = 100; - /// The asset ID for the asset that we use to pay for message delivery fees. - pub FeeAssetId: AssetId = Concrete(TokenLocation::get()); - /// The base fee for the message delivery fees. - pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); -} - -/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our -/// individual routers. -pub type XcmRouter = WithUniqueTopic<( - // Only one router so far - use DMP to communicate with child parachains. - ChildParachainRouter< - Runtime, - XcmPallet, - ExponentialPrice, - >, -)>; - -parameter_types! { - pub const Dot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); - pub const StatemintLocation: MultiLocation = Parachain(STATEMINT_ID).into_location(); - pub const DotForStatemint: (MultiAssetFilter, MultiLocation) = (Dot::get(), StatemintLocation::get()); - pub const CollectivesLocation: MultiLocation = Parachain(COLLECTIVES_ID).into_location(); - pub const DotForCollectives: (MultiAssetFilter, MultiLocation) = (Dot::get(), CollectivesLocation::get()); - pub const MaxAssetsIntoHolding: u32 = 64; -} - -/// Polkadot Relay recognizes/respects the Statemint chain as a teleporter. -pub type TrustedTeleporters = - (xcm_builder::Case, xcm_builder::Case); - -match_types! { - pub type OnlyParachains: impl Contains = { - MultiLocation { parents: 0, interior: X1(Parachain(_)) } - }; - pub type CollectivesOrFellows: impl Contains = { - MultiLocation { parents: 0, interior: X1(Parachain(COLLECTIVES_ID)) } | - MultiLocation { parents: 0, interior: X2(Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }) } - }; -} - -/// The barriers one of which must be passed for an XCM message to be executed. -pub type Barrier = TrailingSetTopicAsId<( - // Weight that is paid for may be consumed. - TakeWeightCredit, - // Expected responses are OK. - AllowKnownQueryResponses, - WithComputedOrigin< - ( - // If the message is one that immediately attemps to pay for execution, then allow it. - AllowTopLevelPaidExecutionFrom, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, - // Collectives and Fellows plurality get free execution. - AllowExplicitUnpaidExecutionFrom, - ), - UniversalLocation, - ConstU32<8>, - >, -)>; - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = LocalOriginConverter; - // Polkadot Relay recognises no chains which act as reserves. - type IsReserve = (); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = WeightInfoBounds< - crate::weights::xcm::PolkadotXcmWeight, - RuntimeCall, - MaxInstructions, - >; - // The weight trader piggybacks on the existing transaction-fee conversion logic. - type Trader = - UsingComponents>; - type ResponseHandler = XcmPallet; - type AssetTrap = XcmPallet; - type AssetLocker = (); - type AssetExchanger = (); - type AssetClaims = XcmPallet; - type SubscriptionService = XcmPallet; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); - // No bridges yet... - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; -} - -parameter_types! { - // `GeneralAdmin` pluralistic body. - pub const GeneralAdminBodyId: BodyId = BodyId::Administration; - // StakingAdmin pluralistic body. - pub const StakingAdminBodyId: BodyId = BodyId::Defense; - // FellowshipAdmin pluralistic body. - pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); -} - -/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. -pub type GeneralAdminToPlurality = - OriginToPluralityVoice; - -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior -/// location of this chain. -pub type LocalOriginToLocation = ( - GeneralAdminToPlurality, - // And a usual Signed origin to be used in XCM as a corresponding AccountId32 - SignedToAccountId32, -); - -/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value. -pub type StakingAdminToPlurality = - OriginToPluralityVoice; - -/// Type to convert the `FellowshipAdmin` origin to a Plurality `MultiLocation` value. -pub type FellowshipAdminToPlurality = - OriginToPluralityVoice; - -/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an -/// interior location of this chain for a destination chain. -pub type LocalPalletOriginToLocation = ( - // GeneralAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. - GeneralAdminToPlurality, - // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. - StakingAdminToPlurality, - // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. - FellowshipAdminToPlurality, -); - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - // We only allow the root, the general admin, the fellowship admin and the staking admin to send - // messages. - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = XcmRouter; - // Anyone can execute XCM messages locally... - type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; - // ...but they must match our filter, which rejects all. - type XcmExecuteFilter = Nothing; // == Deny All - type XcmExecutor = xcm_executor::XcmExecutor; - type XcmTeleportFilter = Everything; // == Allow All - type XcmReserveTransferFilter = Everything; // == Allow All - type Weigher = WeightInfoBounds< - crate::weights::xcm::PolkadotXcmWeight, - RuntimeCall, - MaxInstructions, - >; - 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 = (); - type SovereignAccountOf = SovereignAccountOf; - type MaxLockers = ConstU32<8>; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - type WeightInfo = crate::weights::pallet_xcm::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; -} diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 8f38659b84f5498d7744a70445205400fc1e420c..0b8a8624bb673e7242f3b78066b7fbcaecc60c93 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -21,8 +21,10 @@ beefy-primitives = { package = "sp-consensus-beefy", path = "../../../substrate/ binary-merkle-tree = { path = "../../../substrate/utils/binary-merkle-tree", default-features = false } rococo-runtime-constants = { package = "rococo-runtime-constants", path = "constants", default-features = false } sp-api = { path = "../../../substrate/primitives/api", default-features = false } +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } inherents = { package = "sp-inherents", path = "../../../substrate/primitives/inherents", default-features = false } offchain-primitives = { package = "sp-offchain", path = "../../../substrate/primitives/offchain", default-features = false } +sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } @@ -47,8 +49,10 @@ pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migr 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 } pallet-collective = { path = "../../../substrate/frame/collective", default-features = false } +pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false } pallet-elections-phragmen = { path = "../../../substrate/frame/elections-phragmen", default-features = false } +pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } @@ -62,12 +66,14 @@ pallet-nis = { path = "../../../substrate/frame/nis", default-features = false } pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } +pallet-ranked-collective = { path = "../../../substrate/frame/ranked-collective", default-features = false } pallet-recovery = { path = "../../../substrate/frame/recovery", default-features = false } +pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } pallet-session = { path = "../../../substrate/frame/session", default-features = false } pallet-society = { path = "../../../substrate/frame/society", default-features = false } pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] } pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } @@ -76,6 +82,7 @@ pallet-tips = { path = "../../../substrate/frame/tips", default-features = false pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } +pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } @@ -104,7 +111,7 @@ sp-tracing = { path = "../../../substrate/primitives/tracing", default-features tokio = { version = "1.24.2", features = ["macros"] } [build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } +substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder", optional = true } [features] default = [ "std" ] @@ -125,6 +132,7 @@ std = [ "inherents/std", "log/std", "offchain-primitives/std", + "pallet-asset-rate/std", "pallet-authority-discovery/std", "pallet-authorship/std", "pallet-babe/std", @@ -134,6 +142,7 @@ std = [ "pallet-bounties/std", "pallet-child-bounties/std", "pallet-collective/std", + "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", "pallet-grandpa/std", @@ -148,7 +157,9 @@ std = [ "pallet-offences/std", "pallet-preimage/std", "pallet-proxy/std", + "pallet-ranked-collective/std", "pallet-recovery/std", + "pallet-referenda/std", "pallet-scheduler/std", "pallet-session/std", "pallet-society/std", @@ -162,6 +173,7 @@ std = [ "pallet-treasury/std", "pallet-utility/std", "pallet-vesting/std", + "pallet-whitelist/std", "pallet-xcm-benchmarks?/std", "pallet-xcm/std", "parity-scale-codec/std", @@ -174,7 +186,9 @@ std = [ "serde/std", "serde_derive", "sp-api/std", + "sp-arithmetic/std", "sp-core/std", + "sp-genesis-builder/std", "sp-io/std", "sp-mmr-primitives/std", "sp-runtime/std", @@ -184,6 +198,7 @@ std = [ "sp-storage/std", "sp-tracing/std", "sp-version/std", + "substrate-wasm-builder", "tx-pool-api/std", "xcm-builder/std", "xcm-executor/std", @@ -194,11 +209,13 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-asset-rate/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", "pallet-child-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", @@ -213,7 +230,9 @@ runtime-benchmarks = [ "pallet-offences/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-ranked-collective/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", @@ -224,6 +243,7 @@ runtime-benchmarks = [ "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -241,6 +261,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-babe/try-runtime", @@ -250,6 +271,7 @@ try-runtime = [ "pallet-bounties/try-runtime", "pallet-child-bounties/try-runtime", "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", "pallet-democracy/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-grandpa/try-runtime", @@ -264,7 +286,9 @@ try-runtime = [ "pallet-offences/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", + "pallet-ranked-collective/try-runtime", "pallet-recovery/try-runtime", + "pallet-referenda/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-society/try-runtime", @@ -277,6 +301,7 @@ try-runtime = [ "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-vesting/try-runtime", + "pallet-whitelist/try-runtime", "pallet-xcm/try-runtime", "runtime-common/try-runtime", "runtime-parachains/try-runtime", @@ -287,3 +312,8 @@ try-runtime = [ fast-runtime = [] runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = [ "sp-api/disable-logging" ] diff --git a/polkadot/runtime/rococo/README.md b/polkadot/runtime/rococo/README.md index 465afd25549b69f8e3ef30f926bdefa4b81ed88f..5b2c296f0ced9a053de46bac5d8207d7a1d835d8 100644 --- a/polkadot/runtime/rococo/README.md +++ b/polkadot/runtime/rococo/README.md @@ -2,6 +2,13 @@ Rococo is a testnet runtime with no stability guarantees. +## How to build `rococo` runtime +`EpochDurationInBlocks` parameter is configurable via `ROCOCO_EPOCH_DURATION` environment variable. To build wasm +runtime blob with customized epoch duration the following command shall be exectuted: +```bash +ROCOCO_EPOCH_DURATION=10 ./polkadot/scripts/build-only-wasm.sh rococo-runtime /path/to/output/directory/ +``` + ## How to run `rococo-local` The [Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/) details building, starting, and diff --git a/polkadot/runtime/rococo/build.rs b/polkadot/runtime/rococo/build.rs index e7134e0ef723eae59cbd65a79ad7dda47d958b52..ed32d33105b76c45bac68360e92646019e578b2e 100644 --- a/polkadot/runtime/rococo/build.rs +++ b/polkadot/runtime/rococo/build.rs @@ -14,12 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use substrate_wasm_builder::WasmBuilder; - +#[cfg(feature = "std")] fn main() { - WasmBuilder::new() + // note: needs to be synced with rococo-runtime-constants::time hard-coded string literal + const ROCOCO_EPOCH_DURATION_ENV: &str = "ROCOCO_EPOCH_DURATION"; + + substrate_wasm_builder::WasmBuilder::new() .with_current_project() .import_memory() .export_heap_base() - .build() + .build(); + + println!("cargo:rerun-if-env-changed={}", ROCOCO_EPOCH_DURATION_ENV); } + +#[cfg(not(feature = "std"))] +fn main() {} diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 214e2f3fa980e8793c2683c544cb69b2d0d8d00e..2200f7ddefe1f912f026b98f7232cf7273891d18 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -38,12 +38,13 @@ pub mod currency { /// Time and blocks. pub mod time { use primitives::{BlockNumber, Moment}; - use runtime_common::prod_or_fast; pub const MILLISECS_PER_BLOCK: Moment = 6000; pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; - pub const DEFAULT_EPOCH_DURATION: BlockNumber = prod_or_fast!(1 * HOURS, 1 * MINUTES); + frame_support::parameter_types! { - pub storage EpochDurationInBlocks: BlockNumber = DEFAULT_EPOCH_DURATION; + pub storage EpochDurationInBlocks: BlockNumber = option_env!("ROCOCO_EPOCH_DURATION") + .map(|s| s.parse().expect("`ROCOCO_EPOCH_DURATION` is not a valid `BlockNumber`")) + .unwrap_or(1 * MINUTES); } // These time units are defined in number of blocks. diff --git a/polkadot/runtime/kusama/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs similarity index 90% rename from polkadot/runtime/kusama/src/governance/fellowship.rs rename to polkadot/runtime/rococo/src/governance/fellowship.rs index 8837c19e0eb1461b3c287037ef69e776d46ac832..b5df6cf2df341c5563f31ea6f49f1eeae5b81fc1 100644 --- a/polkadot/runtime/kusama/src/governance/fellowship.rs +++ b/polkadot/runtime/rococo/src/governance/fellowship.rs @@ -14,20 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Elements of governance concerning the Polkadot Fellowship. This is only a temporary arrangement -//! since the Polkadot Fellowship belongs under the Polkadot Relay. However, that is not yet in -//! place, so until then it will need to live here. Once it is in place and there exists a bridge -//! between Polkadot/Kusama then this code can be removed. +//! Elements of governance concerning the Rococo Fellowship. use frame_support::traits::{MapSuccess, TryMapSuccess}; -use sp_arithmetic::traits::CheckedSub; -use sp_runtime::{ - morph_types, - traits::{ConstU16, Replace, TypedGet}, -}; +use sp_runtime::traits::{CheckedReduceBy, ConstU16, Replace}; use super::*; -use crate::{DAYS, QUID}; +use crate::{CENTS, DAYS}; parameter_types! { pub const AlarmInterval: BlockNumber = 1; @@ -46,7 +39,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "candidates", max_deciding: 10, - decision_deposit: 100 * QUID, + decision_deposit: 100 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -68,7 +61,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "members", max_deciding: 10, - decision_deposit: 10 * QUID, + decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -90,7 +83,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "proficients", max_deciding: 10, - decision_deposit: 10 * QUID, + decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -112,7 +105,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "fellows", max_deciding: 10, - decision_deposit: 10 * QUID, + decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -134,7 +127,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "senior fellows", max_deciding: 10, - decision_deposit: 10 * QUID, + decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -156,7 +149,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "experts", max_deciding: 10, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -178,7 +171,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "senior experts", max_deciding: 10, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -200,7 +193,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "masters", max_deciding: 10, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -222,7 +215,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "senior masters", max_deciding: 10, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -244,7 +237,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { pallet_referenda::TrackInfo { name: "grand masters", max_deciding: 10, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, decision_period: 7 * DAYS, confirm_period: 30 * MINUTES, @@ -319,14 +312,6 @@ impl pallet_referenda::Config for Runtime { pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; -morph_types! { - /// A `TryMorph` implementation to reduce a scalar by a particular amount, checking for - /// underflow. - pub type CheckedReduceBy: TryMorph = |r: N::Type| -> Result { - r.checked_sub(&N::get()).ok_or(()) - } where N::Type: CheckedSub; -} - impl pallet_ranked_collective::Config for Runtime { type WeightInfo = weights::pallet_ranked_collective::WeightInfo; type RuntimeEvent = RuntimeEvent; diff --git a/polkadot/runtime/kusama/src/governance/mod.rs b/polkadot/runtime/rococo/src/governance/mod.rs similarity index 96% rename from polkadot/runtime/kusama/src/governance/mod.rs rename to polkadot/runtime/rococo/src/governance/mod.rs index c8a7b360ed4e9685e838864f739d32bb54938cb0..ef2adf60753d541c44eaf6073a3a012e66bf9f5c 100644 --- a/polkadot/runtime/kusama/src/governance/mod.rs +++ b/polkadot/runtime/rococo/src/governance/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! New governance configurations for the Kusama runtime. +//! New governance configurations for the Rococo runtime. use super::*; use frame_support::{ @@ -51,7 +51,7 @@ impl pallet_conviction_voting::Config for Runtime { parameter_types! { pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 1 * QUID; + pub const SubmissionDeposit: Balance = 1 * 3 * CENTS; pub const UndecidingTimeout: BlockNumber = 14 * DAYS; } diff --git a/polkadot/runtime/kusama/src/governance/origins.rs b/polkadot/runtime/rococo/src/governance/origins.rs similarity index 97% rename from polkadot/runtime/kusama/src/governance/origins.rs rename to polkadot/runtime/rococo/src/governance/origins.rs index c5cb035a526947a973eabd8b4bca32c6b280b10d..e4639f40dc432473e1222f6ab1094a31ecd26f68 100644 --- a/polkadot/runtime/kusama/src/governance/origins.rs +++ b/polkadot/runtime/rococo/src/governance/origins.rs @@ -20,7 +20,7 @@ pub use pallet_custom_origins::*; #[frame_support::pallet] pub mod pallet_custom_origins { - use crate::{Balance, GRAND, QUID}; + use crate::{Balance, CENTS, GRAND}; use frame_support::pallet_prelude::*; #[pallet::config] @@ -38,7 +38,7 @@ pub mod pallet_custom_origins { Treasurer, /// Origin for managing the composition of the fellowship. FellowshipAdmin, - /// Origin for managing the registrar and permissioned HRMP channel operations. + /// Origin for managing the registrar. GeneralAdmin, /// Origin for starting auctions. AuctionAdmin, @@ -169,7 +169,7 @@ pub mod pallet_custom_origins { decl_ensure! { pub type Spender: EnsureOrigin { - SmallTipper = 250 * QUID, + SmallTipper = 250 * 3 * CENTS, BigTipper = 1 * GRAND, SmallSpender = 10 * GRAND, MediumSpender = 100 * GRAND, diff --git a/polkadot/runtime/kusama/src/governance/tracks.rs b/polkadot/runtime/rococo/src/governance/tracks.rs similarity index 79% rename from polkadot/runtime/kusama/src/governance/tracks.rs rename to polkadot/runtime/rococo/src/governance/tracks.rs index 08a87a677c353694f68df0ff96b9e6ba111ee058..3765569f183e0414a10fe2852e528ccc9dedc3d7 100644 --- a/polkadot/runtime/kusama/src/governance/tracks.rs +++ b/polkadot/runtime/rococo/src/governance/tracks.rs @@ -72,10 +72,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "root", max_deciding: 1, decision_deposit: 100 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 24 * HOURS, - min_enactment_period: 24 * HOURS, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_ROOT, min_support: SUP_ROOT, }, @@ -86,10 +86,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "whitelisted_caller", max_deciding: 100, decision_deposit: 10 * GRAND, - prepare_period: 30 * MINUTES, - decision_period: 14 * DAYS, - confirm_period: 10 * MINUTES, - min_enactment_period: 10 * MINUTES, + prepare_period: 6 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 4 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_WHITELISTED_CALLER, min_support: SUP_WHITELISTED_CALLER, }, @@ -100,10 +100,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "staking_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_STAKING_ADMIN, min_support: SUP_STAKING_ADMIN, }, @@ -114,10 +114,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "treasurer", max_deciding: 10, decision_deposit: 1 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 24 * HOURS, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_TREASURER, min_support: SUP_TREASURER, }, @@ -128,10 +128,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "lease_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_LEASE_ADMIN, min_support: SUP_LEASE_ADMIN, }, @@ -142,10 +142,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "fellowship_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_FELLOWSHIP_ADMIN, min_support: SUP_FELLOWSHIP_ADMIN, }, @@ -156,10 +156,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "general_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_GENERAL_ADMIN, min_support: SUP_GENERAL_ADMIN, }, @@ -170,10 +170,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "auction_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_AUCTION_ADMIN, min_support: SUP_AUCTION_ADMIN, }, @@ -184,10 +184,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "referendum_canceller", max_deciding: 1_000, decision_deposit: 10 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 7 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_REFERENDUM_CANCELLER, min_support: SUP_REFERENDUM_CANCELLER, }, @@ -198,10 +198,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "referendum_killer", max_deciding: 1_000, decision_deposit: 50 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_REFERENDUM_KILLER, min_support: SUP_REFERENDUM_KILLER, }, @@ -211,10 +211,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "small_tipper", max_deciding: 200, - decision_deposit: 1 * QUID, + decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 10 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 4 * MINUTES, min_enactment_period: 1 * MINUTES, min_approval: APP_SMALL_TIPPER, min_support: SUP_SMALL_TIPPER, @@ -225,11 +225,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "big_tipper", max_deciding: 100, - decision_deposit: 10 * QUID, - prepare_period: 10 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 1 * HOURS, - min_enactment_period: 10 * MINUTES, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 4 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_BIG_TIPPER, min_support: SUP_BIG_TIPPER, }, @@ -239,11 +239,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "small_spender", max_deciding: 50, - decision_deposit: 100 * QUID, - prepare_period: 4 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 12 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 100 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 10 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_SMALL_SPENDER, min_support: SUP_SMALL_SPENDER, }, @@ -253,11 +253,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "medium_spender", max_deciding: 50, - decision_deposit: 200 * QUID, - prepare_period: 4 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 24 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 200 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_MEDIUM_SPENDER, min_support: SUP_MEDIUM_SPENDER, }, @@ -267,11 +267,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "big_spender", max_deciding: 50, - decision_deposit: 400 * QUID, - prepare_period: 4 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 48 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 400 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 14 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_BIG_SPENDER, min_support: SUP_BIG_SPENDER, }, diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 6446ac4f00c11a186117f6602cbb92c9c23df7e6..3c08b9b2f94efd451e3085a951f25fabc4ec96db 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -30,7 +30,10 @@ use primitives::{ ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ - assigned_slots, auctions, claims, crowdloan, impl_runtime_weights, impls::ToAuthor, + assigned_slots, auctions, claims, crowdloan, impl_runtime_weights, + impls::{ + LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter, + }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BlockHashCount, BlockLength, SlowAdjustingFeeUpdate, }; @@ -46,7 +49,9 @@ use runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, - runtime_api_impl::v5 as parachains_runtime_api_impl, + runtime_api_impl::{ + v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, + }, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -58,10 +63,12 @@ use beefy_primitives::{ }; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + genesis_builder_helper::{build_config, create_default_config}, + parameter_types, traits::{ - fungible::HoldConsideration, Contains, EitherOfDiverse, InstanceFilter, - KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, PrivilegeCmp, ProcessMessage, + fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, @@ -77,7 +84,8 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, - Extrinsic as ExtrinsicT, Keccak256, OpaqueKeys, SaturatedConversion, Verify, + Extrinsic as ExtrinsicT, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, + Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, @@ -86,8 +94,11 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use static_assertions::const_assert; -use xcm::latest::Junction; +use xcm::{ + latest::{InteriorMultiLocation, Junction, Junction::PalletInstance}, + VersionedMultiLocation, +}; +use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -101,6 +112,13 @@ mod weights; // XCM configurations. pub mod xcm_config; +// Governance and configurations. +pub mod governance; +use governance::{ + pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer, + TreasurySpender, +}; + mod validator_manager; impl_runtime_weights!(rococo_runtime_constants); @@ -115,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 9430, + spec_version: 10020, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, @@ -135,11 +153,14 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// We currently allow all calls. -pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(_call: &RuntimeCall) -> bool { - true +/// A type to identify calls to the Identity pallet. These will be filtered to prevent invocation, +/// locking the state of the pallet and preventing further updates to identities and sub-identities. +/// The locked state will be the genesis state of a new system chain and then removed from the Relay +/// Chain. +pub struct IdentityCalls; +impl Contains for IdentityCalls { + fn contains(c: &RuntimeCall) -> bool { + matches!(c, RuntimeCall::Identity(_)) } } @@ -149,7 +170,7 @@ parameter_types! { } impl frame_system::Config for Runtime { - type BaseCallFilter = BaseFilter; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type DbWeight = RocksDbWeight; @@ -181,11 +202,6 @@ parameter_types! { pub const NoPreimagePostponement: Option = Some(10); } -type ScheduleOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, ->; - /// Used the compare the privilege of an origin inside the scheduler. pub struct OriginPrivilegeCmp; @@ -198,11 +214,6 @@ impl PrivilegeCmp for OriginPrivilegeCmp { match (left, right) { // Root is greater than anything. (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), - // Check which one has more yes votes. - ( - OriginCaller::Council(pallet_collective::RawOrigin::Members(l_yes_votes, l_count)), - OriginCaller::Council(pallet_collective::RawOrigin::Members(r_yes_votes, r_count)), - ) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))), // For every other origin we don't care, as they are not used for `ScheduleOrigin`. _ => None, } @@ -215,7 +226,9 @@ impl pallet_scheduler::Config for Runtime { type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = ScheduleOrigin; + // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of + // OpenGov to schedule periodic auctions. + type ScheduleOrigin = EitherOf, AuctionAdmin>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = weights::pallet_scheduler::WeightInfo; type OriginPrivilegeCmp = OriginPrivilegeCmp; @@ -375,171 +388,6 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 28; } -parameter_types! { - pub LaunchPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "ROC_LAUNCH_PERIOD"); - pub VotingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1 * MINUTES, "ROC_VOTING_PERIOD"); - pub FastTrackVotingPeriod: BlockNumber = prod_or_fast!(3 * HOURS, 1 * MINUTES, "ROC_FAST_TRACK_VOTING_PERIOD"); - pub const MinimumDeposit: Balance = 100 * CENTS; - pub EnactmentPeriod: BlockNumber = prod_or_fast!(8 * DAYS, 1, "ROC_ENACTMENT_PERIOD"); - pub CooloffPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1 * MINUTES, "ROC_COOLOFF_PERIOD"); - pub const InstantAllowed: bool = true; - pub const MaxVotes: u32 = 100; - pub const MaxProposals: u32 = 100; -} - -impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type VoteLockingPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type MinimumDeposit = MinimumDeposit; - type SubmitOrigin = frame_system::EnsureSigned; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = - pallet_collective::EnsureProportionAtLeast; - /// Two thirds of the technical committee can have an `ExternalMajority/ExternalDefault` vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantAllowed = InstantAllowed; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type BlacklistOrigin = EnsureRoot; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cooloff period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type PalletsOrigin = OriginCaller; - type MaxVotes = MaxVotes; - type WeightInfo = weights::pallet_democracy::WeightInfo; - type MaxProposals = MaxProposals; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; -} - -parameter_types! { - pub CouncilMotionDuration: BlockNumber = prod_or_fast!(3 * DAYS, 2 * MINUTES, "ROC_MOTION_DURATION"); - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; - pub MaxProposalWeight: Weight = Perbill::from_percent(50) * BlockWeights::get().max_block; -} - -type CouncilCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type SetMembersOrigin = EnsureRoot; - type WeightInfo = weights::pallet_collective_council::WeightInfo; - type MaxProposalWeight = MaxProposalWeight; -} - -parameter_types! { - pub const CandidacyBond: Balance = 100 * CENTS; - // 1 storage item created, key size is 32 bytes, value size is 16+16. - pub const VotingBondBase: Balance = deposit(1, 64); - // additional data per vote is 32 bytes (account id). - pub const VotingBondFactor: Balance = deposit(0, 32); - /// Daily council elections - pub TermDuration: BlockNumber = prod_or_fast!(24 * HOURS, 2 * MINUTES, "ROC_TERM_DURATION"); - pub const DesiredMembers: u32 = 19; - pub const DesiredRunnersUp: u32 = 19; - pub const MaxVoters: u32 = 10 * 1000; - pub const MaxVotesPerVoter: u32 = 16; - pub const MaxCandidates: u32 = 1000; - pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; -} - -// Make sure that there are no more than MaxMembers members elected via phragmen. -const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); - -impl pallet_elections_phragmen::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ChangeMembers = Council; - type InitializeMembers = Council; - type CurrencyToVote = runtime_common::CurrencyToVote; - type CandidacyBond = CandidacyBond; - type VotingBondBase = VotingBondBase; - type VotingBondFactor = VotingBondFactor; - type LoserCandidate = Treasury; - type KickedMember = Treasury; - type DesiredMembers = DesiredMembers; - type DesiredRunnersUp = DesiredRunnersUp; - type TermDuration = TermDuration; - type MaxVoters = MaxVoters; - type MaxVotesPerVoter = MaxVotesPerVoter; - type MaxCandidates = MaxCandidates; - type PalletId = PhragmenElectionPalletId; - type WeightInfo = weights::pallet_elections_phragmen::WeightInfo; -} - -parameter_types! { - pub TechnicalMotionDuration: BlockNumber = prod_or_fast!(3 * DAYS, 2 * MINUTES, "ROC_MOTION_DURATION"); - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; -} - -type TechnicalCollective = pallet_collective::Instance2; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type SetMembersOrigin = EnsureRoot; - type WeightInfo = weights::pallet_collective_technical_committee::WeightInfo; - type MaxProposalWeight = MaxProposalWeight; -} - -type MoreThanHalfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, ->; - -impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = MoreThanHalfCouncil; - type RemoveOrigin = MoreThanHalfCouncil; - type SwapOrigin = MoreThanHalfCouncil; - type ResetOrigin = MoreThanHalfCouncil; - type PrimeOrigin = MoreThanHalfCouncil; - type MembershipInitialized = TechnicalCommittee; - type MembershipChanged = TechnicalCommittee; - type MaxMembers = TechnicalMaxMembers; - type WeightInfo = weights::pallet_membership::WeightInfo; -} - parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const ProposalBondMinimum: Balance = 2000 * CENTS; @@ -547,6 +395,10 @@ parameter_types! { pub const SpendPeriod: BlockNumber = 6 * DAYS; pub const Burn: Permill = Permill::from_perthousand(2); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const PayoutSpendPeriod: BlockNumber = 30 * DAYS; + // The asset's interior location for the paying account. This is the Treasury + // pallet instance (which sits at index 18). + pub TreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(18).into(); pub const TipCountdown: BlockNumber = 1 * DAYS; pub const TipFindersFee: Percent = Percent::from_percent(20); @@ -556,18 +408,14 @@ parameter_types! { pub const MaxAuthorities: u32 = 100_000; pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxBalance: Balance = Balance::max_value(); } -type ApproveOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, ->; - impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = ApproveOrigin; - type RejectOrigin = MoreThanHalfCouncil; + type ApproveOrigin = EitherOfDiverse, Treasurer>; + type RejectOrigin = EitherOfDiverse, Treasurer>; type RuntimeEvent = RuntimeEvent; type OnSlash = Treasury; type ProposalBond = ProposalBond; @@ -579,7 +427,24 @@ impl pallet_treasury::Config for Runtime { type MaxApprovals = MaxApprovals; type WeightInfo = weights::pallet_treasury::WeightInfo; type SpendFunds = Bounties; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = TreasurySpender; + type AssetKind = VersionedLocatableAsset; + type Beneficiary = VersionedMultiLocation; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayOverXcm< + TreasuryInteriorLocation, + crate::xcm_config::XcmRouter, + crate::XcmPallet, + ConstU32<{ 6 * HOURS }>, + Self::Beneficiary, + Self::AssetKind, + LocatableAssetConverter, + VersionedMultiLocationConverter, + >; + type BalanceConverter = AssetRate; + type PayoutPeriod = PayoutSpendPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments; } parameter_types! { @@ -620,17 +485,6 @@ impl pallet_child_bounties::Config for Runtime { type WeightInfo = weights::pallet_child_bounties::WeightInfo; } -impl pallet_tips::Config for Runtime { - type MaximumReasonLength = MaximumReasonLength; - type DataDepositPerByte = DataDepositPerByte; - type Tippers = PhragmenElection; - type TipCountdown = TipCountdown; - type TipFindersFee = TipFindersFee; - type TipReportDepositBase = TipReportDepositBase; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::pallet_tips::WeightInfo; -} - impl pallet_offences::Config for Runtime { type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; @@ -741,8 +595,7 @@ impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type Prefix = Prefix; - type MoveClaimOrigin = - pallet_collective::EnsureProportionMoreThan; + type MoveClaimOrigin = EnsureRoot; type WeightInfo = weights::runtime_common_claims::WeightInfo; } @@ -766,8 +619,8 @@ impl pallet_identity::Config for Runtime { type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; - type ForceOrigin = MoreThanHalfCouncil; - type RegistrarOrigin = MoreThanHalfCouncil; + type ForceOrigin = EitherOf, GeneralAdmin>; + type RegistrarOrigin = EitherOf, GeneralAdmin>; type WeightInfo = weights::pallet_identity::WeightInfo; } @@ -908,15 +761,14 @@ impl InstanceFilter for ProxyType { RuntimeCall::Session(..) | RuntimeCall::Grandpa(..) | RuntimeCall::ImOnline(..) | - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | - RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::PhragmenElection(..) | - RuntimeCall::TechnicalMembership(..) | RuntimeCall::Treasury(..) | RuntimeCall::Bounties(..) | RuntimeCall::ChildBounties(..) | - RuntimeCall::Tips(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::FellowshipCollective(..) | + RuntimeCall::FellowshipReferenda(..) | + RuntimeCall::Whitelist(..) | RuntimeCall::Claims(..) | RuntimeCall::Utility(..) | RuntimeCall::Identity(..) | @@ -943,17 +795,18 @@ impl InstanceFilter for ProxyType { RuntimeCall::Slots(..) | RuntimeCall::Auctions(..) // Specifically omitting the entire XCM Pallet ), - ProxyType::Governance => - matches!( - c, - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::PhragmenElection(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::Tips(..) | RuntimeCall::Utility(..) | - RuntimeCall::ChildBounties(..) - ), + ProxyType::Governance => matches!( + c, + RuntimeCall::Bounties(..) | + RuntimeCall::Utility(..) | + RuntimeCall::ChildBounties(..) | + // OpenGov calls + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::FellowshipCollective(..) | + RuntimeCall::FellowshipReferenda(..) | + RuntimeCall::Whitelist(..) + ), ProxyType::IdentityJudgement => matches!( c, RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | @@ -1179,7 +1032,7 @@ impl slots::Config for Runtime { type Registrar = Registrar; type LeasePeriod = LeasePeriod; type LeaseOffset = (); - type ForceOrigin = MoreThanHalfCouncil; + type ForceOrigin = EitherOf, LeaseAdmin>; type WeightInfo = weights::runtime_common_slots::WeightInfo; } @@ -1212,11 +1065,6 @@ parameter_types! { pub const SampleLength: BlockNumber = 2 * MINUTES; } -type AuctionInitiate = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, ->; - impl auctions::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Leaser = Slots; @@ -1224,7 +1072,7 @@ impl auctions::Config for Runtime { type EndingPeriod = EndingPeriod; type SampleLength = SampleLength; type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type InitiateOrigin = AuctionInitiate; + type InitiateOrigin = EitherOf, AuctionAdmin>; type WeightInfo = weights::runtime_common_auctions::WeightInfo; } @@ -1386,6 +1234,18 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = weights::pallet_sudo::WeightInfo; } +impl pallet_asset_rate::Config for Runtime { + type WeightInfo = weights::pallet_asset_rate::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type CreateOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type Currency = Balances; + type AssetKind = ::AssetKind; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments; +} + construct_runtime! { pub enum Runtime { @@ -1420,13 +1280,19 @@ construct_runtime! { AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 12, // Governance stuff; uncallable initially. - Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event} = 13, - Council: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 14, - TechnicalCommittee: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 15, - PhragmenElection: pallet_elections_phragmen::{Pallet, Call, Storage, Event, Config} = 16, - TechnicalMembership: pallet_membership::::{Pallet, Call, Storage, Event, Config} = 17, Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 18, - + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 20, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 21, + // pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1; + FellowshipCollective: pallet_ranked_collective::::{ + Pallet, Call, Storage, Event + } = 22, + // pub type FellowshipReferendaInstance = pallet_referenda::Instance2; + FellowshipReferenda: pallet_referenda::::{ + Pallet, Call, Storage, Event + } = 23, + Origins: pallet_custom_origins::{Origin} = 43, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 44, // Claims. Usable initially. Claims: claims::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 19, @@ -1457,13 +1323,13 @@ construct_runtime! { // Preimage registrar. Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 32, + // Asset rate. + AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event} = 39, + // Bounties modules. Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 35, ChildBounties: pallet_child_bounties = 40, - // Tips module. - Tips: pallet_tips::{Pallet, Call, Storage, Event} = 36, - // NIS pallet. Nis: pallet_nis::{Pallet, Call, Storage, Event, HoldReason} = 38, // pub type NisCounterpartInstance = pallet_balances::Instance2; @@ -1548,6 +1414,52 @@ pub type Migrations = migrations::Unreleased; pub mod migrations { use super::*; + use frame_support::traits::LockIdentifier; + use frame_system::pallet_prelude::BlockNumberFor; + + parameter_types! { + pub const DemocracyPalletName: &'static str = "Democracy"; + pub const CouncilPalletName: &'static str = "Council"; + pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; + pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; + pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; + pub const TipsPalletName: &'static str = "Tips"; + pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; + } + + // Special Config for Gov V1 pallets, allowing us to run migrations for them without + // implementing their configs on [`Runtime`]. + pub struct UnlockConfig; + impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { + type Currency = Balances; + type MaxVotes = ConstU32<100>; + type MaxDeposits = ConstU32<100>; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = DemocracyPalletName; + } + impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig + for UnlockConfig + { + type Currency = Balances; + type MaxVotesPerVoter = ConstU32<16>; + type PalletId = PhragmenElectionPalletId; + type AccountId = AccountId; + type DbWeight = ::DbWeight; + type PalletName = PhragmenElectionPalletName; + } + impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { + type Currency = Balances; + type Hash = Hash; + type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = TipReportDepositBase; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = TipsPalletName; + } + /// Unreleased migrations. Add new ones here: pub type Unreleased = ( pallet_society::migrations::VersionCheckedMigrateToV2, @@ -1558,6 +1470,23 @@ pub mod migrations { parachains_configuration::migration::v8::MigrateToV8, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::VersionCheckedMigrateToV1, + pallet_referenda::migration::v1::MigrateV0ToV1, + pallet_referenda::migration::v1::MigrateV0ToV1, + + // Unlock & unreserve Gov1 funds + + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete all Gov v1 pallet storage key/values. + + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, ); } @@ -1624,28 +1553,28 @@ mod benches { [frame_benchmarking::baseline, Baseline::] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] - [pallet_collective, Council] - [pallet_collective, TechnicalCommittee] - [pallet_democracy, Democracy] - [pallet_elections_phragmen, PhragmenElection] + [pallet_conviction_voting, ConvictionVoting] [pallet_nis, Nis] [pallet_identity, Identity] [pallet_im_online, ImOnline] [pallet_indices, Indices] - [pallet_membership, TechnicalMembership] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_preimage, Preimage] [pallet_proxy, Proxy] + [pallet_ranked_collective, FellowshipCollective] [pallet_recovery, Recovery] + [pallet_referenda, Referenda] + [pallet_referenda, FellowshipReferenda] [pallet_scheduler, Scheduler] [pallet_sudo, Sudo] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] - [pallet_tips, Tips] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_asset_rate, AssetRate] + [pallet_whitelist, Whitelist] // XCM [pallet_xcm, XcmPallet] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::] @@ -1719,6 +1648,7 @@ sp_api::impl_runtime_apis! { } } + #[api_version(8)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1849,6 +1779,23 @@ sp_api::impl_runtime_apis! { key_ownership_proof, ) } + + fn minimum_backing_votes() -> u32 { + parachains_runtime_api_impl::minimum_backing_votes::() + } + + fn para_backing_state(para_id: ParaId) -> Option { + parachains_runtime_api_impl::backing_state::(para_id) + } + + fn async_backing_params() -> primitives::AsyncBackingParams { + parachains_runtime_api_impl::async_backing_params::() + } + + fn disabled_validators() -> Vec { + parachains_staging_runtime_api_impl::disabled_validators::() + } + } #[api_version(3)] @@ -2125,7 +2072,7 @@ sp_api::impl_runtime_apis! { use sp_storage::TrackedStorageKey; use xcm::latest::prelude::*; use xcm_config::{ - LocalCheckAccount, LocationConverter, Rockmine, TokenLocation, XcmConfig, + LocalCheckAccount, LocationConverter, AssetHub, TokenLocation, XcmConfig, }; impl frame_system_benchmarking::Config for Runtime {} @@ -2134,7 +2081,7 @@ sp_api::impl_runtime_apis! { type XcmConfig = XcmConfig; type AccountIdConverter = LocationConverter; fn valid_destination() -> Result { - Ok(Rockmine::get()) + Ok(AssetHub::get()) } fn worst_case_holding(_depositable_count: u32) -> MultiAssets { // Rococo only knows about ROC @@ -2147,7 +2094,7 @@ sp_api::impl_runtime_apis! { parameter_types! { pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - Rockmine::get(), + AssetHub::get(), MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) }, )); pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; @@ -2186,15 +2133,15 @@ sp_api::impl_runtime_apis! { } fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((Rockmine::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + Ok((AssetHub::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) } fn subscribe_origin() -> Result { - Ok(Rockmine::get()) + Ok(AssetHub::get()) } fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = Rockmine::get(); + let origin = AssetHub::get(); let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); let ticket = MultiLocation { parents: 0, interior: Here }; Ok((origin, ticket, assets)) @@ -2229,6 +2176,16 @@ sp_api::impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } #[cfg(test)] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 21558ca3fb90548f08d90bb79fcea531165d3287..9c563a67d98b721b08cb3d84c4f5562682749b1d 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -16,31 +16,31 @@ //! A list of the different weight modules for our runtime. pub mod frame_system; +pub mod pallet_asset_rate; pub mod pallet_balances; pub mod pallet_balances_nis_counterpart_balances; pub mod pallet_bounties; pub mod pallet_child_bounties; -pub mod pallet_collective_council; -pub mod pallet_collective_technical_committee; -pub mod pallet_democracy; -pub mod pallet_elections_phragmen; +pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_im_online; pub mod pallet_indices; -pub mod pallet_membership; pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_nis; pub mod pallet_preimage; pub mod pallet_proxy; +pub mod pallet_ranked_collective; +pub mod pallet_referenda_fellowship_referenda; +pub mod pallet_referenda_referenda; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_sudo; pub mod pallet_timestamp; -pub mod pallet_tips; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; +pub mod pallet_whitelist; pub mod pallet_xcm; pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; diff --git a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs new file mode 100644 index 0000000000000000000000000000000000000000..da2d1958cefcfeb41bcdba7ed2dd9c6b4272e873 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs @@ -0,0 +1,86 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_asset_rate` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-03, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=2 +// --pallet=pallet_asset_rate +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./runtime/rococo/src/weights/ +// --header=./file_header.txt + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_rate`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_rate::WeightInfo for WeightInfo { + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `4702` + // Minimum execution time: 143_000_000 picoseconds. + Weight::from_parts(155_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 156_000_000 picoseconds. + Weight::from_parts(172_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 150_000_000 picoseconds. + Weight::from_parts(160_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_collective.rs deleted file mode 100644 index 9bf6671e2297112790655e99037f0ab412556ddc..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_collective.rs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . -//! Autogenerated weights for `pallet_collective` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::{Weight}}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - // Storage: Collective Members (r:1 w:1) - // Storage: Collective Proposals (r:1 w:0) - // Storage: Collective Voting (r:100 w:100) - // Storage: Collective Prime (r:0 w:1) - /// The range of component `m` is `[1, 100]`. - /// The range of component `n` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - Weight::from_parts(0 as u64, 0) - // Standard Error: 15_000 - .saturating_add(Weight::from_parts(10_832_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 15_000 - .saturating_add(Weight::from_parts(12_894_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(p as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) - } - // Storage: Collective Members (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - Weight::from_parts(19_069_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(2_000 as u64, 0).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(13_000 as u64, 0).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - } - // Storage: Collective Members (r:1 w:0) - // Storage: Collective ProposalOf (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - Weight::from_parts(20_794_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(2_000 as u64, 0).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(22_000 as u64, 0).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - } - // Storage: Collective Members (r:1 w:0) - // Storage: Collective ProposalOf (r:1 w:1) - // Storage: Collective Proposals (r:1 w:1) - // Storage: Collective ProposalCount (r:1 w:1) - // Storage: Collective Voting (r:0 w:1) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_parts(27_870_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(3_000 as u64, 0).saturating_mul(b as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_parts(22_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 1_000 - .saturating_add(Weight::from_parts(94_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - } - // Storage: Collective Members (r:1 w:0) - // Storage: Collective Voting (r:1 w:1) - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - Weight::from_parts(27_249_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(35_000 as u64, 0).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Collective Voting (r:1 w:1) - // Storage: Collective Members (r:1 w:0) - // Storage: Collective Proposals (r:1 w:1) - // Storage: Collective ProposalOf (r:0 w:1) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_parts(30_754_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(28_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(81_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Collective Voting (r:1 w:1) - // Storage: Collective Members (r:1 w:0) - // Storage: Collective ProposalOf (r:1 w:1) - // Storage: Collective Proposals (r:1 w:1) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_parts(39_508_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_000 as u64, 0).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(29_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(90_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Collective Voting (r:1 w:1) - // Storage: Collective Members (r:1 w:0) - // Storage: Collective Prime (r:1 w:0) - // Storage: Collective Proposals (r:1 w:1) - // Storage: Collective ProposalOf (r:0 w:1) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - Weight::from_parts(32_769_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(31_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(83_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Collective Voting (r:1 w:1) - // Storage: Collective Members (r:1 w:0) - // Storage: Collective Prime (r:1 w:0) - // Storage: Collective ProposalOf (r:1 w:1) - // Storage: Collective Proposals (r:1 w:1) - /// The range of component `b` is `[1, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - Weight::from_parts(41_704_000 as u64, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_000 as u64, 0).saturating_mul(b as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(28_000 as u64, 0).saturating_mul(m as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(92_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Collective Proposals (r:1 w:1) - // Storage: Collective Voting (r:0 w:1) - // Storage: Collective ProposalOf (r:0 w:1) - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - Weight::from_parts(22_720_000 as u64, 0) - // Standard Error: 2_000 - .saturating_add(Weight::from_parts(74_000 as u64, 0).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_collective_council.rs b/polkadot/runtime/rococo/src/weights/pallet_collective_council.rs deleted file mode 100644 index 835bdef7e67387d97edd1e7004a4a5d454711960..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_collective_council.rs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_collective` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: Council Members (r:1 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:100 w:100) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15795 + m * (1967 ±16) + p * (4332 ±16)` - // Minimum execution time: 17_182_000 picoseconds. - Weight::from_parts(17_462_000, 0) - .saturating_add(Weight::from_parts(0, 15795)) - // Standard Error: 42_032 - .saturating_add(Weight::from_parts(4_868_618, 0).saturating_mul(m.into())) - // Standard Error: 42_032 - .saturating_add(Weight::from_parts(7_289_594, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `136 + m * (32 ±0)` - // Estimated: `1622 + m * (32 ±0)` - // Minimum execution time: 16_507_000 picoseconds. - Weight::from_parts(16_066_632, 0) - .saturating_add(Weight::from_parts(0, 1622)) - // Standard Error: 21 - .saturating_add(Weight::from_parts(982, 0).saturating_mul(b.into())) - // Standard Error: 220 - .saturating_add(Weight::from_parts(14_026, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:0) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `136 + m * (32 ±0)` - // Estimated: `3602 + m * (32 ±0)` - // Minimum execution time: 18_990_000 picoseconds. - Weight::from_parts(18_411_713, 0) - .saturating_add(Weight::from_parts(0, 3602)) - // Standard Error: 15 - .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(b.into())) - // Standard Error: 164 - .saturating_add(Weight::from_parts(23_067, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalCount (r:1 w:1) - /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `426 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3818 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 25_500_000 picoseconds. - Weight::from_parts(26_304_307, 0) - .saturating_add(Weight::from_parts(0, 3818)) - // Standard Error: 49 - .saturating_add(Weight::from_parts(2_243, 0).saturating_mul(b.into())) - // Standard Error: 515 - .saturating_add(Weight::from_parts(18_905, 0).saturating_mul(m.into())) - // Standard Error: 508 - .saturating_add(Weight::from_parts(120_761, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `875 + m * (64 ±0)` - // Estimated: `4339 + m * (64 ±0)` - // Minimum execution time: 22_166_000 picoseconds. - Weight::from_parts(22_901_859, 0) - .saturating_add(Weight::from_parts(0, 4339)) - // Standard Error: 238 - .saturating_add(Weight::from_parts(40_475, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `464 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3909 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_064_000 picoseconds. - Weight::from_parts(27_961_599, 0) - .saturating_add(Weight::from_parts(0, 3909)) - // Standard Error: 401 - .saturating_add(Weight::from_parts(22_196, 0).saturating_mul(m.into())) - // Standard Error: 391 - .saturating_add(Weight::from_parts(115_698, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `766 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4083 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 38_302_000 picoseconds. - Weight::from_parts(40_639_640, 0) - .saturating_add(Weight::from_parts(0, 4083)) - // Standard Error: 123 - .saturating_add(Weight::from_parts(1_914, 0).saturating_mul(b.into())) - // Standard Error: 1_272 - .saturating_add(Weight::from_parts(150_067, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `484 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3929 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 30_017_000 picoseconds. - Weight::from_parts(30_565_580, 0) - .saturating_add(Weight::from_parts(0, 3929)) - // Standard Error: 378 - .saturating_add(Weight::from_parts(24_396, 0).saturating_mul(m.into())) - // Standard Error: 369 - .saturating_add(Weight::from_parts(114_807, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: Council Voting (r:1 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Members (r:1 w:0) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:0) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:1 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `786 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4103 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_911_000 picoseconds. - Weight::from_parts(42_312_485, 0) - .saturating_add(Weight::from_parts(0, 4103)) - // Standard Error: 83 - .saturating_add(Weight::from_parts(2_208, 0).saturating_mul(b.into())) - // Standard Error: 879 - .saturating_add(Weight::from_parts(20_173, 0).saturating_mul(m.into())) - // Standard Error: 857 - .saturating_add(Weight::from_parts(146_302, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: Council Proposals (r:1 w:1) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Voting (r:0 w:1) - /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council ProposalOf (r:0 w:1) - /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `293 + p * (32 ±0)` - // Estimated: `1778 + p * (32 ±0)` - // Minimum execution time: 15_465_000 picoseconds. - Weight::from_parts(17_387_663, 0) - .saturating_add(Weight::from_parts(0, 1778)) - // Standard Error: 450 - .saturating_add(Weight::from_parts(110_406, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_collective_technical_committee.rs b/polkadot/runtime/rococo/src/weights/pallet_collective_technical_committee.rs deleted file mode 100644 index 6d66dc871cd54edcd9c846fc0a3e059d1f8a42ce..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_collective_technical_committee.rs +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_collective` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_collective -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_collective`. -pub struct WeightInfo(PhantomData); -impl pallet_collective::WeightInfo for WeightInfo { - /// Storage: TechnicalCommittee Members (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:100 w:100) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - /// The range of component `m` is `[0, 100]`. - /// The range of component `n` is `[0, 100]`. - /// The range of component `p` is `[0, 100]`. - fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15766 + m * (1967 ±16) + p * (4332 ±16)` - // Minimum execution time: 17_826_000 picoseconds. - Weight::from_parts(18_046_000, 0) - .saturating_add(Weight::from_parts(0, 15766)) - // Standard Error: 42_164 - .saturating_add(Weight::from_parts(4_858_188, 0).saturating_mul(m.into())) - // Standard Error: 42_164 - .saturating_add(Weight::from_parts(7_379_354, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `107 + m * (32 ±0)` - // Estimated: `1593 + m * (32 ±0)` - // Minimum execution time: 16_992_000 picoseconds. - Weight::from_parts(16_555_669, 0) - .saturating_add(Weight::from_parts(0, 1593)) - // Standard Error: 18 - .saturating_add(Weight::from_parts(976, 0).saturating_mul(b.into())) - // Standard Error: 189 - .saturating_add(Weight::from_parts(12_101, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:0) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[1, 100]`. - fn propose_execute(b: u32, m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `107 + m * (32 ±0)` - // Estimated: `3573 + m * (32 ±0)` - // Minimum execution time: 19_900_000 picoseconds. - Weight::from_parts(19_068_072, 0) - .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_161, 0).saturating_mul(b.into())) - // Standard Error: 129 - .saturating_add(Weight::from_parts(22_376, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalCount (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[2, 100]`. - /// The range of component `p` is `[1, 100]`. - fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `397 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3789 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 26_264_000 picoseconds. - Weight::from_parts(27_099_606, 0) - .saturating_add(Weight::from_parts(0, 3789)) - // Standard Error: 50 - .saturating_add(Weight::from_parts(2_278, 0).saturating_mul(b.into())) - // Standard Error: 525 - .saturating_add(Weight::from_parts(19_424, 0).saturating_mul(m.into())) - // Standard Error: 519 - .saturating_add(Weight::from_parts(120_852, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[5, 100]`. - /// The range of component `m` is `[5, 100]`. - fn vote(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `846 + m * (64 ±0)` - // Estimated: `4310 + m * (64 ±0)` - // Minimum execution time: 22_954_000 picoseconds. - Weight::from_parts(23_675_214, 0) - .saturating_add(Weight::from_parts(0, 4310)) - // Standard Error: 256 - .saturating_add(Weight::from_parts(40_562, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `435 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3880 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_797_000 picoseconds. - Weight::from_parts(28_934_600, 0) - .saturating_add(Weight::from_parts(0, 3880)) - // Standard Error: 374 - .saturating_add(Weight::from_parts(20_716, 0).saturating_mul(m.into())) - // Standard Error: 364 - .saturating_add(Weight::from_parts(115_491, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `737 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4054 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 39_160_000 picoseconds. - Weight::from_parts(40_470_419, 0) - .saturating_add(Weight::from_parts(0, 4054)) - // Standard Error: 82 - .saturating_add(Weight::from_parts(2_146, 0).saturating_mul(b.into())) - // Standard Error: 869 - .saturating_add(Weight::from_parts(21_442, 0).saturating_mul(m.into())) - // Standard Error: 847 - .saturating_add(Weight::from_parts(144_479, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `455 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3900 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 30_953_000 picoseconds. - Weight::from_parts(31_427_489, 0) - .saturating_add(Weight::from_parts(0, 3900)) - // Standard Error: 397 - .saturating_add(Weight::from_parts(24_280, 0).saturating_mul(m.into())) - // Standard Error: 387 - .saturating_add(Weight::from_parts(116_864, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Voting (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:1 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - /// The range of component `b` is `[2, 1024]`. - /// The range of component `m` is `[4, 100]`. - /// The range of component `p` is `[1, 100]`. - fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `757 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4074 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 41_468_000 picoseconds. - Weight::from_parts(43_538_242, 0) - .saturating_add(Weight::from_parts(0, 4074)) - // Standard Error: 80 - .saturating_add(Weight::from_parts(1_994, 0).saturating_mul(b.into())) - // Standard Error: 853 - .saturating_add(Weight::from_parts(19_637, 0).saturating_mul(m.into())) - // Standard Error: 831 - .saturating_add(Weight::from_parts(144_674, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) - } - /// Storage: TechnicalCommittee Proposals (r:1 w:1) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Voting (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: TechnicalCommittee ProposalOf (r:0 w:1) - /// Proof Skipped: TechnicalCommittee ProposalOf (max_values: None, max_size: None, mode: Measured) - /// The range of component `p` is `[1, 100]`. - /// The range of component `p` is `[1, 100]`. - fn disapprove_proposal(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `264 + p * (32 ±0)` - // Estimated: `1749 + p * (32 ±0)` - // Minimum execution time: 15_998_000 picoseconds. - Weight::from_parts(17_837_641, 0) - .saturating_add(Weight::from_parts(0, 1749)) - // Standard Error: 422 - .saturating_add(Weight::from_parts(111_526, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) - } -} diff --git a/polkadot/runtime/kusama/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs similarity index 100% rename from polkadot/runtime/kusama/src/weights/pallet_conviction_voting.rs rename to polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs diff --git a/polkadot/runtime/rococo/src/weights/pallet_democracy.rs b/polkadot/runtime/rococo/src/weights/pallet_democracy.rs deleted file mode 100644 index 00629a5c1103cba6813566097b9590104e712347..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_democracy.rs +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_democracy` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_democracy -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_democracy`. -pub struct WeightInfo(PhantomData); -impl pallet_democracy::WeightInfo for WeightInfo { - /// Storage: Democracy PublicPropCount (r:1 w:1) - /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:0 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `4734` - // Estimated: `18187` - // Minimum execution time: 39_492_000 picoseconds. - Weight::from_parts(39_853_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - fn second() -> Weight { - // Proof Size summary in bytes: - // Measured: `3489` - // Estimated: `6695` - // Minimum execution time: 36_683_000 picoseconds. - Weight::from_parts(37_121_000, 0) - .saturating_add(Weight::from_parts(0, 6695)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn vote_new() -> Weight { - // Proof Size summary in bytes: - // Measured: `3365` - // Estimated: `7260` - // Minimum execution time: 48_191_000 picoseconds. - Weight::from_parts(48_936_000, 0) - .saturating_add(Weight::from_parts(0, 7260)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn vote_existing() -> Weight { - // Proof Size summary in bytes: - // Measured: `3387` - // Estimated: `7260` - // Minimum execution time: 52_175_000 picoseconds. - Weight::from_parts(53_011_000, 0) - .saturating_add(Weight::from_parts(0, 7260)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Cancellations (r:1 w:1) - /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn emergency_cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `299` - // Estimated: `3666` - // Minimum execution time: 26_255_000 picoseconds. - Weight::from_parts(26_768_000, 0) - .saturating_add(Weight::from_parts(0, 3666)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:3 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:0 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn blacklist() -> Weight { - // Proof Size summary in bytes: - // Measured: `5843` - // Estimated: `18187` - // Minimum execution time: 96_376_000 picoseconds. - Weight::from_parts(97_222_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:0) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - fn external_propose() -> Weight { - // Proof Size summary in bytes: - // Measured: `3349` - // Estimated: `6703` - // Minimum execution time: 13_815_000 picoseconds. - Weight::from_parts(14_071_000, 0) - .saturating_add(Weight::from_parts(0, 6703)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_majority() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_456_000 picoseconds. - Weight::from_parts(3_716_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:0 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - fn external_propose_default() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_610_000 picoseconds. - Weight::from_parts(3_768_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:1) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:2) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn fast_track() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `3518` - // Minimum execution time: 27_514_000 picoseconds. - Weight::from_parts(27_905_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Democracy NextExternal (r:1 w:1) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy Blacklist (r:1 w:1) - /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn veto_external() -> Weight { - // Proof Size summary in bytes: - // Measured: `3452` - // Estimated: `6703` - // Minimum execution time: 31_250_000 picoseconds. - Weight::from_parts(31_604_000, 0) - .saturating_add(Weight::from_parts(0, 6703)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy PublicProps (r:1 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy DepositOf (r:1 w:1) - /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn cancel_proposal() -> Weight { - // Proof Size summary in bytes: - // Measured: `5754` - // Estimated: `18187` - // Minimum execution time: 79_757_000 picoseconds. - Weight::from_parts(83_603_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:0 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - fn cancel_referendum() -> Weight { - // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `3518` - // Minimum execution time: 20_034_000 picoseconds. - Weight::from_parts(20_674_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `177 + r * (86 ±0)` - // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 7_053_000 picoseconds. - Weight::from_parts(10_157_848, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 5_462 - .saturating_add(Weight::from_parts(2_710_889, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy LowestUnbaked (r:1 w:1) - /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumCount (r:1 w:0) - /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Democracy LastTabledWasExternal (r:1 w:0) - /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `177 + r * (86 ±0)` - // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 9_585_000 picoseconds. - Weight::from_parts(13_021_372, 0) - .saturating_add(Weight::from_parts(0, 18187)) - // Standard Error: 6_031 - .saturating_add(Weight::from_parts(2_707_449, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:3 w:3) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn delegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `729 + r * (108 ±0)` - // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 41_109_000 picoseconds. - Weight::from_parts(46_477_334, 0) - .saturating_add(Weight::from_parts(0, 19800)) - // Standard Error: 9_372 - .saturating_add(Weight::from_parts(3_815_232, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy VotingOf (r:2 w:2) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Democracy ReferendumInfoOf (r:99 w:99) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn undelegate(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `426 + r * (108 ±0)` - // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 21_283_000 picoseconds. - Weight::from_parts(23_372_139, 0) - .saturating_add(Weight::from_parts(0, 13530)) - // Standard Error: 6_191 - .saturating_add(Weight::from_parts(3_768_585, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) - } - /// Storage: Democracy PublicProps (r:0 w:1) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - fn clear_public_proposals() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_510_000 picoseconds. - Weight::from_parts(3_642_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_remove(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `458` - // Estimated: `7260` - // Minimum execution time: 23_647_000 picoseconds. - Weight::from_parts(36_627_552, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 2_937 - .saturating_add(Weight::from_parts(34_132, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `r` is `[0, 99]`. - fn unlock_set(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `459 + r * (22 ±0)` - // Estimated: `7260` - // Minimum execution time: 33_932_000 picoseconds. - Weight::from_parts(35_331_660, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 615 - .saturating_add(Weight::from_parts(60_730, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `661 + r * (26 ±0)` - // Estimated: `7260` - // Minimum execution time: 16_605_000 picoseconds. - Weight::from_parts(19_057_092, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 873 - .saturating_add(Weight::from_parts(68_964, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:1) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy VotingOf (r:1 w:1) - /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) - /// The range of component `r` is `[1, 100]`. - fn remove_other_vote(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `661 + r * (26 ±0)` - // Estimated: `7260` - // Minimum execution time: 16_801_000 picoseconds. - Weight::from_parts(19_166_788, 0) - .saturating_add(Weight::from_parts(0, 7260)) - // Standard Error: 1_008 - .saturating_add(Weight::from_parts(69_851, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `361` - // Estimated: `3556` - // Minimum execution time: 19_207_000 picoseconds. - Weight::from_parts(19_693_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy NextExternal (r:1 w:0) - /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_external_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `219` - // Estimated: `3518` - // Minimum execution time: 17_333_000 picoseconds. - Weight::from_parts(17_555_000, 0) - .saturating_add(Weight::from_parts(0, 3518)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4893` - // Estimated: `18187` - // Minimum execution time: 33_859_000 picoseconds. - Weight::from_parts(34_538_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy PublicProps (r:1 w:0) - /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_proposal_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `4755` - // Estimated: `18187` - // Minimum execution time: 31_155_000 picoseconds. - Weight::from_parts(31_520_000, 0) - .saturating_add(Weight::from_parts(0, 18187)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:0 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn set_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `216` - // Estimated: `3556` - // Minimum execution time: 15_924_000 picoseconds. - Weight::from_parts(16_151_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Democracy ReferendumInfoOf (r:1 w:0) - /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) - /// Storage: Democracy MetadataOf (r:1 w:1) - /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) - fn clear_referendum_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3666` - // Minimum execution time: 18_983_000 picoseconds. - Weight::from_parts(19_280_000, 0) - .saturating_add(Weight::from_parts(0, 3666)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_elections_phragmen.rs b/polkadot/runtime/rococo/src/weights/pallet_elections_phragmen.rs deleted file mode 100644 index fe6aca5ab881d457ac8c40c8191f655a43261bb2..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_elections_phragmen.rs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_elections_phragmen` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_elections_phragmen -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_elections_phragmen`. -pub struct WeightInfo(PhantomData); -impl pallet_elections_phragmen::WeightInfo for WeightInfo { - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 16]`. - fn vote_equal(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `331 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 30_910_000 picoseconds. - Weight::from_parts(31_851_802, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 4_099 - .saturating_add(Weight::from_parts(137_675, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_more(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `299 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 42_670_000 picoseconds. - Weight::from_parts(43_351_345, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_986 - .saturating_add(Weight::from_parts(142_231, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_less(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `331 + v * (80 ±0)` - // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 42_782_000 picoseconds. - Weight::from_parts(43_611_866, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_968 - .saturating_add(Weight::from_parts(125_939, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Voting (r:1 w:1) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn remove_voter() -> Weight { - // Proof Size summary in bytes: - // Measured: `853` - // Estimated: `4764` - // Minimum execution time: 44_301_000 picoseconds. - Weight::from_parts(44_843_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn submit_candidacy(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2678 + c * (48 ±0)` - // Estimated: `4161 + c * (48 ±0)` - // Minimum execution time: 33_576_000 picoseconds. - Weight::from_parts(26_859_487, 0) - .saturating_add(Weight::from_parts(0, 4161)) - // Standard Error: 854 - .saturating_add(Weight::from_parts(81_887, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `250 + c * (48 ±0)` - // Estimated: `1722 + c * (48 ±0)` - // Minimum execution time: 29_671_000 picoseconds. - Weight::from_parts(22_509_800, 0) - .saturating_add(Weight::from_parts(0, 1722)) - // Standard Error: 908 - .saturating_add(Weight::from_parts(58_320, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_members() -> Weight { - // Proof Size summary in bytes: - // Measured: `2952` - // Estimated: `4437` - // Minimum execution time: 45_934_000 picoseconds. - Weight::from_parts(46_279_000, 0) - .saturating_add(Weight::from_parts(0, 4437)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_runners_up() -> Weight { - // Proof Size summary in bytes: - // Measured: `1647` - // Estimated: `3132` - // Minimum execution time: 30_291_000 picoseconds. - Weight::from_parts(30_611_000, 0) - .saturating_add(Weight::from_parts(0, 3132)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn remove_member_without_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn remove_member_with_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `2952` - // Estimated: `4437` - // Minimum execution time: 63_178_000 picoseconds. - Weight::from_parts(63_850_000, 0) - .saturating_add(Weight::from_parts(0, 4437)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: PhragmenElection Voting (r:10001 w:10000) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:0) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Candidates (r:1 w:0) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:10000 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `35961 + v * (808 ±0)` - // Estimated: `39702 + v * (3774 ±0)` - // Minimum execution time: 379_638_846_000 picoseconds. - Weight::from_parts(380_443_068_000, 0) - .saturating_add(Weight::from_parts(0, 39702)) - // Standard Error: 318_371 - .saturating_add(Weight::from_parts(46_236_987, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) - } - /// Storage: PhragmenElection Candidates (r:1 w:1) - /// Proof Skipped: PhragmenElection Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:1) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection RunnersUp (r:1 w:1) - /// Proof Skipped: PhragmenElection RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PhragmenElection Voting (r:10001 w:0) - /// Proof Skipped: PhragmenElection Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:962 w:962) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PhragmenElection ElectionRounds (r:1 w:1) - /// Proof Skipped: PhragmenElection ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + e * (28 ±0) + v * (607 ±0)` - // Estimated: `2771509 + c * (2560 ±0) + e * (16 ±0) + v * (2744 ±4)` - // Minimum execution time: 35_941_980_000 picoseconds. - Weight::from_parts(36_032_688_000, 0) - .saturating_add(Weight::from_parts(0, 2771509)) - // Standard Error: 554_972 - .saturating_add(Weight::from_parts(43_733_923, 0).saturating_mul(v.into())) - // Standard Error: 35_614 - .saturating_add(Weight::from_parts(2_430_249, 0).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(265)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 2560).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 16).saturating_mul(e.into())) - .saturating_add(Weight::from_parts(0, 2744).saturating_mul(v.into())) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_membership.rs b/polkadot/runtime/rococo/src/weights/pallet_membership.rs deleted file mode 100644 index 4486c7a270c47e790f51f76148b7592a15ff0fbc..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_membership.rs +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_membership` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_membership -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_membership`. -pub struct WeightInfo(PhantomData); -impl pallet_membership::WeightInfo for WeightInfo { - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 99]`. - fn add_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `140 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 17_084_000 picoseconds. - Weight::from_parts(17_897_754, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 295 - .saturating_add(Weight::from_parts(30_882, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn remove_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `244 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_550_000 picoseconds. - Weight::from_parts(20_467_978, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 330 - .saturating_add(Weight::from_parts(31_881, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[2, 100]`. - fn swap_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `244 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 19_994_000 picoseconds. - Weight::from_parts(20_663_824, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 337 - .saturating_add(Weight::from_parts(44_806, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:0) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn reset_member(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `244 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 18_978_000 picoseconds. - Weight::from_parts(21_273_577, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 2_765 - .saturating_add(Weight::from_parts(152_082, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:1) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Proposals (r:1 w:0) - /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalMembership Prime (r:1 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Members (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn change_key(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `244 + m * (64 ±0)` - // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 20_005_000 picoseconds. - Weight::from_parts(21_280_089, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 672 - .saturating_add(Weight::from_parts(41_961, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Members (r:1 w:0) - /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn set_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 8_168_000 picoseconds. - Weight::from_parts(8_579_141, 0) - .saturating_add(Weight::from_parts(0, 4687)) - // Standard Error: 215 - .saturating_add(Weight::from_parts(9_557, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) - } - /// Storage: TechnicalMembership Prime (r:0 w:1) - /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: TechnicalCommittee Prime (r:0 w:1) - /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_344_000 picoseconds. - Weight::from_parts(3_551_700, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 86 - .saturating_add(Weight::from_parts(832, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a556c3a248ef46fdb2b5b5449c4b0c75972a9fd --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs @@ -0,0 +1,175 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_ranked_collective` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_ranked_collective +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_ranked_collective`. +pub struct WeightInfo(PhantomData); +impl pallet_ranked_collective::WeightInfo for WeightInfo { + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:1) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IndexToId` (r:0 w:1) + /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IdToIndex` (r:0 w:1) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + fn add_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3507` + // Minimum execution time: 17_632_000 picoseconds. + Weight::from_parts(18_252_000, 0) + .saturating_add(Weight::from_parts(0, 3507)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:11 w:11) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IdToIndex` (r:11 w:11) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IndexToId` (r:11 w:11) + /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + fn remove_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `517 + r * (281 ±0)` + // Estimated: `3519 + r * (2529 ±0)` + // Minimum execution time: 27_960_000 picoseconds. + Weight::from_parts(30_632_408, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // Standard Error: 22_806 + .saturating_add(Weight::from_parts(13_000_901, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:1) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IndexToId` (r:0 w:1) + /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IdToIndex` (r:0 w:1) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + fn promote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `214 + r * (17 ±0)` + // Estimated: `3507` + // Minimum execution time: 19_900_000 picoseconds. + Weight::from_parts(20_908_316, 0) + .saturating_add(Weight::from_parts(0, 3507)) + // Standard Error: 4_878 + .saturating_add(Weight::from_parts(330_385, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:1) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:1) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IdToIndex` (r:1 w:1) + /// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::IndexToId` (r:1 w:1) + /// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 10]`. + fn demote_member(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `532 + r * (72 ±0)` + // Estimated: `3519` + // Minimum execution time: 27_697_000 picoseconds. + Weight::from_parts(30_341_815, 0) + .saturating_add(Weight::from_parts(0, 3519)) + // Standard Error: 17_010 + .saturating_add(Weight::from_parts(642_213, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Voting` (r:1 w:1) + /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `638` + // Estimated: `83866` + // Minimum execution time: 48_275_000 picoseconds. + Weight::from_parts(49_326_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::VotingCleanup` (r:1 w:0) + /// Proof: `FellowshipCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::Voting` (r:100 w:100) + /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 100]`. + fn cleanup_poll(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `434 + n * (50 ±0)` + // Estimated: `4365 + n * (2540 ±0)` + // Minimum execution time: 15_506_000 picoseconds. + Weight::from_parts(17_634_029, 0) + .saturating_add(Weight::from_parts(0, 4365)) + // Standard Error: 2_117 + .saturating_add(Weight::from_parts(1_126_879, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs new file mode 100644 index 0000000000000000000000000000000000000000..96f172230e13f5aed92b47338b2387f4db79fa27 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs @@ -0,0 +1,524 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_referenda` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_referenda`. +pub struct WeightInfo(PhantomData); +impl pallet_referenda::WeightInfo for WeightInfo { + /// Storage: `FellowshipCollective::Members` (r:1 w:0) + /// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::ReferendumCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `327` + // Estimated: `42428` + // Minimum execution time: 29_909_000 picoseconds. + Weight::from_parts(30_645_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `438` + // Estimated: `83866` + // Minimum execution time: 54_405_000 picoseconds. + Weight::from_parts(55_583_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:0) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2076` + // Estimated: `42428` + // Minimum execution time: 110_477_000 picoseconds. + Weight::from_parts(119_187_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:0) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2117` + // Estimated: `42428` + // Minimum execution time: 111_467_000 picoseconds. + Weight::from_parts(117_758_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `774` + // Estimated: `83866` + // Minimum execution time: 191_135_000 picoseconds. + Weight::from_parts(210_535_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `639` + // Estimated: `83866` + // Minimum execution time: 67_168_000 picoseconds. + Weight::from_parts(68_895_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn refund_decision_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `4365` + // Minimum execution time: 31_298_000 picoseconds. + Weight::from_parts(32_570_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn refund_submission_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `201` + // Estimated: `4365` + // Minimum execution time: 15_674_000 picoseconds. + Weight::from_parts(16_190_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `83866` + // Minimum execution time: 38_927_000 picoseconds. + Weight::from_parts(40_545_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::MetadataOf` (r:1 w:0) + /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `484` + // Estimated: `83866` + // Minimum execution time: 80_209_000 picoseconds. + Weight::from_parts(82_084_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:0) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + fn one_fewer_deciding_queue_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `174` + // Estimated: `4277` + // Minimum execution time: 9_520_000 picoseconds. + Weight::from_parts(10_088_000, 0) + .saturating_add(Weight::from_parts(0, 4277)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2376` + // Estimated: `42428` + // Minimum execution time: 93_893_000 picoseconds. + Weight::from_parts(101_065_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2362` + // Estimated: `42428` + // Minimum execution time: 98_811_000 picoseconds. + Weight::from_parts(103_590_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_insertion() -> Weight { + // Proof Size summary in bytes: + // Measured: `1841` + // Estimated: `4365` + // Minimum execution time: 43_230_000 picoseconds. + Weight::from_parts(46_120_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_slide() -> Weight { + // Proof Size summary in bytes: + // Measured: `1808` + // Estimated: `4365` + // Minimum execution time: 43_092_000 picoseconds. + Weight::from_parts(46_018_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:0) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + fn nudge_referendum_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `1824` + // Estimated: `4365` + // Minimum execution time: 49_697_000 picoseconds. + Weight::from_parts(53_795_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:0) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:1) + /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) + fn nudge_referendum_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `1865` + // Estimated: `4365` + // Minimum execution time: 50_417_000 picoseconds. + Weight::from_parts(53_214_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `335` + // Estimated: `42428` + // Minimum execution time: 25_688_000 picoseconds. + Weight::from_parts(26_575_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `42428` + // Minimum execution time: 26_230_000 picoseconds. + Weight::from_parts(27_235_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + fn nudge_referendum_timed_out() -> Weight { + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `4365` + // Minimum execution time: 17_585_000 picoseconds. + Weight::from_parts(18_225_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `584` + // Estimated: `42428` + // Minimum execution time: 38_243_000 picoseconds. + Weight::from_parts(39_959_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::DecidingCount` (r:1 w:1) + /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `719` + // Estimated: `42428` + // Minimum execution time: 88_424_000 picoseconds. + Weight::from_parts(92_969_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `770` + // Estimated: `42428` + // Minimum execution time: 138_207_000 picoseconds. + Weight::from_parts(151_726_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `755` + // Estimated: `42428` + // Minimum execution time: 131_001_000 picoseconds. + Weight::from_parts(148_651_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `770` + // Estimated: `42428` + // Minimum execution time: 109_612_000 picoseconds. + Weight::from_parts(143_626_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `776` + // Estimated: `42428` + // Minimum execution time: 71_754_000 picoseconds. + Weight::from_parts(77_329_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn nudge_referendum_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `776` + // Estimated: `83866` + // Minimum execution time: 153_244_000 picoseconds. + Weight::from_parts(169_961_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipCollective::MemberCount` (r:1 w:0) + /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `772` + // Estimated: `42428` + // Minimum execution time: 137_997_000 picoseconds. + Weight::from_parts(157_862_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::MetadataOf` (r:0 w:1) + /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `458` + // Estimated: `4365` + // Minimum execution time: 21_794_000 picoseconds. + Weight::from_parts(22_341_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `FellowshipReferenda::MetadataOf` (r:1 w:1) + /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `319` + // Estimated: `4365` + // Minimum execution time: 18_458_000 picoseconds. + Weight::from_parts(19_097_000, 0) + .saturating_add(Weight::from_parts(0, 4365)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs new file mode 100644 index 0000000000000000000000000000000000000000..b7cc5df28b91cc2cc36cade14784b41d7d34ff71 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs @@ -0,0 +1,522 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_referenda` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_referenda`. +pub struct WeightInfo(PhantomData); +impl pallet_referenda::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumCount` (r:1 w:1) + /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `324` + // Estimated: `42428` + // Minimum execution time: 39_852_000 picoseconds. + Weight::from_parts(41_610_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `577` + // Estimated: `83866` + // Minimum execution time: 52_588_000 picoseconds. + Weight::from_parts(54_154_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3334` + // Estimated: `42428` + // Minimum execution time: 70_483_000 picoseconds. + Weight::from_parts(72_731_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3354` + // Estimated: `42428` + // Minimum execution time: 68_099_000 picoseconds. + Weight::from_parts(71_560_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `577` + // Estimated: `83866` + // Minimum execution time: 64_357_000 picoseconds. + Weight::from_parts(66_081_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `577` + // Estimated: `83866` + // Minimum execution time: 62_709_000 picoseconds. + Weight::from_parts(64_534_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + fn refund_decision_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `4401` + // Minimum execution time: 31_296_000 picoseconds. + Weight::from_parts(32_221_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + fn refund_submission_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `407` + // Estimated: `4401` + // Minimum execution time: 31_209_000 picoseconds. + Weight::from_parts(32_168_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `485` + // Estimated: `83866` + // Minimum execution time: 38_887_000 picoseconds. + Weight::from_parts(40_193_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:0) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `726` + // Estimated: `83866` + // Minimum execution time: 106_054_000 picoseconds. + Weight::from_parts(108_318_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:0) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + fn one_fewer_deciding_queue_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `240` + // Estimated: `5477` + // Minimum execution time: 9_263_000 picoseconds. + Weight::from_parts(9_763_000, 0) + .saturating_add(Weight::from_parts(0, 5477)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3254` + // Estimated: `42428` + // Minimum execution time: 50_080_000 picoseconds. + Weight::from_parts(51_858_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3254` + // Estimated: `42428` + // Minimum execution time: 53_889_000 picoseconds. + Weight::from_parts(55_959_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_insertion() -> Weight { + // Proof Size summary in bytes: + // Measured: `3077` + // Estimated: `5477` + // Minimum execution time: 23_266_000 picoseconds. + Weight::from_parts(24_624_000, 0) + .saturating_add(Weight::from_parts(0, 5477)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_slide() -> Weight { + // Proof Size summary in bytes: + // Measured: `3077` + // Estimated: `5477` + // Minimum execution time: 22_846_000 picoseconds. + Weight::from_parts(24_793_000, 0) + .saturating_add(Weight::from_parts(0, 5477)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3081` + // Estimated: `5477` + // Minimum execution time: 28_284_000 picoseconds. + Weight::from_parts(29_940_000, 0) + .saturating_add(Weight::from_parts(0, 5477)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3101` + // Estimated: `5477` + // Minimum execution time: 28_133_000 picoseconds. + Weight::from_parts(29_638_000, 0) + .saturating_add(Weight::from_parts(0, 5477)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `437` + // Estimated: `42428` + // Minimum execution time: 25_710_000 picoseconds. + Weight::from_parts(26_500_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `485` + // Estimated: `42428` + // Minimum execution time: 25_935_000 picoseconds. + Weight::from_parts(26_803_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + fn nudge_referendum_timed_out() -> Weight { + // Proof Size summary in bytes: + // Measured: `344` + // Estimated: `4401` + // Minimum execution time: 17_390_000 picoseconds. + Weight::from_parts(18_042_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `485` + // Estimated: `42428` + // Minimum execution time: 35_141_000 picoseconds. + Weight::from_parts(36_318_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `485` + // Estimated: `42428` + // Minimum execution time: 37_815_000 picoseconds. + Weight::from_parts(39_243_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `538` + // Estimated: `42428` + // Minimum execution time: 30_779_000 picoseconds. + Weight::from_parts(31_845_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `521` + // Estimated: `42428` + // Minimum execution time: 31_908_000 picoseconds. + Weight::from_parts(33_253_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `538` + // Estimated: `42428` + // Minimum execution time: 28_951_000 picoseconds. + Weight::from_parts(30_004_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `42428` + // Minimum execution time: 27_750_000 picoseconds. + Weight::from_parts(28_588_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn nudge_referendum_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `83866` + // Minimum execution time: 43_950_000 picoseconds. + Weight::from_parts(46_164_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `538` + // Estimated: `42428` + // Minimum execution time: 31_050_000 picoseconds. + Weight::from_parts(32_169_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:0 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `560` + // Estimated: `4401` + // Minimum execution time: 21_193_000 picoseconds. + Weight::from_parts(22_116_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `421` + // Estimated: `4401` + // Minimum execution time: 18_065_000 picoseconds. + Weight::from_parts(18_781_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_tips.rs b/polkadot/runtime/rococo/src/weights/pallet_tips.rs deleted file mode 100644 index c4710afd78e2bf2fa6b0501140845681295eee0b..0000000000000000000000000000000000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_tips.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_tips` -//! -//! 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: `[]` -//! 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 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_tips -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_tips`. -pub struct WeightInfo(PhantomData); -impl pallet_tips::WeightInfo for WeightInfo { - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - fn report_awesome(r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3469` - // Minimum execution time: 27_741_000 picoseconds. - Weight::from_parts(28_495_173, 0) - .saturating_add(Weight::from_parts(0, 3469)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_433, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - fn retract_tip() -> Weight { - // Proof Size summary in bytes: - // Measured: `221` - // Estimated: `3686` - // Minimum execution time: 27_275_000 picoseconds. - Weight::from_parts(27_649_000, 0) - .saturating_add(Weight::from_parts(0, 3686)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:1 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Tips (r:0 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 16384]`. - /// The range of component `t` is `[1, 19]`. - fn tip_new(r: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `74 + t * (64 ±0)` - // Estimated: `3539 + t * (64 ±0)` - // Minimum execution time: 19_809_000 picoseconds. - Weight::from_parts(18_182_607, 0) - .saturating_add(Weight::from_parts(0, 3539)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_303, 0).saturating_mul(r.into())) - // Standard Error: 5_156 - .saturating_add(Weight::from_parts(151_789, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) - } - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `295 + t * (112 ±0)` - // Estimated: `3760 + t * (112 ±0)` - // Minimum execution time: 15_528_000 picoseconds. - Weight::from_parts(15_717_755, 0) - .saturating_add(Weight::from_parts(0, 3760)) - // Standard Error: 6_569 - .saturating_add(Weight::from_parts(146_426, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: PhragmenElection Members (r:1 w:0) - /// Proof Skipped: PhragmenElection Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn close_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `334 + t * (112 ±0)` - // Estimated: `3790 + t * (112 ±0)` - // Minimum execution time: 58_304_000 picoseconds. - Weight::from_parts(60_138_785, 0) - .saturating_add(Weight::from_parts(0, 3790)) - // Standard Error: 7_636 - .saturating_add(Weight::from_parts(86_665, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) - } - /// Storage: Tips Tips (r:1 w:1) - /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) - /// Storage: Tips Reasons (r:0 w:1) - /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) - /// The range of component `t` is `[1, 19]`. - fn slash_tip(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3734` - // Minimum execution time: 15_097_000 picoseconds. - Weight::from_parts(15_497_872, 0) - .saturating_add(Weight::from_parts(0, 3734)) - // Standard Error: 785 - .saturating_add(Weight::from_parts(18_377, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index 041d976d82570d711b409fdb4253b56eb45dc15b..144e9d5b872382b7381e2d77c6fb08a8fbece4fa 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs @@ -17,24 +17,24 @@ //! Autogenerated weights for `pallet_treasury` //! //! 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: `[]` +//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, 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: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/debug/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=20 +// --repeat=2 // --pallet=pallet_treasury // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt +// --heap-pages=4096 // --output=./runtime/rococo/src/weights/ +// --header=./file_header.txt #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,13 +47,21 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - fn spend() -> Weight { + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + fn spend_local() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 204_000 picoseconds. - Weight::from_parts(233_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `42` + // Estimated: `1887` + // Minimum execution time: 177_000_000 picoseconds. + Weight::from_parts(191_000_000, 0) + .saturating_add(Weight::from_parts(0, 1887)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: Treasury ProposalCount (r:1 w:1) /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -61,10 +69,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `107` + // Measured: `143` // Estimated: `1489` - // Minimum execution time: 27_592_000 picoseconds. - Weight::from_parts(27_960_000, 0) + // Minimum execution time: 354_000_000 picoseconds. + Weight::from_parts(376_000_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -75,10 +83,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `265` + // Measured: `301` // Estimated: `3593` - // Minimum execution time: 40_336_000 picoseconds. - Weight::from_parts(41_085_000, 0) + // Minimum execution time: 547_000_000 picoseconds. + Weight::from_parts(550_000_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,13 +98,13 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + p * (8 ±0)` + // Measured: `470 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 9_938_000 picoseconds. - Weight::from_parts(12_061_206, 0) + // Minimum execution time: 104_000_000 picoseconds. + Weight::from_parts(121_184_402, 0) .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 801 - .saturating_add(Weight::from_parts(26_602, 0).saturating_mul(p.into())) + // Standard Error: 42_854 + .saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -104,10 +112,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `90` + // Measured: `127` // Estimated: `1887` - // Minimum execution time: 7_421_000 picoseconds. - Weight::from_parts(7_620_000, 0) + // Minimum execution time: 80_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -118,26 +126,98 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Treasury Approvals (r:1 w:1) /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:100 w:100) + /// Storage: Treasury Proposals (r:99 w:99) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:201 w:201) + /// Storage: System Account (r:199 w:199) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Bounties BountyApprovals (r:1 w:1) /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. + /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `296 + p * (251 ±0)` + // Measured: `331 + p * (251 ±0)` // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 62_706_000 picoseconds. - Weight::from_parts(61_351_470, 0) + // Minimum execution time: 887_000_000 picoseconds. + Weight::from_parts(828_616_021, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 32_787 - .saturating_add(Weight::from_parts(37_873_920, 0).saturating_mul(p.into())) + // Standard Error: 695_351 + .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(5)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `4702` + // Minimum execution time: 208_000_000 picoseconds. + Weight::from_parts(222_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet QueryCounter (r:1 w:1) + /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) + /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet SupportedVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet Queries (r:0 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `737` + // Estimated: `5313` + // Minimum execution time: 551_000_000 picoseconds. + Weight::from_parts(569_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet Queries (r:1 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `442` + // Estimated: `5313` + // Minimum execution time: 245_000_000 picoseconds. + Weight::from_parts(281_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `172` + // Estimated: `5313` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(160_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/kusama/src/weights/pallet_whitelist.rs b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs similarity index 50% rename from polkadot/runtime/kusama/src/weights/pallet_whitelist.rs rename to polkadot/runtime/rococo/src/weights/pallet_whitelist.rs index fe2d317651a028294d4d70d94b97896d1bcb5edb..7c307deec4c6f8480019b5559117cfc47ee84b40 100644 --- a/polkadot/runtime/kusama/src/weights/pallet_whitelist.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_whitelist` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-aahe6cbd-project-163-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=kusama-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_whitelist // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_whitelist +// --chain=rococo-dev // --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,68 +48,68 @@ use core::marker::PhantomData; /// Weight functions for `pallet_whitelist`. pub struct WeightInfo(PhantomData); impl pallet_whitelist::WeightInfo for WeightInfo { - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: - // Measured: `118` + // Measured: `223` // Estimated: `3556` - // Minimum execution time: 19_893_000 picoseconds. - Weight::from_parts(20_176_000, 0) + // Minimum execution time: 20_035_000 picoseconds. + Weight::from_parts(20_452_000, 0) .saturating_add(Weight::from_parts(0, 3556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: - // Measured: `247` + // Measured: `352` // Estimated: `3556` - // Minimum execution time: 17_393_000 picoseconds. - Weight::from_parts(18_076_000, 0) + // Minimum execution time: 20_247_000 picoseconds. + Weight::from_parts(20_808_000, 0) .saturating_add(Weight::from_parts(0, 3556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:1 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `323 + n * (1 ±0)` - // Estimated: `3787 + n * (1 ±0)` - // Minimum execution time: 29_485_000 picoseconds. - Weight::from_parts(29_730_000, 0) - .saturating_add(Weight::from_parts(0, 3787)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_530, 0).saturating_mul(n.into())) + // Measured: `428 + n * (1 ±0)` + // Estimated: `3892 + n * (1 ±0)` + // Minimum execution time: 32_633_000 picoseconds. + Weight::from_parts(32_855_000, 0) + .saturating_add(Weight::from_parts(0, 3892)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } - /// Storage: Whitelist WhitelistedCall (r:1 w:1) - /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `247` + // Measured: `352` // Estimated: `3556` - // Minimum execution time: 21_190_000 picoseconds. - Weight::from_parts(21_802_426, 0) + // Minimum execution time: 23_833_000 picoseconds. + Weight::from_parts(24_698_994, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_465, 0).saturating_mul(n.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs index 9f1cf65efa649972f111be4029b00ca40c7554da..417820e6627f6e39c4107df722f4b83f9cca6a4b 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs @@ -289,4 +289,46 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(8)) } + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r: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`) + 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)) + .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)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs index 1d613717dc52798ece0ac9c484b8f91b66f53803..cc485dfbaf7e4e29fe7fdd50960490bc9c05665c 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs @@ -91,7 +91,6 @@ impl XcmWeightInfo for RococoXcmWeight { assets.weigh_multi_assets(XcmBalancesWeight::::withdraw_asset()) } fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { - // Rococo doesn't support ReserveAssetDeposited, so this benchmark has a default weight assets.weigh_multi_assets(XcmBalancesWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 59c49e4f8c821beb00a9493ad7b07928cfe6daf9..60c40429b1ac323e69bca1345c41c3c04c221f79 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-gghbxkbs-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-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 @@ -31,12 +31,12 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::fungible // --chain=rococo-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/rococo/src/weights/xcm/ +// --header=./polkadot/file_header.txt +// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs +// --output=./polkadot/runtime/rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 24_892_000 picoseconds. - Weight::from_parts(25_219_000, 3593) + // Minimum execution time: 23_189_000 picoseconds. + Weight::from_parts(23_896_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 52_112_000 picoseconds. - Weight::from_parts(53_104_000, 6196) + // Minimum execution time: 50_299_000 picoseconds. + Weight::from_parts(50_962_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -83,10 +83,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `210` + // Measured: `243` // Estimated: `6196` - // Minimum execution time: 76_459_000 picoseconds. - Weight::from_parts(79_152_000, 6196) + // Minimum execution time: 71_748_000 picoseconds. + Weight::from_parts(74_072_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -96,8 +96,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -109,10 +109,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 29_734_000 picoseconds. - Weight::from_parts(30_651_000, 3574) + // Measured: `142` + // Estimated: `3607` + // Minimum execution time: 27_806_000 picoseconds. + Weight::from_parts(28_594_000, 3607) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 23_028_000 picoseconds. - Weight::from_parts(23_687_000, 3593) + // Minimum execution time: 21_199_000 picoseconds. + Weight::from_parts(21_857_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,8 +133,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 26_399_000 picoseconds. - Weight::from_parts(27_262_000, 3593) + // Minimum execution time: 23_578_000 picoseconds. + Weight::from_parts(24_060_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -150,10 +150,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3593` - // Minimum execution time: 52_015_000 picoseconds. - Weight::from_parts(53_498_000, 3593) + // Measured: `142` + // Estimated: `3607` + // Minimum execution time: 48_522_000 picoseconds. + Weight::from_parts(49_640_000, 3607) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -169,10 +169,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3593` - // Minimum execution time: 53_833_000 picoseconds. - Weight::from_parts(55_688_000, 3593) + // Measured: `142` + // Estimated: `3607` + // Minimum execution time: 50_429_000 picoseconds. + Weight::from_parts(51_295_000, 3607) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 288ee8400dcf59ee0bd3def0641e25f2df54a35d..a766e2179ea7fa8e6b447463bfb07d7421d49d20 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -17,9 +17,12 @@ //! XCM configuration for Rococo. use super::{ - parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, ParaId, Runtime, + parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, Fellows, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, }; + +use crate::governance::StakingAdmin; + use frame_support::{ match_types, parameter_types, traits::{Everything, Nothing}, @@ -36,10 +39,11 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, - IsChildSystemParachain, IsConcrete, MintLocation, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal, + DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete, + MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -51,8 +55,14 @@ parameter_types! { pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); } -pub type LocationConverter = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type LocationConverter = ( + // We can convert a child parachain using the standard `AccountId` conversion. + ChildParachainConvertsVia, + // We can directly alias an `AccountId32` into a local account. + AccountId32Aliases, + // Allow governance body to be used as a sovereign account. + HashedDescription>, +); /// Our asset transactor. This is what allows us to interest with the runtime facilities from the /// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. @@ -103,7 +113,7 @@ pub type XcmRouter = WithUniqueTopic<( parameter_types! { pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); - pub const Rockmine: MultiLocation = Parachain(1000).into_location(); + pub const AssetHub: MultiLocation = Parachain(1000).into_location(); pub const Contracts: MultiLocation = Parachain(1002).into_location(); pub const Encointer: MultiLocation = Parachain(1003).into_location(); pub const Tick: MultiLocation = Parachain(100).into_location(); @@ -112,7 +122,7 @@ parameter_types! { pub const RocForTick: (MultiAssetFilter, MultiLocation) = (Roc::get(), Tick::get()); pub const RocForTrick: (MultiAssetFilter, MultiLocation) = (Roc::get(), Trick::get()); pub const RocForTrack: (MultiAssetFilter, MultiLocation) = (Roc::get(), Track::get()); - pub const RocForRockmine: (MultiAssetFilter, MultiLocation) = (Roc::get(), Rockmine::get()); + pub const RocForAssetHub: (MultiAssetFilter, MultiLocation) = (Roc::get(), AssetHub::get()); pub const RocForContracts: (MultiAssetFilter, MultiLocation) = (Roc::get(), Contracts::get()); pub const RocForEncointer: (MultiAssetFilter, MultiLocation) = (Roc::get(), Encointer::get()); pub const MaxInstructions: u32 = 100; @@ -122,7 +132,7 @@ pub type TrustedTeleporters = ( xcm_builder::Case, xcm_builder::Case, xcm_builder::Case, - xcm_builder::Case, + xcm_builder::Case, xcm_builder::Case, xcm_builder::Case, ); @@ -141,7 +151,7 @@ pub type Barrier = TrailingSetTopicAsId<( AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then allow it. + // If the message is one that immediately attempts to pay for execution, then allow it. AllowTopLevelPaidExecutionFrom, // Messages coming from system parachains need not pay for execution. AllowExplicitUnpaidExecutionFrom>, @@ -186,6 +196,14 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } +parameter_types! { + pub const CollectiveBodyId: BodyId = BodyId::Unit; + // StakingAdmin pluralistic body. + pub const StakingAdminBodyId: BodyId = BodyId::Defense; + // Fellows pluralistic body. + pub const FellowsBodyId: BodyId = BodyId::Technical; +} + #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); @@ -194,12 +212,33 @@ parameter_types! { /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( - // A usual Signed origin to be used in XCM as a corresponding AccountId32 + // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, ); + +/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value. +pub type StakingAdminToPlurality = + OriginToPluralityVoice; + +/// Type to convert the Fellows origin to a Plurality `MultiLocation` value. +pub type FellowsToPlurality = OriginToPluralityVoice; + +/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an +/// interior location of this chain for a destination chain. +pub type LocalPalletOriginToLocation = ( + // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + StakingAdminToPlurality, + // Fellows origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + FellowsToPlurality, +); + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + // We only allow the root, fellows and the staking admin to send messages. + // This is basically safe to enable for everyone (safe the possibility of someone spamming the + // parachain if they're willing to pay the KSM to send from the Relay-chain), but it's useless + // until we bring in XCM v3 which will make `DescendOrigin` a bit more useful. + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally. type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index a8f26eb5b3d951a09c72a9b40cb78599a24299b6..2e9c773a3f8cf17da29e6e52ea1efb15da147d85 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -28,6 +28,7 @@ sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-staking = { path = "../../../substrate/primitives/staking", default-features = false } sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } sp-session = { path = "../../../substrate/primitives/session", default-features = false } sp-version = { path = "../../../substrate/primitives/version", default-features = false } @@ -124,6 +125,7 @@ std = [ "serde_derive", "sp-api/std", "sp-core/std", + "sp-genesis-builder/std", "sp-io/std", "sp-mmr-primitives/std", "sp-runtime/std", diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 94852ad39f5aae110931c701793d104430ffc199..99fd2198400bf821f406345ac5daabe13d4b009a 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -30,7 +30,7 @@ use polkadot_runtime_parachains::{ disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, runtime_api_impl::v5 as runtime_impl, + paras_inherent as parachains_paras_inherent, runtime_api_impl::v7 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -42,7 +42,9 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + genesis_builder_helper::{build_config, create_default_config}, + parameter_types, traits::{Everything, KeyOwnerProofSystem, WithdrawReasons}, }; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; @@ -1137,4 +1139,14 @@ sp_api::impl_runtime_apis! { Timestamp::now() } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index f4bb66f68cdfee559da0f7825a019e764dc2fde4..58a6cc21eecdb4da8a3c3b28b75aadd8dac51de0 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -24,7 +24,9 @@ inherents = { package = "sp-inherents", path = "../../../substrate/primitives/in offchain-primitives = { package = "sp-offchain", path = "../../../substrate/primitives/offchain", default-features = false } sp-api = { path = "../../../substrate/primitives/api", default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } +sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-mmr-primitives = { path = "../../../substrate/primitives/merkle-mountain-range", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } @@ -39,10 +41,11 @@ sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", def frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] } frame-system = { path = "../../../substrate/frame/system", default-features = false } frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } westend-runtime-constants = { package = "westend-runtime-constants", path = "constants", default-features = false } +pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false } pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false } pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } pallet-babe = { path = "../../../substrate/frame/babe", default-features = false } @@ -64,10 +67,12 @@ pallet-message-queue = { path = "../../../substrate/frame/message-queue", defaul pallet-mmr = { path = "../../../substrate/frame/merkle-mountain-range", default-features = false } pallet-multisig = { path = "../../../substrate/frame/multisig", default-features = false } pallet-nomination-pools = { path = "../../../substrate/frame/nomination-pools", default-features = false } +pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false } pallet-offences = { path = "../../../substrate/frame/offences", default-features = false } pallet-preimage = { path = "../../../substrate/frame/preimage", default-features = false } pallet-proxy = { path = "../../../substrate/frame/proxy", default-features = false } pallet-recovery = { path = "../../../substrate/frame/recovery", default-features = false } +pallet-referenda = { path = "../../../substrate/frame/referenda", default-features = false } pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-features = false } pallet-session = { path = "../../../substrate/frame/session", default-features = false } pallet-society = { path = "../../../substrate/frame/society", default-features = false } @@ -83,6 +88,7 @@ pallet-nomination-pools-runtime-api = { path = "../../../substrate/frame/nominat pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false } pallet-utility = { path = "../../../substrate/frame/utility", default-features = false } pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false } +pallet-whitelist = { path = "../../../substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } @@ -138,6 +144,7 @@ std = [ "inherents/std", "log/std", "offchain-primitives/std", + "pallet-asset-rate/std", "pallet-authority-discovery/std", "pallet-authorship/std", "pallet-babe/std", @@ -146,6 +153,7 @@ std = [ "pallet-beefy-mmr/std", "pallet-beefy/std", "pallet-collective/std", + "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-election-provider-multi-phase/std", "pallet-election-provider-support-benchmarking?/std", @@ -167,6 +175,7 @@ std = [ "pallet-preimage/std", "pallet-proxy/std", "pallet-recovery/std", + "pallet-referenda/std", "pallet-scheduler/std", "pallet-session-benchmarking?/std", "pallet-session/std", @@ -181,6 +190,7 @@ std = [ "pallet-treasury/std", "pallet-utility/std", "pallet-vesting/std", + "pallet-whitelist/std", "pallet-xcm-benchmarks?/std", "pallet-xcm/std", "parity-scale-codec/std", @@ -194,7 +204,9 @@ std = [ "serde_derive", "sp-api/std", "sp-application-crypto/std", + "sp-arithmetic/std", "sp-core/std", + "sp-genesis-builder/std", "sp-io/std", "sp-mmr-primitives/std", "sp-npos-elections/std", @@ -218,10 +230,12 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", + "pallet-asset-rate/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", @@ -242,6 +256,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", @@ -252,6 +267,7 @@ runtime-benchmarks = [ "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -270,6 +286,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-babe/try-runtime", @@ -278,6 +295,7 @@ try-runtime = [ "pallet-beefy-mmr/try-runtime", "pallet-beefy/try-runtime", "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", @@ -295,6 +313,7 @@ try-runtime = [ "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-recovery/try-runtime", + "pallet-referenda/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-society/try-runtime", @@ -306,6 +325,7 @@ try-runtime = [ "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-vesting/try-runtime", + "pallet-whitelist/try-runtime", "pallet-xcm/try-runtime", "runtime-common/try-runtime", "runtime-parachains/try-runtime", @@ -316,3 +336,8 @@ try-runtime = [ fast-runtime = [] runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = [ "sp-api/disable-logging" ] diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index f9830dab3325b62b2a9003498911e79e7778e0d3..0dd64d092c34512dc963499ab418201d253fa167 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -96,6 +96,26 @@ pub mod fee { } } +/// XCM protocol related constants. +pub mod xcm { + /// Pluralistic bodies existing within the consensus. + pub mod body { + // Preallocated for the Root body. + #[allow(dead_code)] + const ROOT_INDEX: u32 = 0; + // The bodies corresponding to the Polkadot OpenGov Origins. + pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + } +} + +/// System Parachains. +pub mod system_parachain { + /// Statemint parachain ID. + pub const ASSET_HUB_ID: u32 = 1000; + /// Collectives parachain ID. + pub const COLLECTIVES_ID: u32 = 1001; +} + #[cfg(test)] mod tests { use super::{ diff --git a/polkadot/runtime/polkadot/src/governance/mod.rs b/polkadot/runtime/westend/src/governance/mod.rs similarity index 89% rename from polkadot/runtime/polkadot/src/governance/mod.rs rename to polkadot/runtime/westend/src/governance/mod.rs index 79c904622dddea96112c29f4e58bdf92f53de3b8..d027f788d71f6bf255b71157bfe21ba1fdc16f5a 100644 --- a/polkadot/runtime/polkadot/src/governance/mod.rs +++ b/polkadot/runtime/westend/src/governance/mod.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! New governance configurations for the Polkadot runtime. +//! New governance configurations for the Kusama runtime. use super::*; -use crate::xcm_config::CollectivesLocation; +use crate::xcm_config::Collectives; use frame_support::{parameter_types, traits::EitherOf}; use frame_system::EnsureRootWithSuccess; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; @@ -32,7 +32,7 @@ mod tracks; pub use tracks::TracksInfo; parameter_types! { - pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1); + pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; } impl pallet_conviction_voting::Config for Runtime { @@ -48,7 +48,7 @@ impl pallet_conviction_voting::Config for Runtime { parameter_types! { pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 1 * DOLLARS; + pub const SubmissionDeposit: Balance = 1 * 3 * CENTS; pub const UndecidingTimeout: BlockNumber = 14 * DAYS; } @@ -70,14 +70,14 @@ impl pallet_whitelist::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WhitelistOrigin = EitherOfDiverse< EnsureRoot, - EnsureXcm>, + EnsureXcm>, >; type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; type Preimages = Preimage; } impl pallet_referenda::Config for Runtime { - type WeightInfo = weights::pallet_referenda::WeightInfo; + type WeightInfo = weights::pallet_referenda_referenda::WeightInfo; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; diff --git a/polkadot/runtime/polkadot/src/governance/origins.rs b/polkadot/runtime/westend/src/governance/origins.rs similarity index 63% rename from polkadot/runtime/polkadot/src/governance/origins.rs rename to polkadot/runtime/westend/src/governance/origins.rs index 551e05e556db414731efe5a003709509544cb63a..e4639f40dc432473e1222f6ab1094a31ecd26f68 100644 --- a/polkadot/runtime/polkadot/src/governance/origins.rs +++ b/polkadot/runtime/westend/src/governance/origins.rs @@ -20,7 +20,7 @@ pub use pallet_custom_origins::*; #[frame_support::pallet] pub mod pallet_custom_origins { - use crate::{Balance, DOLLARS, GRAND}; + use crate::{Balance, CENTS, GRAND}; use frame_support::pallet_prelude::*; #[pallet::config] @@ -32,14 +32,13 @@ pub mod pallet_custom_origins { #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] #[pallet::origin] pub enum Origin { - /// Origin able to cancel slashes and manage minimum commission. + /// Origin for cancelling slashes. StakingAdmin, - /// Origin for spending up to $10,000,000 DOT from the treasury as well as generally - /// administering it. + /// Origin for spending (any amount of) funds. Treasurer, /// Origin for managing the composition of the fellowship. FellowshipAdmin, - /// Origin for managing the registrar and permissioned HRMP channel operations. + /// Origin for managing the registrar. GeneralAdmin, /// Origin for starting auctions. AuctionAdmin, @@ -49,18 +48,44 @@ pub mod pallet_custom_origins { ReferendumCanceller, /// Origin able to kill referenda. ReferendumKiller, - /// Origin able to spend around $250 from the treasury at once. + /// Origin able to spend up to 1 KSM from the treasury at once. SmallTipper, - /// Origin able to spend around $1,000 from the treasury at once. + /// Origin able to spend up to 5 KSM from the treasury at once. BigTipper, - /// Origin able to spend around $10,000 from the treasury at once. + /// Origin able to spend up to 50 KSM from the treasury at once. SmallSpender, - /// Origin able to spend around $100,000 from the treasury at once. + /// Origin able to spend up to 500 KSM from the treasury at once. MediumSpender, - /// Origin able to spend up to $1,000,000 DOT from the treasury at once. + /// Origin able to spend up to 5,000 KSM from the treasury at once. BigSpender, /// Origin able to dispatch a whitelisted call. WhitelistedCaller, + /// Origin commanded by any members of the Polkadot Fellowship (no Dan grade needed). + FellowshipInitiates, + /// Origin commanded by Polkadot Fellows (3rd Dan fellows or greater). + Fellows, + /// Origin commanded by Polkadot Experts (5th Dan fellows or greater). + FellowshipExperts, + /// Origin commanded by Polkadot Masters (7th Dan fellows of greater). + FellowshipMasters, + /// Origin commanded by rank 1 of the Polkadot Fellowship and with a success of 1. + Fellowship1Dan, + /// Origin commanded by rank 2 of the Polkadot Fellowship and with a success of 2. + Fellowship2Dan, + /// Origin commanded by rank 3 of the Polkadot Fellowship and with a success of 3. + Fellowship3Dan, + /// Origin commanded by rank 4 of the Polkadot Fellowship and with a success of 4. + Fellowship4Dan, + /// Origin commanded by rank 5 of the Polkadot Fellowship and with a success of 5. + Fellowship5Dan, + /// Origin commanded by rank 6 of the Polkadot Fellowship and with a success of 6. + Fellowship6Dan, + /// Origin commanded by rank 7 of the Polkadot Fellowship and with a success of 7. + Fellowship7Dan, + /// Origin commanded by rank 8 of the Polkadot Fellowship and with a success of 8. + Fellowship8Dan, + /// Origin commanded by rank 9 of the Polkadot Fellowship and with a success of 9. + Fellowship9Dan, } macro_rules! decl_unit_ensures { @@ -103,6 +128,10 @@ pub mod pallet_custom_origins { ReferendumCanceller, ReferendumKiller, WhitelistedCaller, + FellowshipInitiates: u16 = 0, + Fellows: u16 = 3, + FellowshipExperts: u16 = 5, + FellowshipMasters: u16 = 7, ); macro_rules! decl_ensure { @@ -140,7 +169,7 @@ pub mod pallet_custom_origins { decl_ensure! { pub type Spender: EnsureOrigin { - SmallTipper = 250 * DOLLARS, + SmallTipper = 250 * 3 * CENTS, BigTipper = 1 * GRAND, SmallSpender = 10 * GRAND, MediumSpender = 100 * GRAND, @@ -148,4 +177,18 @@ pub mod pallet_custom_origins { Treasurer = 10_000 * GRAND, } } + + decl_ensure! { + pub type EnsureFellowship: EnsureOrigin { + Fellowship1Dan = 1, + Fellowship2Dan = 2, + Fellowship3Dan = 3, + Fellowship4Dan = 4, + Fellowship5Dan = 5, + Fellowship6Dan = 6, + Fellowship7Dan = 7, + Fellowship8Dan = 8, + Fellowship9Dan = 9, + } + } } diff --git a/polkadot/runtime/polkadot/src/governance/tracks.rs b/polkadot/runtime/westend/src/governance/tracks.rs similarity index 79% rename from polkadot/runtime/polkadot/src/governance/tracks.rs rename to polkadot/runtime/westend/src/governance/tracks.rs index 2b6d470e516e64cd31b791c724670f5bbf8c556c..3765569f183e0414a10fe2852e528ccc9dedc3d7 100644 --- a/polkadot/runtime/polkadot/src/governance/tracks.rs +++ b/polkadot/runtime/westend/src/governance/tracks.rs @@ -72,10 +72,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "root", max_deciding: 1, decision_deposit: 100 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 24 * HOURS, - min_enactment_period: 24 * HOURS, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_ROOT, min_support: SUP_ROOT, }, @@ -86,10 +86,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "whitelisted_caller", max_deciding: 100, decision_deposit: 10 * GRAND, - prepare_period: 30 * MINUTES, - decision_period: 28 * DAYS, - confirm_period: 10 * MINUTES, - min_enactment_period: 10 * MINUTES, + prepare_period: 6 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 4 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_WHITELISTED_CALLER, min_support: SUP_WHITELISTED_CALLER, }, @@ -100,10 +100,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "staking_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_STAKING_ADMIN, min_support: SUP_STAKING_ADMIN, }, @@ -114,10 +114,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "treasurer", max_deciding: 10, decision_deposit: 1 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 24 * HOURS, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_TREASURER, min_support: SUP_TREASURER, }, @@ -128,10 +128,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "lease_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_LEASE_ADMIN, min_support: SUP_LEASE_ADMIN, }, @@ -142,10 +142,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "fellowship_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_FELLOWSHIP_ADMIN, min_support: SUP_FELLOWSHIP_ADMIN, }, @@ -156,10 +156,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "general_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_GENERAL_ADMIN, min_support: SUP_GENERAL_ADMIN, }, @@ -170,10 +170,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "auction_admin", max_deciding: 10, decision_deposit: 5 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_AUCTION_ADMIN, min_support: SUP_AUCTION_ADMIN, }, @@ -184,10 +184,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "referendum_canceller", max_deciding: 1_000, decision_deposit: 10 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 7 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_REFERENDUM_CANCELLER, min_support: SUP_REFERENDUM_CANCELLER, }, @@ -198,10 +198,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 name: "referendum_killer", max_deciding: 1_000, decision_deposit: 50 * GRAND, - prepare_period: 2 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 3 * HOURS, - min_enactment_period: 10 * MINUTES, + prepare_period: 8 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 8 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_REFERENDUM_KILLER, min_support: SUP_REFERENDUM_KILLER, }, @@ -211,10 +211,10 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "small_tipper", max_deciding: 200, - decision_deposit: 1 * DOLLARS, + decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 10 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 4 * MINUTES, min_enactment_period: 1 * MINUTES, min_approval: APP_SMALL_TIPPER, min_support: SUP_SMALL_TIPPER, @@ -225,11 +225,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "big_tipper", max_deciding: 100, - decision_deposit: 10 * DOLLARS, - prepare_period: 10 * MINUTES, - decision_period: 7 * DAYS, - confirm_period: 1 * HOURS, - min_enactment_period: 10 * MINUTES, + decision_deposit: 10 * 3 * CENTS, + prepare_period: 4 * MINUTES, + decision_period: 14 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 3 * MINUTES, min_approval: APP_BIG_TIPPER, min_support: SUP_BIG_TIPPER, }, @@ -239,11 +239,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "small_spender", max_deciding: 50, - decision_deposit: 100 * DOLLARS, - prepare_period: 4 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 12 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 100 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 10 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_SMALL_SPENDER, min_support: SUP_SMALL_SPENDER, }, @@ -253,11 +253,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "medium_spender", max_deciding: 50, - decision_deposit: 200 * DOLLARS, - prepare_period: 4 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 24 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 200 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 12 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_MEDIUM_SPENDER, min_support: SUP_MEDIUM_SPENDER, }, @@ -267,11 +267,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 pallet_referenda::TrackInfo { name: "big_spender", max_deciding: 50, - decision_deposit: 400 * DOLLARS, - prepare_period: 4 * HOURS, - decision_period: 28 * DAYS, - confirm_period: 48 * HOURS, - min_enactment_period: 24 * HOURS, + decision_deposit: 400 * 3 * CENTS, + prepare_period: 10 * MINUTES, + decision_period: 20 * MINUTES, + confirm_period: 14 * MINUTES, + min_enactment_period: 5 * MINUTES, min_approval: APP_BIG_SPENDER, min_support: SUP_BIG_SPENDER, }, @@ -310,6 +310,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { origins::Origin::SmallSpender => Ok(32), origins::Origin::MediumSpender => Ok(33), origins::Origin::BigSpender => Ok(34), + _ => Err(()), } } else { Err(()) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 5cb6cbbab20e71e0ffbe5d1e607c2c91985c6b2c..0e93b3449fec5b8ba20128b37460faa71abb78c0 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -17,7 +17,7 @@ //! The Westend runtime. This can be compiled with `#[no_std]`, ready for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. +// `construct_runtime!` does a lot of recursion and requires us to increase the limit. #![recursion_limit = "512"] use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; @@ -27,10 +27,13 @@ use beefy_primitives::{ }; use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen}; use frame_support::{ - construct_runtime, parameter_types, + construct_runtime, + genesis_builder_helper::{build_config, create_default_config}, + parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, InstanceFilter, KeyOwnerProofSystem, - LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, + fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, + InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, + ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, @@ -50,9 +53,14 @@ use primitives::{ ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ - assigned_slots, auctions, crowdloan, elections::OnChainAccuracy, impl_runtime_weights, - impls::ToAuthor, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256, - BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, + assigned_slots, auctions, crowdloan, + elections::OnChainAccuracy, + impl_runtime_weights, + impls::{ + LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter, + }, + paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256, BlockHashCount, + BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, }; use runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, @@ -63,7 +71,7 @@ use runtime_parachains::{ initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, runtime_api_impl::{ - v5 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, + v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, }, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, @@ -76,17 +84,21 @@ use sp_runtime::{ generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, - Keccak256, OpaqueKeys, SaturatedConversion, Verify, + IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, }; use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::latest::Junction; +use xcm::{ + latest::{InteriorMultiLocation, Junction, Junction::PalletInstance}, + VersionedMultiLocation, +}; +use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -106,6 +118,13 @@ mod bag_thresholds; mod weights; pub mod xcm_config; +// Governance and configurations. +pub mod governance; +use governance::{ + pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, StakingAdmin, + Treasurer, TreasurySpender, +}; + #[cfg(test)] mod tests; @@ -121,7 +140,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 9430, + spec_version: 10020, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, @@ -141,13 +160,24 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } +/// A type to identify calls to the Identity pallet. These will be filtered to prevent invocation, +/// locking the state of the pallet and preventing further updates to identities and sub-identities. +/// The locked state will be the genesis state of a new system chain and then removed from the Relay +/// Chain. +pub struct IdentityCalls; +impl Contains for IdentityCalls { + fn contains(c: &RuntimeCall) -> bool { + matches!(c, RuntimeCall::Identity(_)) + } +} + parameter_types! { pub const Version: RuntimeVersion = VERSION; pub const SS58Prefix: u8 = 42; } impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; + type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; @@ -185,7 +215,9 @@ impl pallet_scheduler::Config for Runtime { type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; + // The goal of having ScheduleOrigin include AuctionAdmin is to allow the auctions track of + // OpenGov to schedule periodic auctions. + type ScheduleOrigin = EitherOf, AuctionAdmin>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = weights::pallet_scheduler::WeightInfo; type OriginPrivilegeCmp = frame_support::traits::EqualPrivilegeOnly; @@ -271,9 +303,9 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<0>; } parameter_types! { @@ -671,7 +703,62 @@ impl pallet_fast_unstake::Config for Runtime { } parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 2000 * CENTS; + pub const ProposalBondMaximum: Balance = 1 * GRAND; + pub const SpendPeriod: BlockNumber = 6 * DAYS; + pub const Burn: Permill = Permill::from_perthousand(2); + pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub const PayoutSpendPeriod: BlockNumber = 30 * DAYS; + // The asset's interior location for the paying account. This is the Treasury + // pallet instance (which sits at index 37). + pub TreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(37).into(); + + pub const TipCountdown: BlockNumber = 1 * DAYS; + pub const TipFindersFee: Percent = Percent::from_percent(20); + pub const TipReportDepositBase: Balance = 100 * CENTS; + pub const DataDepositPerByte: Balance = 1 * CENTS; + pub const MaxApprovals: u32 = 100; pub const MaxAuthorities: u32 = 100_000; + pub const MaxKeys: u32 = 10_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxBalance: Balance = Balance::max_value(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = EitherOfDiverse, Treasurer>; + type RejectOrigin = EitherOfDiverse, Treasurer>; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = ProposalBondMaximum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type SpendOrigin = TreasurySpender; + type AssetKind = VersionedLocatableAsset; + type Beneficiary = VersionedMultiLocation; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayOverXcm< + TreasuryInteriorLocation, + crate::xcm_config::XcmRouter, + crate::XcmPallet, + ConstU32<{ 6 * HOURS }>, + Self::Beneficiary, + Self::AssetKind, + LocatableAssetConverter, + VersionedMultiLocationConverter, + >; + type BalanceConverter = AssetRate; + type PayoutPeriod = PayoutSpendPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments; } impl pallet_offences::Config for Runtime { @@ -687,8 +774,6 @@ impl pallet_authority_discovery::Config for Runtime { parameter_types! { pub const NposSolutionPriority: TransactionPriority = TransactionPriority::max_value() / 2; pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); - pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; } impl pallet_im_online::Config for Runtime { @@ -802,8 +887,8 @@ impl pallet_identity::Config for Runtime { type MaxSubAccounts = MaxSubAccounts; type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; - type RegistrarOrigin = frame_system::EnsureRoot; - type ForceOrigin = frame_system::EnsureRoot; + type ForceOrigin = EitherOf, GeneralAdmin>; + type RegistrarOrigin = EitherOf, GeneralAdmin>; type WeightInfo = weights::pallet_identity::WeightInfo; } @@ -900,6 +985,7 @@ parameter_types! { pub enum ProxyType { Any, NonTransfer, + Governance, Staking, SudoBalances, IdentityJudgement, @@ -932,6 +1018,9 @@ impl InstanceFilter for ProxyType { RuntimeCall::ImOnline(..) | RuntimeCall::Utility(..) | RuntimeCall::Identity(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) | RuntimeCall::Recovery(pallet_recovery::Call::as_recovered{..}) | RuntimeCall::Recovery(pallet_recovery::Call::vouch_recovery{..}) | RuntimeCall::Recovery(pallet_recovery::Call::claim_recovery{..}) | @@ -977,6 +1066,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility(..) => true, _ => false, }, + ProxyType::Governance => matches!( + c, + // OpenGov calls + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) + ), ProxyType::IdentityJudgement => matches!( c, RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | @@ -1172,7 +1268,7 @@ impl parachains_slashing::Config for Runtime { parameter_types! { pub const ParaDeposit: Balance = 2000 * CENTS; - pub const DataDepositPerByte: Balance = deposit(0, 1); + pub const RegistrarDataDepositPerByte: Balance = deposit(0, 1); } impl paras_registrar::Config for Runtime { @@ -1181,7 +1277,7 @@ impl paras_registrar::Config for Runtime { type Currency = Balances; type OnSwap = (Crowdloan, Slots); type ParaDeposit = ParaDeposit; - type DataDepositPerByte = DataDepositPerByte; + type DataDepositPerByte = RegistrarDataDepositPerByte; type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; } @@ -1195,7 +1291,7 @@ impl slots::Config for Runtime { type Registrar = Registrar; type LeasePeriod = LeasePeriod; type LeaseOffset = (); - type ForceOrigin = EnsureRoot; + type ForceOrigin = EitherOf, LeaseAdmin>; type WeightInfo = weights::runtime_common_slots::WeightInfo; } @@ -1235,7 +1331,7 @@ impl auctions::Config for Runtime { type EndingPeriod = EndingPeriod; type SampleLength = SampleLength; type Randomness = pallet_babe::RandomnessFromOneEpochAgo; - type InitiateOrigin = EnsureRoot; + type InitiateOrigin = EitherOf, AuctionAdmin>; type WeightInfo = weights::runtime_common_auctions::WeightInfo; } @@ -1248,6 +1344,7 @@ impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_nomination_pools::WeightInfo; type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; @@ -1267,6 +1364,18 @@ parameter_types! { pub const MigrationMaxKeyLen: u32 = 512; } +impl pallet_asset_rate::Config for Runtime { + type WeightInfo = weights::pallet_asset_rate::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type CreateOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type Currency = Balances; + type AssetKind = ::AssetKind; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments; +} + construct_runtime! { pub enum Runtime { @@ -1335,11 +1444,20 @@ construct_runtime! { VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 25, // Nomination pools for staking. - NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event, Config} = 29, + NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event, Config, FreezeReason} = 29, // Fast unstake pallet: extension to staking. FastUnstake: pallet_fast_unstake = 30, + // OpenGov + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 31, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 32, + Origins: pallet_custom_origins::{Origin} = 35, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 36, + + // Treasury + Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 37, + // Parachains pallets. Start indices at 40 to leave room. ParachainsOrigin: parachains_origin::{Pallet, Origin} = 41, Configuration: parachains_configuration::{Pallet, Call, Storage, Config} = 42, @@ -1370,6 +1488,9 @@ construct_runtime! { // Generalized message queue MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 100, + + // Asset rate. + AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event} = 101, } } @@ -1433,6 +1554,9 @@ pub mod migrations { UpgradeSessionKeys, parachains_configuration::migration::v9::MigrateToV9, paras_registrar::migration::VersionCheckedMigrateToV1, + pallet_nomination_pools::migration::versioned_migrations::V5toV6, + pallet_referenda::migration::v1::MigrateV0ToV1, + pallet_nomination_pools::migration::versioned_migrations::V6ToV7, ); } @@ -1473,6 +1597,7 @@ mod benches { // Substrate [pallet_bags_list, VoterList] [pallet_balances, Balances] + [pallet_conviction_voting, ConvictionVoting] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [frame_election_provider_support, ElectionProviderBench::] [pallet_fast_unstake, FastUnstake] @@ -1486,14 +1611,18 @@ mod benches { [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_recovery, Recovery] + [pallet_referenda, Referenda] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] [pallet_sudo, Sudo] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] + [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_whitelist, Whitelist] + [pallet_asset_rate, AssetRate] // XCM [pallet_xcm, XcmPallet] // NOTE: Make sure you point to the individual modules below. @@ -1568,7 +1697,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(6)] + #[api_version(8)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1701,7 +1830,19 @@ sp_api::impl_runtime_apis! { } fn minimum_backing_votes() -> u32 { - parachains_staging_runtime_api_impl::minimum_backing_votes::() + parachains_runtime_api_impl::minimum_backing_votes::() + } + + fn para_backing_state(para_id: ParaId) -> Option { + parachains_runtime_api_impl::backing_state::(para_id) + } + + fn async_backing_params() -> primitives::AsyncBackingParams { + parachains_runtime_api_impl::async_backing_params::() + } + + fn disabled_validators() -> Vec { + parachains_staging_runtime_api_impl::disabled_validators::() } } @@ -2039,13 +2180,13 @@ sp_api::impl_runtime_apis! { AssetId::*, Fungibility::*, InteriorMultiLocation, Junction, Junctions::*, MultiAsset, MultiAssets, MultiLocation, NetworkId, Response, }; - use xcm_config::{Westmint, TokenLocation}; + use xcm_config::{AssetHub, TokenLocation}; impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationConverter; fn valid_destination() -> Result { - Ok(Westmint::get()) + Ok(AssetHub::get()) } fn worst_case_holding(_depositable_count: u32) -> MultiAssets { // Westend only knows about WND. @@ -2058,7 +2199,7 @@ sp_api::impl_runtime_apis! { parameter_types! { pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( - Westmint::get(), + AssetHub::get(), MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) }, )); pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None; @@ -2097,15 +2238,15 @@ sp_api::impl_runtime_apis! { } fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> { - Ok((Westmint::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) + Ok((AssetHub::get(), frame_system::Call::remark_with_event { remark: vec![] }.into())) } fn subscribe_origin() -> Result { - Ok(Westmint::get()) + Ok(AssetHub::get()) } fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> { - let origin = Westmint::get(); + let origin = AssetHub::get(); let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into(); let ticket = MultiLocation { parents: 0, interior: Here }; Ok((origin, ticket, assets)) @@ -2141,6 +2282,16 @@ sp_api::impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } #[cfg(all(test, feature = "try-runtime"))] diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 531de5527de52deb2d3979658f6a28f5b5194787..9ae6798d70b6e234c7ffbbfd99f2f97c56fb30a4 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -17,8 +17,10 @@ pub mod frame_election_provider_support; pub mod frame_system; +pub mod pallet_asset_rate; pub mod pallet_bags_list; pub mod pallet_balances; +pub mod pallet_conviction_voting; pub mod pallet_election_provider_multi_phase; pub mod pallet_fast_unstake; pub mod pallet_identity; @@ -29,13 +31,17 @@ pub mod pallet_multisig; pub mod pallet_nomination_pools; pub mod pallet_preimage; pub mod pallet_proxy; +pub mod pallet_referenda_fellowship_referenda; +pub mod pallet_referenda_referenda; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_staking; pub mod pallet_sudo; pub mod pallet_timestamp; +pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; +pub mod pallet_whitelist; pub mod pallet_xcm; pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; diff --git a/polkadot/runtime/westend/src/weights/pallet_asset_rate.rs b/polkadot/runtime/westend/src/weights/pallet_asset_rate.rs new file mode 100644 index 0000000000000000000000000000000000000000..810dd01a170263a257629aad42dc166b9bd75f41 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_asset_rate.rs @@ -0,0 +1,86 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_asset_rate` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-04, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --chain=polkadot-dev +// --steps=50 +// --repeat=2 +// --pallet=pallet_asset_rate +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./runtime/polkadot/src/weights/ +// --header=./file_header.txt + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_rate`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_rate::WeightInfo for WeightInfo { + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `4702` + // Minimum execution time: 67_000_000 picoseconds. + Weight::from_parts(69_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 69_000_000 picoseconds. + Weight::from_parts(71_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 70_000_000 picoseconds. + Weight::from_parts(90_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/westend/src/weights/pallet_conviction_voting.rs new file mode 100644 index 0000000000000000000000000000000000000000..8965a7392ed2859b245ff96a80e13dd5eea66403 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_conviction_voting.rs @@ -0,0 +1,194 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_conviction_voting` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_conviction_voting +// --chain=westend-dev +// --header=./file_header.txt +// --output=./runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_conviction_voting`. +pub struct WeightInfo(PhantomData); +impl pallet_conviction_voting::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn vote_new() -> Weight { + // Proof Size summary in bytes: + // Measured: `13445` + // Estimated: `42428` + // Minimum execution time: 152_223_000 picoseconds. + Weight::from_parts(162_148_000, 0) + .saturating_add(Weight::from_parts(0, 42428)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn vote_existing() -> Weight { + // Proof Size summary in bytes: + // Measured: `14166` + // Estimated: `83866` + // Minimum execution time: 220_361_000 picoseconds. + Weight::from_parts(236_478_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn remove_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `13918` + // Estimated: `83866` + // Minimum execution time: 198_787_000 picoseconds. + Weight::from_parts(204_983_000, 0) + .saturating_add(Weight::from_parts(0, 83866)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + fn remove_other_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `13004` + // Estimated: `30706` + // Minimum execution time: 88_469_000 picoseconds. + Weight::from_parts(95_942_000, 0) + .saturating_add(Weight::from_parts(0, 30706)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 512]`. + fn delegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `29640 + r * (365 ±0)` + // Estimated: `83866 + r * (3411 ±0)` + // Minimum execution time: 79_951_000 picoseconds. + Weight::from_parts(1_844_983_097, 0) + .saturating_add(Weight::from_parts(0, 83866)) + // Standard Error: 160_158 + .saturating_add(Weight::from_parts(43_973_863, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 512]`. + fn undelegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `29555 + r * (365 ±0)` + // Estimated: `83866 + r * (3411 ±0)` + // Minimum execution time: 47_976_000 picoseconds. + Weight::from_parts(1_877_857_335, 0) + .saturating_add(Weight::from_parts(0, 83866)) + // Standard Error: 168_477 + .saturating_add(Weight::from_parts(43_303_902, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `12218` + // Estimated: `30706` + // Minimum execution time: 102_868_000 picoseconds. + Weight::from_parts(110_438_000, 0) + .saturating_add(Weight::from_parts(0, 30706)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs b/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs index 9d43eb2498927cac586eb56c4247d262adee27b0..49bc687a3e4fa2afba34567769bb3b68c2d55d89 100644 --- a/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs +++ b/polkadot/runtime/westend/src/weights/pallet_nomination_pools.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_nomination_pools` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-22, 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-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=westend-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_nomination_pools // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_nomination_pools +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,552 +48,574 @@ use core::marker::PhantomData; /// Weight functions for `pallet_nomination_pools`. pub struct WeightInfo(PhantomData); impl pallet_nomination_pools::WeightInfo for WeightInfo { - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3281` + // Measured: `3318` // Estimated: `8877` - // Minimum execution time: 196_298_000 picoseconds. - Weight::from_parts(202_857_000, 0) + // Minimum execution time: 187_795_000 picoseconds. + Weight::from_parts(193_857_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(19)) .saturating_add(T::DbWeight::get().writes(12)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3291` + // Measured: `3328` // Estimated: `8877` - // Minimum execution time: 191_639_000 picoseconds. - Weight::from_parts(197_000_000, 0) + // Minimum execution time: 186_245_000 picoseconds. + Weight::from_parts(190_916_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(16)) .saturating_add(T::DbWeight::get().writes(12)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3186` + // Measured: `3274` // Estimated: `8799` - // Minimum execution time: 224_836_000 picoseconds. - Weight::from_parts(230_990_000, 0) + // Minimum execution time: 217_918_000 picoseconds. + Weight::from_parts(224_772_000, 0) .saturating_add(Weight::from_parts(0, 8799)) .saturating_add(T::DbWeight::get().reads(16)) .saturating_add(T::DbWeight::get().writes(12)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_payout() -> Weight { // Proof Size summary in bytes: // Measured: `1137` // Estimated: `4182` - // Minimum execution time: 79_609_000 picoseconds. - Weight::from_parts(81_434_000, 0) + // Minimum execution time: 76_958_000 picoseconds. + Weight::from_parts(78_278_000, 0) .saturating_add(Weight::from_parts(0, 4182)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(261), added: 2736, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(261), added: 2736, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3560` + // Measured: `3597` // Estimated: `8877` - // Minimum execution time: 175_473_000 picoseconds. - Weight::from_parts(179_976_000, 0) + // Minimum execution time: 170_992_000 picoseconds. + Weight::from_parts(179_987_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(20)) .saturating_add(T::DbWeight::get().writes(13)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1614` + // Measured: `1670` // Estimated: `4764` - // Minimum execution time: 63_011_000 picoseconds. - Weight::from_parts(65_966_680, 0) + // Minimum execution time: 60_740_000 picoseconds. + Weight::from_parts(64_502_831, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_422 - .saturating_add(Weight::from_parts(58_078, 0).saturating_mul(s.into())) + // Standard Error: 2_724 + .saturating_add(Weight::from_parts(37_725, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(261), added: 2736, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(261), added: 2736, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2042` + // Measured: `2098` // Estimated: `4764` - // Minimum execution time: 134_765_000 picoseconds. - Weight::from_parts(140_539_571, 0) + // Minimum execution time: 127_322_000 picoseconds. + Weight::from_parts(132_064_603, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 4_169 - .saturating_add(Weight::from_parts(61_448, 0).saturating_mul(s.into())) + // Standard Error: 3_424 + .saturating_add(Weight::from_parts(64_590, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(261), added: 2736, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(261), added: 2736, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:1 w:0) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2398` - // Estimated: `6196` - // Minimum execution time: 226_632_000 picoseconds. - Weight::from_parts(234_263_474, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(21)) - .saturating_add(T::DbWeight::get().writes(18)) + // Measured: `2454` + // Estimated: `8538` + // Minimum execution time: 236_510_000 picoseconds. + Weight::from_parts(243_943_334, 0) + .saturating_add(Weight::from_parts(0, 8538)) + // Standard Error: 4_864 + .saturating_add(Weight::from_parts(14_974, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(23)) + .saturating_add(T::DbWeight::get().writes(19)) } - /// Storage: NominationPools LastPoolId (r:1 w:1) - /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:1 w:0) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:1 w:0) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `NominationPools::LastPoolId` (r:1 w:1) + /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:1 w:0) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1222` - // Estimated: `6196` - // Minimum execution time: 197_132_000 picoseconds. - Weight::from_parts(202_099_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(22)) - .saturating_add(T::DbWeight::get().writes(15)) + // Estimated: `8538` + // Minimum execution time: 197_883_000 picoseconds. + Weight::from_parts(201_750_000, 0) + .saturating_add(Weight::from_parts(0, 8538)) + .saturating_add(T::DbWeight::get().reads(24)) + .saturating_add(T::DbWeight::get().writes(16)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) + /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:17 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1779` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 68_142_000 picoseconds. - Weight::from_parts(68_977_842, 0) + // Minimum execution time: 65_505_000 picoseconds. + Weight::from_parts(67_148_657, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 10_560 - .saturating_add(Weight::from_parts(1_606_142, 0).saturating_mul(n.into())) + // Standard Error: 9_115 + .saturating_add(Weight::from_parts(1_421_198, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_state() -> Weight { // Proof Size summary in bytes: // Measured: `1367` // Estimated: `4556` - // Minimum execution time: 36_343_000 picoseconds. - Weight::from_parts(37_669_000, 0) + // Minimum execution time: 34_157_000 picoseconds. + Weight::from_parts(35_557_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForMetadata (r:1 w:1) - /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForMetadata` (r:1 w:1) + /// Proof: `NominationPools::CounterForMetadata` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `497` // Estimated: `3735` - // Minimum execution time: 14_157_000 picoseconds. - Weight::from_parts(15_201_514, 0) + // Minimum execution time: 13_806_000 picoseconds. + Weight::from_parts(14_540_018, 0) .saturating_add(Weight::from_parts(0, 3735)) - // Standard Error: 194 - .saturating_add(Weight::from_parts(718, 0).saturating_mul(n.into())) + // Standard Error: 123 + .saturating_add(Weight::from_parts(644, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: NominationPools MinJoinBond (r:0 w:1) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:0 w:1) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:0 w:1) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:0 w:1) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:0 w:1) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:0 w:1) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:0 w:1) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:0 w:1) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_configs() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_082_000 picoseconds. - Weight::from_parts(6_275_000, 0) + // Minimum execution time: 5_870_000 picoseconds. + Weight::from_parts(6_253_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: // Measured: `497` // Estimated: `3685` - // Minimum execution time: 19_952_000 picoseconds. - Weight::from_parts(20_880_000, 0) + // Minimum execution time: 18_290_000 picoseconds. + Weight::from_parts(18_961_000, 0) .saturating_add(Weight::from_parts(0, 3685)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `1942` // Estimated: `4556` - // Minimum execution time: 66_233_000 picoseconds. - Weight::from_parts(68_181_000, 0) + // Minimum execution time: 63_708_000 picoseconds. + Weight::from_parts(65_570_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn set_commission() -> Weight { // Proof Size summary in bytes: // Measured: `736` // Estimated: `3685` - // Minimum execution time: 33_533_000 picoseconds. - Weight::from_parts(34_915_000, 0) + // Minimum execution time: 34_291_000 picoseconds. + Weight::from_parts(34_767_000, 0) .saturating_add(Weight::from_parts(0, 3685)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_commission_max() -> Weight { // Proof Size summary in bytes: // Measured: `537` // Estimated: `3685` - // Minimum execution time: 18_920_000 picoseconds. - Weight::from_parts(19_410_000, 0) + // Minimum execution time: 18_406_000 picoseconds. + Weight::from_parts(18_999_000, 0) .saturating_add(Weight::from_parts(0, 3685)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: // Measured: `497` // Estimated: `3685` - // Minimum execution time: 19_388_000 picoseconds. - Weight::from_parts(20_346_000, 0) + // Minimum execution time: 18_440_000 picoseconds. + Weight::from_parts(19_230_000, 0) .saturating_add(Weight::from_parts(0, 3685)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: NominationPools PoolMembers (r:1 w:0) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(717), added: 3192, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:1 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(717), added: 3192, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `508` // Estimated: `4182` - // Minimum execution time: 14_137_000 picoseconds. - Weight::from_parts(14_846_000, 0) + // Minimum execution time: 14_310_000 picoseconds. + Weight::from_parts(14_681_000, 0) .saturating_add(Weight::from_parts(0, 4182)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_commission() -> Weight { // Proof Size summary in bytes: // Measured: `934` // Estimated: `3685` - // Minimum execution time: 66_667_000 picoseconds. - Weight::from_parts(68_573_000, 0) + // Minimum execution time: 64_526_000 picoseconds. + Weight::from_parts(66_800_000, 0) .saturating_add(Weight::from_parts(0, 3685)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + fn adjust_pool_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `866` + // Estimated: `4764` + // Minimum execution time: 73_472_000 picoseconds. + Weight::from_parts(74_698_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } } diff --git a/polkadot/runtime/kusama/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs similarity index 100% rename from polkadot/runtime/kusama/src/weights/pallet_referenda_fellowship_referenda.rs rename to polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs diff --git a/polkadot/runtime/kusama/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_referenda.rs similarity index 100% rename from polkadot/runtime/kusama/src/weights/pallet_referenda_referenda.rs rename to polkadot/runtime/westend/src/weights/pallet_referenda_referenda.rs diff --git a/polkadot/runtime/kusama/src/weights/pallet_treasury.rs b/polkadot/runtime/westend/src/weights/pallet_treasury.rs similarity index 51% rename from polkadot/runtime/kusama/src/weights/pallet_treasury.rs rename to polkadot/runtime/westend/src/weights/pallet_treasury.rs index fe2e4f9cee8f8edd52ddb76f30410edabb8c1bf4..144e9d5b872382b7381e2d77c6fb08a8fbece4fa 100644 --- a/polkadot/runtime/kusama/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/westend/src/weights/pallet_treasury.rs @@ -17,27 +17,24 @@ //! Autogenerated weights for `pallet_treasury` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/debug/polkadot // benchmark // pallet -// --chain=kusama-dev +// --chain=rococo-dev // --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --repeat=2 // --pallet=pallet_treasury // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --output=./runtime/rococo/src/weights/ // --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,12 +53,12 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// Storage: Treasury Proposals (r:0 w:1) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend() -> Weight { + fn spend_local() -> Weight { // Proof Size summary in bytes: - // Measured: `6` + // Measured: `42` // Estimated: `1887` - // Minimum execution time: 14_076_000 picoseconds. - Weight::from_parts(14_546_000, 0) + // Minimum execution time: 177_000_000 picoseconds. + Weight::from_parts(191_000_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -72,10 +69,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `107` + // Measured: `143` // Estimated: `1489` - // Minimum execution time: 27_324_000 picoseconds. - Weight::from_parts(27_723_000, 0) + // Minimum execution time: 354_000_000 picoseconds. + Weight::from_parts(376_000_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,10 +83,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `265` + // Measured: `301` // Estimated: `3593` - // Minimum execution time: 41_722_000 picoseconds. - Weight::from_parts(42_638_000, 0) + // Minimum execution time: 547_000_000 picoseconds. + Weight::from_parts(550_000_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -101,13 +98,13 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + p * (8 ±0)` + // Measured: `470 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 8_332_000 picoseconds. - Weight::from_parts(10_971_007, 0) + // Minimum execution time: 104_000_000 picoseconds. + Weight::from_parts(121_184_402, 0) .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 1_480 - .saturating_add(Weight::from_parts(78_440, 0).saturating_mul(p.into())) + // Standard Error: 42_854 + .saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -115,10 +112,10 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `90` + // Measured: `127` // Estimated: `1887` - // Minimum execution time: 6_465_000 picoseconds. - Weight::from_parts(6_632_000, 0) + // Minimum execution time: 80_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -129,26 +126,98 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Treasury Approvals (r:1 w:1) /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:100 w:100) + /// Storage: Treasury Proposals (r:99 w:99) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:201 w:201) + /// Storage: System Account (r:199 w:199) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Bounties BountyApprovals (r:1 w:1) /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. + /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `264 + p * (251 ±0)` + // Measured: `331 + p * (251 ±0)` // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 67_339_000 picoseconds. - Weight::from_parts(61_523_213, 0) + // Minimum execution time: 887_000_000 picoseconds. + Weight::from_parts(828_616_021, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 28_817 - .saturating_add(Weight::from_parts(44_009_562, 0).saturating_mul(p.into())) + // Standard Error: 695_351 + .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(5)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `4702` + // Minimum execution time: 208_000_000 picoseconds. + Weight::from_parts(222_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet QueryCounter (r:1 w:1) + /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) + /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet SupportedVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet Queries (r:0 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `737` + // Estimated: `5313` + // Minimum execution time: 551_000_000 picoseconds. + Weight::from_parts(569_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet Queries (r:1 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `442` + // Estimated: `5313` + // Minimum execution time: 245_000_000 picoseconds. + Weight::from_parts(281_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `172` + // Estimated: `5313` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(160_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_whitelist.rs b/polkadot/runtime/westend/src/weights/pallet_whitelist.rs new file mode 100644 index 0000000000000000000000000000000000000000..6177ac799e6a41b47f0216bf145e1009acf39679 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_whitelist.rs @@ -0,0 +1,116 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_whitelist` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-o7yfgx5n-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_whitelist +// --chain=westend-dev +// --header=./file_header.txt +// --output=./runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_whitelist`. +pub struct WeightInfo(PhantomData); +impl pallet_whitelist::WeightInfo for WeightInfo { + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + fn whitelist_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `122` + // Estimated: `3556` + // Minimum execution time: 21_188_000 picoseconds. + Weight::from_parts(21_804_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + fn remove_whitelisted_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `3556` + // Minimum execution time: 17_655_000 picoseconds. + Weight::from_parts(19_443_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 4194294]`. + fn dispatch_whitelisted_call(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `327 + n * (1 ±0)` + // Estimated: `3791 + n * (1 ±0)` + // Minimum execution time: 30_540_000 picoseconds. + Weight::from_parts(30_886_000, 0) + .saturating_add(Weight::from_parts(0, 3791)) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_779, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 10000]`. + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `3556` + // Minimum execution time: 21_082_000 picoseconds. + Weight::from_parts(21_922_294, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_412, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs index e6ff97fa08784d5f9fc75d9274295c2ee666843a..9beb15303d871cd4ae0b6b0ce3148291d745395b 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs @@ -282,4 +282,46 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) } + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) + /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r: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`) + 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)) + .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)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index c6fa6bb93eb6ab69b256597bbedd59210bfcbf67..d5b3d8257ba54cd665933d10a5518d73382327e1 100644 --- a/polkadot/runtime/westend/src/weights/xcm/mod.rs +++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs @@ -94,7 +94,6 @@ impl XcmWeightInfo for WestendXcmWeight { assets.weigh_multi_assets(XcmBalancesWeight::::withdraw_asset()) } fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { - // Westend doesn't support ReserveAssetDeposited, so this benchmark has a default weight assets.weigh_multi_assets(XcmBalancesWeight::::reserve_asset_deposited()) } fn receive_teleported_asset(assets: &MultiAssets) -> Weight { diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index b92749bfa15b314573052ed4472bc664cd39e3ae..87e63fbe31070be2a45dc3f9c2b8ba36eaac83bb 100644 --- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-gghbxkbs-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-nbnwcyh-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 @@ -31,12 +31,12 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::fungible // --chain=westend-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/westend/src/weights/xcm/ +// --header=./polkadot/file_header.txt +// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs +// --output=./polkadot/runtime/westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 24_887_000 picoseconds. - Weight::from_parts(25_361_000, 3593) + // Minimum execution time: 24_642_000 picoseconds. + Weight::from_parts(24_973_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 52_408_000 picoseconds. - Weight::from_parts(53_387_000, 6196) + // Minimum execution time: 50_882_000 picoseconds. + Weight::from_parts(51_516_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -83,10 +83,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `177` + // Measured: `210` // Estimated: `6196` - // Minimum execution time: 74_753_000 picoseconds. - Weight::from_parts(76_838_000, 6196) + // Minimum execution time: 73_923_000 picoseconds. + Weight::from_parts(75_454_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -96,8 +96,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_000_000_000_000 picoseconds. - Weight::from_parts(2_000_000_000_000, 0) + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -109,10 +109,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `3541` - // Minimum execution time: 29_272_000 picoseconds. - Weight::from_parts(30_061_000, 3541) + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 29_035_000 picoseconds. + Weight::from_parts(30_086_000, 3574) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 23_112_000 picoseconds. - Weight::from_parts(23_705_000, 3593) + // Minimum execution time: 22_094_000 picoseconds. + Weight::from_parts(22_560_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,8 +133,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 26_077_000 picoseconds. - Weight::from_parts(26_486_000, 3593) + // Minimum execution time: 24_771_000 picoseconds. + Weight::from_parts(25_280_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -150,10 +150,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `109` // Estimated: `3593` - // Minimum execution time: 51_022_000 picoseconds. - Weight::from_parts(52_498_000, 3593) + // Minimum execution time: 49_777_000 picoseconds. + Weight::from_parts(50_833_000, 3593) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -169,10 +169,10 @@ impl WeightInfo { /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `109` // Estimated: `3593` - // Minimum execution time: 53_062_000 picoseconds. - Weight::from_parts(54_300_000, 3593) + // Minimum execution time: 51_425_000 picoseconds. + Weight::from_parts(52_213_000, 3593) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index afa0733b4c9afeaf52d42a62690a27a970fd595b..f025e5f1f3e116c377647dee17132ce1ca45aebd 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -17,35 +17,40 @@ //! XCM configurations for Westend. use super::{ - parachains_origin, weights, AccountId, AllPalletsWithSystem, Balances, Dmp, ParaId, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, + parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin, + GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, + TransactionByteFee, WeightToFee, XcmPallet, }; + use frame_support::{ - parameter_types, + match_types, parameter_types, traits::{Everything, Nothing}, }; use frame_system::EnsureRoot; +use pallet_xcm::XcmPassthrough; use runtime_common::{ xcm_sender::{ChildParachainRouter, ExponentialPrice}, ToAuthor, }; use sp_core::ConstU32; -use westend_runtime_constants::currency::CENTS; +use westend_runtime_constants::{ + currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, +}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, - IsConcrete, MintLocation, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, DescribeBodyTerminal, + DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; parameter_types! { pub const TokenLocation: MultiLocation = Here.into_location(); pub const ThisNetwork: NetworkId = Westend; - pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); + pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get())); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); /// The asset ID for the asset that we use to pay for message delivery fees. @@ -54,8 +59,14 @@ parameter_types! { pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); } -pub type LocationConverter = - (ChildParachainConvertsVia, AccountId32Aliases); +pub type LocationConverter = ( + // We can convert a child parachain using the standard `AccountId` conversion. + ChildParachainConvertsVia, + // We can directly alias an `AccountId32` into a local account. + AccountId32Aliases, + // Allow governance body to be used as a sovereign account. + HashedDescription>, +); pub type LocalAssetTransactor = XcmCurrencyAdapter< // Use this currency: @@ -71,9 +82,17 @@ pub type LocalAssetTransactor = XcmCurrencyAdapter< >; type LocalOriginConverter = ( + // If the origin kind is `Sovereign`, then return a `Signed` origin with the account determined + // by the `LocationConverter` converter. SovereignSignedViaLocation, + // If the origin kind is `Native` and the XCM origin is a child parachain, then we can express + // it with the special `parachains_origin::Origin` origin variant. ChildParachainAsNative, + // If the origin kind is `Native` and the XCM origin is the `AccountId32` location, then it can + // be expressed using the `Signed` origin variant. SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, ); /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our @@ -88,22 +107,27 @@ pub type XcmRouter = WithUniqueTopic<( )>; parameter_types! { - pub const Westmint: MultiLocation = Parachain(1000).into_location(); - pub const Collectives: MultiLocation = Parachain(1001).into_location(); pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); - pub const WndForWestmint: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Westmint::get()); + pub const AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location(); + pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get()); + pub const Collectives: MultiLocation = Parachain(COLLECTIVES_ID).into_location(); pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parachain(1000).into()); -} - pub type TrustedTeleporters = - (xcm_builder::Case, xcm_builder::Case); + (xcm_builder::Case, xcm_builder::Case); + +match_types! { + pub type OnlyParachains: impl Contains = { + MultiLocation { parents: 0, interior: X1(Parachain(_)) } + }; + pub type CollectivesOrFellows: impl Contains = { + MultiLocation { parents: 0, interior: X1(Parachain(COLLECTIVES_ID)) } | + MultiLocation { parents: 0, interior: X2(Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }) } + }; +} /// The barriers one of which must be passed for an XCM message to be executed. pub type Barrier = TrailingSetTopicAsId<( @@ -113,12 +137,12 @@ pub type Barrier = TrailingSetTopicAsId<( AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then allow it. + // If the message is one that immediately attempts to pay for execution, then allow it. AllowTopLevelPaidExecutionFrom, - // Messages coming from system parachains need not pay for execution. - AllowExplicitUnpaidExecutionFrom>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, + // Collectives and Fellows plurality get free execution. + AllowExplicitUnpaidExecutionFrom, ), UniversalLocation, ConstU32<8>, @@ -135,8 +159,11 @@ impl xcm_executor::Config for XcmConfig { type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; - type Weigher = - WeightInfoBounds, RuntimeCall, MaxInstructions>; + type Weigher = WeightInfoBounds< + crate::weights::xcm::WestendXcmWeight, + RuntimeCall, + MaxInstructions, + >; type Trader = UsingComponents>; type ResponseHandler = XcmPallet; @@ -155,16 +182,54 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } +parameter_types! { + // `GeneralAdmin` pluralistic body. + pub const GeneralAdminBodyId: BodyId = BodyId::Administration; + // StakingAdmin pluralistic body. + pub const StakingAdminBodyId: BodyId = BodyId::Defense; + // FellowshipAdmin pluralistic body. + pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parachain(1000).into()); +} + +/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. +pub type GeneralAdminToPlurality = + OriginToPluralityVoice; + /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( + GeneralAdminToPlurality, // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, ); +/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value. +pub type StakingAdminToPlurality = + OriginToPluralityVoice; + +/// Type to convert the `FellowshipAdmin` origin to a Plurality `MultiLocation` value. +pub type FellowshipAdminToPlurality = + OriginToPluralityVoice; + +/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an +/// interior location of this chain for a destination chain. +pub type LocalPalletOriginToLocation = ( + // GeneralAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + GeneralAdminToPlurality, + // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + StakingAdminToPlurality, + // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + FellowshipAdminToPlurality, +); + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; @@ -173,8 +238,11 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = - WeightInfoBounds, RuntimeCall, MaxInstructions>; + type Weigher = WeightInfoBounds< + crate::weights::xcm::WestendXcmWeight, + RuntimeCall, + MaxInstructions, + >; type UniversalLocation = UniversalLocation; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/scripts/build-demos.sh b/polkadot/scripts/build-demos.sh deleted file mode 100755 index 285da143c17d8ec4c0f4147dea62dc34843050bf..0000000000000000000000000000000000000000 --- a/polkadot/scripts/build-demos.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# This script assumes that all pre-requisites are installed. - -set -e - -PROJECT_ROOT=`git rev-parse --show-toplevel` -source `dirname "$0"`/common.sh - -export CARGO_INCREMENTAL=0 - -# Save current directory. -pushd . - -cd $ROOT - -for DEMO in "${DEMOS[@]}" -do - echo "*** Building wasm binaries in $DEMO" - cd "$PROJECT_ROOT/$DEMO" - - ./build.sh - - cd - >> /dev/null -done - -# Restore initial directory. -popd diff --git a/polkadot/scripts/init.sh b/polkadot/scripts/init.sh deleted file mode 100755 index cf5ecf97926fea7a5e8fd2a91df96853f90e8ee7..0000000000000000000000000000000000000000 --- a/polkadot/scripts/init.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo "*** Initializing WASM build environment" - -if [ -z $CI_PROJECT_NAME ] ; then - rustup update nightly - rustup update stable -fi - -rustup target add wasm32-unknown-unknown --toolchain nightly - -# Install wasm-gc. It's useful for stripping slimming down wasm binaries. -command -v wasm-gc || \ - cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force diff --git a/polkadot/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls new file mode 100644 index 0000000000000000000000000000000000000000..05abe9ba7368c43b766d1c888cd631aa9903d6b2 --- /dev/null +++ b/polkadot/scripts/list-syscalls/execute-worker-syscalls @@ -0,0 +1,74 @@ +0 (read) +1 (write) +2 (open) +3 (close) +4 (stat) +5 (fstat) +7 (poll) +8 (lseek) +9 (mmap) +10 (mprotect) +11 (munmap) +12 (brk) +13 (rt_sigaction) +14 (rt_sigprocmask) +15 (rt_sigreturn) +16 (ioctl) +19 (readv) +20 (writev) +24 (sched_yield) +25 (mremap) +28 (madvise) +39 (getpid) +41 (socket) +42 (connect) +45 (recvfrom) +46 (sendmsg) +53 (socketpair) +56 (clone) +60 (exit) +61 (wait4) +62 (kill) +72 (fcntl) +79 (getcwd) +80 (chdir) +82 (rename) +83 (mkdir) +87 (unlink) +89 (readlink) +96 (gettimeofday) +97 (getrlimit) +99 (sysinfo) +102 (getuid) +110 (getppid) +131 (sigaltstack) +140 (getpriority) +141 (setpriority) +144 (sched_setscheduler) +157 (prctl) +158 (arch_prctl) +165 (mount) +166 (umount2) +200 (tkill) +202 (futex) +204 (sched_getaffinity) +213 (epoll_create) +217 (getdents64) +218 (set_tid_address) +228 (clock_gettime) +230 (clock_nanosleep) +231 (exit_group) +232 (epoll_wait) +233 (epoll_ctl) +257 (openat) +262 (newfstatat) +263 (unlinkat) +272 (unshare) +273 (set_robust_list) +281 (epoll_pwait) +284 (eventfd) +290 (eventfd2) +291 (epoll_create1) +302 (prlimit64) +318 (getrandom) +319 (memfd_create) diff --git a/polkadot/scripts/list-syscalls/list-syscalls.rb b/polkadot/scripts/list-syscalls/list-syscalls.rb new file mode 100755 index 0000000000000000000000000000000000000000..9cef6f74b2ebe5588fca908f3787791a956ba50e --- /dev/null +++ b/polkadot/scripts/list-syscalls/list-syscalls.rb @@ -0,0 +1,608 @@ +#!/usr/bin/ruby + +# A script to statically list syscalls used by a given binary. +# +# Syntax: list-syscalls.rb [--only-used-syscalls] +# +# NOTE: For accurate results, build the binary with musl and LTO enabled. +# Example: ./polkadot/scripts/list-syscalls/list-syscalls.rb target/x86_64-unknown-linux-musl/production/polkadot-prepare-worker --only-used-syscalls +# +# Author: @koute +# Source: https://gist.github.com/koute/166f82bfee5e27324077891008fca6eb + +require 'shellwords' +require 'set' + +SYNTAX_STRING = 'Syntax: list-syscalls.rb [--only-used-syscalls]'.freeze + +# Generated from `libc` using the following regex: +# 'pub const SYS_([a-z0-9_]+): ::c_long = (\d+);' +# ' \2 => "\1",' +SYSCALLS = { + 0 => 'read', + 1 => 'write', + 2 => 'open', + 3 => 'close', + 4 => 'stat', + 5 => 'fstat', + 6 => 'lstat', + 7 => 'poll', + 8 => 'lseek', + 9 => 'mmap', + 10 => 'mprotect', + 11 => 'munmap', + 12 => 'brk', + 13 => 'rt_sigaction', + 14 => 'rt_sigprocmask', + 15 => 'rt_sigreturn', + 16 => 'ioctl', + 17 => 'pread64', + 18 => 'pwrite64', + 19 => 'readv', + 20 => 'writev', + 21 => 'access', + 22 => 'pipe', + 23 => 'select', + 24 => 'sched_yield', + 25 => 'mremap', + 26 => 'msync', + 27 => 'mincore', + 28 => 'madvise', + 29 => 'shmget', + 30 => 'shmat', + 31 => 'shmctl', + 32 => 'dup', + 33 => 'dup2', + 34 => 'pause', + 35 => 'nanosleep', + 36 => 'getitimer', + 37 => 'alarm', + 38 => 'setitimer', + 39 => 'getpid', + 40 => 'sendfile', + 41 => 'socket', + 42 => 'connect', + 43 => 'accept', + 44 => 'sendto', + 45 => 'recvfrom', + 46 => 'sendmsg', + 47 => 'recvmsg', + 48 => 'shutdown', + 49 => 'bind', + 50 => 'listen', + 51 => 'getsockname', + 52 => 'getpeername', + 53 => 'socketpair', + 54 => 'setsockopt', + 55 => 'getsockopt', + 56 => 'clone', + 57 => 'fork', + 58 => 'vfork', + 59 => 'execve', + 60 => 'exit', + 61 => 'wait4', + 62 => 'kill', + 63 => 'uname', + 64 => 'semget', + 65 => 'semop', + 66 => 'semctl', + 67 => 'shmdt', + 68 => 'msgget', + 69 => 'msgsnd', + 70 => 'msgrcv', + 71 => 'msgctl', + 72 => 'fcntl', + 73 => 'flock', + 74 => 'fsync', + 75 => 'fdatasync', + 76 => 'truncate', + 77 => 'ftruncate', + 78 => 'getdents', + 79 => 'getcwd', + 80 => 'chdir', + 81 => 'fchdir', + 82 => 'rename', + 83 => 'mkdir', + 84 => 'rmdir', + 85 => 'creat', + 86 => 'link', + 87 => 'unlink', + 88 => 'symlink', + 89 => 'readlink', + 90 => 'chmod', + 91 => 'fchmod', + 92 => 'chown', + 93 => 'fchown', + 94 => 'lchown', + 95 => 'umask', + 96 => 'gettimeofday', + 97 => 'getrlimit', + 98 => 'getrusage', + 99 => 'sysinfo', + 100 => 'times', + 101 => 'ptrace', + 102 => 'getuid', + 103 => 'syslog', + 104 => 'getgid', + 105 => 'setuid', + 106 => 'setgid', + 107 => 'geteuid', + 108 => 'getegid', + 109 => 'setpgid', + 110 => 'getppid', + 111 => 'getpgrp', + 112 => 'setsid', + 113 => 'setreuid', + 114 => 'setregid', + 115 => 'getgroups', + 116 => 'setgroups', + 117 => 'setresuid', + 118 => 'getresuid', + 119 => 'setresgid', + 120 => 'getresgid', + 121 => 'getpgid', + 122 => 'setfsuid', + 123 => 'setfsgid', + 124 => 'getsid', + 125 => 'capget', + 126 => 'capset', + 127 => 'rt_sigpending', + 128 => 'rt_sigtimedwait', + 129 => 'rt_sigqueueinfo', + 130 => 'rt_sigsuspend', + 131 => 'sigaltstack', + 132 => 'utime', + 133 => 'mknod', + 134 => 'uselib', + 135 => 'personality', + 136 => 'ustat', + 137 => 'statfs', + 138 => 'fstatfs', + 139 => 'sysfs', + 140 => 'getpriority', + 141 => 'setpriority', + 142 => 'sched_setparam', + 143 => 'sched_getparam', + 144 => 'sched_setscheduler', + 145 => 'sched_getscheduler', + 146 => 'sched_get_priority_max', + 147 => 'sched_get_priority_min', + 148 => 'sched_rr_get_interval', + 149 => 'mlock', + 150 => 'munlock', + 151 => 'mlockall', + 152 => 'munlockall', + 153 => 'vhangup', + 154 => 'modify_ldt', + 155 => 'pivot_root', + 156 => '_sysctl', + 157 => 'prctl', + 158 => 'arch_prctl', + 159 => 'adjtimex', + 160 => 'setrlimit', + 161 => 'chroot', + 162 => 'sync', + 163 => 'acct', + 164 => 'settimeofday', + 165 => 'mount', + 166 => 'umount2', + 167 => 'swapon', + 168 => 'swapoff', + 169 => 'reboot', + 170 => 'sethostname', + 171 => 'setdomainname', + 172 => 'iopl', + 173 => 'ioperm', + 174 => 'create_module', + 175 => 'init_module', + 176 => 'delete_module', + 177 => 'get_kernel_syms', + 178 => 'query_module', + 179 => 'quotactl', + 180 => 'nfsservctl', + 181 => 'getpmsg', + 182 => 'putpmsg', + 183 => 'afs_syscall', + 184 => 'tuxcall', + 185 => 'security', + 186 => 'gettid', + 187 => 'readahead', + 188 => 'setxattr', + 189 => 'lsetxattr', + 190 => 'fsetxattr', + 191 => 'getxattr', + 192 => 'lgetxattr', + 193 => 'fgetxattr', + 194 => 'listxattr', + 195 => 'llistxattr', + 196 => 'flistxattr', + 197 => 'removexattr', + 198 => 'lremovexattr', + 199 => 'fremovexattr', + 200 => 'tkill', + 201 => 'time', + 202 => 'futex', + 203 => 'sched_setaffinity', + 204 => 'sched_getaffinity', + 205 => 'set_thread_area', + 206 => 'io_setup', + 207 => 'io_destroy', + 208 => 'io_getevents', + 209 => 'io_submit', + 210 => 'io_cancel', + 211 => 'get_thread_area', + 212 => 'lookup_dcookie', + 213 => 'epoll_create', + 214 => 'epoll_ctl_old', + 215 => 'epoll_wait_old', + 216 => 'remap_file_pages', + 217 => 'getdents64', + 218 => 'set_tid_address', + 219 => 'restart_syscall', + 220 => 'semtimedop', + 221 => 'fadvise64', + 222 => 'timer_create', + 223 => 'timer_settime', + 224 => 'timer_gettime', + 225 => 'timer_getoverrun', + 226 => 'timer_delete', + 227 => 'clock_settime', + 228 => 'clock_gettime', + 229 => 'clock_getres', + 230 => 'clock_nanosleep', + 231 => 'exit_group', + 232 => 'epoll_wait', + 233 => 'epoll_ctl', + 234 => 'tgkill', + 235 => 'utimes', + 236 => 'vserver', + 237 => 'mbind', + 238 => 'set_mempolicy', + 239 => 'get_mempolicy', + 240 => 'mq_open', + 241 => 'mq_unlink', + 242 => 'mq_timedsend', + 243 => 'mq_timedreceive', + 244 => 'mq_notify', + 245 => 'mq_getsetattr', + 246 => 'kexec_load', + 247 => 'waitid', + 248 => 'add_key', + 249 => 'request_key', + 250 => 'keyctl', + 251 => 'ioprio_set', + 252 => 'ioprio_get', + 253 => 'inotify_init', + 254 => 'inotify_add_watch', + 255 => 'inotify_rm_watch', + 256 => 'migrate_pages', + 257 => 'openat', + 258 => 'mkdirat', + 259 => 'mknodat', + 260 => 'fchownat', + 261 => 'futimesat', + 262 => 'newfstatat', + 263 => 'unlinkat', + 264 => 'renameat', + 265 => 'linkat', + 266 => 'symlinkat', + 267 => 'readlinkat', + 268 => 'fchmodat', + 269 => 'faccessat', + 270 => 'pselect6', + 271 => 'ppoll', + 272 => 'unshare', + 273 => 'set_robust_list', + 274 => 'get_robust_list', + 275 => 'splice', + 276 => 'tee', + 277 => 'sync_file_range', + 278 => 'vmsplice', + 279 => 'move_pages', + 280 => 'utimensat', + 281 => 'epoll_pwait', + 282 => 'signalfd', + 283 => 'timerfd_create', + 284 => 'eventfd', + 285 => 'fallocate', + 286 => 'timerfd_settime', + 287 => 'timerfd_gettime', + 288 => 'accept4', + 289 => 'signalfd4', + 290 => 'eventfd2', + 291 => 'epoll_create1', + 292 => 'dup3', + 293 => 'pipe2', + 294 => 'inotify_init1', + 295 => 'preadv', + 296 => 'pwritev', + 297 => 'rt_tgsigqueueinfo', + 298 => 'perf_event_open', + 299 => 'recvmmsg', + 300 => 'fanotify_init', + 301 => 'fanotify_mark', + 302 => 'prlimit64', + 303 => 'name_to_handle_at', + 304 => 'open_by_handle_at', + 305 => 'clock_adjtime', + 306 => 'syncfs', + 307 => 'sendmmsg', + 308 => 'setns', + 309 => 'getcpu', + 310 => 'process_vm_readv', + 311 => 'process_vm_writev', + 312 => 'kcmp', + 313 => 'finit_module', + 314 => 'sched_setattr', + 315 => 'sched_getattr', + 316 => 'renameat2', + 317 => 'seccomp', + 318 => 'getrandom', + 319 => 'memfd_create', + 320 => 'kexec_file_load', + 321 => 'bpf', + 322 => 'execveat', + 323 => 'userfaultfd', + 324 => 'membarrier', + 325 => 'mlock2', + 326 => 'copy_file_range', + 327 => 'preadv2', + 328 => 'pwritev2', + 329 => 'pkey_mprotect', + 330 => 'pkey_alloc', + 331 => 'pkey_free', + 332 => 'statx', + 334 => 'rseq', + 424 => 'pidfd_send_signal', + 425 => 'io_uring_setup', + 426 => 'io_uring_enter', + 427 => 'io_uring_register', + 428 => 'open_tree', + 429 => 'move_mount', + 430 => 'fsopen', + 431 => 'fsconfig', + 432 => 'fsmount', + 433 => 'fspick', + 434 => 'pidfd_open', + 435 => 'clone3', + 436 => 'close_range', + 437 => 'openat2', + 438 => 'pidfd_getfd', + 439 => 'faccessat2', + 440 => 'process_madvise', + 441 => 'epoll_pwait2', + 442 => 'mount_setattr', + 443 => 'quotactl_fd', + 444 => 'landlock_create_ruleset', + 445 => 'landlock_add_rule', + 446 => 'landlock_restrict_self', + 447 => 'memfd_secret', + 448 => 'process_mrelease', + 449 => 'futex_waitv', + 450 => 'set_mempolicy_home_node' +}.map { |num, name| [num, "#{num} (#{name})"] }.to_h + +REGS_R64 = %w[ + rax + rbx + rcx + rdx + rsi + rdi + rsp + rbp + r8 + r9 + r10 + r11 + r12 + r13 + r14 + r15 +] + +REGS_R32 = %w[ + eax + ebx + ecx + edx + esi + edi + esp + ebp + r8d + r9d + r10d + r11d + r12d + r13d + r14d + r15d +] + +REGS_R16 = %w[ + ax + bx + cx + dx + si + di + sp + bp + r8w + r9w + r10w + r11w + r12w + r13w + r14w + r15w +] + +REGS_R8 = %w[ + al + bl + cl + dl + sil + dil + spl + bpl + r8b + r9b + r10b + r11b + r12b + r13b + r14b + r15b +] + +REG_MAP = (REGS_R64.map { |r| [r, r] } + REGS_R32.zip(REGS_R64) + REGS_R16.zip(REGS_R64) + REGS_R8.zip(REGS_R64)).to_h +REGS_R = (REGS_R64 + REGS_R32 + REGS_R16 + REGS_R8).join('|') + +if ARGV.empty? + warn SYNTAX_STRING + exit 1 +end + +file_path = ARGV[0] +raise "no such file: #{file_path}" unless File.exist? file_path + +only_used_syscalls = false +ARGV[1..].each do |arg| + if arg == '--only-used-syscalls' + only_used_syscalls = true + else + warn "invalid argument '#{arg}':\n#{SYNTAX_STRING}" + exit 1 + end +end + +puts 'Running objdump...' unless only_used_syscalls +dump = `objdump -wd -j .text -M intel #{file_path.shellescape}` +raise 'objdump failed' unless $?.exitstatus == 0 + +puts 'Parsing objdump output...' unless only_used_syscalls +current_fn = nil +code_for_fn = {} +fns_with_syscall = Set.new +fns_with_indirect_syscall = Set.new +dump.split("\n").each do |line| + if line =~ /\A[0-9a-f]+ <(.+?)>:/ + current_fn = Regexp.last_match(1) + next + end + + next unless current_fn + next if %w[syscall __syscall_cp_c].include?(current_fn) # These are for indirect syscalls. + + code = line.strip.split("\t")[2] + next if [nil, ''].include?(code) + + code_for_fn[current_fn] ||= [] + code_for_fn[current_fn] << code.gsub(/[\t ]+/, ' ') + + fns_with_syscall.add(current_fn) if code == 'syscall' + fns_with_indirect_syscall.add(current_fn) if code =~ /<(syscall|__syscall_cp)>/ +end + +unless only_used_syscalls + puts "Found #{fns_with_syscall.length} functions doing direct syscalls" + puts "Found #{fns_with_indirect_syscall.length} functions doing indirect syscalls" +end + +syscalls_for_fn = {} +not_found_count = 0 +(fns_with_syscall + fns_with_indirect_syscall).each do |fn_name| + syscalls_for_fn[fn_name] ||= [] + + if fn_name =~ /_ZN11parking_lot9raw_mutex8RawMutex9lock_slow.+/ + # Hardcode 'SYS_futex' as this function produces a really messy assembly. + syscalls_for_fn[fn_name] << 202 + next + end + + code = code_for_fn[fn_name] + + found = false + regs = {} + code.each do |inst| + if inst =~ /mov (#{REGS_R}),(.+)/ + reg = Regexp.last_match(1) + value = Regexp.last_match(2) + regs[REG_MAP[reg]] = if value =~ /#{REGS_R}/ + regs[REG_MAP[value]] + elsif value =~ /0x([0-9a-f]+)/ + Regexp.last_match(1).to_i(16) + end + elsif inst =~ /xor (#{REGS_R}),(#{REGS_R})/ + reg_1 = Regexp.last_match(1) + reg_2 = Regexp.last_match(1) + regs[REG_MAP[reg_1]] = 0 if reg_1 == reg_2 + elsif inst =~ /lea (#{REGS_R}),(.+)/ + reg = Regexp.last_match(1) + value = Regexp.last_match(2) + regs[REG_MAP[reg]] = ('syscall' if value.strip =~ /\[rip\+0x[a-z0-9]+\]\s*#\s*[0-9a-f]+\s*/) + elsif inst =~ /(call|jmp) (#{REGS_R})/ + reg = Regexp.last_match(2) + if regs[REG_MAP[reg]] == 'syscall' + if !regs['rdi'].nil? + syscalls_for_fn[fn_name] << regs['rdi'] + found = true + else + found = false + end + end + elsif inst =~ /(call|jmp) [0-9a-f]+ <(syscall|__syscall_cp)>/ + if !regs['rdi'].nil? + syscalls_for_fn[fn_name] << regs['rdi'] + found = true + else + found = false + end + elsif inst == 'syscall' + if !regs['rax'].nil? + syscalls_for_fn[fn_name] << regs['rax'] + found = true + else + found = false + end + end + end + + next if found + + puts "WARN: Function triggers a syscall but couldn't figure out which one: #{fn_name}" + puts ' ' + code.join("\n ") + puts + not_found_count += 1 +end + +puts "WARN: Failed to figure out syscall for #{not_found_count} function(s)" if not_found_count > 0 + +fns_for_syscall = {} +syscalls_for_fn.each do |fn_name, syscalls| + syscalls.each do |syscall| + fns_for_syscall[syscall] ||= [] + fns_for_syscall[syscall] << fn_name + end +end + +if only_used_syscalls + puts syscalls_for_fn.values.flatten.sort.uniq.map { |sc| SYSCALLS[sc] || sc }.join("\n") +else + puts 'Functions per syscall:' + fns_for_syscall.sort_by { |sc, _| sc }.each do |syscall, fn_names| + fn_names = fn_names.sort.uniq + + puts " #{SYSCALLS[syscall] || syscall} [#{fn_names.length} functions]" + fn_names.each do |fn_name| + puts " #{fn_name}" + end + end + + puts + puts 'Used syscalls:' + puts ' ' + syscalls_for_fn.values.flatten.sort.uniq.map { |sc| SYSCALLS[sc] || sc }.join("\n ") +end diff --git a/polkadot/scripts/list-syscalls/prepare-worker-syscalls b/polkadot/scripts/list-syscalls/prepare-worker-syscalls new file mode 100644 index 0000000000000000000000000000000000000000..f1597f20675652a130a7e23e9039b0ad153ee306 --- /dev/null +++ b/polkadot/scripts/list-syscalls/prepare-worker-syscalls @@ -0,0 +1,76 @@ +0 (read) +1 (write) +2 (open) +3 (close) +4 (stat) +5 (fstat) +7 (poll) +8 (lseek) +9 (mmap) +10 (mprotect) +11 (munmap) +12 (brk) +13 (rt_sigaction) +14 (rt_sigprocmask) +15 (rt_sigreturn) +16 (ioctl) +19 (readv) +20 (writev) +24 (sched_yield) +25 (mremap) +28 (madvise) +39 (getpid) +41 (socket) +42 (connect) +45 (recvfrom) +46 (sendmsg) +53 (socketpair) +56 (clone) +60 (exit) +61 (wait4) +62 (kill) +72 (fcntl) +79 (getcwd) +80 (chdir) +82 (rename) +83 (mkdir) +87 (unlink) +89 (readlink) +96 (gettimeofday) +97 (getrlimit) +98 (getrusage) +99 (sysinfo) +102 (getuid) +110 (getppid) +131 (sigaltstack) +140 (getpriority) +141 (setpriority) +144 (sched_setscheduler) +157 (prctl) +158 (arch_prctl) +165 (mount) +166 (umount2) +200 (tkill) +202 (futex) +203 (sched_setaffinity) +204 (sched_getaffinity) +213 (epoll_create) +217 (getdents64) +218 (set_tid_address) +228 (clock_gettime) +230 (clock_nanosleep) +231 (exit_group) +232 (epoll_wait) +233 (epoll_ctl) +257 (openat) +262 (newfstatat) +263 (unlinkat) +272 (unshare) +273 (set_robust_list) +281 (epoll_pwait) +284 (eventfd) +290 (eventfd2) +291 (epoll_create1) +302 (prlimit64) +309 (getcpu) +318 (getrandom) diff --git a/polkadot/scripts/run_all_benches.sh b/polkadot/scripts/run_all_benches.sh deleted file mode 100755 index 923013f351555c348cdd5c169f8d7382ac5f0a5b..0000000000000000000000000000000000000000 --- a/polkadot/scripts/run_all_benches.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# Runs all benchmarks for all pallets, for each of the runtimes specified below -# Should be run on a reference machine to gain accurate benchmarks -# current reference machine: https://github.com/paritytech/substrate/pull/5848 - -runtimes=( - polkadot - kusama - westend -) - -for runtime in "${runtimes[@]}"; do - "$(dirname "$0")/run_benches_for_runtime.sh" "$runtime" -done diff --git a/polkadot/scripts/update-rust-stable.sh b/polkadot/scripts/update-rust-stable.sh deleted file mode 100755 index 6aae75d8cb2daa2dee5a332d19c31cd8f4fe818f..0000000000000000000000000000000000000000 --- a/polkadot/scripts/update-rust-stable.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# -# Script for updating the UI tests for a new rust stable version. -# -# It needs to be called like this: -# -# update-rust-stable.sh 1.61 -# -# This will run all UI tests with the rust stable 1.61. The script -# requires that rustup is installed. -set -e - -if [ "$#" -ne 1 ]; then - echo "Please specify the rust version to use. E.g. update-rust-stable.sh 1.61" - exit -fi - -RUST_VERSION=$1 - -if ! command -v rustup &> /dev/null -then - echo "rustup needs to be installed" - exit -fi - -rustup install $RUST_VERSION -rustup component add rust-src --toolchain $RUST_VERSION - -# Ensure we run the ui tests -export RUN_UI_TESTS=1 -# We don't need any wasm files for ui tests -export SKIP_WASM_BUILD=1 -# Let trybuild overwrite the .stderr files -export TRYBUILD=overwrite - -# Run all the relevant UI tests -# -# Any new UI tests in different crates need to be added here as well. -rustup run $RUST_VERSION cargo test -p orchestra ui diff --git a/polkadot/tests/benchmark_block.rs b/polkadot/tests/benchmark_block.rs index bc91b31bc7b64430b757b9f87f39a0eb34b7238f..99f95ef611a48266105ba6b413641867fab21101 100644 --- a/polkadot/tests/benchmark_block.rs +++ b/polkadot/tests/benchmark_block.rs @@ -18,6 +18,7 @@ #![cfg(unix)] use assert_cmd::cargo::cargo_bin; +use common::run_with_timeout; use nix::{ sys::signal::{kill, Signal::SIGINT}, unistd::Pid, @@ -32,25 +33,28 @@ use tempfile::tempdir; pub mod common; -static RUNTIMES: [&str; 4] = ["polkadot", "kusama", "westend", "rococo"]; +static RUNTIMES: &[&str] = &["westend", "rococo"]; /// `benchmark block` works for all dev runtimes using the wasm executor. #[tokio::test] async fn benchmark_block_works() { for runtime in RUNTIMES { - let tmp_dir = tempdir().expect("could not create a temp dir"); - let base_path = tmp_dir.path(); - let runtime = format!("{}-dev", runtime); - - // Build a chain with a single block. - build_chain(&runtime, base_path).await.unwrap(); - // Benchmark the one block. - benchmark_block(&runtime, base_path, 1).unwrap(); + run_with_timeout(Duration::from_secs(10 * 60), async move { + let tmp_dir = tempdir().expect("could not create a temp dir"); + let base_path = tmp_dir.path(); + let runtime = format!("{}-dev", runtime); + + // Build a chain with a single block. + build_chain(&runtime, base_path).await; + // Benchmark the one block. + benchmark_block(&runtime, base_path, 1).unwrap(); + }) + .await } } /// Builds a chain with one block for the given runtime and base path. -async fn build_chain(runtime: &str, base_path: &Path) -> Result<(), String> { +async fn build_chain(runtime: &str, base_path: &Path) { let mut cmd = Command::new(cargo_bin("polkadot")) .stdout(process::Stdio::piped()) .stderr(process::Stdio::piped()) @@ -64,13 +68,10 @@ async fn build_chain(runtime: &str, base_path: &Path) -> Result<(), String> { let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); // Wait for the chain to produce one block. - let ok = common::wait_n_finalized_blocks(1, Duration::from_secs(60), &ws_url).await; + common::wait_n_finalized_blocks(1, &ws_url).await; // Send SIGINT to node. kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); - // Wait for the node to handle it and exit. - assert!(common::wait_for(&mut cmd, 30).map(|x| x.success()).unwrap_or_default()); - - ok.map_err(|e| format!("Node did not build the chain: {:?}", e)) + assert!(cmd.wait().unwrap().success()); } /// Benchmarks the given block with the wasm executor. diff --git a/polkadot/tests/benchmark_extrinsic.rs b/polkadot/tests/benchmark_extrinsic.rs index e701fd9c923c2eb736ed34493a865afcca6d6145..529eb29362d4dda4fba34592ce5ff9066ca61796 100644 --- a/polkadot/tests/benchmark_extrinsic.rs +++ b/polkadot/tests/benchmark_extrinsic.rs @@ -17,7 +17,7 @@ use assert_cmd::cargo::cargo_bin; use std::{process::Command, result::Result}; -static RUNTIMES: [&str; 4] = ["polkadot", "kusama", "westend", "rococo"]; +static RUNTIMES: &[&str] = &["westend", "rococo"]; static EXTRINSICS: [(&str, &str); 2] = [("system", "remark"), ("balances", "transfer_keep_alive")]; diff --git a/polkadot/tests/benchmark_overhead.rs b/polkadot/tests/benchmark_overhead.rs index 295479594eb9ba56a5d64e2df34a014bdd8ecd9f..b0912225347df5f4dd563f7dd0ff8075e76923c9 100644 --- a/polkadot/tests/benchmark_overhead.rs +++ b/polkadot/tests/benchmark_overhead.rs @@ -18,26 +18,26 @@ use assert_cmd::cargo::cargo_bin; use std::{process::Command, result::Result}; use tempfile::tempdir; -static RUNTIMES: [&str; 4] = ["polkadot", "kusama", "westend", "rococo"]; +static RUNTIMES: &[&str] = &["westend", "rococo"]; /// `benchmark overhead` works for all dev runtimes. #[test] fn benchmark_overhead_works() { for runtime in RUNTIMES { let runtime = format!("{}-dev", runtime); - assert!(benchmark_overhead(runtime).is_ok()); + assert!(benchmark_overhead(&runtime).is_ok()); } } /// `benchmark overhead` rejects all non-dev runtimes. #[test] fn benchmark_overhead_rejects_non_dev_runtimes() { - for runtime in RUNTIMES { - assert!(benchmark_overhead(runtime.into()).is_err()); + for runtime in RUNTIMES.into_iter() { + assert!(benchmark_overhead(runtime).is_err()); } } -fn benchmark_overhead(runtime: String) -> Result<(), String> { +fn benchmark_overhead(runtime: &str) -> Result<(), String> { let tmp_dir = tempdir().expect("could not create a temp dir"); let base_path = tmp_dir.path(); diff --git a/polkadot/tests/common.rs b/polkadot/tests/common.rs index 940a0c6f18d0fe47575df6177fcc4f84fa7f3071..15721c990e01b30b97db32151b0899c1e5a3888b 100644 --- a/polkadot/tests/common.rs +++ b/polkadot/tests/common.rs @@ -16,50 +16,24 @@ use polkadot_core_primitives::{Block, Hash, Header}; use std::{ + future::Future, io::{BufRead, BufReader, Read}, - process::{Child, ExitStatus}, - thread, time::Duration, }; use substrate_rpc_client::{ws_client, ChainApi}; -use tokio::time::timeout; -/// Wait for the given `child` the given amount of `secs`. -/// -/// Returns the `Some(exit status)` or `None` if the process did not finish in the given time. -pub fn wait_for(child: &mut Child, secs: usize) -> Option { - for _ in 0..secs { - match child.try_wait().unwrap() { - Some(status) => return Some(status), - None => thread::sleep(Duration::from_secs(1)), - } - } - eprintln!("Took to long to exit. Killing..."); - let _ = child.kill(); - child.wait().unwrap(); - - None -} - -/// Wait for at least `n` blocks to be finalized within the specified time. -pub async fn wait_n_finalized_blocks( - n: usize, - timeout_duration: Duration, - url: &str, -) -> Result<(), tokio::time::error::Elapsed> { - timeout(timeout_duration, wait_n_finalized_blocks_from(n, url)).await +/// Run the given `future` and panic if the `timeout` is hit. +pub async fn run_with_timeout(timeout: Duration, future: impl Future) { + tokio::time::timeout(timeout, future).await.expect("Hit timeout"); } /// Wait for at least `n` blocks to be finalized from a specified node. -async fn wait_n_finalized_blocks_from(n: usize, url: &str) { +pub async fn wait_n_finalized_blocks(n: usize, url: &str) { let mut built_blocks = std::collections::HashSet::new(); let mut interval = tokio::time::interval(Duration::from_secs(6)); loop { - let rpc = match ws_client(url).await { - Ok(rpc_service) => rpc_service, - Err(_) => continue, - }; + let Ok(rpc) = ws_client(url).await else { continue }; if let Ok(block) = ChainApi::<(), Hash, Header, Block>::finalized_head(&rpc).await { built_blocks.insert(block); @@ -67,6 +41,7 @@ async fn wait_n_finalized_blocks_from(n: usize, url: &str) { break } }; + interval.tick().await; } } diff --git a/polkadot/tests/purge_chain_works.rs b/polkadot/tests/purge_chain_works.rs index 3e9a378147810e5d2edf377fa7c5ed93ecf16952..f5a73e232e0cb22ee18c7a6100e21f44d208d78f 100644 --- a/polkadot/tests/purge_chain_works.rs +++ b/polkadot/tests/purge_chain_works.rs @@ -14,7 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +#![cfg(unix)] + use assert_cmd::cargo::cargo_bin; +use common::run_with_timeout; +use nix::{ + sys::signal::{kill, Signal::SIGINT}, + unistd::Pid, +}; use std::{ process::{self, Command}, time::Duration, @@ -24,105 +31,91 @@ use tempfile::tempdir; pub mod common; #[tokio::test] -#[cfg(unix)] async fn purge_chain_rocksdb_works() { - use nix::{ - sys::signal::{kill, Signal::SIGINT}, - unistd::Pid, - }; - - let tmpdir = tempdir().expect("could not create temp dir"); - - let mut cmd = Command::new(cargo_bin("polkadot")) - .stdout(process::Stdio::piped()) - .stderr(process::Stdio::piped()) - .args(["--dev", "-d"]) - .arg(tmpdir.path()) - .arg("--port") - .arg("33034") - .arg("--no-hardware-benchmarks") - .spawn() - .unwrap(); - - let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); - - // Let it produce 1 block. - common::wait_n_finalized_blocks(1, Duration::from_secs(60), &ws_url) - .await - .unwrap(); - - // Send SIGINT to node. - kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); - // Wait for the node to handle it and exit. - assert!(common::wait_for(&mut cmd, 30).map(|x| x.success()).unwrap_or_default()); - assert!(tmpdir.path().join("chains/polkadot_dev").exists()); - assert!(tmpdir.path().join("chains/polkadot_dev/db/full").exists()); - assert!(tmpdir.path().join("chains/polkadot_dev/db/full/parachains").exists()); - - // Purge chain - let status = Command::new(cargo_bin("polkadot")) - .args(["purge-chain", "--dev", "-d"]) - .arg(tmpdir.path()) - .arg("-y") - .status() - .unwrap(); - assert!(status.success()); - - // Make sure that the chain folder exists, but `db/full` is deleted. - assert!(tmpdir.path().join("chains/polkadot_dev").exists()); - assert!(!tmpdir.path().join("chains/polkadot_dev/db/full").exists()); + run_with_timeout(Duration::from_secs(10 * 60), async move { + let tmpdir = tempdir().expect("could not create temp dir"); + + let mut cmd = Command::new(cargo_bin("polkadot")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .args(["--dev", "-d"]) + .arg(tmpdir.path()) + .arg("--port") + .arg("33034") + .arg("--no-hardware-benchmarks") + .spawn() + .unwrap(); + + let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); + + // Let it produce 1 block. + common::wait_n_finalized_blocks(1, &ws_url).await; + + // Send SIGINT to node. + kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); + // Wait for the node to handle it and exit. + assert!(cmd.wait().unwrap().success()); + assert!(tmpdir.path().join("chains/rococo_dev").exists()); + assert!(tmpdir.path().join("chains/rococo_dev/db/full").exists()); + + // Purge chain + let status = Command::new(cargo_bin("polkadot")) + .args(["purge-chain", "--dev", "-d"]) + .arg(tmpdir.path()) + .arg("-y") + .status() + .unwrap(); + assert!(status.success()); + + // Make sure that the chain folder exists, but `db/full` is deleted. + assert!(tmpdir.path().join("chains/rococo_dev").exists()); + assert!(!tmpdir.path().join("chains/rococo_dev/db/full").exists()); + }) + .await; } #[tokio::test] -#[cfg(unix)] async fn purge_chain_paritydb_works() { - use nix::{ - sys::signal::{kill, Signal::SIGINT}, - unistd::Pid, - }; - - let tmpdir = tempdir().expect("could not create temp dir"); - - let mut cmd = Command::new(cargo_bin("polkadot")) - .stdout(process::Stdio::piped()) - .stderr(process::Stdio::piped()) - .args(["--dev", "-d"]) - .arg(tmpdir.path()) - .arg("--database") - .arg("paritydb-experimental") - .arg("--no-hardware-benchmarks") - .spawn() - .unwrap(); - - let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); - - // Let it produce 1 block. - common::wait_n_finalized_blocks(1, Duration::from_secs(60), &ws_url) - .await - .unwrap(); - - // Send SIGINT to node. - kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); - // Wait for the node to handle it and exit. - assert!(common::wait_for(&mut cmd, 30).map(|x| x.success()).unwrap_or_default()); - assert!(tmpdir.path().join("chains/polkadot_dev").exists()); - assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/full").exists()); - assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/parachains").exists()); - - // Purge chain - let status = Command::new(cargo_bin("polkadot")) - .args(["purge-chain", "--dev", "-d"]) - .arg(tmpdir.path()) - .arg("--database") - .arg("paritydb-experimental") - .arg("-y") - .status() - .unwrap(); - assert!(status.success()); - - // Make sure that the chain folder exists, but `db/full` is deleted. - assert!(tmpdir.path().join("chains/polkadot_dev").exists()); - assert!(!tmpdir.path().join("chains/polkadot_dev/paritydb/full").exists()); - // Parachains removal requires calling "purge-chain --parachains". - assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/parachains").exists()); + run_with_timeout(Duration::from_secs(10 * 60), async move { + let tmpdir = tempdir().expect("could not create temp dir"); + + let mut cmd = Command::new(cargo_bin("polkadot")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .args(["--dev", "-d"]) + .arg(tmpdir.path()) + .arg("--database") + .arg("paritydb-experimental") + .arg("--no-hardware-benchmarks") + .spawn() + .unwrap(); + + let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); + + // Let it produce 1 block. + common::wait_n_finalized_blocks(1, &ws_url).await; + + // Send SIGINT to node. + kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap(); + // Wait for the node to handle it and exit. + assert!(cmd.wait().unwrap().success()); + assert!(tmpdir.path().join("chains/rococo_dev").exists()); + assert!(tmpdir.path().join("chains/rococo_dev/paritydb/full").exists()); + + // Purge chain + let status = Command::new(cargo_bin("polkadot")) + .args(["purge-chain", "--dev", "-d"]) + .arg(tmpdir.path()) + .arg("--database") + .arg("paritydb-experimental") + .arg("-y") + .status() + .unwrap(); + assert!(status.success()); + + // Make sure that the chain folder exists, but `db/full` is deleted. + assert!(tmpdir.path().join("chains/rococo_dev").exists()); + assert!(!tmpdir.path().join("chains/rococo_dev/paritydb/full").exists()); + }) + .await; } diff --git a/polkadot/tests/running_the_node_and_interrupt.rs b/polkadot/tests/running_the_node_and_interrupt.rs index d3935cbb02ad176e56e1a248b9410f71b714ec95..079c34e0421e8a1936359b03bc46f3fea87f4b8b 100644 --- a/polkadot/tests/running_the_node_and_interrupt.rs +++ b/polkadot/tests/running_the_node_and_interrupt.rs @@ -15,10 +15,7 @@ // along with Substrate. If not, see . use assert_cmd::cargo::cargo_bin; -use std::{ - process::{self, Command}, - time::Duration, -}; +use std::process::{self, Command}; use tempfile::tempdir; pub mod common; @@ -49,17 +46,13 @@ async fn running_the_node_works_and_can_be_interrupted() { let (ws_url, _) = common::find_ws_url_from_output(cmd.stderr.take().unwrap()); // Let it produce three blocks. - common::wait_n_finalized_blocks(3, Duration::from_secs(60), &ws_url) - .await - .unwrap(); + common::wait_n_finalized_blocks(3, &ws_url).await; assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); kill(Pid::from_raw(cmd.id().try_into().unwrap()), signal).unwrap(); - assert_eq!( - common::wait_for(&mut cmd, 30).map(|x| x.success()), - Some(true), - "the process must exit gracefully after signal {}", - signal, + assert!( + cmd.wait().unwrap().success(), + "the process must exit gracefully after signal {signal}", ); } diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 99948cb68b18bc4a44487f8eb2e4175e030bc0ff..95ca57ea728e16837843207e04d97f6b472979be 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,11 +6,9 @@ edition.workspace = true license.workspace = true [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } westend-runtime = { path = "../../runtime/westend" } -kusama-runtime = { package = "staging-kusama-runtime", path = "../../runtime/kusama" } -polkadot-runtime = { path = "../../runtime/polkadot" } diff --git a/polkadot/utils/generate-bags/src/main.rs b/polkadot/utils/generate-bags/src/main.rs index 6d0b0e19e899691f8ea0d6d41fbcba59303631a5..511980518c05807ba904cae053a0c24d5de41eff 100644 --- a/polkadot/utils/generate-bags/src/main.rs +++ b/polkadot/utils/generate-bags/src/main.rs @@ -22,8 +22,6 @@ use clap::{Parser, ValueEnum}; use generate_bags::generate_thresholds; -use kusama_runtime::Runtime as KusamaRuntime; -use polkadot_runtime::Runtime as PolkadotRuntime; use std::path::{Path, PathBuf}; use westend_runtime::Runtime as WestendRuntime; @@ -31,8 +29,6 @@ use westend_runtime::Runtime as WestendRuntime; #[value(rename_all = "PascalCase")] enum Runtime { Westend, - Kusama, - Polkadot, } impl Runtime { @@ -41,8 +37,6 @@ impl Runtime { ) -> Box Result<(), std::io::Error>> { match self { Runtime::Westend => Box::new(generate_thresholds::), - Runtime::Kusama => Box::new(generate_thresholds::), - Runtime::Polkadot => Box::new(generate_thresholds::), } } } @@ -54,7 +48,7 @@ struct Opt { n_bags: usize, /// Which runtime to generate. - #[arg(long, ignore_case = true, value_enum, default_value_t = Runtime::Polkadot)] + #[arg(long, ignore_case = true, value_enum, default_value_t = Runtime::Westend)] runtime: Runtime, /// Where to write the output. diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index ed49f77bb81aee23b62c325ec57692f3c3c8b5dc..e305edc039b5ab68c91bf587f322678c91e02cc1 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -7,11 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] -polkadot-runtime = { path = "../../../runtime/polkadot" } -kusama-runtime = { package = "staging-kusama-runtime", path = "../../../runtime/kusama" } westend-runtime = { path = "../../../runtime/westend" } -polkadot-runtime-constants = { path = "../../../runtime/polkadot/constants" } -kusama-runtime-constants = { path = "../../../runtime/kusama/constants" } westend-runtime-constants = { path = "../../../runtime/westend/constants" } pallet-bags-list-remote-tests = { path = "../../../../substrate/frame/bags-list/remote-tests" } @@ -19,6 +15,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/utils/remote-ext-tests/bags-list/src/main.rs b/polkadot/utils/remote-ext-tests/bags-list/src/main.rs index 6fb66ab2160147e8373ef1d115bda10f0249cfa6..1b7b6c5b694eeb109c18027c555dfa448eacb7bc 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/src/main.rs +++ b/polkadot/utils/remote-ext-tests/bags-list/src/main.rs @@ -29,16 +29,14 @@ enum Command { #[derive(Clone, Debug, ValueEnum)] #[value(rename_all = "PascalCase")] enum Runtime { - Polkadot, - Kusama, Westend, } #[derive(Parser)] struct Cli { - #[arg(long, short, default_value = "wss://kusama-rpc.polkadot.io:443")] + #[arg(long, short, default_value = "wss://westend-rpc.polkadot.io:443")] uri: String, - #[arg(long, short, ignore_case = true, value_enum, default_value_t = Runtime::Kusama)] + #[arg(long, short, ignore_case = true, value_enum, default_value_t = Runtime::Westend)] runtime: Runtime, #[arg(long, short, ignore_case = true, value_enum, default_value_t = Command::SanityCheck)] command: Command, @@ -60,16 +58,6 @@ async fn main() { use pallet_bags_list_remote_tests::*; match options.runtime { - Runtime::Polkadot => sp_core::crypto::set_default_ss58_version( - ::SS58Prefix::get() - .try_into() - .unwrap(), - ), - Runtime::Kusama => sp_core::crypto::set_default_ss58_version( - ::SS58Prefix::get() - .try_into() - .unwrap(), - ), Runtime::Westend => sp_core::crypto::set_default_ss58_version( ::SS58Prefix::get() .try_into() @@ -78,27 +66,6 @@ async fn main() { }; match (options.runtime, options.command) { - (Runtime::Kusama, Command::CheckMigration) => { - use kusama_runtime::{Block, Runtime}; - use kusama_runtime_constants::currency::UNITS; - migration::execute::(UNITS as u64, "KSM", options.uri.clone()).await; - }, - (Runtime::Kusama, Command::SanityCheck) => { - use kusama_runtime::{Block, Runtime}; - use kusama_runtime_constants::currency::UNITS; - try_state::execute::(UNITS as u64, "KSM", options.uri.clone()).await; - }, - (Runtime::Kusama, Command::Snapshot) => { - use kusama_runtime::{Block, Runtime}; - use kusama_runtime_constants::currency::UNITS; - snapshot::execute::( - options.snapshot_limit, - UNITS.try_into().unwrap(), - options.uri.clone(), - ) - .await; - }, - (Runtime::Westend, Command::CheckMigration) => { use westend_runtime::{Block, Runtime}; use westend_runtime_constants::currency::UNITS; @@ -119,26 +86,5 @@ async fn main() { ) .await; }, - - (Runtime::Polkadot, Command::CheckMigration) => { - use polkadot_runtime::{Block, Runtime}; - use polkadot_runtime_constants::currency::UNITS; - migration::execute::(UNITS as u64, "DOT", options.uri.clone()).await; - }, - (Runtime::Polkadot, Command::SanityCheck) => { - use polkadot_runtime::{Block, Runtime}; - use polkadot_runtime_constants::currency::UNITS; - try_state::execute::(UNITS as u64, "DOT", options.uri.clone()).await; - }, - (Runtime::Polkadot, Command::Snapshot) => { - use polkadot_runtime::{Block, Runtime}; - use polkadot_runtime_constants::currency::UNITS; - snapshot::execute::( - options.snapshot_limit, - UNITS.try_into().unwrap(), - options.uri.clone(), - ) - .await; - }, } } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 504b795403991dc3229f005027baa8fc97790617..760fa33b693e50d565445853a07cd0a317ac6487 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -20,6 +20,7 @@ use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError, BenchmarkRe use frame_support::{ pallet_prelude::Get, traits::fungible::{Inspect, Mutate}, + weights::Weight, }; use sp_runtime::traits::{Bounded, Zero}; use sp_std::{prelude::*, vec}; @@ -134,7 +135,7 @@ benchmarks_instance_pallet! { reserve_asset_deposited { let (trusted_reserve, transferable_reserve_asset) = T::TrustedReserve::get() .ok_or(BenchmarkError::Override( - BenchmarkResult::from_weight(T::BlockWeights::get().max_block) + BenchmarkResult::from_weight(Weight::MAX) ))?; let assets: MultiAssets = vec![ transferable_reserve_asset ].into(); @@ -187,7 +188,7 @@ benchmarks_instance_pallet! { }: { executor.bench_process(xcm).map_err(|_| { BenchmarkError::Override( - BenchmarkResult::from_weight(T::BlockWeights::get().max_block) + BenchmarkResult::from_weight(Weight::MAX) ) })?; } verify { diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 9dfb63c2c9c6411f2d198cbdfc42c1d292b23c0a..321bb294b88d89187924a88a98302c33dd860fb9 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -203,10 +203,10 @@ pub mod pallet { >; /// Our XCM filter which messages to be executed using `XcmExecutor` must pass. - type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; + type XcmExecuteFilter: Contains<(MultiLocation, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall>; + type XcmExecutor: ExecuteXcm<::RuntimeCall>; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; @@ -216,7 +216,7 @@ pub mod pallet { type XcmReserveTransferFilter: Contains<(MultiLocation, Vec)>; /// Means of measuring the weight consumed by an XCM message locally. - type Weigher: WeightBounds<::RuntimeCall>; + type Weigher: WeightBounds<::RuntimeCall>; /// This chain's Universal Location. type UniversalLocation: Get; @@ -227,7 +227,6 @@ pub mod pallet { /// The runtime `Call` type. type RuntimeCall: Parameter + GetDispatchInfo - + IsType<::RuntimeCall> + Dispatchable< RuntimeOrigin = ::RuntimeOrigin, PostInfo = PostDispatchInfo, @@ -787,6 +786,8 @@ pub mod pallet { /// Teleport some assets from the local chain to some destination chain. /// + /// **This function is deprecated: Use `limited_teleport_assets` instead.** + /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited, /// with all fees taken as needed from the asset. @@ -830,12 +831,14 @@ pub mod pallet { assets: Box, fee_asset_item: u32, ) -> DispatchResult { - Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item, None) + Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item, Unlimited) } /// Transfer some assets from the local chain to the sovereign account of a destination /// chain and forward a notification XCM. /// + /// **This function is deprecated: Use `limited_reserve_transfer_assets` instead.** + /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited, /// with all fees taken as needed from the asset. @@ -879,7 +882,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - None, + Unlimited, ) } @@ -898,7 +901,7 @@ pub mod pallet { #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( origin: OriginFor, - message: Box::RuntimeCall>>, + message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; @@ -1055,7 +1058,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - Some(weight_limit), + weight_limit, ) } @@ -1109,7 +1112,7 @@ pub mod pallet { beneficiary, assets, fee_asset_item, - Some(weight_limit), + weight_limit, ) } @@ -1197,7 +1200,7 @@ impl Pallet { beneficiary: Box, assets: Box, fee_asset_item: u32, - maybe_weight_limit: Option, + weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; @@ -1218,22 +1221,6 @@ impl Pallet { .map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; let assets: MultiAssets = assets.into(); - let weight_limit = match maybe_weight_limit { - Some(weight_limit) => weight_limit, - None => { - let fees = fees.clone(); - let mut remote_message = Xcm(vec![ - ReserveAssetDeposited(assets.clone()), - ClearOrigin, - BuyExecution { fees, weight_limit: Limited(Weight::zero()) }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ]); - // use local weight for remote message and hope for the best. - let remote_weight = T::Weigher::weight(&mut remote_message) - .map_err(|()| Error::::UnweighableMessage)?; - Limited(remote_weight) - }, - }; let xcm = Xcm(vec![ BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, @@ -1257,7 +1244,7 @@ impl Pallet { beneficiary: Box, assets: Box, fee_asset_item: u32, - maybe_weight_limit: Option, + weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; @@ -1278,22 +1265,6 @@ impl Pallet { .map_err(|_| Error::::CannotReanchor)?; let max_assets = assets.len() as u32; let assets: MultiAssets = assets.into(); - let weight_limit = match maybe_weight_limit { - Some(weight_limit) => weight_limit, - None => { - let fees = fees.clone(); - let mut remote_message = Xcm(vec![ - ReceiveTeleportedAsset(assets.clone()), - ClearOrigin, - BuyExecution { fees, weight_limit: Limited(Weight::zero()) }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, - ]); - // use local weight for remote message and hope for the best. - let remote_weight = T::Weigher::weight(&mut remote_message) - .map_err(|()| Error::::UnweighableMessage)?; - Limited(remote_weight) - }, - }; let xcm = Xcm(vec![ BuyExecution { fees, weight_limit }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, diff --git a/polkadot/xcm/pallet-xcm/src/tests.rs b/polkadot/xcm/pallet-xcm/src/tests.rs index 486887598c7829a5740ab951e8574f9feacb8c44..5d8aee8d665f4d2a98af0aeef3622219d3a87634 100644 --- a/polkadot/xcm/pallet-xcm/src/tests.rs +++ b/polkadot/xcm/pallet-xcm/src/tests.rs @@ -375,7 +375,7 @@ fn teleport_assets_works() { Xcm(vec![ ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), ClearOrigin, - buy_limited_execution((Here, SEND_AMOUNT), Weight::from_parts(4000, 4000)), + buy_execution((Here, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), )] @@ -508,7 +508,7 @@ fn reserve_transfer_assets_works() { Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, - buy_limited_execution((Parent, SEND_AMOUNT), Weight::from_parts(4000, 4000)), + buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]), )] diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 6beaa1d667f06fd76ef7f5ef36498fd6b367df47..56df0d94f586002cdc0e5aee58a5a9dfc7470599 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -11,5 +11,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = "1.0.28" -syn = "2.0.36" +syn = "2.0.38" Inflector = "0.11.4" diff --git a/polkadot/xcm/xcm-builder/src/asset_conversion.rs b/polkadot/xcm/xcm-builder/src/asset_conversion.rs index a246436a9d6d3ece32175f80b4c97ccc37c65530..5b76ed764a8128c80afcf7369e96628553a2b570 100644 --- a/polkadot/xcm/xcm-builder/src/asset_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/asset_conversion.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. +//! Adapters to work with [`frame_support::traits::fungibles`] through XCM. use frame_support::traits::{Contains, Get}; use sp_runtime::traits::MaybeEquivalence; diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 0d04e0971bf7bbd4be0f32b088d5a518f4d58030..3b13cab2c1ea84ba2422809daa4a0a6d807eb50e 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -52,7 +52,7 @@ impl ShouldExecute for TakeWeightCredit { } } -const MAX_ASSETS_FOR_BUY_EXECUTION: usize = 1; +const MAX_ASSETS_FOR_BUY_EXECUTION: usize = 2; /// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking /// payments into account. diff --git a/polkadot/xcm/xcm-builder/src/filter_asset_location.rs b/polkadot/xcm/xcm-builder/src/filter_asset_location.rs index 68dd86d9bfeb371e4a4baca92a0e20b31d32f3fc..df81f536f7b7133fb6dcbaa311e40e29860deb65 100644 --- a/polkadot/xcm/xcm-builder/src/filter_asset_location.rs +++ b/polkadot/xcm/xcm-builder/src/filter_asset_location.rs @@ -14,11 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Various implementations of `ContainsPair`. +//! Various implementations of `ContainsPair` or +//! `Contains<(MultiLocation, Vec)>`. -use frame_support::traits::{ContainsPair, Get}; -use sp_std::marker::PhantomData; -use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; +use frame_support::traits::{Contains, ContainsPair, Get}; +use sp_std::{marker::PhantomData, vec::Vec}; +use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation, WildMultiAsset}; /// Accepts an asset iff it is a native asset. pub struct NativeAsset; @@ -40,3 +41,171 @@ impl> ContainsPair( + sp_std::marker::PhantomData<(Location, AssetFilters)>, +); +impl, AssetFilters: Get>> + Contains<(MultiLocation, Vec)> for LocationWithAssetFilters +{ + fn contains((location, assets): &(MultiLocation, Vec)) -> bool { + log::trace!(target: "xcm::contains", "LocationWithAssetFilters location: {:?}, assets: {:?}", location, assets); + + // `location` must match the `Location` filter. + if !Location::contains(location) { + return false + } + + // All `assets` must match at least one of the `AssetFilters`. + let filters = AssetFilters::get(); + assets.iter().all(|asset| { + for filter in &filters { + if filter.matches(asset) { + return true + } + } + false + }) + } +} + +/// Implementation of `Get>` which accepts every asset. +/// (For example, it can be used with `LocationWithAssetFilters`). +pub struct AllAssets; +impl Get> for AllAssets { + fn get() -> Vec { + sp_std::vec![MultiAssetFilter::Wild(WildMultiAsset::All)] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::traits::Equals; + use xcm::latest::prelude::*; + + #[test] + fn location_with_asset_filters_works() { + frame_support::parameter_types! { + pub ParaA: MultiLocation = MultiLocation::new(1, X1(Parachain(1001))); + pub ParaB: MultiLocation = MultiLocation::new(1, X1(Parachain(1002))); + pub ParaC: MultiLocation = MultiLocation::new(1, X1(Parachain(1003))); + + pub AssetXLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(1111))); + pub AssetYLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(2222))); + pub AssetZLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(3333))); + + pub OnlyAssetXOrAssetY: sp_std::vec::Vec = sp_std::vec![ + Wild(AllOf { fun: WildFungible, id: Concrete(AssetXLocation::get()) }), + Wild(AllOf { fun: WildFungible, id: Concrete(AssetYLocation::get()) }), + ]; + pub OnlyAssetZ: sp_std::vec::Vec = sp_std::vec![ + Wild(AllOf { fun: WildFungible, id: Concrete(AssetZLocation::get()) }) + ]; + } + + let test_data: Vec<(MultiLocation, Vec, bool)> = vec![ + (ParaA::get(), vec![(AssetXLocation::get(), 1).into()], true), + (ParaA::get(), vec![(AssetYLocation::get(), 1).into()], true), + (ParaA::get(), vec![(AssetZLocation::get(), 1).into()], false), + ( + ParaA::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()], + true, + ), + ( + ParaA::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + false, + ), + ( + ParaA::get(), + vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + false, + ), + ( + ParaA::get(), + vec![ + (AssetXLocation::get(), 1).into(), + (AssetYLocation::get(), 1).into(), + (AssetZLocation::get(), 1).into(), + ], + false, + ), + (ParaB::get(), vec![(AssetXLocation::get(), 1).into()], false), + (ParaB::get(), vec![(AssetYLocation::get(), 1).into()], false), + (ParaB::get(), vec![(AssetZLocation::get(), 1).into()], true), + ( + ParaB::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()], + false, + ), + ( + ParaB::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + false, + ), + ( + ParaB::get(), + vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + false, + ), + ( + ParaB::get(), + vec![ + (AssetXLocation::get(), 1).into(), + (AssetYLocation::get(), 1).into(), + (AssetZLocation::get(), 1).into(), + ], + false, + ), + (ParaC::get(), vec![(AssetXLocation::get(), 1).into()], true), + (ParaC::get(), vec![(AssetYLocation::get(), 1).into()], true), + (ParaC::get(), vec![(AssetZLocation::get(), 1).into()], true), + ( + ParaC::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()], + true, + ), + ( + ParaC::get(), + vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + true, + ), + ( + ParaC::get(), + vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()], + true, + ), + ( + ParaC::get(), + vec![ + (AssetXLocation::get(), 1).into(), + (AssetYLocation::get(), 1).into(), + (AssetZLocation::get(), 1).into(), + ], + true, + ), + ]; + + type Filter = ( + // For ParaA accept only asset X and Y. + LocationWithAssetFilters, OnlyAssetXOrAssetY>, + // For ParaB accept only asset Z. + LocationWithAssetFilters, OnlyAssetZ>, + // For ParaC accept all assets. + LocationWithAssetFilters, AllAssets>, + ); + + for (location, assets, expected_result) in test_data { + assert_eq!( + Filter::contains(&(location, assets.clone())), + expected_result, + "expected_result: {expected_result} not matched for (location, assets): ({:?}, {:?})!", location, assets, + ) + } + } +} diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index d7fded01e2db7a0114bada2bdce5a06249907efc..2179421b3ebc92bb6dd3d81d72baeddd913186af 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. +//! Adapters to work with [`frame_support::traits::fungibles`] through XCM. use frame_support::traits::{ tokens::{ diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index e3f91040963840d2b29ceaa30fc1a8e373de4817..21ada3244a3031b866b579daa07c91a2dba7b423 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -32,10 +32,10 @@ pub use location_conversion::ForeignChainAliasAccount; pub use location_conversion::{ Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32, ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal, - DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeFamily, DescribeLocation, - DescribePalletTerminal, DescribeTerminus, GlobalConsensusConvertsFor, - GlobalConsensusParachainConvertsFor, HashedDescription, ParentIsPreset, - SiblingParachainConvertsVia, + DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeBodyTerminal, DescribeFamily, + DescribeLocation, DescribePalletTerminal, DescribeTerminus, DescribeTreasuryVoiceTerminal, + GlobalConsensusConvertsFor, GlobalConsensusParachainConvertsFor, HashedDescription, + LocalTreasuryVoiceConvertsVia, ParentIsPreset, SiblingParachainConvertsVia, }; mod origin_conversion; @@ -83,6 +83,9 @@ pub use weight::{ FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds, }; +mod matches_location; +pub use matches_location::{StartsWith, StartsWithExplicitGlobalConsensus}; + mod matches_token; pub use matches_token::{IsAbstract, IsConcrete}; @@ -90,7 +93,7 @@ mod matcher; pub use matcher::{CreateMatcher, MatchXcm, Matcher}; mod filter_asset_location; -pub use filter_asset_location::{Case, NativeAsset}; +pub use filter_asset_location::{AllAssets, Case, LocationWithAssetFilters, NativeAsset}; mod routing; pub use routing::{WithTopicSource, WithUniqueTopic}; @@ -99,7 +102,7 @@ mod universal_exports; pub use universal_exports::{ ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError, ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable, - SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter, + NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter, }; mod origin_aliases; diff --git a/polkadot/xcm/xcm-builder/src/location_conversion.rs b/polkadot/xcm/xcm-builder/src/location_conversion.rs index ec23116e0e82df672e98a09914042db83523ec03..25d16f7eb8ccc7c6bc40e4454e77be012de172b4 100644 --- a/polkadot/xcm/xcm-builder/src/location_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/location_conversion.rs @@ -84,13 +84,39 @@ impl DescribeLocation for DescribeAccountKey20Terminal { } } +/// Create a description of the remote treasury `location` if possible. No two locations should have +/// the same descriptor. +pub struct DescribeTreasuryVoiceTerminal; + +impl DescribeLocation for DescribeTreasuryVoiceTerminal { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice })) => + Some((b"Treasury", b"Voice").encode()), + _ => None, + } + } +} + pub type DescribeAccountIdTerminal = (DescribeAccountId32Terminal, DescribeAccountKey20Terminal); +pub struct DescribeBodyTerminal; +impl DescribeLocation for DescribeBodyTerminal { + fn describe_location(l: &MultiLocation) -> Option> { + match (l.parents, &l.interior) { + (0, X1(Plurality { id, part })) => Some((b"Body", id, part).encode()), + _ => return None, + } + } +} + pub type DescribeAllTerminal = ( DescribeTerminus, DescribePalletTerminal, DescribeAccountId32Terminal, DescribeAccountKey20Terminal, + DescribeTreasuryVoiceTerminal, + DescribeBodyTerminal, ); pub struct DescribeFamily(PhantomData); @@ -317,6 +343,25 @@ impl>, AccountId: From<[u8; 32]> + Into<[u8; 32]> } } +/// Returns specified `TreasuryAccount` as `AccountId32` if passed `location` matches Treasury +/// plurality. +pub struct LocalTreasuryVoiceConvertsVia( + PhantomData<(TreasuryAccount, AccountId)>, +); +impl, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone> + ConvertLocation for LocalTreasuryVoiceConvertsVia +{ + fn convert_location(location: &MultiLocation) -> Option { + match *location { + MultiLocation { + parents: 0, + interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }), + } => Some((TreasuryAccount::get().into() as [u8; 32]).into()), + _ => None, + } + } +} + /// Conversion implementation which converts from a `[u8; 32]`-based `AccountId` into a /// `MultiLocation` consisting solely of a `AccountId32` junction with a fixed value for its /// network (provided by `Network`) and the `AccountId`'s `[u8; 32]` datum for the `id`. @@ -431,10 +476,13 @@ impl #[cfg(test)] mod tests { use super::*; - + use primitives::AccountId; pub type ForeignChainAliasAccount = HashedDescription; + pub type ForeignChainAliasTreasuryAccount = + HashedDescription>; + use frame_support::parameter_types; use xcm::latest::Junction; @@ -925,4 +973,70 @@ mod tests { }; assert!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).is_none()); } + + #[test] + fn remote_account_convert_on_para_sending_from_remote_para_treasury() { + let relay_treasury_to_para_location = MultiLocation { + parents: 1, + interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }), + }; + let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location( + &relay_treasury_to_para_location, + ) + .unwrap(); + + assert_eq!( + [ + 18, 84, 93, 74, 187, 212, 254, 71, 192, 127, 112, 51, 3, 42, 54, 24, 220, 185, 161, + 67, 205, 154, 108, 116, 108, 166, 226, 211, 29, 11, 244, 115 + ], + actual_description + ); + + let para_to_para_treasury_location = MultiLocation { + parents: 1, + interior: X2( + Parachain(1001), + Plurality { id: BodyId::Treasury, part: BodyPart::Voice }, + ), + }; + let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location( + ¶_to_para_treasury_location, + ) + .unwrap(); + + assert_eq!( + [ + 202, 52, 249, 30, 7, 99, 135, 128, 153, 139, 176, 141, 138, 234, 163, 150, 7, 36, + 204, 92, 220, 137, 87, 57, 73, 91, 243, 189, 245, 200, 217, 204 + ], + actual_description + ); + } + + #[test] + fn local_account_convert_on_para_from_relay_treasury() { + let location = MultiLocation { + parents: 0, + interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }), + }; + + parameter_types! { + pub TreasuryAccountId: AccountId = AccountId::new([42u8; 32]); + } + + let actual_description = + LocalTreasuryVoiceConvertsVia::::convert_location( + &location, + ) + .unwrap(); + + assert_eq!( + [ + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 + ], + actual_description + ); + } } diff --git a/polkadot/xcm/xcm-builder/src/matches_location.rs b/polkadot/xcm/xcm-builder/src/matches_location.rs new file mode 100644 index 0000000000000000000000000000000000000000..cfc71eafd0284b8c0c09695252fd49ac7e2a4b9c --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/matches_location.rs @@ -0,0 +1,50 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Various implementations and utilities for matching and filtering `MultiLocation` and +//! `InteriorMultiLocation` types. + +use frame_support::traits::{Contains, Get}; +use xcm::latest::{InteriorMultiLocation, MultiLocation, NetworkId}; + +/// An implementation of `Contains` that checks for `MultiLocation` or +/// `InteriorMultiLocation` if starts with the provided type `T`. +pub struct StartsWith(sp_std::marker::PhantomData); +impl> Contains for StartsWith { + fn contains(t: &MultiLocation) -> bool { + t.starts_with(&T::get()) + } +} +impl> Contains for StartsWith { + fn contains(t: &InteriorMultiLocation) -> bool { + t.starts_with(&T::get()) + } +} + +/// An implementation of `Contains` that checks for `MultiLocation` or +/// `InteriorMultiLocation` if starts with expected `GlobalConsensus(NetworkId)` provided as type +/// `T`. +pub struct StartsWithExplicitGlobalConsensus(sp_std::marker::PhantomData); +impl> Contains for StartsWithExplicitGlobalConsensus { + fn contains(location: &MultiLocation) -> bool { + matches!(location.interior.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get())) + } +} +impl> Contains for StartsWithExplicitGlobalConsensus { + fn contains(location: &InteriorMultiLocation) -> bool { + matches!(location.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get())) + } +} diff --git a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index 6cf5980df0e9e2227c8bda76a41493efcd248e32..4aebb496d497c6240f10f4013e583f76fd0ad213 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. +//! Adapters to work with [`frame_support::traits::fungibles`] through XCM. use crate::{AssetChecking, MintLocation}; use frame_support::{ diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 7593ea5f17c084ac7f31aaeb439e4dc7a19924c2..45dc2d4a3b9a44c075874e945b5f25453e344912 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -27,8 +27,14 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()))]; + pub BridgeTable: Vec = vec![ + NetworkExportTableItem::new( + Remote::get(), + None, + MultiLocation::parent(), + Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()) + ) + ]; // ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions // x (10 + 10) weight each). } diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs index 124a909bc072b01810a8708841514f292725095a..f11143ab9f6fc9095bc6bdcc220e5742e86a9bcc 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs @@ -24,8 +24,14 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(Remote::get(), (Parent, Parachain(1)).into(), None)]; + pub BridgeTable: Vec = vec![ + NetworkExportTableItem::new( + Remote::get(), + None, + (Parent, Parachain(1)).into(), + None + ) + ]; } type TheBridge = TestBridge< BridgeBlobDispatcher, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs index 2ff1f9fb9764695b5290a0b34c50d38f19fc84fb..7218e0a04880fdb2a49ec470385e551f1ab884ac 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs @@ -24,8 +24,14 @@ parameter_types! { pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(Remote::get(), Parachain(1).into(), None)]; + pub BridgeTable: Vec = vec![ + NetworkExportTableItem::new( + Remote::get(), + None, + Parachain(1).into(), + None + ) + ]; } type TheBridge = TestBridge< BridgeBlobDispatcher, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs index cdd6b89b7b1b53cfe789715ae7cded58e7830e66..45b5efbc44c549b9a68fbcfc968a6589854d74df 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs @@ -24,8 +24,14 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> - = vec![(Remote::get(), MultiLocation::parent(), None)]; + pub BridgeTable: Vec = vec![ + NetworkExportTableItem::new( + Remote::get(), + None, + MultiLocation::parent(), + None + ) + ]; } type TheBridge = TestBridge>; diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index c663b0a4d76f41b7e9a184f63202ace61376089a..5b6fa3ee5a0b05fbfb868f813b673e749dfaaf18 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -49,22 +49,12 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: BlockNumber = 250; -} - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type Block = Block; - type BlockHashCount = BlockHashCount; - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); type AccountData = pallet_balances::AccountData; type AccountId = AccountId; + type BlockHashCount = ConstU32<256>; type Lookup = sp_runtime::traits::IdentityLookup; } diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index d1b8c8c721fecfc831a0eb9d624aead984f11866..dbe9571d461ad66f604af593ec7bc66fc9bf3cb2 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -117,16 +117,54 @@ impl ExporterFor for Tuple { } } +/// Configuration item representing a single exporter in the `NetworkExportTable`. +pub struct NetworkExportTableItem { + /// Supported remote network. + pub remote_network: NetworkId, + /// Remote location filter. + /// If `Some`, the requested remote location must be equal to one of the items in the vector. + /// These are locations in the remote network. + /// If `None`, then the check is skipped. + pub remote_location_filter: Option>, + /// Locally-routable bridge with bridging capabilities to the `remote_network` and + /// `remote_location`. See [`ExporterFor`] for more details. + pub bridge: MultiLocation, + /// The local payment. + /// See [`ExporterFor`] for more details. + pub payment: Option, +} + +impl NetworkExportTableItem { + pub fn new( + remote_network: NetworkId, + remote_location_filter: Option>, + bridge: MultiLocation, + payment: Option, + ) -> Self { + Self { remote_network, remote_location_filter, bridge, payment } + } +} + +/// An adapter for the implementation of `ExporterFor`, which attempts to find the +/// `(bridge_location, payment)` for the requested `network` and `remote_location` in the provided +/// `T` table containing various exporters. pub struct NetworkExportTable(sp_std::marker::PhantomData); -impl)>>> ExporterFor - for NetworkExportTable -{ +impl>> ExporterFor for NetworkExportTable { fn exporter_for( network: &NetworkId, - _: &InteriorMultiLocation, + remote_location: &InteriorMultiLocation, _: &Xcm<()>, ) -> Option<(MultiLocation, Option)> { - T::get().into_iter().find(|(ref j, ..)| j == network).map(|(_, l, p)| (l, p)) + T::get() + .into_iter() + .find(|item| { + &item.remote_network == network && + item.remote_location_filter + .as_ref() + .map(|filters| filters.iter().any(|filter| filter == remote_location)) + .unwrap_or(true) + }) + .map(|item| (item.bridge, item.payment)) } } @@ -171,7 +209,9 @@ impl, + pub universal_dest: VersionedInteriorMultiLocation, + pub message: VersionedXcm<()>, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -500,7 +542,7 @@ mod tests { pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234)); pub DifferentRemote: NetworkId = ByGenesis([22; 32]); // no routers - pub BridgeTable: Vec<(NetworkId, MultiLocation, Option)> = vec![]; + pub BridgeTable: Vec = vec![]; } // check with local destination (should be remote) @@ -535,4 +577,74 @@ mod tests { >, >(remote_dest, |result| assert_eq!(Err(NotApplicable), result)); } + + #[test] + fn network_export_table_works() { + frame_support::parameter_types! { + pub NetworkA: NetworkId = ByGenesis([0; 32]); + pub Parachain1000InNetworkA: InteriorMultiLocation = X1(Parachain(1000)); + pub Parachain2000InNetworkA: InteriorMultiLocation = X1(Parachain(2000)); + + pub NetworkB: NetworkId = ByGenesis([1; 32]); + + pub BridgeToALocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1234))); + pub BridgeToBLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(4321))); + + pub PaymentForNetworkAAndParachain2000: MultiAsset = (MultiLocation::parent(), 150).into(); + + pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ + // NetworkA allows `Parachain(1000)` as remote location WITHOUT payment. + NetworkExportTableItem::new( + NetworkA::get(), + Some(vec![Parachain1000InNetworkA::get()]), + BridgeToALocation::get(), + None + ), + // NetworkA allows `Parachain(2000)` as remote location WITH payment. + NetworkExportTableItem::new( + NetworkA::get(), + Some(vec![Parachain2000InNetworkA::get()]), + BridgeToALocation::get(), + Some(PaymentForNetworkAAndParachain2000::get()) + ), + // NetworkB allows all remote location. + NetworkExportTableItem::new( + NetworkB::get(), + None, + BridgeToBLocation::get(), + None + ) + ]; + } + + let test_data = vec![ + (NetworkA::get(), X1(Parachain(1000)), Some((BridgeToALocation::get(), None))), + (NetworkA::get(), X2(Parachain(1000), GeneralIndex(1)), None), + ( + NetworkA::get(), + X1(Parachain(2000)), + Some((BridgeToALocation::get(), Some(PaymentForNetworkAAndParachain2000::get()))), + ), + (NetworkA::get(), X2(Parachain(2000), GeneralIndex(1)), None), + (NetworkA::get(), X1(Parachain(3000)), None), + (NetworkB::get(), X1(Parachain(1000)), Some((BridgeToBLocation::get(), None))), + (NetworkB::get(), X1(Parachain(2000)), Some((BridgeToBLocation::get(), None))), + (NetworkB::get(), X1(Parachain(3000)), Some((BridgeToBLocation::get(), None))), + ]; + + for (network, remote_location, expected_result) in test_data { + assert_eq!( + NetworkExportTable::::exporter_for( + &network, + &remote_location, + &Xcm::default() + ), + expected_result, + "expected_result: {:?} not matched for network: {:?} and remote_location: {:?}", + expected_result, + network, + remote_location, + ) + } + } } diff --git a/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.toml b/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.toml deleted file mode 100644 index 918fb5bf4f62c6be92009a62143fb5972d8c2292..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.toml +++ /dev/null @@ -1,34 +0,0 @@ -[settings] -timeout = 1000 - -[relaychain] -default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" -chain = "rococo-local" -default_command = "polkadot" - - [relaychain.default_resources] - limits = { memory = "4G", cpu = "2" } - requests = { memory = "2G", cpu = "1" } - - [[relaychain.nodes]] - name = "alice" - args = [ "-lparachain=debug,runtime=debug"] - - [[relaychain.nodes]] - name = "bob" - image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" - args = [ "-lparachain=debug,runtime=debug"] - -[[parachains]] -id = 100 - - [parachains.collator] - name = "collator01" - image = "{{COL_IMAGE}}" - command = "undying-collator" - args = ["-lparachain=debug"] - -[types.Header] -number = "u64" -parent_hash = "Hash" -post_state = "Hash" diff --git a/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl b/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl deleted file mode 100644 index 46c1d77acf46cec2a0925ed80bc93487e7c12452..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl +++ /dev/null @@ -1,23 +0,0 @@ -Description: Async Backing Compatibility Test -Network: ./001-async-backing-compatibility.toml -Creds: config - -# General -alice: is up -bob: is up - -# Check authority status -alice: reports node_roles is 4 -bob: reports node_roles is 4 - -# Check peers -alice: reports peers count is at least 2 within 20 seconds -bob: reports peers count is at least 2 within 20 seconds - -# Parachain registration -alice: parachain 100 is registered within 225 seconds -bob: parachain 100 is registered within 225 seconds - -# Ensure parachain progress -alice: parachain 100 block height is at least 10 within 250 seconds -bob: parachain 100 block height is at least 10 within 250 seconds diff --git a/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml b/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml deleted file mode 100644 index e61f7dd47ef6e09ed82173b21e58cd4445a8da28..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml +++ /dev/null @@ -1,54 +0,0 @@ -[settings] -timeout = 1000 - -[relaychain] -default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" -chain = "rococo-local" -default_command = "polkadot" - - [relaychain.default_resources] - limits = { memory = "4G", cpu = "2" } - requests = { memory = "2G", cpu = "1" } - - [[relaychain.nodes]] - name = "alice" - args = [ "-lparachain=debug,runtime=debug"] - - [[relaychain.nodes]] - name = "bob" - args = [ "-lparachain=debug,runtime=debug"] - - [[relaychain.nodes]] - name = "charlie" - image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" - args = [ "-lparachain=debug,runtime=debug"] - - [[relaychain.nodes]] - name = "dave" - image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" - args = [ "-lparachain=debug,runtime=debug"] - -[[parachains]] -id = 100 -addToGenesis = true - - [parachains.collator] - name = "collator02" - image = "{{COL_IMAGE}}" - command = "undying-collator" - args = ["-lparachain=debug"] - -[[parachains]] -id = 101 -addToGenesis = true - - [parachains.collator] - name = "collator02" - image = "{{COL_IMAGE}}" - command = "undying-collator" - args = ["-lparachain=debug"] - -[types.Header] -number = "u64" -parent_hash = "Hash" -post_state = "Hash" diff --git a/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl b/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl deleted file mode 100644 index 6213d1afb81e23ecd441cc566551461b0a802033..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl +++ /dev/null @@ -1,34 +0,0 @@ -Description: Async Backing Runtime Upgrade Test -Network: ./002-async-backing-runtime-upgrade.toml -Creds: config - -# General -alice: is up -bob: is up -charlie: is up -dave: is up - -# Check peers -alice: reports peers count is at least 3 within 20 seconds -bob: reports peers count is at least 3 within 20 seconds - -# Parachain registration -alice: parachain 100 is registered within 225 seconds -bob: parachain 100 is registered within 225 seconds -charlie: parachain 100 is registered within 225 seconds -dave: parachain 100 is registered within 225 seconds -alice: parachain 101 is registered within 225 seconds -bob: parachain 101 is registered within 225 seconds -charlie: parachain 101 is registered within 225 seconds -dave: parachain 101 is registered within 225 seconds - -# Ensure parachain progress -alice: parachain 100 block height is at least 10 within 250 seconds -bob: parachain 100 block height is at least 10 within 250 seconds - -# Runtime upgrade (according to previous runtime tests, avg. is 30s) -alice: run ../misc/0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_BIN_URL}}" within 40 seconds -bob: run ../misc/0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_BIN_URL}}" within 40 seconds - -# Bootstrap the runtime upgrade -sleep 30 seconds diff --git a/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.toml b/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.toml deleted file mode 100644 index 4dca4d3d531268c45026a7da938b186334aee5de..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.toml +++ /dev/null @@ -1,40 +0,0 @@ -[settings] -timeout = 1000 - -[relaychain] -default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" -chain = "rococo-local" -default_command = "polkadot" - - [relaychain.default_resources] - limits = { memory = "4G", cpu = "2" } - requests = { memory = "2G", cpu = "1" } - - [[relaychain.nodes]] - name = "alice" - args = [ "-lparachain=debug"] - - [[relaychain.nodes]] - name = "bob" - image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" - args = [ "-lparachain=debug"] - -[[parachains]] -id = 100 - - [[parachains.collators]] - name = "collator01" - image = "docker.io/paritypr/colander:master" - command = "undying-collator" - args = ["-lparachain=debug"] - - [[parachains.collators]] - name = "collator02" - image = "{{COL_IMAGE}}" - command = "undying-collator" - args = ["-lparachain=debug"] - -[types.Header] -number = "u64" -parent_hash = "Hash" -post_state = "Hash" diff --git a/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl b/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl deleted file mode 100644 index 98436b0459cf80a4f7f494d7af9a6684da73cdf9..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl +++ /dev/null @@ -1,19 +0,0 @@ -Description: Async Backing Collator Mix Test -Network: ./003-async-backing-collator-mix.toml -Creds: config - -# General -alice: is up -bob: is up - -# Check peers -alice: reports peers count is at least 3 within 20 seconds -bob: reports peers count is at least 3 within 20 seconds - -# Parachain registration -alice: parachain 100 is registered within 225 seconds -bob: parachain 100 is registered within 225 seconds - -# Ensure parachain progress -alice: parachain 100 block height is at least 10 within 250 seconds -bob: parachain 100 block height is at least 10 within 250 seconds diff --git a/polkadot/zombienet_tests/async_backing/README.md b/polkadot/zombienet_tests/async_backing/README.md deleted file mode 100644 index 9774ea3c25c96d434643d1e565a3e933fbc2412c..0000000000000000000000000000000000000000 --- a/polkadot/zombienet_tests/async_backing/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# async-backing zombienet tests - -This directory contains zombienet tests made explicitly for the async-backing feature branch. - -## coverage - -- Network protocol upgrade deploying both master and async branch (compatibility). -- Runtime ugprade while running both master and async backing branch nodes. -- Async backing test with a mix of collators collating via async backing and sync backing. diff --git a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index a0a87d60d4e3ec381686a8dd02dbb605209dd2af..e6aeb8e245c2bab3e53628498aeb2c7caa626e0f 100644 --- a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml @@ -1,7 +1,7 @@ [settings] timeout = 1000 -[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] +[relaychain.genesis.runtime.configuration.config] max_validators_per_core = 5 needed_approvals = 8 diff --git a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml index 7c4f5a9f1bcab8550755bfefadd1a1c425b4ac06..ef27d7b92f029d7978c9b7ab1a175c882fbb1d70 100644 --- a/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml +++ b/polkadot/zombienet_tests/functional/0004-parachains-garbage-candidate.toml @@ -2,7 +2,7 @@ timeout = 1000 bootnode = true -[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] +[relaychain.genesis.runtime.configuration.config] max_validators_per_core = 1 needed_approvals = 2 diff --git a/polkadot/zombienet_tests/misc/0001-paritydb.toml b/polkadot/zombienet_tests/misc/0001-paritydb.toml index 38fa56898196ae21934e786a26cb6265ed915282..99dc9c66e26ee6b04bfea1951d7818e23be70118 100644 --- a/polkadot/zombienet_tests/misc/0001-paritydb.toml +++ b/polkadot/zombienet_tests/misc/0001-paritydb.toml @@ -2,7 +2,7 @@ timeout = 1000 bootnode = true -[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] +[relaychain.genesis.runtime.configuration.config] max_validators_per_core = 1 needed_approvals = 3 diff --git a/polkadot/zombienet_tests/misc/0002-download-polkadot-from-pr.sh b/polkadot/zombienet_tests/misc/0002-download-polkadot-from-pr.sh index 0d4b2807579564f0fcbad3e43f400f8a68f082fc..b55534559278df65cab369ea02d924abdc5746ad 100644 --- a/polkadot/zombienet_tests/misc/0002-download-polkadot-from-pr.sh +++ b/polkadot/zombienet_tests/misc/0002-download-polkadot-from-pr.sh @@ -12,8 +12,10 @@ export PATH=$CFG_DIR:$PATH cd $CFG_DIR # see 0002-upgrade-node.zndsl to view the args. -curl -L -O $1/polkadot -curl -L -O $1/polkadot-prepare-worker -curl -L -O $1/polkadot-execute-worker +curl -L -O $1/polkadot & +curl -L -O $1/polkadot-prepare-worker & +curl -L -O $1/polkadot-execute-worker & +wait + chmod +x $CFG_DIR/polkadot $CFG_DIR/polkadot-prepare-worker $CFG_DIR/polkadot-execute-worker echo $(polkadot --version) diff --git a/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl b/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl index fdf16b7286c910bef0d2052a8a1f6c5c595352d7..9191fb027de0d0240805d6cb65e68adfc4f15942 100644 --- a/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl +++ b/polkadot/zombienet_tests/misc/0002-upgrade-node.zndsl @@ -11,8 +11,8 @@ dave: parachain 2001 block height is at least 10 within 200 seconds # with the version of polkadot you want to download. # avg 30s in our infra -alice: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 40 seconds -bob: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 40 seconds +alice: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 60 seconds +bob: run ./0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_ARTIFACTS_URL}}" within 60 seconds alice: restart after 5 seconds bob: restart after 5 seconds diff --git a/polkadot/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.toml b/polkadot/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.toml index 0becb408550a61e4a05af7ca80b4df79acedee00..d72e3ebdb3354dedc5c90e50dd697d1883365d0f 100644 --- a/polkadot/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.toml +++ b/polkadot/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.toml @@ -30,8 +30,8 @@ cumulus_based = true [parachains.collator] name = "collator01" - image = "{{COL_IMAGE}}" - command = "polkadot-collator" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" [[parachains.collator.env]] name = "RUST_LOG" diff --git a/prdoc/pr_1255.prdoc b/prdoc/pr_1255.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..793b5c3c8597a785276637a796eb83be5738f42a --- /dev/null +++ b/prdoc/pr_1255.prdoc @@ -0,0 +1,22 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Fix for Reward Deficit in the pool + +doc: + - audience: Core Dev + description: Instead of fragile calculation of current balance by looking at free balance - ED, Nomination Pool now freezes ED in the pool reward account to restrict an account from going below minimum balance. This also has a nice side effect that if ED changes, we know how much is the imbalance in ED frozen in the pool and the current required ED. A pool operator can diligently top up the pool with the deficit in ED or vice versa, withdraw the excess they transferred to the pool. + notes: + - Introduces new call `adjust_pool_deposit` that allows to top up the deficit or withdraw the excess deposit for the pool. + - Switch to using Fungible trait from Currency trait. + +migrations: + db: [] + + runtime: + - { pallet: "pallet-nomination-pools", description: "One time migration of freezing ED from each of the existing pools."} + +crates: + - name: pallet-nomination-pools + +host_functions: [] \ No newline at end of file diff --git a/prdoc/pr_1818.prdoc b/prdoc/pr_1818.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cbafa02f9af563e88f38a4fb4f74e4ae7c13fc1a --- /dev/null +++ b/prdoc/pr_1818.prdoc @@ -0,0 +1,16 @@ +title: FRAME pallets warning for unchecked weight witness + +doc: + - audience: Core Dev + description: | + FRAME pallets now emit a warning when a call uses a function argument that starts with an underscore in its weight declaration. + +migrations: + db: [ ] + runtime: [ ] + +host_functions: [] + +crates: +- name: "frame-support-procedural" + semver: minor diff --git a/prdoc/pr_1921.prdoc b/prdoc/pr_1921.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5ed0137cd5f9ee850265fe816060d34fbdf9fb38 --- /dev/null +++ b/prdoc/pr_1921.prdoc @@ -0,0 +1,19 @@ +title: Fix para-scheduler migration + +doc: + - audience: Core Dev + description: | + Changing the `MigrateToV1` migration in the `ParachainScheduler` pallet to be truly idempotent. It is achieved by wrapping it in a `VersionedMigration`. + +migrations: + db: [] + + runtime: + - pallet: "ParachainScheduler" + description: Non-critical fixup for `MigrateToV1`. + +crates: + - name: "polkadot-runtime-parachains" + semver: patch + +host_functions: [] diff --git a/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..785cc7bd3291ccdaff1d80558e9f3d52418068c3 --- /dev/null +++ b/scripts/update-ui-tests.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Script for updating the UI tests for a new rust stable version. +# Exit on error +set -e + +# by default current rust stable will be used +RUSTUP_RUN="" +# check if we have a parameter +# ./scripts/update-ui-tests.sh 1.70 +if [ ! -z "$1" ]; then + echo "RUST_VERSION: $1" + # This will run all UI tests with the rust stable 1.70. + # The script requires that rustup is installed. + RUST_VERSION=$1 + RUSTUP_RUN="rustup run $RUST_VERSION" + + + echo "installing rustup $RUST_VERSION" + if ! command -v rustup &> /dev/null + then + echo "rustup needs to be installed" + exit + fi + + rustup install $RUST_VERSION + rustup component add rust-src --toolchain $RUST_VERSION +fi + +# Ensure we run the ui tests +export RUN_UI_TESTS=1 +# We don't need any wasm files for ui tests +export SKIP_WASM_BUILD=1 +# Let trybuild overwrite the .stderr files +export TRYBUILD=overwrite + +# ./substrate +$RUSTUP_RUN cargo test -p sp-runtime-interface ui +$RUSTUP_RUN cargo test -p sp-api-test ui +$RUSTUP_RUN cargo test -p frame-election-provider-solution-type ui +$RUSTUP_RUN cargo test -p frame-support-test ui diff --git a/substrate/.gitattributes b/substrate/.gitattributes index a77c52fccdb778ebfd76020760d45bcb4da922ab..4cb3ef4972feb1eba84cf44d7d5f88a19f1ba0a2 100644 --- a/substrate/.gitattributes +++ b/substrate/.gitattributes @@ -1,4 +1,2 @@ Cargo.lock linguist-generated=true -/.gitlab-ci.yml filter=ci-prettier -/scripts/ci/gitlab/pipeline/*.yml filter=ci-prettier frame/**/src/weights.rs linguist-generated=true diff --git a/substrate/.github/dependabot.yml b/substrate/.github/dependabot.yml deleted file mode 100644 index 04cf0d1e1a5a4fa5bcdfeaa3e3ec378b0cc20de4..0000000000000000000000000000000000000000 --- a/substrate/.github/dependabot.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "cargo" - directory: "/" - labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] - schedule: - interval: "daily" - - package-ecosystem: github-actions - directory: '/' - labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] - schedule: - interval: daily diff --git a/substrate/.github/pr-custom-review.yml b/substrate/.github/pr-custom-review.yml deleted file mode 100644 index 059f4a283af075c2e23c6d65be8803a6b8898ec9..0000000000000000000000000000000000000000 --- a/substrate/.github/pr-custom-review.yml +++ /dev/null @@ -1,39 +0,0 @@ -# 🔒 PROTECTED: Changes to locks-review-team should be approved by the current locks-review-team -locks-review-team: locks-review -team-leads-team: polkadot-review -action-review-team: ci - -rules: - - name: Core developers - check_type: changed_files - condition: - include: .* - # excluding files from 'CI team' and 'FRAME coders' rules - exclude: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.*|^\.config/nextest.toml|^frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) - min_approvals: 2 - teams: - - core-devs - - - name: FRAME coders - check_type: changed_files - condition: - include: ^frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) - all: - - min_approvals: 2 - teams: - - core-devs - - min_approvals: 1 - teams: - - frame-coders - - - name: CI team - check_type: changed_files - condition: - include: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.*|^\.config/nextest.toml - min_approvals: 2 - teams: - - ci - -prevent-review-request: - teams: - - core-devs diff --git a/substrate/.github/stale.yml b/substrate/.github/stale.yml deleted file mode 100644 index 61d0fd0228d97afaee6e9a9d30d0440d7fb1f670..0000000000000000000000000000000000000000 --- a/substrate/.github/stale.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 30 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 14 -# Issues with these labels will never be considered stale -exemptLabels: - - "D9-needsaudit 👮" -# Label to use when marking an issue as stale -staleLabel: "A3-stale" -# we only bother with pull requests -only: pulls -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - Hey, is anyone still working on this? Due to the inactivity this issue has - been automatically marked as stale. It will be closed if no further activity - occurs. Thank you for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/substrate/.github/workflows/auto-label-issues.yml b/substrate/.github/workflows/auto-label-issues.yml deleted file mode 100644 index 12ffce702cdcca9e3ed65dfceb1d35e8c078bdac..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/auto-label-issues.yml +++ /dev/null @@ -1,17 +0,0 @@ -# If the author of the issues is not a contributor to the project, label -# the issue with 'Z0-unconfirmed' - -name: Label New Issues -on: - issues: - types: [opened] - -jobs: - label-new-issues: - runs-on: ubuntu-latest - steps: - - name: Label drafts - uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4 - if: github.event.issue.author_association == 'NONE' - with: - add-labels: "I10-unconfirmed" diff --git a/substrate/.github/workflows/burnin-label-notification.yml b/substrate/.github/workflows/burnin-label-notification.yml deleted file mode 100644 index f45455d31db1e2dcd9ed34708630304312a3168a..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/burnin-label-notification.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Notify devops when burn-in label applied -on: - pull_request: - types: [labeled] - -jobs: - notify-devops: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - - steps: - - name: Notify devops - if: startsWith(github.event.label.name, 'A1-') - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: "m.parity.io" - message: | - @room Burn-in request received for [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }}) diff --git a/substrate/.github/workflows/check-D-labels.yml b/substrate/.github/workflows/check-D-labels.yml deleted file mode 100644 index 7bb358ce1182e4b4bae1dc94bd986567cee1b599..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/check-D-labels.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Check D labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - paths: - - frame/** - - primitives/** - -env: - IMAGE: paritytech/ruled_labels:0.4.0 - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - run: docker pull $IMAGE - - - name: Check labels - env: - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_substrate.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags audit --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags audit diff --git a/substrate/.github/workflows/check-labels.yml b/substrate/.github/workflows/check-labels.yml deleted file mode 100644 index 55b8f7389fa7f128b7134549b8517c9677bd9562..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/check-labels.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Check labels - -on: - pull_request: - types: [labeled, opened, synchronize, unlabeled] - -env: - IMAGE: paritytech/ruled_labels:0.4.0 - -jobs: - check-labels: - runs-on: ubuntu-latest - steps: - - name: Pull image - run: docker pull $IMAGE - - - name: Check labels - env: - MOUNT: /work - GITHUB_PR: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_BASE: https://api.github.com/repos - REPO: ${{ github.repository }} - RULES_PATH: labels/ruled_labels - CHECK_SPECS: specs_substrate.yaml - run: | - echo "REPO: ${REPO}" - echo "GITHUB_PR: ${GITHUB_PR}" - # Clone repo with labels specs - git clone https://github.com/paritytech/labels - # Fetch the labels for the PR under test - labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") - - if [ -z "${labels}" ]; then - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags PR --no-label - fi - - labels_args=${labels: :-1} - printf "Checking labels: %s\n" "${labels_args}" - - # Prevent the shell from splitting labels with spaces - IFS="," - - # --dev is more useful to debug mode to debug - docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags PR diff --git a/substrate/.github/workflows/md-link-check.yml b/substrate/.github/workflows/md-link-check.yml deleted file mode 100644 index e1387f6da13f71396cdd761f0967a2c35c7169eb..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/md-link-check.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Check Links - -on: - pull_request: - branches: - - master - push: - branches: - - master - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: gaurav-nelson/github-action-markdown-link-check@0a51127e9955b855a9bbfa1ff5577f1d1338c9a5 # 1.0.14 - with: - use-quiet-mode: 'yes' - config-file: '.github/workflows/mlc_config.json' diff --git a/substrate/.github/workflows/mlc_config.json b/substrate/.github/workflows/mlc_config.json deleted file mode 100644 index e7e620b39e0a9b2dd60eb57498ba99c1b6635443..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/mlc_config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "^https://crates.io", - } - ] -} diff --git a/substrate/.github/workflows/monthly-tag.yml b/substrate/.github/workflows/monthly-tag.yml deleted file mode 100644 index 055207d85a4dd22b65097a0c3b41f1896c358954..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/monthly-tag.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Monthly Snapshot Tag - -on: - schedule: - - cron: "0 1 1 * *" - workflow_dispatch: - -jobs: - build: - name: Take Snapshot - runs-on: ubuntu-latest - steps: - - name: Get the tags by date - id: tags - run: | - echo "new=$(date +'monthly-%Y-%m')" >> $GITHUB_OUTPUT - echo "old=$(date -d'1 month ago' +'monthly-%Y-%m')" >> $GITHUB_OUTPUT - - name: Checkout branch "master" - uses: actions/checkout@v3 - with: - ref: 'master' - fetch-depth: 0 - - name: Generate changelog - id: changelog - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "# Automatic snapshot pre-release ${{ steps.tags.outputs.new }}" > Changelog.md - echo "" >> Changelog.md - echo "## Changes since last snapshot (${{ steps.tags.outputs.old }})" >> Changelog.md - echo "" >> Changelog.md - ./scripts/ci/github/generate_changelog.sh ${{ steps.tags.outputs.old }} >> Changelog.md - - name: Release snapshot - id: release-snapshot - uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 latest version, repo archived - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.tags.outputs.new }} - release_name: ${{ steps.tags.outputs.new }} - draft: false - prerelease: true - body_path: Changelog.md diff --git a/substrate/.github/workflows/pr-custom-review.yml b/substrate/.github/workflows/pr-custom-review.yml deleted file mode 100644 index 8e40c9ee72989d9ef244247456aa578d3836f8c6..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/pr-custom-review.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Assign reviewers - -on: - pull_request: - branches: - - master - - main - types: - - opened - - reopened - - synchronize - - review_requested - - review_request_removed - - ready_for_review - - converted_to_draft - pull_request_review: - -jobs: - pr-custom-review: - runs-on: ubuntu-latest - steps: - - name: Skip if pull request is in Draft - # `if: github.event.pull_request.draft == true` should be kept here, at - # the step level, rather than at the job level. The latter is not - # recommended because when the PR is moved from "Draft" to "Ready to - # review" the workflow will immediately be passing (since it was skipped), - # even though it hasn't actually ran, since it takes a few seconds for - # the workflow to start. This is also disclosed in: - # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17 - # That scenario would open an opportunity for the check to be bypassed: - # 1. Get your PR approved - # 2. Move it to Draft - # 3. Push whatever commits you want - # 4. Move it to "Ready for review"; now the workflow is passing (it was - # skipped) and "Check reviews" is also passing (it won't be updated - # until the workflow is finished) - if: github.event.pull_request.draft == true - run: exit 1 - - name: pr-custom-review - uses: paritytech/pr-custom-review@action-v3 - with: - checks-reviews-api: http://pcr.parity-prod.parity.io/api/v1/check_reviews diff --git a/substrate/.github/workflows/release-bot.yml b/substrate/.github/workflows/release-bot.yml deleted file mode 100644 index 05bea32abc697e4f0aa5ce42f30f7cc475cfa63a..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/release-bot.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Pushes release updates to a pre-defined Matrix room -on: - release: - types: - - edited - - prereleased - - published -jobs: - ping_matrix: - runs-on: ubuntu-latest - strategy: - matrix: - channel: - - name: 'General: Rust, Polkadot, Substrate' - room: '!aJymqQYtCjjqImFLSb:parity.io' - pre-release: false - - steps: - - name: send message - uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 - with: - room_id: ${{ matrix.channel.room }} - access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} - server: "m.parity.io" - message: | - ***${{github.event.repository.full_name}}:*** A release has been ${{github.event.action}}
- Release version [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) - - ----- - - ${{github.event.release.body}}
diff --git a/substrate/.github/workflows/release-tagging.yml b/substrate/.github/workflows/release-tagging.yml deleted file mode 100644 index 1862582f40eba2f33a5d94fd356870d4f4c49cce..0000000000000000000000000000000000000000 --- a/substrate/.github/workflows/release-tagging.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Github action to ensure the `release` tag always tracks latest release - -name: Retag release - -on: - release: - types: [ published ] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Set Git tag - uses: s3krit/walking-tag-action@d04f7a53b72ceda4e20283736ce3627011275178 # latest version from master - with: - tag-name: release - tag-message: Latest release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/substrate/.gitlab-ci.yml b/substrate/.gitlab-ci.yml deleted file mode 100644 index f00836528973ecb068f8075d647d94236e293904..0000000000000000000000000000000000000000 --- a/substrate/.gitlab-ci.yml +++ /dev/null @@ -1,412 +0,0 @@ -# .gitlab-ci.yml -# -# substrate -# -# pipelines can be triggered manually in the web -# -# Currently the file is divided into subfiles. Each stage has a different file which -# can be found here: scripts/ci/gitlab/pipeline/.yml -# -# Instead of YAML anchors "extends" is used. -# Useful links: -# https://docs.gitlab.com/ee/ci/yaml/index.html#extends -# https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#reference-tags -# -# SAMPLE JOB TEMPLATE - This is not a complete example but is enough to build a -# simple CI job. For full documentation, visit https://docs.gitlab.com/ee/ci/yaml/ -# -# my-example-job: -# stage: test # One of the stages listed below this job (required) -# image: paritytech/tools:latest # Any docker image (required) -# allow_failure: true # Allow the pipeline to continue if this job fails (default: false) -# needs: -# - job: test-linux # Any jobs that are required to run before this job (optional) -# variables: -# MY_ENVIRONMENT_VARIABLE: "some useful value" # Environment variables passed to the job (optional) -# script: -# - echo "List of shell commands to run in your job" -# - echo "You can also just specify a script here, like so:" -# - ./scripts/ci/gitlab/my_amazing_script.sh - -stages: - - check - - test - - build - - publish - - notify - - zombienet - - deploy - -workflow: - rules: - - if: $CI_COMMIT_TAG - - if: $CI_COMMIT_BRANCH - -variables: - GIT_STRATEGY: fetch - GIT_DEPTH: 100 - CARGO_INCREMENTAL: 0 - DOCKER_OS: "debian:bullseye" - ARCH: "x86_64" - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] - BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" - BUILDAH_COMMAND: "buildah --storage-driver overlay2" - RELENG_SCRIPTS_BRANCH: "master" - - RUSTY_CACHIER_SINGLE_BRANCH: master - RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" - RUSTY_CACHIER_MINIO_ALIAS: rustycachier_gcs - RUSTY_CACHIER_MINIO_BUCKET: parity-build-rusty-cachier - RUSTY_CACHIER_COMPRESSION_METHOD: zstd - - NEXTEST_FAILURE_OUTPUT: immediate-final - NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.55" - -default: - retry: - max: 2 - when: - - runner_system_failure - - unknown_failure - - api_failure - cache: {} - interruptible: true - -.collect-artifacts: - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 7 days - paths: - - artifacts/ - -.collect-artifacts-short: - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 3 hours - paths: - - artifacts/ - -.prepare-env: - before_script: - # TODO: remove unset invocation when we'll be free from 'ENV RUSTC_WRAPPER=sccache' & sccache - # itself in all images - - unset RUSTC_WRAPPER - # $WASM_BUILD_WORKSPACE_HINT enables wasm-builder to find the Cargo.lock from within generated - # packages - - export WASM_BUILD_WORKSPACE_HINT="$PWD" - # ensure that RUSTFLAGS are set correctly - - echo $RUSTFLAGS - -.job-switcher: - before_script: - - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi - -.kubernetes-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.timestamp, before_script] - - !reference [.job-switcher, before_script] - - !reference [.prepare-env, before_script] - tags: - - kubernetes-parity-build - -.rust-info-script: - script: - - rustup show - - cargo --version - - rustup +nightly show - - cargo +nightly --version - -.pipeline-stopper-vars: - script: - - !reference [.job-switcher, before_script] - - echo "Collecting env variables for the cancel-pipeline job" - - echo "FAILED_JOB_URL=${CI_JOB_URL}" > pipeline-stopper.env - - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env - - echo "PR_NUM=${CI_COMMIT_REF_NAME}" >> pipeline-stopper.env - -.pipeline-stopper-artifacts: - artifacts: - reports: - dotenv: pipeline-stopper.env - -.docker-env: - image: "${CI_IMAGE}" - before_script: - - !reference [.timestamp, before_script] - - !reference [.job-switcher, before_script] - - !reference [.prepare-env, before_script] - - !reference [.rust-info-script, script] - - !reference [.rusty-cachier, before_script] - - !reference [.pipeline-stopper-vars, script] - after_script: - - !reference [.rusty-cachier, after_script] - tags: - - linux-docker-vm-c2 - -# rusty-cachier's hidden job. Parts of this job are used to instrument the pipeline's other real jobs with rusty-cachier -# Description of the commands is available here - https://gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client#description -.rusty-cachier: - before_script: - - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash - - rusty-cachier environment check --gracefully - - $(rusty-cachier environment inject) - - rusty-cachier project mtime - after_script: - - env RUSTY_CACHIER_SUPRESS_OUTPUT=true rusty-cachier snapshot destroy - -.test-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - -# handle the specific case where benches could store incorrect bench data because of the downstream staging runs -# exclude cargo-check-benches from such runs -.test-refs-check-benches: - rules: - - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "pipeline" && $CI_IMAGE =~ /staging$/ - when: never - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - -.test-refs-no-trigger: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^ci-release-.*$/ - -.test-refs-no-trigger-prs-only: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.publish-refs: - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - -.build-refs: - # publish-refs + PRs - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - -.zombienet-refs: - extends: .build-refs - -.crates-publishing-variables: - variables: - CRATESIO_CRATES_OWNER: parity-crate-owner - REPO: substrate - REPO_OWNER: paritytech - -.crates-publishing-pipeline: - extends: .crates-publishing-variables - rules: - - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME == "master" && $PIPELINE == "automatic-crate-publishing" - -.crates-publishing-template: - extends: - - .docker-env - - .crates-publishing-variables - # collect artifacts even on failure so that we know how the crates were generated (they'll be - # generated to the artifacts folder according to SPUB_TMP further down) - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 7 days - paths: - - artifacts/ - variables: - SPUB_TMP: artifacts - # disable timestamping for the crate publishing jobs, they leave stray child processes behind - # which don't interact well with the timestamping script - CI_DISABLE_TIMESTAMP: 1 - -#### stage: .pre - -check-crates-publishing-pipeline: - stage: .pre - extends: - - .kubernetes-env - - .crates-publishing-pipeline - script: - - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git - - ONLY_CHECK_PIPELINE=true ./releng-scripts/publish-crates - -# By default our pipelines are interruptible, but some special pipelines shouldn't be interrupted: -# * multi-project pipelines such as the ones triggered by the scripts repo -# * the scheduled automatic-crate-publishing pipeline -# -# In those cases, we add an uninterruptible .pre job; once that one has started, -# the entire pipeline becomes uninterruptible -uninterruptible-pipeline: - extends: .kubernetes-env - variables: - CI_IMAGE: "paritytech/tools:latest" - stage: .pre - interruptible: false - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - - if: $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" - script: "true" - -include: - # check jobs - - scripts/ci/gitlab/pipeline/check.yml - # tests jobs - - scripts/ci/gitlab/pipeline/test.yml - # build jobs - - scripts/ci/gitlab/pipeline/build.yml - # publish jobs - - scripts/ci/gitlab/pipeline/publish.yml - # zombienet jobs - - scripts/ci/gitlab/pipeline/zombienet.yml - # The crate-publishing pipeline requires a customized `interruptible` configuration. Unfortunately - # `interruptible` can't currently be dynamically set based on variables as per: - # - https://gitlab.com/gitlab-org/gitlab/-/issues/38349 - # - https://gitlab.com/gitlab-org/gitlab/-/issues/194023 - # Thus we work around that limitation by using conditional includes. - # For crate-publishing pipelines: run it with defaults + `interruptible: false`. The WHOLE - # pipeline is made uninterruptible to ensure that test jobs also get a chance to run to - # completion, because the publishing jobs depends on them AS INTENDED: crates should not be - # published before their source code is checked. - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/timestamp.yml - - project: parity/infrastructure/ci_cd/shared - ref: main - file: /common/ci-unified.yml - - -#### stage: notify - -# This job notifies rusty-cachier about the latest commit with the cache. -# This info is later used for the cache distribution and an overlay creation. -# Note that we don't use any .rusty-cachier references as we assume that a pipeline has reached this stage with working rusty-cachier. -rusty-cachier-notify: - stage: notify - extends: .kubernetes-env - variables: - CI_IMAGE: paritytech/rusty-cachier-env:latest - GIT_STRATEGY: none - dependencies: [] - script: - - curl -s https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.parity.io/parity/infrastructure/ci_cd/rusty-cachier/client/-/raw/release/util/install.sh | bash - - rusty-cachier cache notify - -#### stage: .post - -# This job cancels the whole pipeline if any of provided jobs fail. -# In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests -# to fail the pipeline as soon as possible to shorten the feedback loop. -.cancel-pipeline-template: - stage: .post - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - when: on_failure - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "${FAILED_JOB_URL}" - FAILED_JOB_NAME: "${FAILED_JOB_NAME}" - PR_NUM: "${PR_NUM}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" - -remove-cancel-pipeline-message: - stage: .post - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "https://gitlab.com" - FAILED_JOB_NAME: "nope" - PR_NUM: "${CI_COMMIT_REF_NAME}" - trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" - branch: "as-improve" - -# need to copy jobs this way because otherwise gitlab will wait -# for all 3 jobs to finish instead of cancelling if one fails -cancel-pipeline-test-linux-stable1: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 1/3" - -cancel-pipeline-test-linux-stable2: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 2/3" - -cancel-pipeline-test-linux-stable3: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 3/3" - -cancel-pipeline-cargo-check-benches1: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-benches 1/2" - -cancel-pipeline-cargo-check-benches2: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-benches 2/2" - -cancel-pipeline-test-linux-stable-int: - extends: .cancel-pipeline-template - needs: - - job: test-linux-stable-int - -cancel-pipeline-cargo-check-each-crate-1: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 1/2" - -cancel-pipeline-cargo-check-each-crate-2: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 2/2" - -cancel-pipeline-cargo-check-each-crate-macos: - extends: .cancel-pipeline-template - needs: - - job: cargo-check-each-crate-macos - -cancel-pipeline-check-tracing: - extends: .cancel-pipeline-template - needs: - - job: check-tracing diff --git a/substrate/.maintain/init.sh b/substrate/.maintain/init.sh deleted file mode 100755 index 1405a41ef333e6af863080d83f854d3edb5fb4fa..0000000000000000000000000000000000000000 --- a/substrate/.maintain/init.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo "*** Initializing WASM build environment" - -if [ -z $CI_PROJECT_NAME ] ; then - rustup update nightly - rustup update stable -fi - -rustup target add wasm32-unknown-unknown --toolchain nightly diff --git a/substrate/.maintain/update-rust-stable.sh b/substrate/.maintain/update-rust-stable.sh deleted file mode 100755 index b253bb4105313c6663948e55ee826dff3059d22d..0000000000000000000000000000000000000000 --- a/substrate/.maintain/update-rust-stable.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -# -# Script for updating the UI tests for a new rust stable version. -# -# It needs to be called like this: -# -# update-rust-stable.sh 1.61 -# -# This will run all UI tests with the rust stable 1.61. The script -# requires that rustup is installed. -set -e - -if [ "$#" -ne 1 ]; then - echo "Please specify the rust version to use. E.g. update-rust-stable.sh 1.61" - exit -fi - -RUST_VERSION=$1 - -if ! command -v rustup &> /dev/null -then - echo "rustup needs to be installed" - exit -fi - -rustup install $RUST_VERSION -rustup component add rust-src --toolchain $RUST_VERSION - -# Ensure we run the ui tests -export RUN_UI_TESTS=1 -# We don't need any wasm files for ui tests -export SKIP_WASM_BUILD=1 -# Let trybuild overwrite the .stderr files -export TRYBUILD=overwrite - -# Run all the relevant UI tests -# -# Any new UI tests in different crates need to be added here as well. -rustup run $RUST_VERSION cargo test -p sp-runtime-interface ui -rustup run $RUST_VERSION cargo test -p sp-api-test ui -rustup run $RUST_VERSION cargo test -p frame-election-provider-solution-type ui -rustup run $RUST_VERSION cargo test -p frame-support-test ui diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..d77f02c60603150ce2627ae5594d1fc96d1bfac8 --- /dev/null +++ b/substrate/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "substrate" +description = "Next-generation framework for blockchain innovation" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository.workspace = true +authors.workspace = true +edition.workspace = true +version = "1.0.0" + +# The dependencies are only needed for docs. +[dependencies] +aquamarine = "0.3.2" + +subkey = { path = "bin/utils/subkey" } +chain-spec-builder = { path = "bin/utils/chain-spec-builder" } + +sc-service = { path = "client/service" } +sc-cli = { path = "client/cli" } +sc-consensus-aura = { path = "client/consensus/aura" } +sc-consensus-babe = { path = "client/consensus/babe" } +sc-consensus-grandpa = { path = "client/consensus/grandpa" } +sc-consensus-beefy = { path = "client/consensus/beefy" } +sc-consensus-manual-seal = { path = "client/consensus/manual-seal" } +sc-consensus-pow = { path = "client/consensus/pow" } + +sp-runtime = { path = "primitives/runtime" } +frame-support = { path = "frame/support" } diff --git a/substrate/bin/node-template/README.md b/substrate/bin/node-template/README.md index a07328df88c1bf86907bee784474907a17cf6bc8..6390c9524ce185f7cda7679b874f532694d34a0b 100644 --- a/substrate/bin/node-template/README.md +++ b/substrate/bin/node-template/README.md @@ -7,12 +7,12 @@ in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) repository. The parachain template is generated directly at each Polkadot release branch from the [Node Template in -Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) +Substrate](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template) upstream It is usually best to use the stand-alone version to start a new project. All bugs, suggestions, and feature requests should be made upstream in the -[Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) +[Substrate](https://github.com/paritytech/polkadot-sdk/tree/master/substrate) repository. ## Getting Started @@ -186,7 +186,7 @@ template and note the following: The runtime in this project is constructed using many FRAME pallets that ship with [the Substrate -repository](https://github.com/paritytech/substrate/tree/master/frame) and a +repository](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame) and a template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. @@ -221,5 +221,5 @@ the correct dependencies, activate direnv `direnv allow`. ### Docker Please follow the [Substrate Docker instructions -here](https://github.com/paritytech/substrate/blob/master/docker/README.md) to +here](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/docker/README.md) to build the Docker container with the Substrate Node Template binary. diff --git a/substrate/bin/node-template/docs/rust-setup.md b/substrate/bin/node-template/docs/rust-setup.md index 38fddd5026bb0d81a38929ed1f1267b310cc0d73..00089ab6a061360b0d35d31e42fb7ec0e7ae4abd 100644 --- a/substrate/bin/node-template/docs/rust-setup.md +++ b/substrate/bin/node-template/docs/rust-setup.md @@ -179,7 +179,7 @@ If you want to guarantee that your build works on your computer as you update Ru use a specific Rust nightly version that is known to be compatible with the version of Substrate they are using; this version will vary from project to project and different projects may use different mechanisms to communicate this version to developers. For instance, the Polkadot client specifies this information in its [release -notes](https://github.com/paritytech/polkadot/releases). +notes](https://github.com/paritytech/polkadot-sdk/releases). ```bash # Specify the specific nightly toolchain in the date below: diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index b510ed34c23a643675e005712d359ca355b73f5b..23840cce2229ba0b83057584fa6657f8424f5c8a 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"]} sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 65d0cfca59c418baaf1bd3d57013f3c6108c2cf7..eb3ff37b425fb491aa4ea5ccd3e705dbc332ae16 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -39,6 +39,7 @@ sp-std = { path = "../../../primitives/std", default-features = false} sp-storage = { path = "../../../primitives/storage", default-features = false} sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false} sp-version = { path = "../../../primitives/version", default-features = false} +sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } # Used for the node template's RPCs frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", default-features = false} @@ -79,6 +80,7 @@ std = [ "sp-consensus-aura/std", "sp-consensus-grandpa/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-offchain/std", "sp-runtime/std", diff --git a/substrate/bin/node-template/runtime/src/lib.rs b/substrate/bin/node-template/runtime/src/lib.rs index 216be9588bca1ad936a4a5941a24c100b79e22e6..4653b49bf2c344c6cd433a5881565488a0d50fa9 100644 --- a/substrate/bin/node-template/runtime/src/lib.rs +++ b/substrate/bin/node-template/runtime/src/lib.rs @@ -23,6 +23,7 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use frame_support::genesis_builder_helper::{build_config, create_default_config}; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, @@ -571,4 +572,14 @@ impl_runtime_apis! { Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } diff --git a/substrate/bin/node-template/scripts/init.sh b/substrate/bin/node-template/scripts/init.sh deleted file mode 100755 index f976f7235d700c8f2e5064bd638ff9fb4d7ff48b..0000000000000000000000000000000000000000 --- a/substrate/bin/node-template/scripts/init.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -# This script is meant to be run on Unix/Linux based systems -set -e - -echo "*** Initializing WASM build environment" - -if [ -z $CI_PROJECT_NAME ] ; then - rustup update nightly - rustup update stable -fi - -rustup target add wasm32-unknown-unknown --toolchain nightly diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 05c13e312b213f1c0b0fedf8bb23849f1c32aa88..c111d345623d584c2748d7659bc034e1a66e6087 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -13,7 +13,7 @@ publish = false [dependencies] array-bytes = "6.1" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index f14f89fcd3ab2da9aab235a89606730295b30666..23d0a0cc1ee5e1974e7394e841837e074ae04fc4 100644 --- a/substrate/bin/node/bench/src/construct.rs +++ b/substrate/bin/node/bench/src/construct.rs @@ -35,7 +35,7 @@ use sc_transaction_pool_api::{ }; use sp_consensus::{Environment, Proposer}; use sp_inherents::InherentDataProvider; -use sp_runtime::{generic::BlockId, traits::NumberFor, OpaqueExtrinsic}; +use sp_runtime::{traits::NumberFor, OpaqueExtrinsic}; use crate::{ common::SizeType, @@ -233,7 +233,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { /// Returns a future that imports a bunch of unverified transactions to the pool. fn submit_at( &self, - _at: &BlockId, + _at: Self::Hash, _source: TransactionSource, _xts: Vec>, ) -> PoolFuture>, Self::Error> { @@ -243,7 +243,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { /// Returns a future that imports one unverified transaction to the pool. fn submit_one( &self, - _at: &BlockId, + _at: Self::Hash, _source: TransactionSource, _xt: TransactionFor, ) -> PoolFuture, Self::Error> { @@ -252,7 +252,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { fn submit_and_watch( &self, - _at: &BlockId, + _at: Self::Hash, _source: TransactionSource, _xt: TransactionFor, ) -> PoolFuture>>, Self::Error> { diff --git a/substrate/bin/node/bench/src/txpool.rs b/substrate/bin/node/bench/src/txpool.rs index a3524ac5bc8901be636e23c2cc666feb7cfb460d..e56bb559a7b555f192f552e750d20f2313a2a0a9 100644 --- a/substrate/bin/node/bench/src/txpool.rs +++ b/substrate/bin/node/bench/src/txpool.rs @@ -27,7 +27,6 @@ use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes}; use sc_transaction_pool::BasicPool; use sc_transaction_pool_api::{TransactionPool, TransactionSource}; -use sp_runtime::generic::BlockId; use crate::core::{self, Mode, Path}; @@ -58,10 +57,11 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription { impl core::Benchmark for PoolBenchmark { fn run(&mut self, mode: Mode) -> std::time::Duration { let context = self.database.create_context(); + let genesis_hash = context.client.chain_info().genesis_hash; let _ = context .client - .runtime_version_at(context.client.chain_info().genesis_hash) + .runtime_version_at(genesis_hash) .expect("Failed to get runtime version") .spec_version; @@ -90,7 +90,7 @@ impl core::Benchmark for PoolBenchmark { let start = std::time::Instant::now(); let submissions = generated_transactions .into_iter() - .map(|tx| txpool.submit_one(&BlockId::Number(0), TransactionSource::External, tx)); + .map(|tx| txpool.submit_one(genesis_hash, TransactionSource::External, tx)); futures::executor::block_on(futures::future::join_all(submissions)); let elapsed = start.elapsed(); diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 84d8de11a35f974dc025413a8cb98d56a9f9fe3f..49dc39099be03b9470d712245c8d3642c3d8aaaa 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -38,7 +38,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.4.3", features = ["derive"], optional = true } +clap = { version = "4.4.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { version = "1.0.188", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } @@ -60,6 +60,7 @@ sp-keystore = { path = "../../../primitives/keystore" } sp-consensus = { path = "../../../primitives/consensus/common" } sp-transaction-storage-proof = { path = "../../../primitives/transaction-storage-proof" } sp-io = { path = "../../../primitives/io" } +sp-mixnet = { path = "../../../primitives/mixnet" } sp-statement-store = { path = "../../../primitives/statement-store" } # client dependencies @@ -82,6 +83,7 @@ sc-service = { path = "../../../client/service", default-features = false} sc-telemetry = { path = "../../../client/telemetry" } sc-executor = { path = "../../../client/executor" } sc-authority-discovery = { path = "../../../client/authority-discovery" } +sc-mixnet = { path = "../../../client/mixnet" } sc-sync-state-rpc = { path = "../../../client/sync-state-rpc" } sc-sysinfo = { path = "../../../client/sysinfo" } sc-storage-monitor = { path = "../../../client/storage-monitor" } @@ -135,7 +137,7 @@ pallet-timestamp = { path = "../../../frame/timestamp" } substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] -clap = { version = "4.4.3", optional = true } +clap = { version = "4.4.6", optional = true } clap_complete = { version = "4.0.2", optional = true } node-inspect = { path = "../inspect", optional = true} frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true} diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index b877aa7350228ca7b0d2a766ba9aba0e8b96b71c..246de8f3e925df6e3d91994af1467975a1669f4c 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -100,7 +100,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { wasm_runtime_overrides: None, }; - node_cli::service::new_full_base(config, false, |_, _| ()) + node_cli::service::new_full_base(config, None, false, |_, _| ()) .expect("creating a full node doesn't fail") } diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index d3e8c02a958f7e3379c199c64653d53fe3230429..47f890574151d8f8023f901cacd6832d0dea69e5 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -34,7 +34,7 @@ use sc_transaction_pool::PoolLimit; use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; use sp_core::{crypto::Pair, sr25519}; use sp_keyring::Sr25519Keyring; -use sp_runtime::{generic::BlockId, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use tokio::runtime::Handle; fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { @@ -96,7 +96,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { wasm_runtime_overrides: None, }; - node_cli::service::new_full_base(config, false, |_, _| ()).expect("Creates node") + node_cli::service::new_full_base(config, None, false, |_, _| ()).expect("Creates node") } fn create_accounts(num: usize) -> Vec { @@ -191,7 +191,7 @@ async fn submit_tx_and_wait_for_inclusion( let best_hash = client.chain_info().best_hash; let mut watch = tx_pool - .submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone()) + .submit_and_watch(best_hash, TransactionSource::External, tx.clone()) .await .expect("Submits tx to pool") .fuse(); diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 51beaad03688a7db72830094b821ad4f27276078..52b480925aa941895397538081f25c0680d9bc7e 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -33,6 +33,7 @@ use serde::{Deserialize, Serialize}; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public}; +use sp_mixnet::types::AuthorityId as MixnetId; use sp_runtime::{ traits::{IdentifyAccount, Verify}, Perbill, @@ -72,8 +73,9 @@ fn session_keys( babe: BabeId, im_online: ImOnlineId, authority_discovery: AuthorityDiscoveryId, + mixnet: MixnetId, ) -> SessionKeys { - SessionKeys { grandpa, babe, im_online, authority_discovery } + SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet } } fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { @@ -93,6 +95,7 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { BabeId, ImOnlineId, AuthorityDiscoveryId, + MixnetId, )> = vec![ ( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy @@ -111,6 +114,9 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), + // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") + .unchecked_into(), ), ( // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 @@ -129,6 +135,9 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), + // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") + .unchecked_into(), ), ( // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp @@ -147,6 +156,9 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), + // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") + .unchecked_into(), ), ( // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 @@ -165,6 +177,9 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig { // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), + // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") + .unchecked_into(), ), ]; @@ -217,7 +232,7 @@ where /// Helper function to generate stash, controller and session key from seed. pub fn authority_keys_from_seed( seed: &str, -) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId) { +) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId) { ( get_account_id_from_seed::(&format!("{}//stash", seed)), get_account_id_from_seed::(seed), @@ -225,6 +240,7 @@ pub fn authority_keys_from_seed( get_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), + get_from_seed::(seed), ) } @@ -237,6 +253,7 @@ pub fn testnet_genesis( BabeId, ImOnlineId, AuthorityDiscoveryId, + MixnetId, )>, initial_nominators: Vec, root_key: AccountId, @@ -306,7 +323,13 @@ pub fn testnet_genesis( ( x.0.clone(), x.0.clone(), - session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()), + session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + ), ) }) .collect::>(), @@ -367,6 +390,7 @@ pub fn testnet_genesis( ..Default::default() }, glutton: Default::default(), + mixnet: Default::default(), } } @@ -475,7 +499,7 @@ pub(crate) mod tests { sc_service_test::connectivity(integration_test_config_with_two_authorities(), |config| { let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = - new_full_base(config, false, |_, _| ())?; + new_full_base(config, None, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index 4e0d6303870cba960ee42f77ed105c1021cbb380..f3c0435fd32dcaa71f9f94b78dcae01ff07c8b81 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -27,6 +27,10 @@ pub struct Cli { #[clap(flatten)] pub run: sc_cli::RunCmd, + #[allow(missing_docs)] + #[clap(flatten)] + pub mixnet_params: sc_cli::MixnetParams, + /// Disable automatic hardware benchmarks. /// /// By default these benchmarks are automatically ran at startup and measure diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 8fb413dba17780fd17a07bc47bc722ab833d98c2..16d0415ff2637fe4f613cb302bec81a7966224e8 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -50,7 +50,7 @@ impl SubstrateCli for Cli { } fn support_url() -> String { - "https://github.com/paritytech/substrate/issues/new".into() + "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { @@ -111,7 +111,7 @@ pub fn run() -> Result<()> { }, BenchmarkCmd::Block(cmd) => { // ensure that we keep the task manager alive - let partial = new_partial(&config)?; + let partial = new_partial(&config, None)?; cmd.run(partial.client) }, #[cfg(not(feature = "runtime-benchmarks"))] @@ -122,7 +122,7 @@ pub fn run() -> Result<()> { #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => { // ensure that we keep the task manager alive - let partial = new_partial(&config)?; + let partial = new_partial(&config, None)?; let db = partial.backend.expose_db(); let storage = partial.backend.expose_storage(); @@ -130,7 +130,7 @@ pub fn run() -> Result<()> { }, BenchmarkCmd::Overhead(cmd) => { // ensure that we keep the task manager alive - let partial = new_partial(&config)?; + let partial = new_partial(&config, None)?; let ext_builder = RemarkBuilder::new(partial.client.clone()); cmd.run( @@ -143,7 +143,7 @@ pub fn run() -> Result<()> { }, BenchmarkCmd::Extrinsic(cmd) => { // ensure that we keep the task manager alive - let partial = service::new_partial(&config)?; + let partial = service::new_partial(&config, None)?; // Register the *Remark* and *TKA* builders. let ext_factory = ExtrinsicFactory(vec![ Box::new(RemarkBuilder::new(partial.client.clone())), @@ -178,21 +178,21 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, import_queue, .. } = - new_partial(&config)?; + new_partial(&config, None)?; Ok((cmd.run(client, import_queue), task_manager)) }) }, Some(Subcommand::ExportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { client, task_manager, .. } = new_partial(&config)?; + let PartialComponents { client, task_manager, .. } = new_partial(&config, None)?; Ok((cmd.run(client, config.database), task_manager)) }) }, Some(Subcommand::ExportState(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { client, task_manager, .. } = new_partial(&config)?; + let PartialComponents { client, task_manager, .. } = new_partial(&config, None)?; Ok((cmd.run(client, config.chain_spec), task_manager)) }) }, @@ -200,7 +200,7 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, import_queue, .. } = - new_partial(&config)?; + new_partial(&config, None)?; Ok((cmd.run(client, import_queue), task_manager)) }) }, @@ -211,7 +211,8 @@ pub fn run() -> Result<()> { Some(Subcommand::Revert(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; + let PartialComponents { client, task_manager, backend, .. } = + new_partial(&config, None)?; let aux_revert = Box::new(|client: Arc, backend, blocks| { sc_consensus_babe::revert(client.clone(), backend, blocks)?; grandpa::revert(client, blocks)?; diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 977c90e73e9ff0217ba8fb34cbd78be28a83092a..5a85f4cde0ae0ac22c4edecec32691d9b781e877 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -134,6 +134,7 @@ pub fn create_extrinsic( /// Creates a new partial node. pub fn new_partial( config: &Configuration, + mixnet_config: Option<&sc_mixnet::Config>, ) -> Result< sc_service::PartialComponents< FullClient, @@ -154,6 +155,7 @@ pub fn new_partial( grandpa::SharedVoterState, Option, Arc, + Option, ), >, ServiceError, @@ -246,6 +248,8 @@ pub fn new_partial( ) .map_err(|e| ServiceError::Other(format!("Statement store error: {:?}", e)))?; + let (mixnet_api, mixnet_api_backend) = mixnet_config.map(sc_mixnet::Api::new).unzip(); + let (rpc_extensions_builder, rpc_setup) = { let (_, grandpa_link, _) = &import_setup; @@ -287,6 +291,7 @@ pub fn new_partial( }, statement_store: rpc_statement_store.clone(), backend: rpc_backend.clone(), + mixnet_api: mixnet_api.as_ref().cloned(), }; node_rpc::create_full(deps).map_err(Into::into) @@ -303,7 +308,14 @@ pub fn new_partial( select_chain, import_queue, transaction_pool, - other: (rpc_extensions_builder, import_setup, rpc_setup, telemetry, statement_store), + other: ( + rpc_extensions_builder, + import_setup, + rpc_setup, + telemetry, + statement_store, + mixnet_api_backend, + ), }) } @@ -326,6 +338,7 @@ pub struct NewFullBase { /// Creates a full service from the configuration. pub fn new_full_base( config: Configuration, + mixnet_config: Option, disable_hardware_benchmarks: bool, with_startup_data: impl FnOnce( &sc_consensus_babe::BabeBlockImport, @@ -347,31 +360,36 @@ pub fn new_full_base( keystore_container, select_chain, transaction_pool, - other: (rpc_builder, import_setup, rpc_setup, mut telemetry, statement_store), - } = new_partial(&config)?; + other: + (rpc_builder, import_setup, rpc_setup, mut telemetry, statement_store, mixnet_api_backend), + } = new_partial(&config, mixnet_config.as_ref())?; let shared_voter_state = rpc_setup; let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; let mut net_config = sc_network::config::FullNetworkConfiguration::new(&config.network); - let grandpa_protocol_name = grandpa::protocol_standard_name( - &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), - &config.chain_spec, - ); + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + + let grandpa_protocol_name = grandpa::protocol_standard_name(&genesis_hash, &config.chain_spec); net_config.add_notification_protocol(grandpa::grandpa_peers_set_config( grandpa_protocol_name.clone(), )); let statement_handler_proto = sc_network_statement::StatementHandlerPrototype::new( - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), + genesis_hash, config.chain_spec.fork_id(), ); net_config.add_notification_protocol(statement_handler_proto.set_config()); + let mixnet_protocol_name = + sc_mixnet::protocol_name(genesis_hash.as_ref(), config.chain_spec.fork_id()); + if let Some(mixnet_config) = &mixnet_config { + net_config.add_notification_protocol(sc_mixnet::peers_set_config( + mixnet_protocol_name.clone(), + mixnet_config, + )); + } + let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), import_setup.1.shared_authority_set().clone(), @@ -391,6 +409,20 @@ pub fn new_full_base( block_relay: None, })?; + if let Some(mixnet_config) = mixnet_config { + let mixnet = sc_mixnet::run( + mixnet_config, + mixnet_api_backend.expect("Mixnet API backend created if mixnet enabled"), + client.clone(), + sync_service.clone(), + network.clone(), + mixnet_protocol_name, + transaction_pool.clone(), + Some(keystore_container.keystore()), + ); + task_manager.spawn_handle().spawn("mixnet", None, mixnet); + } + let role = config.role.clone(); let force_authoring = config.force_authoring; let backoff_authoring_blocks = @@ -546,7 +578,7 @@ pub fn new_full_base( // and vote data availability than the observer. The observer has not // been tested extensively yet and having most nodes in a network run it // could lead to finality stalls. - let grandpa_config = grandpa::GrandpaParams { + let grandpa_params = grandpa::GrandpaParams { config: grandpa_config, link: grandpa_link, network: network.clone(), @@ -563,7 +595,7 @@ pub fn new_full_base( task_manager.spawn_essential_handle().spawn_blocking( "grandpa-voter", None, - grandpa::run_grandpa_voter(grandpa_config)?, + grandpa::run_grandpa_voter(grandpa_params)?, ); } @@ -623,8 +655,9 @@ pub fn new_full_base( /// Builds a new service for a full client. pub fn new_full(config: Configuration, cli: Cli) -> Result { + let mixnet_config = cli.mixnet_params.config(config.role.is_authority()); let database_source = config.database.clone(); - let task_manager = new_full_base(config, cli.no_hardware_benchmarks, |_, _| ()) + let task_manager = new_full_base(config, mixnet_config, cli.no_hardware_benchmarks, |_, _| ()) .map(|NewFullBase { task_manager, .. }| task_manager)?; sc_storage_monitor::StorageMonitorService::try_spawn( @@ -702,6 +735,7 @@ mod tests { let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = new_full_base( config, + None, false, |block_import: &sc_consensus_babe::BabeBlockImport, babe_link: &sc_consensus_babe::BabeLink| { @@ -876,7 +910,7 @@ mod tests { crate::chain_spec::tests::integration_test_config_with_two_authorities(), |config| { let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = - new_full_base(config, false, |_, _| ())?; + new_full_base(config, None, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, diff --git a/substrate/bin/node/executor/tests/submit_transaction.rs b/substrate/bin/node/executor/tests/submit_transaction.rs index 7678a3c6e5a9fc9e7d0060bd57a5de0239fc3129..5cbb0103d471b96902bb341bcd796e6cf09eac76 100644 --- a/substrate/bin/node/executor/tests/submit_transaction.rs +++ b/substrate/bin/node/executor/tests/submit_transaction.rs @@ -239,7 +239,7 @@ fn submitted_transaction_should_be_valid() { let author = extrinsic.signature.clone().unwrap().0; let address = Indices::lookup(author).unwrap(); let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; - let account = frame_system::AccountInfo { data, ..Default::default() }; + let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() }; >::insert(&address, account); // check validity diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index f28ceb459571255f4f70046cb9786fc3af4bf302..4a92db2918589da64edbeef74ca1f04bb620a354 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index ec8d16bd27ded50a577ba41eaeae25492afa595d..43db4ab9d34f709c43809e5bf909b979eebba6c5 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -23,6 +23,7 @@ sc-consensus-babe = { path = "../../../client/consensus/babe" } sc-consensus-babe-rpc = { path = "../../../client/consensus/babe/rpc" } sc-consensus-grandpa = { path = "../../../client/consensus/grandpa" } sc-consensus-grandpa-rpc = { path = "../../../client/consensus/grandpa/rpc" } +sc-mixnet = { path = "../../../client/mixnet" } sc-rpc = { path = "../../../client/rpc" } sc-rpc-api = { path = "../../../client/rpc-api" } sc-rpc-spec-v2 = { path = "../../../client/rpc-spec-v2" } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 6d8aa5ff0a9da9f33c2ac3123d108ccffe98571b..acc58777e912d546b337dc4ca8a664095a8c33a7 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -92,6 +92,8 @@ pub struct FullDeps { pub statement_store: Arc, /// The backend used by the node. pub backend: Arc, + /// Mixnet API. + pub mixnet_api: Option, } /// Instantiate all Full RPC extensions. @@ -106,6 +108,7 @@ pub fn create_full( grandpa, statement_store, backend, + mixnet_api, }: FullDeps, ) -> Result, Box> where @@ -133,6 +136,7 @@ where use sc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer}; use sc_rpc::{ dev::{Dev, DevApiServer}, + mixnet::MixnetApiServer, statement::StatementApiServer, }; use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer}; @@ -196,5 +200,10 @@ where sc_rpc::statement::StatementStore::new(statement_store, deny_unsafe).into_rpc(); io.merge(statement_store)?; + if let Some(mixnet_api) = mixnet_api { + let mixnet = sc_rpc::mixnet::Mixnet::new(mixnet_api).into_rpc(); + io.merge(mixnet)?; + } + Ok(io) } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 09c1fd9c6f315888a54c65b066a5850a7e11a2b8..e356a7b6024df346e283d70bdde696b09d89211e 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -32,8 +32,10 @@ sp-authority-discovery = { path = "../../../primitives/authority-discovery", def sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false} sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false} sp-block-builder = { path = "../../../primitives/block-builder", default-features = false} +sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" } sp-inherents = { path = "../../../primitives/inherents", default-features = false} node-primitives = { path = "../primitives", default-features = false} +sp-mixnet = { path = "../../../primitives/mixnet", default-features = false } sp-offchain = { path = "../../../primitives/offchain", default-features = false} sp-core = { path = "../../../primitives/core", default-features = false} sp-std = { path = "../../../primitives/std", default-features = false} @@ -87,6 +89,7 @@ pallet-identity = { path = "../../../frame/identity", default-features = false} pallet-lottery = { path = "../../../frame/lottery", default-features = false} pallet-membership = { path = "../../../frame/membership", default-features = false} pallet-message-queue = { path = "../../../frame/message-queue", default-features = false} +pallet-mixnet = { path = "../../../frame/mixnet", default-features = false } pallet-mmr = { path = "../../../frame/merkle-mountain-range", default-features = false} pallet-multisig = { path = "../../../frame/multisig", default-features = false} pallet-nfts = { path = "../../../frame/nfts", default-features = false} @@ -184,6 +187,7 @@ std = [ "pallet-lottery/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-mixnet/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nft-fractionalization/std", @@ -231,8 +235,10 @@ std = [ "sp-consensus-babe/std", "sp-consensus-grandpa/std", "sp-core/std", + "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-mixnet/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -279,6 +285,7 @@ runtime-benchmarks = [ "pallet-lottery/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-mixnet/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nft-fractionalization/runtime-benchmarks", @@ -352,6 +359,7 @@ try-runtime = [ "pallet-lottery/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-mixnet/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nft-fractionalization/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index df8fb06467d99dd74a5b749e66263170c34a3607..2070e3f12d04fd49419f5da032b125f28b6ff4a4 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -30,13 +30,14 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, instances::{Instance1, Instance2}, ord_parameter_types, pallet_prelude::Get, parameter_types, traits::{ fungible::{Balanced, Credit, HoldConsideration, ItemOf}, - tokens::{nonfungibles_v2::Inspect, GetSalary, PayFromAccount}, + tokens::{nonfungibles_v2::Inspect, pay::PayAssetFromAccount, GetSalary, PayFromAccount}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency, EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced, @@ -520,8 +521,8 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type WeightInfo = pallet_balances::weights::SubstrateWeight; - type FreezeIdentifier = (); - type MaxFreezes = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = RuntimeHoldReason; type MaxHolds = ConstU32<2>; } @@ -588,6 +589,7 @@ impl_opaque_keys! { pub babe: Babe, pub im_online: ImOnline, pub authority_discovery: AuthorityDiscovery, + pub mixnet: Mixnet, } } @@ -881,6 +883,7 @@ impl pallet_nomination_pools::Config for Runtime { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; @@ -1046,7 +1049,7 @@ impl pallet_democracy::Config for Runtime { pallet_collective::EnsureProportionAtLeast; type InstantOrigin = pallet_collective::EnsureProportionAtLeast; - type InstantAllowed = frame_support::traits::ConstBool; + type InstantAllowed = ConstBool; type FastTrackVotingPeriod = FastTrackVotingPeriod; // To cancel a proposal which has been passed, 2/3 of the council must agree to it. type CancellationOrigin = @@ -1184,6 +1187,7 @@ parameter_types! { pub const MaximumReasonLength: u32 = 300; pub const MaxApprovals: u32 = 100; pub const MaxBalance: Balance = Balance::max_value(); + pub const SpendPayoutPeriod: BlockNumber = 30 * DAYS; } impl pallet_treasury::Config for Runtime { @@ -1209,6 +1213,14 @@ impl pallet_treasury::Config for Runtime { type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; + type AssetKind = u32; + type Beneficiary = AccountId; + type BeneficiaryLookup = Indices; + type Paymaster = PayAssetFromAccount; + type BalanceConverter = AssetRate; + type PayoutPeriod = SpendPayoutPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_asset_rate::Config for Runtime { @@ -1288,6 +1300,7 @@ impl pallet_tips::Config for Runtime { type TipCountdown = TipCountdown; type TipFindersFee = TipFindersFee; type TipReportDepositBase = TipReportDepositBase; + type MaxTipAmount = ConstU128<{ 500 * DOLLARS }>; type WeightInfo = pallet_tips::weights::SubstrateWeight; } @@ -2016,6 +2029,29 @@ impl pallet_broker::Config for Runtime { type PriceAdapter = pallet_broker::Linear; } +parameter_types! { + pub const MixnetNumCoverToCurrentBlocks: BlockNumber = 3; + pub const MixnetNumRequestsToCurrentBlocks: BlockNumber = 3; + pub const MixnetNumCoverToPrevBlocks: BlockNumber = 3; + pub const MixnetNumRegisterStartSlackBlocks: BlockNumber = 3; + pub const MixnetNumRegisterEndSlackBlocks: BlockNumber = 3; + pub const MixnetRegistrationPriority: TransactionPriority = ImOnlineUnsignedPriority::get() - 1; +} + +impl pallet_mixnet::Config for Runtime { + type MaxAuthorities = MaxAuthorities; + type MaxExternalAddressSize = ConstU32<128>; + type MaxExternalAddressesPerMixnode = ConstU32<16>; + type NextSessionRotation = Babe; + type NumCoverToCurrentBlocks = MixnetNumCoverToCurrentBlocks; + type NumRequestsToCurrentBlocks = MixnetNumRequestsToCurrentBlocks; + type NumCoverToPrevBlocks = MixnetNumCoverToPrevBlocks; + type NumRegisterStartSlackBlocks = MixnetNumRegisterStartSlackBlocks; + type NumRegisterEndSlackBlocks = MixnetNumRegisterEndSlackBlocks; + type RegistrationPriority = MixnetRegistrationPriority; + type MinMixnodes = ConstU32<7>; // Low to allow small testing networks +} + construct_runtime!( pub struct Runtime { @@ -2092,6 +2128,7 @@ construct_runtime!( SafeMode: pallet_safe_mode, Statement: pallet_statement, Broker: pallet_broker, + Mixnet: pallet_mixnet, } ); @@ -2651,6 +2688,24 @@ impl_runtime_apis! { } } + impl sp_mixnet::runtime_api::MixnetApi for Runtime { + fn session_status() -> sp_mixnet::types::SessionStatus { + Mixnet::session_status() + } + + fn prev_mixnodes() -> Result, sp_mixnet::types::MixnodesErr> { + Mixnet::prev_mixnodes() + } + + fn current_mixnodes() -> Result, sp_mixnet::types::MixnodesErr> { + Mixnet::current_mixnodes() + } + + fn maybe_register(session_index: sp_mixnet::types::SessionIndex, mixnode: sp_mixnet::types::Mixnode) -> bool { + Mixnet::maybe_register(session_index, mixnode) + } + } + impl sp_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { SessionKeys::generate(seed) @@ -2750,6 +2805,16 @@ impl_runtime_apis! { Ok(batches) } } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } #[cfg(test)] diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 6e7bcebfc00d180d855479dcb6154ef83dd3d44a..ab5311751a55fe39b994f8131e9131bdd3ae2227 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -109,5 +109,6 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec) -> Run trash_data_count: Default::default(), ..Default::default() }, + mixnet: Default::default(), } } diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index b4b714d9083d60ef5c13688f2c00179216f5a33d..22a8f5deb19f737537227ae21b4c0c20770f7759 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -64,6 +64,7 @@ pub fn to_session_keys( babe: sr25519_keyring.to_owned().public().into(), im_online: sr25519_keyring.to_owned().public().into(), authority_discovery: sr25519_keyring.to_owned().public().into(), + mixnet: sr25519_keyring.to_owned().public().into(), } } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index c626a1612eb120b1bfb8b87690f087bb3247ddca..c7690faf7d065dd941f71aaf7f74d0166f8ee7ce 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -22,7 +22,7 @@ crate-type = ["rlib"] [dependencies] ansi_term = "0.12.1" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } rand = "0.8" node-cli = { path = "../../node/cli" } sc-chain-spec = { path = "../../../client/chain-spec" } diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 528b6b70115a07c3225d52c0bf30a727bf1eebd7..2b88e40ef74fd804a086f83b2903572aef373904 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -179,7 +179,7 @@ pub fn generate_authority_keys_and_store( .map_err(|err| err.to_string())? .into(); - let (_, _, grandpa, babe, im_online, authority_discovery) = + let (_, _, grandpa, babe, im_online, authority_discovery, mixnet) = chain_spec::authority_keys_from_seed(seed); let insert_key = |key_type, public| { @@ -198,6 +198,8 @@ pub fn generate_authority_keys_and_store( sp_core::crypto::key_types::AUTHORITY_DISCOVERY, authority_discovery.as_slice(), )?; + + insert_key(sp_core::crypto::key_types::MIXNET, mixnet.as_slice())?; } Ok(()) diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 8a5f4ec49c54368a7f0cef5512ced66b7f45a561..6606d8ac365f9f9e68805808ef6db62662fbeac5 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index b3a8f0d8970b6148a68abe9abbfa98080a84e4d3..57c2996ab4063143694f3c2b44af93aae74bf775 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -79,7 +79,7 @@ pub struct ProposerFactory { /// The soft deadline indicates where we should stop attempting to add transactions /// to the block, which exhaust resources. After soft deadline is reached, /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS` - /// transactions which exhaust resrouces, we will conclude that the block is full. + /// transactions which exhaust resources, we will conclude that the block is full. soft_deadline_percent: Percent, telemetry: Option, /// When estimating the block size, should the proof be included? @@ -642,8 +642,8 @@ mod tests { client.clone(), ); - block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)])) - .unwrap(); + let hashof0 = client.info().genesis_hash; + block_on(txpool.submit_at(hashof0, SOURCE, vec![extrinsic(0), extrinsic(1)])).unwrap(); block_on( txpool.maintain(chain_event( @@ -658,7 +658,7 @@ mod tests { let cell = Mutex::new((false, time::Instant::now())); let proposer = proposer_factory.init_with_now( - &client.expect_header(client.info().genesis_hash).unwrap(), + &client.expect_header(hashof0).unwrap(), Box::new(move || { let mut value = cell.lock(); if !value.0 { @@ -736,7 +736,7 @@ mod tests { let genesis_hash = client.info().best_hash; - block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap(); + block_on(txpool.submit_at(genesis_hash, SOURCE, vec![extrinsic(0)])).unwrap(); block_on( txpool.maintain(chain_event( @@ -800,7 +800,7 @@ mod tests { }; block_on(txpool.submit_at( - &BlockId::number(0), + client.info().genesis_hash, SOURCE, vec![medium(0), medium(1), huge(2), medium(3), huge(4), medium(5), medium(6)], )) @@ -897,9 +897,8 @@ mod tests { spawner.clone(), client.clone(), ); - let genesis_header = client - .expect_header(client.info().genesis_hash) - .expect("there should be header"); + let genesis_hash = client.info().genesis_hash; + let genesis_header = client.expect_header(genesis_hash).expect("there should be header"); let extrinsics_num = 5; let extrinsics = std::iter::once( @@ -922,7 +921,7 @@ mod tests { .sum::() + Vec::::new().encoded_size(); - block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics.clone())).unwrap(); + block_on(txpool.submit_at(genesis_hash, SOURCE, extrinsics.clone())).unwrap(); block_on(txpool.maintain(chain_event(genesis_header.clone()))); @@ -999,6 +998,7 @@ mod tests { spawner.clone(), client.clone(), ); + let genesis_hash = client.info().genesis_hash; let tiny = |nonce| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)).nonce(nonce).build() @@ -1011,7 +1011,7 @@ mod tests { block_on( txpool.submit_at( - &BlockId::number(0), + genesis_hash, SOURCE, // add 2 * MAX_SKIPPED_TRANSACTIONS that exhaust resources (0..MAX_SKIPPED_TRANSACTIONS * 2) @@ -1024,13 +1024,9 @@ mod tests { ) .unwrap(); - block_on( - txpool.maintain(chain_event( - client - .expect_header(client.info().genesis_hash) - .expect("there should be header"), - )), - ); + block_on(txpool.maintain(chain_event( + client.expect_header(genesis_hash).expect("there should be header"), + ))); assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 3); let mut proposer_factory = @@ -1038,7 +1034,7 @@ mod tests { let cell = Mutex::new(time::Instant::now()); let proposer = proposer_factory.init_with_now( - &client.expect_header(client.info().genesis_hash).unwrap(), + &client.expect_header(genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); let old = *value; @@ -1071,6 +1067,7 @@ mod tests { spawner.clone(), client.clone(), ); + let genesis_hash = client.info().genesis_hash; let tiny = |who| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)) @@ -1086,7 +1083,7 @@ mod tests { block_on( txpool.submit_at( - &BlockId::number(0), + genesis_hash, SOURCE, (0..MAX_SKIPPED_TRANSACTIONS + 2) .into_iter() @@ -1098,13 +1095,9 @@ mod tests { ) .unwrap(); - block_on( - txpool.maintain(chain_event( - client - .expect_header(client.info().genesis_hash) - .expect("there should be header"), - )), - ); + block_on(txpool.maintain(chain_event( + client.expect_header(genesis_hash).expect("there should be header"), + ))); assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 2 + 4); let mut proposer_factory = @@ -1114,7 +1107,7 @@ mod tests { let cell = Arc::new(Mutex::new((0, time::Instant::now()))); let cell2 = cell.clone(); let proposer = proposer_factory.init_with_now( - &client.expect_header(client.info().genesis_hash).unwrap(), + &client.expect_header(genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); let (called, old) = *value; diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index f0ad4c68d1f0b50b35325ad1b7820296d2a2632e..74b8b656a4042bdd348cf2997fa3b9ae686fe2cd 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = "2.0.36" +syn = "2.0.38" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index b781e8782ec7b1d646ce9f15cbb0c2c85cf25145..98928700328fc9837fb6beed721faee473b3f1ba 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4.27" -clap = { version = "4.4.3", features = ["derive", "string"] } +clap = { version = "4.4.6", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" libp2p-identity = { version = "0.1.3", features = ["peerid", "ed25519"]} @@ -33,6 +33,7 @@ tokio = { version = "1.22.0", features = ["signal", "rt-multi-thread", "parking_ sc-client-api = { path = "../api" } sc-client-db = { path = "../db", default-features = false} sc-keystore = { path = "../keystore" } +sc-mixnet = { path = "../mixnet" } sc-network = { path = "../network" } sc-service = { path = "../service", default-features = false} sc-telemetry = { path = "../telemetry" } diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index 67acb82c2c3042fd8eb72f8241ec3e85e1a43688..c55b97675da25d871736d517081280508ce5ed1e 100644 --- a/substrate/client/cli/src/arg_enums.rs +++ b/substrate/client/cli/src/arg_enums.rs @@ -125,7 +125,7 @@ pub enum CryptoScheme { Ed25519, /// Use sr25519. Sr25519, - /// Use + /// Use ecdsa. Ecdsa, } diff --git a/substrate/client/cli/src/commands/inspect_node_key.rs b/substrate/client/cli/src/commands/inspect_node_key.rs index 19b5a31ca12c046ae112e91d1669f796c29909f5..6cf025a2d115066ed18277e4036a028965e3c32f 100644 --- a/substrate/client/cli/src/commands/inspect_node_key.rs +++ b/substrate/client/cli/src/commands/inspect_node_key.rs @@ -85,7 +85,7 @@ mod tests { fn inspect_node_key() { let path = tempfile::tempdir().unwrap().into_path().join("node-id").into_os_string(); let path = path.to_str().unwrap(); - let cmd = GenerateNodeKeyCmd::parse_from(&["generate-node-key", "--file", path.clone()]); + let cmd = GenerateNodeKeyCmd::parse_from(&["generate-node-key", "--file", path]); assert!(cmd.run().is_ok()); diff --git a/substrate/client/cli/src/commands/purge_chain_cmd.rs b/substrate/client/cli/src/commands/purge_chain_cmd.rs index 2ff3d4b9a04c017095180625a1b3c299ab4bd8b8..6e7b8143a5bb7f2a3e4c12dfc032d617a98cadec 100644 --- a/substrate/client/cli/src/commands/purge_chain_cmd.rs +++ b/substrate/client/cli/src/commands/purge_chain_cmd.rs @@ -48,7 +48,7 @@ pub struct PurgeChainCmd { impl PurgeChainCmd { /// Run the purge command pub fn run(&self, database_config: DatabaseSource) -> error::Result<()> { - let db_path = database_config.path().ok_or_else(|| { + let db_path = database_config.path().and_then(|p| p.parent()).ok_or_else(|| { error::Error::Input("Cannot purge custom database implementation".into()) })?; diff --git a/substrate/client/cli/src/commands/utils.rs b/substrate/client/cli/src/commands/utils.rs index ff159909b879c18f6f081021c4e97ed4e8417fdb..fc725f570e5ec2c3011012145bce1d390fa636a9 100644 --- a/substrate/client/cli/src/commands/utils.rs +++ b/substrate/client/cli/src/commands/utils.rs @@ -136,7 +136,7 @@ pub fn print_from_uri( OutputType::Text => { println!( "Secret Key URI `{}` is account:\n \ - Network ID: {} \n \ + Network ID: {}\n \ Secret seed: {}\n \ Public key (hex): {}\n \ Account ID: {}\n \ diff --git a/substrate/client/cli/src/params/mixnet_params.rs b/substrate/client/cli/src/params/mixnet_params.rs new file mode 100644 index 0000000000000000000000000000000000000000..4758a84ec458d6c508d2fe01cec119c6eddcf189 --- /dev/null +++ b/substrate/client/cli/src/params/mixnet_params.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Args; +use sp_core::H256; +use std::str::FromStr; + +fn parse_kx_secret(s: &str) -> Result { + H256::from_str(s).map(H256::to_fixed_bytes).map_err(|err| err.to_string()) +} + +/// Parameters used to create the mixnet configuration. +#[derive(Debug, Clone, Args)] +pub struct MixnetParams { + /// Enable the mixnet service. + /// + /// This will make the mixnet RPC methods available. If the node is running as a validator, it + /// will also attempt to register and operate as a mixnode. + #[arg(long)] + pub mixnet: bool, + + /// The mixnet key-exchange secret to use in session 0. + /// + /// Should be 64 hex characters, giving a 32-byte secret. + /// + /// WARNING: Secrets provided as command-line arguments are easily exposed. Use of this option + /// should be limited to development and testing. + #[arg(long, value_name = "SECRET", value_parser = parse_kx_secret)] + pub mixnet_session_0_kx_secret: Option, +} + +impl MixnetParams { + /// Returns the mixnet configuration, or `None` if the mixnet is disabled. + pub fn config(&self, is_authority: bool) -> Option { + self.mixnet.then(|| { + let mut config = sc_mixnet::Config { + core: sc_mixnet::CoreConfig { + session_0_kx_secret: self.mixnet_session_0_kx_secret, + ..Default::default() + }, + ..Default::default() + }; + if !is_authority { + // Only authorities can be mixnodes; don't attempt to register + config.substrate.register = false; + // Only mixnodes need to allow connections from non-mixnodes + config.substrate.num_gateway_slots = 0; + } + config + }) + } +} diff --git a/substrate/client/cli/src/params/mod.rs b/substrate/client/cli/src/params/mod.rs index a73bd8844fec4200e44fb8fb3cd42bf3d9f5eabf..f07223ec6a73ea93b2b1ae6b76238ed9a45aab50 100644 --- a/substrate/client/cli/src/params/mod.rs +++ b/substrate/client/cli/src/params/mod.rs @@ -19,6 +19,7 @@ mod database_params; mod import_params; mod keystore_params; mod message_params; +mod mixnet_params; mod network_params; mod node_key_params; mod offchain_worker_params; @@ -39,9 +40,10 @@ use sp_runtime::{ use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ - database_params::*, import_params::*, keystore_params::*, message_params::*, network_params::*, - node_key_params::*, offchain_worker_params::*, prometheus_params::*, pruning_params::*, - runtime_params::*, shared_params::*, telemetry_params::*, transaction_pool_params::*, + database_params::*, import_params::*, keystore_params::*, message_params::*, mixnet_params::*, + network_params::*, node_key_params::*, offchain_worker_params::*, prometheus_params::*, + pruning_params::*, runtime_params::*, shared_params::*, telemetry_params::*, + transaction_pool_params::*, }; /// Parse Ss58AddressFormat diff --git a/substrate/client/consensus/beefy/README.md b/substrate/client/consensus/beefy/README.md index d9099dc7c661df409b0240356273bed5f30879ea..1a5a9667fdbb74d9dbd872629b19974ed6b08497 100644 --- a/substrate/client/consensus/beefy/README.md +++ b/substrate/client/consensus/beefy/README.md @@ -159,7 +159,7 @@ ambiguity despite using block number instead of a hash. A collection of **votes* a Commitment and a collection of signatures is going to be called **Signed Commitment**. A valid (see later for the rules) Signed Commitment is also called a **BEEFY Justification** or **BEEFY Finality Proof**. For more details on the actual data structures please see -[BEEFY primitives definitions](https://github.com/paritytech/substrate/tree/master/primitives/beefy/src). +[BEEFY primitives definitions](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/primitives/beefy/src). A **round** is an attempt by BEEFY validators to produce a BEEFY Justification. **Round number** is simply defined as a block number the validators are voting for, or to be more precise, the diff --git a/substrate/client/consensus/beefy/src/communication/gossip.rs b/substrate/client/consensus/beefy/src/communication/gossip.rs index 8c025ca0676197203035d652646a727e89354085..342cd0511a511bc0fc520c438fc23abbbd3a9897 100644 --- a/substrate/client/consensus/beefy/src/communication/gossip.rs +++ b/substrate/client/consensus/beefy/src/communication/gossip.rs @@ -16,11 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeMap, sync::Arc, time::Duration}; +use std::{collections::BTreeSet, sync::Arc, time::Duration}; use sc_network::{PeerId, ReputationChange}; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; -use sp_core::hashing::twox_64; use sp_runtime::traits::{Block, Hash, Header, NumberFor}; use codec::{Decode, DecodeAll, Encode}; @@ -115,9 +114,6 @@ where <::Hashing as Hash>::hash(b"beefy-justifications") } -/// A type that represents hash of the message. -pub type MessageHash = [u8; 8]; - #[derive(Clone, Debug)] pub(crate) struct GossipFilterCfg<'a, B: Block> { pub start: NumberFor, @@ -133,18 +129,21 @@ struct FilterInner { } struct Filter { + // specifies live rounds inner: Option>, - live_votes: BTreeMap, fnv::FnvHashSet>, + // cache of seen valid justifications in active rounds + rounds_with_valid_proofs: BTreeSet>, } impl Filter { pub fn new() -> Self { - Self { inner: None, live_votes: BTreeMap::new() } + Self { inner: None, rounds_with_valid_proofs: BTreeSet::new() } } /// Update filter to new `start` and `set_id`. fn update(&mut self, cfg: GossipFilterCfg) { - self.live_votes.retain(|&round, _| round >= cfg.start && round <= cfg.end); + self.rounds_with_valid_proofs + .retain(|&round| round >= cfg.start && round <= cfg.end); // only clone+overwrite big validator_set if set_id changed match self.inner.as_mut() { Some(f) if f.validator_set.id() == cfg.validator_set.id() => { @@ -203,14 +202,14 @@ impl Filter { .unwrap_or(Consider::RejectOutOfScope) } - /// Add new _known_ `hash` to the round's known votes. - fn add_known_vote(&mut self, round: NumberFor, hash: MessageHash) { - self.live_votes.entry(round).or_default().insert(hash); + /// Add new _known_ `round` to the set of seen valid justifications. + fn mark_round_as_proven(&mut self, round: NumberFor) { + self.rounds_with_valid_proofs.insert(round); } - /// Check if `hash` is already part of round's known votes. - fn is_known_vote(&self, round: NumberFor, hash: &MessageHash) -> bool { - self.live_votes.get(&round).map(|known| known.contains(hash)).unwrap_or(false) + /// Check if `round` is already part of seen valid justifications. + fn is_already_proven(&self, round: NumberFor) -> bool { + self.rounds_with_valid_proofs.contains(&round) } fn validator_set(&self) -> Option<&ValidatorSet> { @@ -273,16 +272,13 @@ where &self, vote: VoteMessage, AuthorityId, Signature>, sender: &PeerId, - data: &[u8], ) -> Action { - let msg_hash = twox_64(data); let round = vote.commitment.block_number; let set_id = vote.commitment.validator_set_id; self.known_peers.lock().note_vote_for(*sender, round); // Verify general usefulness of the message. - // We are going to discard old votes right away (without verification) - // Also we keep track of already received votes to avoid verifying duplicates. + // We are going to discard old votes right away (without verification). { let filter = self.gossip_filter.read(); @@ -293,10 +289,6 @@ where Consider::Accept => {}, } - if filter.is_known_vote(round, &msg_hash) { - return Action::Keep(self.votes_topic, benefit::KNOWN_VOTE_MESSAGE) - } - // ensure authority is part of the set. if !filter .validator_set() @@ -309,7 +301,6 @@ where } if BeefyKeystore::verify(&vote.id, &vote.signature, &vote.commitment.encode()) { - self.gossip_filter.write().add_known_vote(round, msg_hash); Action::Keep(self.votes_topic, benefit::VOTE_MESSAGE) } else { debug!( @@ -328,34 +319,46 @@ where let (round, set_id) = proof_block_num_and_set_id::(&proof); self.known_peers.lock().note_vote_for(*sender, round); - let guard = self.gossip_filter.read(); - // Verify general usefulness of the justification. - match guard.consider_finality_proof(round, set_id) { - Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), - Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), - Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), - Consider::Accept => {}, + let action = { + let guard = self.gossip_filter.read(); + + // Verify general usefulness of the justification. + match guard.consider_finality_proof(round, set_id) { + Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), + Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), + Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), + Consider::Accept => {}, + } + + if guard.is_already_proven(round) { + return Action::Discard(benefit::NOT_INTERESTED) + } + + // Verify justification signatures. + guard + .validator_set() + .map(|validator_set| { + if let Err((_, signatures_checked)) = + verify_with_validator_set::(round, validator_set, &proof) + { + debug!( + target: LOG_TARGET, + "🥩 Bad signatures on message: {:?}, from: {:?}", proof, sender + ); + let mut cost = cost::INVALID_PROOF; + cost.value += + cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); + Action::Discard(cost) + } else { + Action::Keep(self.justifs_topic, benefit::VALIDATED_PROOF) + } + }) + .unwrap_or(Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)) + }; + if matches!(action, Action::Keep(_, _)) { + self.gossip_filter.write().mark_round_as_proven(round); } - // Verify justification signatures. - guard - .validator_set() - .map(|validator_set| { - if let Err((_, signatures_checked)) = - verify_with_validator_set::(round, validator_set, &proof) - { - debug!( - target: LOG_TARGET, - "🥩 Bad signatures on message: {:?}, from: {:?}", proof, sender - ); - let mut cost = cost::INVALID_PROOF; - cost.value += - cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); - Action::Discard(cost) - } else { - Action::Keep(self.justifs_topic, benefit::VALIDATED_PROOF) - } - }) - .unwrap_or(Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)) + action } } @@ -375,7 +378,7 @@ where ) -> ValidationResult { let raw = data; let action = match GossipMessage::::decode_all(&mut data) { - Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender, raw), + Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender), Ok(GossipMessage::FinalityProof(proof)) => self.validate_finality_proof(proof, sender), Err(e) => { debug!(target: LOG_TARGET, "Error decoding message: {}", e); @@ -483,41 +486,6 @@ pub(crate) mod tests { }; use sp_keystore::{testing::MemoryKeystore, Keystore}; - #[test] - fn known_votes_insert_remove() { - let mut filter = Filter::::new(); - let msg_hash = twox_64(b"data"); - let keys = vec![Keyring::Alice.public()]; - let validator_set = ValidatorSet::::new(keys.clone(), 1).unwrap(); - - filter.add_known_vote(1, msg_hash); - filter.add_known_vote(1, msg_hash); - filter.add_known_vote(2, msg_hash); - assert_eq!(filter.live_votes.len(), 2); - - filter.add_known_vote(3, msg_hash); - assert!(filter.is_known_vote(3, &msg_hash)); - assert!(!filter.is_known_vote(3, &twox_64(b"other"))); - assert!(!filter.is_known_vote(4, &msg_hash)); - assert_eq!(filter.live_votes.len(), 3); - - assert!(filter.inner.is_none()); - assert_eq!(filter.consider_vote(1, 1), Consider::RejectOutOfScope); - - filter.update(GossipFilterCfg { start: 3, end: 10, validator_set: &validator_set }); - assert_eq!(filter.live_votes.len(), 1); - assert!(filter.live_votes.contains_key(&3)); - assert_eq!(filter.consider_vote(2, 1), Consider::RejectPast); - assert_eq!(filter.consider_vote(3, 1), Consider::Accept); - assert_eq!(filter.consider_vote(4, 1), Consider::Accept); - assert_eq!(filter.consider_vote(20, 1), Consider::RejectFuture); - assert_eq!(filter.consider_vote(4, 2), Consider::RejectFuture); - - let validator_set = ValidatorSet::::new(keys, 2).unwrap(); - filter.update(GossipFilterCfg { start: 5, end: 10, validator_set: &validator_set }); - assert!(filter.live_votes.is_empty()); - } - struct TestContext; impl ValidatorContext for TestContext { fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { @@ -610,20 +578,6 @@ pub(crate) mod tests { assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); expected_report.cost_benefit = benefit::VOTE_MESSAGE; assert_eq!(report_stream.try_recv().unwrap(), expected_report); - assert_eq!( - gv.gossip_filter - .read() - .live_votes - .get(&vote.commitment.block_number) - .map(|x| x.len()), - Some(1) - ); - - // second time we should hit the cache - let res = gv.validate(&mut context, &sender, &encoded); - assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); - expected_report.cost_benefit = benefit::KNOWN_VOTE_MESSAGE; - assert_eq!(report_stream.try_recv().unwrap(), expected_report); // reject vote, voter not in validator set let mut bad_vote = vote.clone(); @@ -692,7 +646,7 @@ pub(crate) mod tests { // reject proof, bad signatures (Bob instead of Alice) let bad_validator_set = ValidatorSet::::new(vec![Keyring::Bob.public()], 0).unwrap(); - let proof = dummy_proof(20, &bad_validator_set); + let proof = dummy_proof(21, &bad_validator_set); let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); diff --git a/substrate/client/consensus/beefy/src/communication/mod.rs b/substrate/client/consensus/beefy/src/communication/mod.rs index 7f9535bfc23f1322fbe4995f596e83360c85fc68..10a6071aae658d2988874092dcaade873870ca37 100644 --- a/substrate/client/consensus/beefy/src/communication/mod.rs +++ b/substrate/client/consensus/beefy/src/communication/mod.rs @@ -102,7 +102,7 @@ mod cost { mod benefit { use sc_network::ReputationChange as Rep; pub(super) const VOTE_MESSAGE: Rep = Rep::new(100, "BEEFY: Round vote message"); - pub(super) const KNOWN_VOTE_MESSAGE: Rep = Rep::new(50, "BEEFY: Known vote"); + pub(super) const NOT_INTERESTED: Rep = Rep::new(10, "BEEFY: Not interested in round"); pub(super) const VALIDATED_PROOF: Rep = Rep::new(100, "BEEFY: Justification"); } diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 72df3cab85503960936f161165a8fadb3d7742a4..89a5d51c88702df76f7e3f0e7bb4f65076531066 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -33,7 +33,7 @@ use crate::{ worker::PersistedState, }; use futures::{stream::Fuse, StreamExt}; -use log::{error, info}; +use log::{debug, error, info}; use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; @@ -428,7 +428,7 @@ where let best_beefy = *header.number(); // If no session boundaries detected so far, just initialize new rounds here. if sessions.is_empty() { - let active_set = expect_validator_set(runtime, backend, &header, beefy_genesis)?; + let active_set = expect_validator_set(runtime, backend, &header)?; let mut rounds = Rounds::new(best_beefy, active_set); // Mark the round as already finalized. rounds.conclude(best_beefy); @@ -447,7 +447,7 @@ where if *header.number() == beefy_genesis { // We've reached BEEFY genesis, initialize voter here. - let genesis_set = expect_validator_set(runtime, backend, &header, beefy_genesis)?; + let genesis_set = expect_validator_set(runtime, backend, &header)?; info!( target: LOG_TARGET, "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ @@ -532,7 +532,6 @@ fn expect_validator_set( runtime: &R, backend: &BE, at_header: &B::Header, - beefy_genesis: NumberFor, ) -> ClientResult> where B: Block, @@ -540,6 +539,7 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, { + debug!(target: LOG_TARGET, "🥩 Try to find validator set active at header: {:?}", at_header); runtime .runtime_api() .validator_set(at_header.hash()) @@ -550,14 +550,14 @@ where // Digest emitted when validator set active 'at_header' was enacted. let blockchain = backend.blockchain(); let mut header = at_header.clone(); - while *header.number() >= beefy_genesis { + loop { + debug!(target: LOG_TARGET, "🥩 look for auth set change digest in header number: {:?}", *header.number()); match worker::find_authorities_change::(&header) { Some(active) => return Some(active), // Move up the chain. None => header = blockchain.expect_header(*header.parent_hash()).ok()?, } } - None }) .ok_or_else(|| ClientError::Backend("Could not find initial validator set".into())) } diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 3bb65e9d57f435b78b9faccffb687bc4ab64757d..902feca163983c594baa54f01688ad183c171a03 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -247,7 +247,7 @@ impl TestNetFactory for BeefyTestNet { #[derive(Clone)] pub(crate) struct TestApi { pub beefy_genesis: u64, - pub validator_set: BeefyValidatorSet, + pub validator_set: Option, pub mmr_root_hash: MmrRootHash, pub reported_equivocations: Option, AuthorityId, Signature>>>>>, @@ -261,7 +261,7 @@ impl TestApi { ) -> Self { TestApi { beefy_genesis, - validator_set: validator_set.clone(), + validator_set: Some(validator_set.clone()), mmr_root_hash, reported_equivocations: None, } @@ -270,7 +270,7 @@ impl TestApi { pub fn with_validator_set(validator_set: &BeefyValidatorSet) -> Self { TestApi { beefy_genesis: 1, - validator_set: validator_set.clone(), + validator_set: Some(validator_set.clone()), mmr_root_hash: GOOD_MMR_ROOT, reported_equivocations: None, } @@ -300,7 +300,7 @@ sp_api::mock_impl_runtime_apis! { } fn validator_set() -> Option { - Some(self.inner.validator_set.clone()) + self.inner.validator_set.clone() } fn submit_report_equivocation_unsigned_extrinsic( @@ -1188,6 +1188,54 @@ async fn should_initialize_voter_at_latest_finalized() { assert_eq!(state, persisted_state); } +#[tokio::test] +async fn should_initialize_voter_at_custom_genesis_when_state_unavailable() { + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + // custom pallet genesis is block number 7 + let custom_pallet_genesis = 7; + let mut api = TestApi::new(custom_pallet_genesis, &validator_set, GOOD_MMR_ROOT); + // remove validator set from `TestApi`, practically simulating unavailable/pruned runtime state + api.validator_set = None; + + // push 30 blocks with `AuthorityChange` digests every 5 blocks + let hashes = net.generate_blocks_and_sync(30, 5, &validator_set, false).await; + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + // finalize 30 without justifications + net.peer(0).client().as_client().finalize_block(hashes[30], None).unwrap(); + + // load persistent state - nothing in DB, should init at genesis + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + + // Test initialization at session boundary. + // verify voter initialized with all sessions pending, first one starting at block 5 (start of + // session containing `custom_pallet_genesis`). + let sessions = persisted_state.voting_oracle().sessions(); + // should have enqueued 6 sessions (every 5 blocks from 5 to 30) + assert_eq!(sessions.len(), 6); + assert_eq!(sessions[0].session_start(), 7); + assert_eq!(sessions[1].session_start(), 10); + assert_eq!(sessions[2].session_start(), 15); + assert_eq!(sessions[3].session_start(), 20); + assert_eq!(sessions[4].session_start(), 25); + assert_eq!(sessions[5].session_start(), 30); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), custom_pallet_genesis); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 7 (genesis) + assert_eq!(persisted_state.best_beefy_block(), 0); + assert_eq!(persisted_state.best_grandpa_number(), 30); + assert_eq!(persisted_state.voting_oracle().voting_target(), Some(custom_pallet_genesis)); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} + #[tokio::test] async fn beefy_finalizing_after_pallet_genesis() { sp_tracing::try_init_simple(); @@ -1302,7 +1350,7 @@ async fn gossipped_finality_proofs() { // Only Alice and Bob are running the voter -> finality threshold not reached let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(&validators), 0).unwrap(); - let session_len = 30; + let session_len = 10; let min_block_delta = 1; let mut net = BeefyTestNet::new(3); @@ -1332,14 +1380,8 @@ async fn gossipped_finality_proofs() { let net = Arc::new(Mutex::new(net)); - // Pump net + Charlie gossip to see peers. - let timeout = Box::pin(tokio::time::sleep(Duration::from_millis(200))); - let gossip_engine_pump = &mut charlie_gossip_engine; - let pump_with_timeout = future::select(gossip_engine_pump, timeout); - run_until(pump_with_timeout, &net).await; - - // push 10 blocks - let hashes = net.lock().generate_blocks_and_sync(10, session_len, &validator_set, true).await; + // push 42 blocks + let hashes = net.lock().generate_blocks_and_sync(42, session_len, &validator_set, true).await; let peers = peers.into_iter().enumerate(); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index a239e34030c27f79ff6c8468e0e847851ef8792a..309d8c5135bef96447bc87b1485775fb96f6b255 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -604,6 +604,11 @@ where VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, }; + if block_num <= self.persisted_state.voting_oracle.best_beefy_block { + // we've already finalized this round before, short-circuit. + return Ok(()) + } + // Finalize inner round and update voting_oracle state. self.persisted_state.voting_oracle.finalize(block_num)?; @@ -629,7 +634,7 @@ where self.backend .append_justification(hash, (BEEFY_ENGINE_ID, finality_proof.encode())) }) { - error!( + debug!( target: LOG_TARGET, "🥩 Error {:?} on appending justification: {:?}", e, finality_proof ); @@ -648,7 +653,7 @@ where } /// Handle previously buffered justifications, that now land in the voting interval. - fn try_pending_justififactions(&mut self) -> Result<(), Error> { + fn try_pending_justifications(&mut self) -> Result<(), Error> { // Interval of blocks for which we can process justifications and votes right now. let (start, end) = self.voting_oracle().accepted_interval()?; // Process pending justifications. @@ -782,7 +787,7 @@ where fn process_new_state(&mut self) { // Handle pending justifications and/or votes for now GRANDPA finalized blocks. - if let Err(err) = self.try_pending_justififactions() { + if let Err(err) = self.try_pending_justifications() { debug!(target: LOG_TARGET, "🥩 {}", err); } diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index 1e5db966e66dbdbc453f9cdc04ff80d2f15ad9b2..41cd5f3127e8ead7508bb2a7c375aab9bc355892 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -351,7 +351,7 @@ mod tests { use sc_transaction_pool::{BasicPool, FullChainApi, Options, RevalidationType}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource}; use sp_inherents::InherentData; - use sp_runtime::generic::{BlockId, Digest, DigestItem}; + use sp_runtime::generic::{Digest, DigestItem}; use substrate_test_runtime_client::{ AccountKeyring::*, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, }; @@ -400,10 +400,11 @@ mod tests { let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); let genesis_hash = client.info().genesis_hash; + let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone())); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), - api(), + pool_api, None, RevalidationType::Full, spawner.clone(), @@ -444,7 +445,7 @@ mod tests { rt.block_on(future); }); // submit a transaction to pool. - let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await; + let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported assert!(result.is_ok()); // assert that the background task returns ok @@ -475,10 +476,11 @@ mod tests { let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); let genesis_hash = client.info().genesis_hash; + let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone())); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), - api(), + pool_api, None, RevalidationType::Full, spawner.clone(), @@ -535,7 +537,7 @@ mod tests { let mut finality_stream = client.finality_notification_stream(); // submit a transaction to pool. - let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await; + let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported assert!(result.is_ok()); // assert that the background task returns ok @@ -571,10 +573,11 @@ mod tests { let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); let genesis_hash = client.info().genesis_hash; + let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone())); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), - api(), + pool_api, None, RevalidationType::Full, spawner.clone(), @@ -602,7 +605,7 @@ mod tests { rt.block_on(future); }); // submit a transaction to pool. - let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await; + let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported assert!(result.is_ok()); let (tx, rx) = futures::channel::oneshot::channel(); @@ -688,7 +691,7 @@ mod tests { rt.block_on(future); }); // submit a transaction to pool. - let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await; + let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await; // assert that it was successfully imported assert!(result.is_ok()); @@ -719,7 +722,7 @@ mod tests { } ); - assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 1)).await.is_ok()); + assert!(pool.submit_one(created_block.hash, SOURCE, uxt(Alice, 1)).await.is_ok()); let header = client.header(created_block.hash).expect("db error").expect("imported above"); assert_eq!(header.number, 1); @@ -741,7 +744,7 @@ mod tests { .is_ok()); assert_matches::assert_matches!(rx1.await.expect("should be no error receiving"), Ok(_)); - assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Bob, 0)).await.is_ok()); + assert!(pool.submit_one(created_block.hash, SOURCE, uxt(Bob, 0)).await.is_ok()); let (tx2, rx2) = futures::channel::oneshot::channel(); assert!(sink .send(EngineCommand::SealNewBlock { diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..86c5a37754afb8c7de3e2cae539e51d47ee57282 --- /dev/null +++ b/substrate/client/mixnet/Cargo.toml @@ -0,0 +1,36 @@ +[package] +description = "Substrate mixnet service" +name = "sc-mixnet" +version = "0.1.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +array-bytes = "4.1" +arrayvec = "0.7.2" +blake2 = "0.10.4" +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +futures = "0.3.25" +futures-timer = "3.0.2" +libp2p-identity = { version = "0.1.3", features = ["peerid"] } +log = "0.4.17" +mixnet = "0.7.0" +multiaddr = "0.17.1" +parking_lot = "0.12.1" +sc-client-api = { path = "../api" } +sc-network = { path = "../network" } +sc-transaction-pool-api = { path = "../transaction-pool/api" } +sp-api = { path = "../../primitives/api" } +sp-consensus = { path = "../../primitives/consensus/common" } +sp-core = { path = "../../primitives/core" } +sp-keystore = { path = "../../primitives/keystore" } +sp-mixnet = { path = "../../primitives/mixnet" } +sp-runtime = { path = "../../primitives/runtime" } +thiserror = "1.0" diff --git a/substrate/client/mixnet/README.md b/substrate/client/mixnet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cd8d14740838715c16529000da688ca3ef0aabd4 --- /dev/null +++ b/substrate/client/mixnet/README.md @@ -0,0 +1,3 @@ +Substrate mixnet service. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/mixnet/src/api.rs b/substrate/client/mixnet/src/api.rs new file mode 100644 index 0000000000000000000000000000000000000000..42a2e395345dc321d88cda1a3edcfbc545b0a0d2 --- /dev/null +++ b/substrate/client/mixnet/src/api.rs @@ -0,0 +1,69 @@ +// 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 super::{config::Config, error::Error, request::Request}; +use futures::{ + channel::{mpsc, oneshot}, + SinkExt, +}; +use sp_core::Bytes; +use std::future::Future; + +/// The other end of an [`Api`]. This should be passed to [`run`](super::run::run). +pub struct ApiBackend { + pub(super) request_receiver: mpsc::Receiver, +} + +/// Interface to the mixnet service. +#[derive(Clone)] +pub struct Api { + request_sender: mpsc::Sender, +} + +impl Api { + /// Create a new `Api`. The [`ApiBackend`] should be passed to [`run`](super::run::run). + pub fn new(config: &Config) -> (Self, ApiBackend) { + let (request_sender, request_receiver) = mpsc::channel(config.substrate.request_buffer); + (Self { request_sender }, ApiBackend { request_receiver }) + } + + /// Submit an extrinsic via the mixnet. + /// + /// Returns a [`Future`] which returns another `Future`. + /// + /// The first `Future` resolves as soon as there is space in the mixnet service queue. The + /// second `Future` resolves once a reply is received over the mixnet (or sooner if there is an + /// error). + /// + /// The first `Future` references `self`, but the second does not. This makes it possible to + /// submit concurrent mixnet requests using a single `Api` instance. + pub async fn submit_extrinsic( + &mut self, + extrinsic: Bytes, + ) -> impl Future> { + let (reply_sender, reply_receiver) = oneshot::channel(); + let res = self + .request_sender + .feed(Request::SubmitExtrinsic { extrinsic, reply_sender }) + .await; + async move { + res.map_err(|_| Error::ServiceUnavailable)?; + reply_receiver.await.map_err(|_| Error::ServiceUnavailable)? + } + } +} diff --git a/substrate/client/mixnet/src/config.rs b/substrate/client/mixnet/src/config.rs new file mode 100644 index 0000000000000000000000000000000000000000..b716237ab7b534fb6a1922c2fda61637578328a1 --- /dev/null +++ b/substrate/client/mixnet/src/config.rs @@ -0,0 +1,88 @@ +// 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 . + +pub use mixnet::core::Config as CoreConfig; +use std::time::Duration; + +/// Substrate-specific mixnet configuration. +#[derive(Clone, Debug)] +pub struct SubstrateConfig { + /// Attempt to register the local node as a mixnode? + pub register: bool, + /// Maximum number of incoming mixnet connections to accept from non-mixnodes. If the local + /// node will never be a mixnode, this can be set to 0. + pub num_gateway_slots: u32, + + /// Number of requests to the mixnet service that can be buffered, in addition to the one per + /// [`Api`](super::api::Api) instance. Note that this does not include requests that are being + /// actively handled. + pub request_buffer: usize, + /// Used to determine the number of SURBs to include in request messages: the maximum number of + /// SURBs needed for a single reply is multiplied by this. This should not be set to 0. + pub surb_factor: usize, + + /// Maximum number of submit extrinsic requests waiting for their delay to elapse. When at the + /// limit, any submit extrinsic requests that arrive will simply be dropped. + pub extrinsic_queue_capacity: usize, + /// Mean delay between receiving a submit extrinsic request and actually submitting the + /// extrinsic. This should really be the same for all nodes! + pub mean_extrinsic_delay: Duration, + /// Maximum number of extrinsics being actively submitted. If a submit extrinsic request's + /// delay elapses and we are already at this limit, the request will simply be dropped. + pub max_pending_extrinsics: usize, +} + +impl Default for SubstrateConfig { + fn default() -> Self { + Self { + register: true, + num_gateway_slots: 150, + + request_buffer: 4, + surb_factor: 2, + + extrinsic_queue_capacity: 50, + mean_extrinsic_delay: Duration::from_secs(1), + max_pending_extrinsics: 20, + } + } +} + +/// Mixnet configuration. +#[derive(Clone, Debug)] +pub struct Config { + /// Core configuration. + pub core: CoreConfig, + /// Request manager configuration. + pub request_manager: mixnet::request_manager::Config, + /// Reply manager configuration. + pub reply_manager: mixnet::reply_manager::Config, + /// Substrate-specific configuration. + pub substrate: SubstrateConfig, +} + +impl Default for Config { + fn default() -> Self { + Self { + core: Default::default(), + request_manager: Default::default(), + reply_manager: Default::default(), + substrate: Default::default(), + } + } +} diff --git a/substrate/client/mixnet/src/error.rs b/substrate/client/mixnet/src/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..88942dbe3b36fa6afbe12f6f971c2c73898b8a96 --- /dev/null +++ b/substrate/client/mixnet/src/error.rs @@ -0,0 +1,56 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use codec::{Decode, Encode}; +use mixnet::core::PostErr; + +/// Error handling a request. Sent in replies over the mixnet. +#[derive(Debug, thiserror::Error, Decode, Encode)] +pub enum RemoteErr { + /// An error that doesn't map to any of the other variants. + #[error("{0}")] + Other(String), + /// Failed to decode the request. + #[error("Failed to decode the request: {0}")] + Decode(String), +} + +/// Mixnet error. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Failed to communicate with the mixnet service. Possibly it panicked. The node probably + /// needs to be restarted. + #[error( + "Failed to communicate with the mixnet service; the node probably needs to be restarted" + )] + ServiceUnavailable, + /// Did not receive a reply after the configured number of attempts. + #[error("Did not receive a reply from the mixnet after the configured number of attempts")] + NoReply, + /// Received a malformed reply. + #[error("Received a malformed reply from the mixnet")] + BadReply, + /// Failed to post the request to the mixnet. Note that some [`PostErr`] variants, eg + /// [`PostErr::NotEnoughSpaceInQueue`], are handled internally and will never be returned from + /// the top-level API. + #[error("Failed to post the request to the mixnet: {0}")] + Post(#[from] PostErr), + /// Error reported by destination mixnode. + #[error("Error reported by the destination mixnode: {0}")] + Remote(#[from] RemoteErr), +} diff --git a/substrate/client/mixnet/src/extrinsic_queue.rs b/substrate/client/mixnet/src/extrinsic_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..b6f6f9ebae99843efbcb561effcfb9983e71b30c --- /dev/null +++ b/substrate/client/mixnet/src/extrinsic_queue.rs @@ -0,0 +1,94 @@ +// 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 . + +//! [`ExtrinsicQueue`] is a queue for extrinsics received from the mixnet. These extrinsics are +//! explicitly delayed by a random amount, to decorrelate the times at which they are received from +//! the times at which they are broadcast to peers. + +use mixnet::reply_manager::ReplyContext; +use std::{cmp::Ordering, collections::BinaryHeap, time::Instant}; + +/// An extrinsic that should be submitted to the transaction pool after `deadline`. `Eq` and `Ord` +/// are implemented for this to support use in `BinaryHeap`s. Only `deadline` is compared. +struct DelayedExtrinsic { + /// When the extrinsic should actually be submitted to the pool. + deadline: Instant, + extrinsic: E, + reply_context: ReplyContext, +} + +impl PartialEq for DelayedExtrinsic { + fn eq(&self, other: &Self) -> bool { + self.deadline == other.deadline + } +} + +impl Eq for DelayedExtrinsic {} + +impl PartialOrd for DelayedExtrinsic { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for DelayedExtrinsic { + fn cmp(&self, other: &Self) -> Ordering { + // Extrinsics with the earliest deadline considered greatest + self.deadline.cmp(&other.deadline).reverse() + } +} + +pub struct ExtrinsicQueue { + capacity: usize, + queue: BinaryHeap>, + next_deadline_changed: bool, +} + +impl ExtrinsicQueue { + pub fn new(capacity: usize) -> Self { + Self { capacity, queue: BinaryHeap::with_capacity(capacity), next_deadline_changed: false } + } + + pub fn next_deadline(&self) -> Option { + self.queue.peek().map(|extrinsic| extrinsic.deadline) + } + + pub fn next_deadline_changed(&mut self) -> bool { + let changed = self.next_deadline_changed; + self.next_deadline_changed = false; + changed + } + + pub fn has_space(&self) -> bool { + self.queue.len() < self.capacity + } + + pub fn insert(&mut self, deadline: Instant, extrinsic: E, reply_context: ReplyContext) { + debug_assert!(self.has_space()); + let prev_deadline = self.next_deadline(); + self.queue.push(DelayedExtrinsic { deadline, extrinsic, reply_context }); + if self.next_deadline() != prev_deadline { + self.next_deadline_changed = true; + } + } + + pub fn pop(&mut self) -> Option<(E, ReplyContext)> { + self.next_deadline_changed = true; + self.queue.pop().map(|extrinsic| (extrinsic.extrinsic, extrinsic.reply_context)) + } +} diff --git a/substrate/client/mixnet/src/lib.rs b/substrate/client/mixnet/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..dfbb50dad6b4927a3e1c0d64de4ec78a35b4d555 --- /dev/null +++ b/substrate/client/mixnet/src/lib.rs @@ -0,0 +1,44 @@ +// 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 mixnet service. This implements the [Substrate Mix Network +//! Specification](https://paritytech.github.io/mixnet-spec/). + +#![warn(missing_docs)] +#![forbid(unsafe_code)] + +mod api; +mod config; +mod error; +mod extrinsic_queue; +mod maybe_inf_delay; +mod packet_dispatcher; +mod peer_id; +mod protocol; +mod request; +mod run; +mod sync_with_runtime; + +pub use self::{ + api::{Api, ApiBackend}, + config::{Config, CoreConfig, SubstrateConfig}, + error::{Error, RemoteErr}, + protocol::{peers_set_config, protocol_name}, + run::run, +}; +pub use mixnet::core::{KxSecret, PostErr, TopologyErr}; diff --git a/substrate/client/mixnet/src/maybe_inf_delay.rs b/substrate/client/mixnet/src/maybe_inf_delay.rs new file mode 100644 index 0000000000000000000000000000000000000000..feb0d038560a38e751c339df416140a0bbd5ff9a --- /dev/null +++ b/substrate/client/mixnet/src/maybe_inf_delay.rs @@ -0,0 +1,111 @@ +// 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 futures::{future::FusedFuture, FutureExt}; +use futures_timer::Delay; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll, Waker}, + time::Duration, +}; + +enum Inner { + Infinite { + /// Waker from the most recent `poll` call. If `None`, either `poll` has not been called + /// yet, we returned `Poll::Ready` from the last call, or the waker is attached to `delay`. + waker: Option, + delay: Option, + }, + Finite(Delay), +} + +/// Like [`Delay`] but the duration can be infinite (in which case the future will never fire). +/// Unlike [`Delay`], implements [`FusedFuture`], with [`is_terminated`](Self::is_terminated) +/// returning `true` when the delay is infinite. As with [`Delay`], once [`poll`](Self::poll) +/// returns [`Poll::Ready`], it will continue to do so until [`reset`](Self::reset) is called. +pub struct MaybeInfDelay(Inner); + +impl MaybeInfDelay { + /// Create a new `MaybeInfDelay` future. If `duration` is [`Some`], the future will fire after + /// the given duration has elapsed. If `duration` is [`None`], the future will "never" fire + /// (although see [`reset`](Self::reset)). + pub fn new(duration: Option) -> Self { + match duration { + Some(duration) => Self(Inner::Finite(Delay::new(duration))), + None => Self(Inner::Infinite { waker: None, delay: None }), + } + } + + /// Reset the timer. `duration` is handled just like in [`new`](Self::new). Note that while + /// this is similar to `std::mem::replace(&mut self, MaybeInfDelay::new(duration))`, with + /// `replace` you would have to manually ensure [`poll`](Self::poll) was called again; with + /// `reset` this is not necessary. + pub fn reset(&mut self, duration: Option) { + match duration { + Some(duration) => match &mut self.0 { + Inner::Infinite { waker, delay } => { + let mut delay = match delay.take() { + Some(mut delay) => { + delay.reset(duration); + delay + }, + None => Delay::new(duration), + }; + if let Some(waker) = waker.take() { + let mut cx = Context::from_waker(&waker); + match delay.poll_unpin(&mut cx) { + Poll::Pending => (), // Waker attached to delay + Poll::Ready(_) => waker.wake(), + } + } + self.0 = Inner::Finite(delay); + }, + Inner::Finite(delay) => delay.reset(duration), + }, + None => + self.0 = match std::mem::replace( + &mut self.0, + Inner::Infinite { waker: None, delay: None }, + ) { + Inner::Finite(delay) => Inner::Infinite { waker: None, delay: Some(delay) }, + infinite => infinite, + }, + } + } +} + +impl Future for MaybeInfDelay { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match &mut self.0 { + Inner::Infinite { waker, .. } => { + *waker = Some(cx.waker().clone()); + Poll::Pending + }, + Inner::Finite(delay) => delay.poll_unpin(cx), + } + } +} + +impl FusedFuture for MaybeInfDelay { + fn is_terminated(&self) -> bool { + matches!(self.0, Inner::Infinite { .. }) + } +} diff --git a/substrate/client/mixnet/src/packet_dispatcher.rs b/substrate/client/mixnet/src/packet_dispatcher.rs new file mode 100644 index 0000000000000000000000000000000000000000..856208ecb34260f5cf03c183cf68683dec6710d0 --- /dev/null +++ b/substrate/client/mixnet/src/packet_dispatcher.rs @@ -0,0 +1,198 @@ +// 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 . + +//! [`AddressedPacket`] dispatching. + +use super::peer_id::{from_core_peer_id, to_core_peer_id}; +use arrayvec::ArrayVec; +use libp2p_identity::PeerId; +use log::{debug, warn}; +use mixnet::core::{AddressedPacket, NetworkStatus, Packet, PeerId as CorePeerId}; +use parking_lot::Mutex; +use sc_network::{NetworkNotification, ProtocolName}; +use std::{collections::HashMap, future::Future, sync::Arc}; + +const LOG_TARGET: &str = "mixnet"; + +/// Packet queue for a peer. +/// +/// Ideally we would use `Rc>`, but that would prevent the top-level future from being +/// automatically marked `Send`. I believe it would be safe to manually mark it `Send`, but using +/// `Arc>` here is not really a big deal. +struct PeerQueue(Mutex, 2>>); + +impl PeerQueue { + fn new() -> Self { + Self(Mutex::new(ArrayVec::new())) + } + + /// Push `packet` onto the queue. Returns `true` if the queue was previously empty. Fails if + /// the queue is full. + fn push(&self, packet: Box) -> Result { + let mut queue = self.0.lock(); + if queue.is_full() { + Err(()) + } else { + let was_empty = queue.is_empty(); + queue.push(packet); + Ok(was_empty) + } + } + + /// Drop all packets from the queue. + fn clear(&self) { + let mut queue = self.0.lock(); + queue.clear(); + } + + /// Pop the packet at the head of the queue and return it, or, if the queue is empty, return + /// `None`. Also returns `true` if there are more packets in the queue. + fn pop(&self) -> (Option>, bool) { + let mut queue = self.0.lock(); + let packet = queue.pop(); + (packet, !queue.is_empty()) + } +} + +/// A peer which has packets ready to send but is not currently being serviced. +pub struct ReadyPeer { + id: PeerId, + /// The peer's packet queue. Not empty. + queue: Arc, +} + +impl ReadyPeer { + /// If a future is returned, and if that future returns `Some`, this function should be called + /// again to send the next packet queued for the peer; `self` is placed in the `Some` to make + /// this straightforward. Otherwise, we have either sent or dropped all packets queued for the + /// peer, and it can be forgotten about for the time being. + pub fn send_packet( + self, + network: &impl NetworkNotification, + protocol_name: ProtocolName, + ) -> Option>> { + match network.notification_sender(self.id, protocol_name) { + Err(err) => { + debug!( + target: LOG_TARGET, + "Failed to get notification sender for peer ID {}: {err}", self.id + ); + self.queue.clear(); + None + }, + Ok(sender) => Some(async move { + match sender.ready().await.and_then(|mut ready| { + let (packet, more_packets) = self.queue.pop(); + let packet = + packet.expect("Should only be called if there is a packet to send"); + ready.send((packet as Box<[_]>).into())?; + Ok(more_packets) + }) { + Err(err) => { + debug!( + target: LOG_TARGET, + "Notification sender for peer ID {} failed: {err}", self.id + ); + self.queue.clear(); + None + }, + Ok(more_packets) => more_packets.then(|| self), + } + }), + } + } +} + +pub struct PacketDispatcher { + /// Peer ID of the local node. Only used to implement [`NetworkStatus`]. + local_peer_id: CorePeerId, + /// Packet queue for each connected peer. These queues are very short and only exist to give + /// packets somewhere to sit while waiting for notification senders to be ready. + peer_queues: HashMap>, +} + +impl PacketDispatcher { + pub fn new(local_peer_id: &CorePeerId) -> Self { + Self { local_peer_id: *local_peer_id, peer_queues: HashMap::new() } + } + + pub fn add_peer(&mut self, id: &PeerId) { + let Some(core_id) = to_core_peer_id(id) else { + debug!(target: LOG_TARGET, + "Cannot add peer; failed to convert libp2p peer ID {id} to mixnet peer ID"); + return + }; + if self.peer_queues.insert(core_id, Arc::new(PeerQueue::new())).is_some() { + warn!(target: LOG_TARGET, "Two stream opened notifications for peer ID {id}"); + } + } + + pub fn remove_peer(&mut self, id: &PeerId) { + let Some(core_id) = to_core_peer_id(id) else { + debug!(target: LOG_TARGET, + "Cannot remove peer; failed to convert libp2p peer ID {id} to mixnet peer ID"); + return + }; + if self.peer_queues.remove(&core_id).is_none() { + warn!(target: LOG_TARGET, "Stream closed notification for unknown peer ID {id}"); + } + } + + /// If the peer is not connected or the peer's packet queue is full, the packet is dropped. + /// Otherwise the packet is pushed onto the peer's queue, and if the queue was previously empty + /// a [`ReadyPeer`] is returned. + pub fn dispatch(&mut self, packet: AddressedPacket) -> Option { + let Some(queue) = self.peer_queues.get_mut(&packet.peer_id) else { + debug!(target: LOG_TARGET, "Dropped packet to mixnet peer ID {:x?}; not connected", + packet.peer_id); + return None + }; + + match queue.push(packet.packet) { + Err(_) => { + debug!( + target: LOG_TARGET, + "Dropped packet to mixnet peer ID {:x?}; peer queue full", packet.peer_id + ); + None + }, + Ok(true) => { + // Queue was empty. Construct and return a ReadyPeer. + let Some(id) = from_core_peer_id(&packet.peer_id) else { + debug!(target: LOG_TARGET, "Cannot send packet; \ + failed to convert mixnet peer ID {:x?} to libp2p peer ID", + packet.peer_id); + queue.clear(); + return None + }; + Some(ReadyPeer { id, queue: queue.clone() }) + }, + Ok(false) => None, // Queue was not empty + } + } +} + +impl NetworkStatus for PacketDispatcher { + fn local_peer_id(&self) -> CorePeerId { + self.local_peer_id + } + + fn is_connected(&self, peer_id: &CorePeerId) -> bool { + self.peer_queues.contains_key(peer_id) + } +} diff --git a/substrate/client/mixnet/src/peer_id.rs b/substrate/client/mixnet/src/peer_id.rs new file mode 100644 index 0000000000000000000000000000000000000000..7984da8c75be77e245cd88b06451d38f443f904d --- /dev/null +++ b/substrate/client/mixnet/src/peer_id.rs @@ -0,0 +1,44 @@ +// 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 libp2p_identity::PeerId; +use mixnet::core::PeerId as CorePeerId; + +/// Convert a libp2p [`PeerId`] into a mixnet core [`PeerId`](CorePeerId). +/// +/// This will succeed only if `peer_id` is an Ed25519 public key ("hashed" using the identity +/// hasher). Returns `None` on failure. +pub fn to_core_peer_id(peer_id: &PeerId) -> Option { + let hash = peer_id.as_ref(); + if hash.code() != 0 { + // Hash is not identity + return None + } + let public = libp2p_identity::PublicKey::try_decode_protobuf(hash.digest()).ok()?; + public.try_into_ed25519().ok().map(|public| public.to_bytes()) +} + +/// Convert a mixnet core [`PeerId`](CorePeerId) into a libp2p [`PeerId`]. +/// +/// This will succeed only if `peer_id` represents a point on the Ed25519 curve. Returns `None` on +/// failure. +pub fn from_core_peer_id(core_peer_id: &CorePeerId) -> Option { + let public = libp2p_identity::ed25519::PublicKey::try_from_bytes(core_peer_id).ok()?; + let public: libp2p_identity::PublicKey = public.into(); + Some(public.into()) +} diff --git a/substrate/client/mixnet/src/protocol.rs b/substrate/client/mixnet/src/protocol.rs new file mode 100644 index 0000000000000000000000000000000000000000..555c267b86e0c5b95d52df355c552448e9c19ce4 --- /dev/null +++ b/substrate/client/mixnet/src/protocol.rs @@ -0,0 +1,42 @@ +// 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 super::config::Config; +use mixnet::core::PACKET_SIZE; +use sc_network::{config::NonDefaultSetConfig, ProtocolName}; + +/// Returns the protocol name to use for the mixnet controlled by the given chain. +pub fn protocol_name(genesis_hash: &[u8], fork_id: Option<&str>) -> ProtocolName { + let name = if let Some(fork_id) = fork_id { + format!("/{}/{}/mixnet/1", array_bytes::bytes2hex("", genesis_hash), fork_id) + } else { + format!("/{}/mixnet/1", array_bytes::bytes2hex("", genesis_hash)) + }; + name.into() +} + +/// Returns the peers set configuration for the mixnet protocol. +pub fn peers_set_config(name: ProtocolName, config: &Config) -> NonDefaultSetConfig { + let mut set_config = NonDefaultSetConfig::new(name, PACKET_SIZE as u64); + if config.substrate.num_gateway_slots != 0 { + // out_peers is always 0; we are only interested in connecting to mixnodes, which we do by + // setting them as reserved nodes + set_config.allow_non_reserved(config.substrate.num_gateway_slots, 0); + } + set_config +} diff --git a/substrate/client/mixnet/src/request.rs b/substrate/client/mixnet/src/request.rs new file mode 100644 index 0000000000000000000000000000000000000000..18a74c7ea5cf1aa7d9ae2a9f1805a0dbc32ebbf5 --- /dev/null +++ b/substrate/client/mixnet/src/request.rs @@ -0,0 +1,119 @@ +// 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 . + +//! Sender-side request logic. Some things from this module are also used on the receiver side, eg +//! [`extrinsic_delay`], but most of the receiver-side request logic lives elsewhere. + +use super::{config::SubstrateConfig, error::Error}; +use blake2::{ + digest::{consts::U16, Mac}, + Blake2bMac, +}; +use codec::{Decode, DecodeAll}; +use futures::channel::oneshot; +use log::debug; +use mixnet::core::{Delay, MessageId, PostErr, Scattered}; +use sp_core::Bytes; +use std::time::Duration; + +const LOG_TARGET: &str = "mixnet"; + +fn send_err(reply_sender: oneshot::Sender>, err: Error) { + if let Err(Err(err)) = reply_sender.send(Err(err)) { + debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}"); + } +} + +fn send_reply(reply_sender: oneshot::Sender>, mut data: &[u8]) { + let res = match Result::decode_all(&mut data) { + Ok(res) => res.map_err(Error::Remote), + Err(_) => Err(Error::BadReply), + }; + match reply_sender.send(res) { + Ok(_) => (), + Err(Ok(_)) => debug!(target: LOG_TARGET, "Failed to send reply to requester"), + Err(Err(err)) => debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}"), + } +} + +/// First byte of a submit extrinsic request, identifying it as such. +pub const SUBMIT_EXTRINSIC: u8 = 1; + +const EXTRINSIC_DELAY_PERSONA: &[u8; 16] = b"submit-extrn-dly"; + +/// Returns the artificial delay that should be inserted between receipt of a submit extrinsic +/// request with the given message ID and import of the extrinsic into the local transaction pool. +pub fn extrinsic_delay(message_id: &MessageId, config: &SubstrateConfig) -> Duration { + let h = Blake2bMac::::new_with_salt_and_personal(message_id, b"", EXTRINSIC_DELAY_PERSONA) + .expect("Key, salt, and persona sizes are fixed and small enough"); + let delay = Delay::exp(h.finalize().into_bytes().as_ref()); + delay.to_duration(config.mean_extrinsic_delay) +} + +/// Request parameters and local reply channel. Stored by the +/// [`RequestManager`](mixnet::request_manager::RequestManager). +pub enum Request { + SubmitExtrinsic { extrinsic: Bytes, reply_sender: oneshot::Sender> }, +} + +impl Request { + /// Forward an error to the user of the mixnet service. + fn send_err(self, err: Error) { + match self { + Request::SubmitExtrinsic { reply_sender, .. } => send_err(reply_sender, err), + } + } + + /// Forward a reply to the user of the mixnet service. + pub fn send_reply(self, data: &[u8]) { + match self { + Request::SubmitExtrinsic { reply_sender, .. } => send_reply(reply_sender, data), + } + } +} + +impl mixnet::request_manager::Request for Request { + type Context = SubstrateConfig; + + fn with_data(&self, f: impl FnOnce(Scattered) -> T, _context: &Self::Context) -> T { + match self { + Request::SubmitExtrinsic { extrinsic, .. } => + f([&[SUBMIT_EXTRINSIC], extrinsic.as_ref()].as_slice().into()), + } + } + + fn num_surbs(&self, context: &Self::Context) -> usize { + match self { + Request::SubmitExtrinsic { .. } => context.surb_factor, + } + } + + fn handling_delay(&self, message_id: &MessageId, context: &Self::Context) -> Duration { + match self { + Request::SubmitExtrinsic { .. } => extrinsic_delay(message_id, context), + } + } + + fn handle_post_err(self, err: PostErr, _context: &Self::Context) { + self.send_err(err.into()); + } + + fn handle_retry_limit_reached(self, _context: &Self::Context) { + self.send_err(Error::NoReply); + } +} diff --git a/substrate/client/mixnet/src/run.rs b/substrate/client/mixnet/src/run.rs new file mode 100644 index 0000000000000000000000000000000000000000..09020469d5eee42782b1f3178f3402f83d5edbce --- /dev/null +++ b/substrate/client/mixnet/src/run.rs @@ -0,0 +1,388 @@ +// 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 . + +//! Top-level mixnet service function. + +use super::{ + api::ApiBackend, + config::{Config, SubstrateConfig}, + error::RemoteErr, + extrinsic_queue::ExtrinsicQueue, + maybe_inf_delay::MaybeInfDelay, + packet_dispatcher::PacketDispatcher, + peer_id::to_core_peer_id, + request::{extrinsic_delay, Request, SUBMIT_EXTRINSIC}, + sync_with_runtime::sync_with_runtime, +}; +use codec::{Decode, DecodeAll, Encode}; +use futures::{ + future::{pending, Either}, + stream::FuturesUnordered, + StreamExt, +}; +use log::{debug, error, trace, warn}; +use mixnet::{ + core::{Events, Message, Mixnet, Packet}, + reply_manager::{ReplyContext, ReplyManager}, + request_manager::RequestManager, +}; +use sc_client_api::{BlockchainEvents, HeaderBackend}; +use sc_network::{ + Event::{NotificationStreamClosed, NotificationStreamOpened, NotificationsReceived}, + NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo, ProtocolName, +}; +use sc_transaction_pool_api::{ + LocalTransactionPool, OffchainTransactionPoolFactory, TransactionPool, +}; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_consensus::SyncOracle; +use sp_keystore::{KeystoreExt, KeystorePtr}; +use sp_mixnet::{runtime_api::MixnetApi, types::Mixnode}; +use sp_runtime::{ + traits::{Block, Header}, + transaction_validity::TransactionSource, + Saturating, +}; +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; + +const LOG_TARGET: &str = "mixnet"; + +const MIN_BLOCKS_BETWEEN_REGISTRATION_ATTEMPTS: u32 = 3; + +fn complete_submit_extrinsic( + reply_manager: &mut ReplyManager, + reply_context: ReplyContext, + data: Result<(), RemoteErr>, + mixnet: &mut Mixnet, +) { + reply_manager.complete(reply_context, data.encode(), mixnet); +} + +fn handle_packet( + packet: &Packet, + mixnet: &mut Mixnet, + request_manager: &mut RequestManager, + reply_manager: &mut ReplyManager, + extrinsic_queue: &mut ExtrinsicQueue, + config: &SubstrateConfig, +) { + match mixnet.handle_packet(packet) { + Some(Message::Request(message)) => { + let Some((reply_context, data)) = reply_manager.insert(message, mixnet) else { return }; + + match data.as_slice() { + [SUBMIT_EXTRINSIC, encoded_extrinsic @ ..] => { + if !extrinsic_queue.has_space() { + debug!(target: LOG_TARGET, "No space in extrinsic queue; dropping request"); + // We don't send a reply in this case; we want the requester to retry + reply_manager.abandon(reply_context); + return + } + + // Decode the extrinsic + let mut encoded_extrinsic = encoded_extrinsic; + let extrinsic = match E::decode_all(&mut encoded_extrinsic) { + Ok(extrinsic) => extrinsic, + Err(err) => { + complete_submit_extrinsic( + reply_manager, + reply_context, + Err(RemoteErr::Decode(format!("Bad extrinsic: {}", err))), + mixnet, + ); + return + }, + }; + + let deadline = + Instant::now() + extrinsic_delay(reply_context.message_id(), config); + extrinsic_queue.insert(deadline, extrinsic, reply_context); + }, + _ => { + debug!(target: LOG_TARGET, "Unrecognised request; discarding"); + // To keep things simple we don't bother sending a reply in this case. The + // requester will give up and try another mixnode eventually. + reply_manager.abandon(reply_context); + }, + } + }, + Some(Message::Reply(message)) => { + let Some(request) = request_manager.remove(&message.request_id) else { + trace!( + target: LOG_TARGET, + "Received reply to already-completed request with message ID {:x?}", + message.request_id + ); + return + }; + request.send_reply(&message.data); + }, + None => (), + } +} + +fn time_until(instant: Instant) -> Duration { + instant.saturating_duration_since(Instant::now()) +} + +/// Run the mixnet service. If `keystore` is `None`, the service will not attempt to register the +/// local node as a mixnode, even if `config.register` is `true`. +pub async fn run( + config: Config, + mut api_backend: ApiBackend, + client: Arc, + sync: Arc, + network: Arc, + protocol_name: ProtocolName, + transaction_pool: Arc

, + keystore: Option, +) where + B: Block, + C: BlockchainEvents + ProvideRuntimeApi + HeaderBackend, + C::Api: MixnetApi, + S: SyncOracle, + N: NetworkStateInfo + NetworkEventStream + NetworkNotification + NetworkPeers, + P: TransactionPool + LocalTransactionPool + 'static, +{ + let local_peer_id = network.local_peer_id(); + let Some(local_peer_id) = to_core_peer_id(&local_peer_id) else { + error!(target: LOG_TARGET, + "Failed to convert libp2p local peer ID {local_peer_id} to mixnet peer ID; \ + mixnet not running"); + return + }; + + let offchain_transaction_pool_factory = + OffchainTransactionPoolFactory::new(transaction_pool.clone()); + + let mut mixnet = Mixnet::new(config.core); + // It would make sense to reset this to 0 when the session changes, but registrations aren't + // allowed at the start of a session anyway, so it doesn't really matter + let mut min_register_block = 0u32.into(); + let mut packet_dispatcher = PacketDispatcher::new(&local_peer_id); + let mut request_manager = RequestManager::new(config.request_manager); + let mut reply_manager = ReplyManager::new(config.reply_manager); + let mut extrinsic_queue = ExtrinsicQueue::new(config.substrate.extrinsic_queue_capacity); + + let mut finality_notifications = client.finality_notification_stream(); + // Import notifications only used for triggering registration attempts + let mut import_notifications = if config.substrate.register && keystore.is_some() { + Some(client.import_notification_stream()) + } else { + None + }; + let mut network_events = network.event_stream("mixnet").fuse(); + let mut next_forward_packet_delay = MaybeInfDelay::new(None); + let mut next_authored_packet_delay = MaybeInfDelay::new(None); + let mut ready_peers = FuturesUnordered::new(); + let mut next_retry_delay = MaybeInfDelay::new(None); + let mut next_extrinsic_delay = MaybeInfDelay::new(None); + let mut submit_extrinsic_results = FuturesUnordered::new(); + + loop { + let mut next_request = if request_manager.has_space() { + Either::Left(api_backend.request_receiver.select_next_some()) + } else { + Either::Right(pending()) + }; + + let mut next_import_notification = import_notifications.as_mut().map_or_else( + || Either::Right(pending()), + |notifications| Either::Left(notifications.select_next_some()), + ); + + futures::select! { + request = next_request => + request_manager.insert(request, &mut mixnet, &packet_dispatcher, &config.substrate), + + notification = finality_notifications.select_next_some() => { + // To avoid trying to connect to old mixnodes, ignore finality notifications while + // offline or major syncing. This is a bit racy but should be good enough. + if !sync.is_offline() && !sync.is_major_syncing() { + let api = client.runtime_api(); + sync_with_runtime(&mut mixnet, api, notification.hash); + request_manager.update_session_status( + &mut mixnet, &packet_dispatcher, &config.substrate); + } + } + + notification = next_import_notification => { + if notification.is_new_best && (*notification.header.number() >= min_register_block) { + let mut api = client.runtime_api(); + api.register_extension(KeystoreExt(keystore.clone().expect( + "Import notification stream only setup if we have a keystore"))); + api.register_extension(offchain_transaction_pool_factory + .offchain_transaction_pool(notification.hash)); + let session_index = mixnet.session_status().current_index; + let mixnode = Mixnode { + kx_public: *mixnet.next_kx_public(), + peer_id: local_peer_id, + external_addresses: network.external_addresses().into_iter() + .map(|addr| addr.to_string().into_bytes()).collect(), + }; + match api.maybe_register(notification.hash, session_index, mixnode) { + Ok(true) => min_register_block = notification.header.number().saturating_add( + MIN_BLOCKS_BETWEEN_REGISTRATION_ATTEMPTS.into()), + Ok(false) => (), + Err(err) => debug!(target: LOG_TARGET, + "Error trying to register for the next session: {err}"), + } + } + } + + event = network_events.select_next_some() => match event { + NotificationStreamOpened { remote, protocol, .. } + if protocol == protocol_name => packet_dispatcher.add_peer(&remote), + NotificationStreamClosed { remote, protocol } + if protocol == protocol_name => packet_dispatcher.remove_peer(&remote), + NotificationsReceived { remote, messages } => { + for message in messages { + if message.0 == protocol_name { + match message.1.as_ref().try_into() { + Ok(packet) => handle_packet(packet, + &mut mixnet, &mut request_manager, &mut reply_manager, + &mut extrinsic_queue, &config.substrate), + Err(_) => debug!(target: LOG_TARGET, + "Dropped incorrectly sized packet ({} bytes) from {remote}", + message.1.len(), + ), + } + } + } + } + _ => () + }, + + _ = next_forward_packet_delay => { + if let Some(packet) = mixnet.pop_next_forward_packet() { + if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { + if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + ready_peers.push(fut); + } + } + } else { + warn!(target: LOG_TARGET, + "Next forward packet deadline reached, but no packet in queue; \ + this is a bug"); + } + } + + _ = next_authored_packet_delay => { + if let Some(packet) = mixnet.pop_next_authored_packet(&packet_dispatcher) { + if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { + if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + ready_peers.push(fut); + } + } + } + } + + ready_peer = ready_peers.select_next_some() => { + if let Some(ready_peer) = ready_peer { + if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + ready_peers.push(fut); + } + } + } + + _ = next_retry_delay => { + if !request_manager.pop_next_retry(&mut mixnet, &packet_dispatcher, &config.substrate) { + warn!(target: LOG_TARGET, + "Next retry deadline reached, but no request in retry queue; \ + this is a bug"); + } + } + + _ = next_extrinsic_delay => { + if let Some((extrinsic, reply_context)) = extrinsic_queue.pop() { + if submit_extrinsic_results.len() < config.substrate.max_pending_extrinsics { + let fut = transaction_pool.submit_one( + client.info().best_hash, + TransactionSource::External, + extrinsic); + submit_extrinsic_results.push(async move { + (fut.await, reply_context) + }); + } else { + // There are already too many pending extrinsics, just drop this one. We + // don't send a reply; we want the requester to retry. + debug!(target: LOG_TARGET, + "Too many pending extrinsics; dropped submit extrinsic request"); + reply_manager.abandon(reply_context); + } + } else { + warn!(target: LOG_TARGET, + "Next extrinsic deadline reached, but no extrinsic in queue; \ + this is a bug"); + } + } + + res_reply_context = submit_extrinsic_results.select_next_some() => { + let (res, reply_context) = res_reply_context; + let res = match res { + Ok(_) => Ok(()), + Err(err) => Err(RemoteErr::Other(err.to_string())), + }; + complete_submit_extrinsic(&mut reply_manager, reply_context, res, &mut mixnet); + } + } + + let events = mixnet.take_events(); + if !events.is_empty() { + if events.contains(Events::RESERVED_PEERS_CHANGED) { + let reserved_peer_addrs = mixnet + .reserved_peers() + .flat_map(|mixnode| mixnode.extra.iter()) // External addresses + .cloned() + .collect(); + if let Err(err) = + network.set_reserved_peers(protocol_name.clone(), reserved_peer_addrs) + { + debug!(target: LOG_TARGET, "Setting reserved peers failed: {err}"); + } + } + if events.contains(Events::NEXT_FORWARD_PACKET_DEADLINE_CHANGED) { + next_forward_packet_delay + .reset(mixnet.next_forward_packet_deadline().map(time_until)); + } + if events.contains(Events::NEXT_AUTHORED_PACKET_DEADLINE_CHANGED) { + next_authored_packet_delay.reset(mixnet.next_authored_packet_delay()); + } + if events.contains(Events::SPACE_IN_AUTHORED_PACKET_QUEUE) { + // Note this may cause the next retry deadline to change, but should not trigger + // any mixnet events + request_manager.process_post_queues( + &mut mixnet, + &packet_dispatcher, + &config.substrate, + ); + } + } + + if request_manager.next_retry_deadline_changed() { + next_retry_delay.reset(request_manager.next_retry_deadline().map(time_until)); + } + + if extrinsic_queue.next_deadline_changed() { + next_extrinsic_delay.reset(extrinsic_queue.next_deadline().map(time_until)); + } + } +} diff --git a/substrate/client/mixnet/src/sync_with_runtime.rs b/substrate/client/mixnet/src/sync_with_runtime.rs new file mode 100644 index 0000000000000000000000000000000000000000..4a80b3c75f43d88ac5fd714e55fd8e7cb4c26d1c --- /dev/null +++ b/substrate/client/mixnet/src/sync_with_runtime.rs @@ -0,0 +1,228 @@ +// 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 . + +//! [`sync_with_runtime`] synchronises the session status and mixnode sets from the blockchain +//! runtime to the core mixnet state. It is called every time a block is finalised. + +use super::peer_id::from_core_peer_id; +use libp2p_identity::PeerId; +use log::{debug, info}; +use mixnet::core::{ + Mixnet, Mixnode as CoreMixnode, MixnodesErr as CoreMixnodesErr, RelSessionIndex, + SessionPhase as CoreSessionPhase, SessionStatus as CoreSessionStatus, +}; +use multiaddr::{multiaddr, Multiaddr, Protocol}; +use sp_api::{ApiError, ApiRef}; +use sp_mixnet::{ + runtime_api::MixnetApi, + types::{ + Mixnode as RuntimeMixnode, MixnodesErr as RuntimeMixnodesErr, + SessionPhase as RuntimeSessionPhase, SessionStatus as RuntimeSessionStatus, + }, +}; +use sp_runtime::traits::Block; + +const LOG_TARGET: &str = "mixnet"; + +/// Convert a [`RuntimeSessionStatus`] to a [`CoreSessionStatus`]. +/// +/// The [`RuntimeSessionStatus`] and [`CoreSessionStatus`] types are effectively the same. +/// [`RuntimeSessionStatus`] is used in the runtime to avoid depending on the [`mixnet`] crate +/// there. +fn to_core_session_status(status: RuntimeSessionStatus) -> CoreSessionStatus { + CoreSessionStatus { + current_index: status.current_index, + phase: match status.phase { + RuntimeSessionPhase::CoverToCurrent => CoreSessionPhase::CoverToCurrent, + RuntimeSessionPhase::RequestsToCurrent => CoreSessionPhase::RequestsToCurrent, + RuntimeSessionPhase::CoverToPrev => CoreSessionPhase::CoverToPrev, + RuntimeSessionPhase::DisconnectFromPrev => CoreSessionPhase::DisconnectFromPrev, + }, + } +} + +fn parse_external_addresses(external_addresses: Vec>) -> Vec { + external_addresses + .into_iter() + .flat_map(|addr| { + let addr = match String::from_utf8(addr) { + Ok(addr) => addr, + Err(addr) => { + debug!( + target: LOG_TARGET, + "Mixnode external address {:x?} is not valid UTF-8", + addr.into_bytes(), + ); + return None + }, + }; + match addr.parse() { + Ok(addr) => Some(addr), + Err(err) => { + debug!( + target: LOG_TARGET, + "Could not parse mixnode address {addr}: {err}", + ); + None + }, + } + }) + .collect() +} + +/// Modify `external_addresses` such that there is at least one address and the final component of +/// each address matches `peer_id`. +fn fixup_external_addresses(external_addresses: &mut Vec, peer_id: &PeerId) { + // Ensure the final component of each address matches peer_id + external_addresses.retain_mut(|addr| match PeerId::try_from_multiaddr(addr) { + Some(addr_peer_id) if addr_peer_id == *peer_id => true, + Some(_) => { + debug!( + target: LOG_TARGET, + "Mixnode address {} does not match mixnode peer ID {}, ignoring", + addr, + peer_id + ); + false + }, + None if matches!(addr.iter().last(), Some(Protocol::P2p(_))) => { + debug!( + target: LOG_TARGET, + "Mixnode address {} has unrecognised P2P protocol, ignoring", + addr + ); + false + }, + None => { + addr.push(Protocol::P2p(*peer_id.as_ref())); + true + }, + }); + + // If there are no addresses, insert one consisting of just the peer ID + if external_addresses.is_empty() { + external_addresses.push(multiaddr!(P2p(*peer_id.as_ref()))); + } +} + +/// Convert a [`RuntimeMixnode`] to a [`CoreMixnode`]. If the conversion fails, an error message is +/// logged, but a [`CoreMixnode`] is still returned. +/// +/// It would be possible to handle conversion failure in a better way, but this would complicate +/// things for what should be a rare case. Note that even if the conversion here succeeds, there is +/// no guarantee that we will be able to connect to the mixnode or send packets to it. The most +/// common failure case is expected to be that a mixnode is simply unreachable over the network. +fn into_core_mixnode(mixnode: RuntimeMixnode) -> CoreMixnode> { + let external_addresses = if let Some(peer_id) = from_core_peer_id(&mixnode.peer_id) { + let mut external_addresses = parse_external_addresses(mixnode.external_addresses); + fixup_external_addresses(&mut external_addresses, &peer_id); + external_addresses + } else { + debug!( + target: LOG_TARGET, + "Failed to convert mixnet peer ID {:x?} to libp2p peer ID", + mixnode.peer_id, + ); + Vec::new() + }; + + CoreMixnode { + kx_public: mixnode.kx_public, + peer_id: mixnode.peer_id, + extra: external_addresses, + } +} + +fn maybe_set_mixnodes( + mixnet: &mut Mixnet>, + rel_session_index: RelSessionIndex, + mixnodes: &dyn Fn() -> Result, RuntimeMixnodesErr>, ApiError>, +) { + let current_session_index = mixnet.session_status().current_index; + mixnet.maybe_set_mixnodes(rel_session_index, &mut || { + // Note that RelSessionIndex::Prev + 0 would panic, but this closure will not get called in + // that case so we are fine. Do not move this out of the closure! + let session_index = rel_session_index + current_session_index; + match mixnodes() { + Ok(Ok(mixnodes)) => Ok(mixnodes.into_iter().map(into_core_mixnode).collect()), + Ok(Err(err)) => { + info!(target: LOG_TARGET, "Session {session_index}: Mixnet disabled: {err}"); + Err(CoreMixnodesErr::Permanent) // Disable the session slot + }, + Err(err) => { + debug!( + target: LOG_TARGET, + "Session {session_index}: Error getting mixnodes from runtime: {err}" + ); + Err(CoreMixnodesErr::Transient) // Just leave the session slot empty; try again next block + }, + } + }); +} + +pub fn sync_with_runtime(mixnet: &mut Mixnet>, api: ApiRef, hash: B::Hash) +where + B: Block, + A: MixnetApi, +{ + let session_status = match api.session_status(hash) { + Ok(session_status) => session_status, + Err(err) => { + debug!(target: LOG_TARGET, "Error getting session status from runtime: {err}"); + return + }, + }; + mixnet.set_session_status(to_core_session_status(session_status)); + + maybe_set_mixnodes(mixnet, RelSessionIndex::Prev, &|| api.prev_mixnodes(hash)); + maybe_set_mixnodes(mixnet, RelSessionIndex::Current, &|| api.current_mixnodes(hash)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fixup_empty_external_addresses() { + let peer_id = PeerId::random(); + let mut external_addresses = Vec::new(); + fixup_external_addresses(&mut external_addresses, &peer_id); + assert_eq!(external_addresses, vec![multiaddr!(P2p(peer_id))]); + } + + #[test] + fn fixup_misc_external_addresses() { + let peer_id = PeerId::random(); + let other_peer_id = PeerId::random(); + let mut external_addresses = vec![ + multiaddr!(Tcp(0u16), P2p(peer_id)), + multiaddr!(Tcp(1u16), P2p(other_peer_id)), + multiaddr!(Tcp(2u16)), + Multiaddr::empty(), + ]; + fixup_external_addresses(&mut external_addresses, &peer_id); + assert_eq!( + external_addresses, + vec![ + multiaddr!(Tcp(0u16), P2p(peer_id)), + multiaddr!(Tcp(2u16), P2p(peer_id)), + multiaddr!(P2p(peer_id)), + ] + ); + } +} diff --git a/substrate/client/network/common/src/role.rs b/substrate/client/network/common/src/role.rs index cd43f6655b72cc2d5f1b35c0187ebcfb7a2a9b8c..fd02c00e2324afb59e10c441b5018ea292149fad 100644 --- a/substrate/client/network/common/src/role.rs +++ b/substrate/client/network/common/src/role.rs @@ -16,6 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +// file-level lint whitelist to avoid problem with bitflags macro below +// TODO: can be dropped after an update to bitflags 2.4 +#![allow(clippy::bad_bit_mask)] + use codec::{self, Encode, EncodeLike, Input, Output}; /// Role that the peer sent to us during the handshake, with the addition of what our local node diff --git a/substrate/client/network/common/src/sync.rs b/substrate/client/network/common/src/sync.rs index 5a6f90b290d2f20fc76737d1d32fa804ade51f2c..4ca21221f87febc84231b34af73433a0e29d33c5 100644 --- a/substrate/client/network/common/src/sync.rs +++ b/substrate/client/network/common/src/sync.rs @@ -36,7 +36,7 @@ use sp_runtime::{ }; use warp::WarpSyncProgress; -use std::{any::Any, fmt, fmt::Formatter, pin::Pin, sync::Arc, task::Poll}; +use std::{any::Any, fmt, fmt::Formatter, pin::Pin, sync::Arc}; /// The sync status of a peer we are trying to sync with #[derive(Debug)] @@ -116,11 +116,18 @@ impl fmt::Display for BadPeer { impl std::error::Error for BadPeer {} +/// Action that the parent of [`ChainSync`] should perform if we want to import blocks. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ImportBlocksAction { + pub origin: BlockOrigin, + pub blocks: Vec>, +} + /// Result of [`ChainSync::on_block_data`]. #[derive(Debug, Clone, PartialEq, Eq)] pub enum OnBlockData { /// The block should be imported. - Import(BlockOrigin, Vec>), + Import(ImportBlocksAction), /// A new block request needs to be made to the given peer. Request(PeerId, BlockRequest), /// Continue processing events. @@ -134,7 +141,7 @@ pub enum OnBlockJustification { Nothing, /// The justification should be imported. Import { - peer: PeerId, + peer_id: PeerId, hash: Block::Hash, number: NumberFor, justifications: Justifications, @@ -204,6 +211,23 @@ pub enum PeerRequest { WarpProof, } +#[derive(Debug)] +pub enum PeerRequestType { + Block, + State, + WarpProof, +} + +impl PeerRequest { + pub fn get_type(&self) -> PeerRequestType { + match self { + PeerRequest::Block(_) => PeerRequestType::Block, + PeerRequest::State => PeerRequestType::State, + PeerRequest::WarpProof => PeerRequestType::WarpProof, + } + } +} + /// Wrapper for implementation-specific state request. /// /// NOTE: Implementation must be able to encode and decode it for network purposes. @@ -289,12 +313,10 @@ pub trait ChainSync: Send { /// Returns the current number of peers stored within this state machine. fn num_peers(&self) -> usize; - /// Returns the number of peers we're connected to and that are being queried. - fn num_active_peers(&self) -> usize; - /// Handle a new connected peer. /// /// Call this method whenever we connect to a new peer. + #[must_use] fn new_peer( &mut self, who: PeerId, @@ -326,6 +348,7 @@ pub trait ChainSync: Send { /// /// If this corresponds to a valid block, this outputs the block that /// must be imported in the import queue. + #[must_use] fn on_block_data( &mut self, who: &PeerId, @@ -336,6 +359,7 @@ pub trait ChainSync: Send { /// Handle a response from the remote to a justification request that we made. /// /// `request` must be the original request that triggered `response`. + #[must_use] fn on_block_justification( &mut self, who: PeerId, @@ -365,14 +389,9 @@ pub trait ChainSync: Send { /// Call when a peer has disconnected. /// Canceled obsolete block request may result in some blocks being ready for /// import, so this functions checks for such blocks and returns them. - fn peer_disconnected(&mut self, who: &PeerId); + #[must_use] + fn peer_disconnected(&mut self, who: &PeerId) -> Option>; /// Return some key metrics. fn metrics(&self) -> Metrics; - - /// Advance the state of `ChainSync` - fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()>; - - /// Send block request to peer - fn send_block_request(&mut self, who: PeerId, request: BlockRequest); } diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 89513e004c6df701d6bfc93f023282629abac782..b78f15f8529c6e1ef7bb338a2d41811c47be8700 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -1423,7 +1423,6 @@ impl NetworkBehaviour for Notifications { let delay_id = self.next_delay_id; self.next_delay_id.0 += 1; let delay = futures_timer::Delay::new(ban_duration); - let peer_id = peer_id; self.delays.push( async move { delay.await; diff --git a/substrate/client/network/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index c9baa0a77d4ba401da0ea3cc565134c034724102..3a305011ded0296c7f56711182b2ec520febe94a 100644 --- a/substrate/client/network/src/protocol_controller.rs +++ b/substrate/client/network/src/protocol_controller.rs @@ -493,8 +493,8 @@ impl ProtocolController { } } - /// Remove the peer from the set of reserved peers. The peer is moved to the set of regular - /// nodes. + /// Remove the peer from the set of reserved peers. The peer is either moved to the set of + /// regular nodes or disconnected. fn on_remove_reserved_peer(&mut self, peer_id: PeerId) { let state = match self.reserved_nodes.remove(&peer_id) { Some(state) => state, @@ -508,7 +508,14 @@ impl ProtocolController { }; if let PeerState::Connected(direction) = state { - if self.reserved_only { + // Disconnect if we're at (or over) the regular node limit + let disconnect = self.reserved_only || + match direction { + Direction::Inbound => self.num_in >= self.max_in, + Direction::Outbound => self.num_out >= self.max_out, + }; + + if disconnect { // Disconnect the node. trace!( target: LOG_TARGET, diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index f10dd7869bbbc9f14522fae50c6fa166b84a716f..39312cc4b327dbc024a8cc3d3a9b934ae6bee315 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -29,6 +29,7 @@ prost = "0.11" schnellru = "0.2.1" smallvec = "1.11.0" thiserror = "1.0" +tokio-stream = "0.1.14" fork-tree = { path = "../../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } sc-client-api = { path = "../../api" } diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index 240c1ca1f8b26aba92f2d8db53be9684d69fee5d..cad50fef3e3211970a417643742a02f8221b4935 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -212,6 +212,31 @@ impl BlockCollection { ready } + /// Returns the block header of the first block that is ready for importing. + /// `from` is the maximum block number for the start of the range that we are interested in. + /// The function will return None if the first block ready is higher than `from`. + /// The logic is structured to be consistent with ready_blocks(). + pub fn first_ready_block_header(&self, from: NumberFor) -> Option { + let mut prev = from; + for (&start, range_data) in &self.blocks { + if start > prev { + break + } + + match range_data { + BlockRangeState::Complete(blocks) => { + let len = (blocks.len() as u32).into(); + prev = start + len; + if let Some(BlockData { block, .. }) = blocks.first() { + return block.header.clone() + } + }, + _ => continue, + } + } + None + } + pub fn clear_queued(&mut self, hash: &B::Hash) { if let Some((from, to)) = self.queued_blocks.remove(hash) { let mut block_num = from; diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index c93ba89c6220e7625cfd662bea984eebfa81d1b7..1a383cdde4794231e13126c69d125005340b78ce 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -23,10 +23,13 @@ use crate::{ block_announce_validator::{ BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, }, - block_relay_protocol::BlockDownloader, + block_relay_protocol::{BlockDownloader, BlockResponseError}, + pending_responses::{PendingResponses, ResponseEvent}, + schema::v1::{StateRequest, StateResponse}, service::{self, chain_sync::ToServiceCommand}, warp::WarpSyncParams, - ChainSync, ClientError, SyncingService, + BlockRequestAction, ChainSync, ClientError, ImportBlocksAction, ImportJustificationsAction, + OnBlockResponse, SyncingService, }; use codec::{Decode, Encode}; @@ -36,24 +39,33 @@ use futures::{ FutureExt, StreamExt, }; use futures_timer::Delay; -use libp2p::PeerId; +use libp2p::{request_response::OutboundFailure, PeerId}; +use log::{debug, trace}; use prometheus_endpoint::{ - register, Gauge, GaugeVec, MetricSource, Opts, PrometheusError, Registry, SourcedGauge, U64, + register, Counter, Gauge, GaugeVec, MetricSource, Opts, PrometheusError, Registry, + SourcedGauge, U64, }; +use prost::Message; use schnellru::{ByLength, LruMap}; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::ImportQueueService; use sc_network::{ - config::{FullNetworkConfiguration, NonDefaultSetConfig, ProtocolId}, + config::{ + FullNetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, + ProtocolId, SetConfig, + }, + request_responses::{IfDisconnected, RequestFailure}, utils::LruHashSet, NotificationsSink, ProtocolName, ReputationChange, }; use sc_network_common::{ role::Roles, sync::{ - message::{BlockAnnounce, BlockAnnouncesHandshake, BlockState}, - BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, SyncEvent, + message::{BlockAnnounce, BlockAnnouncesHandshake, BlockRequest, BlockState}, + warp::{EncodedProof, WarpProofRequest}, + BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, OpaqueStateRequest, + OpaqueStateResponse, PeerRequest, SyncEvent, }, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -63,6 +75,7 @@ use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::{ collections::{HashMap, HashSet}, + iter, num::NonZeroUsize, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, @@ -98,6 +111,9 @@ const INACTIVITY_EVICT_THRESHOLD: Duration = Duration::from_secs(30); /// before it starts evicting peers. const INITIAL_EVICTION_WAIT_PERIOD: Duration = Duration::from_secs(2 * 60); +/// Maximum allowed size for a block announce. +const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; + mod rep { use sc_network::ReputationChange as Rep; /// Peer has different genesis. @@ -106,6 +122,14 @@ mod rep { pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); /// Block announce substream with the peer has been inactive too long pub const INACTIVE_SUBSTREAM: Rep = Rep::new(-(1 << 10), "Inactive block announce substream"); + /// We received a message that failed to decode. + pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); + /// Peer is on unsupported protocol version. + pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); + /// Reputation change when a peer refuses a request. + pub const REFUSED: Rep = Rep::new(-(1 << 10), "Request refused"); + /// Reputation change when a peer doesn't respond in time to our messages. + pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); } struct Metrics { @@ -113,6 +137,8 @@ struct Metrics { queued_blocks: Gauge, fork_targets: Gauge, justifications: GaugeVec, + import_queue_blocks_submitted: Counter, + import_queue_justifications_submitted: Counter, } impl Metrics { @@ -142,6 +168,20 @@ impl Metrics { )?; register(g, r)? }, + import_queue_blocks_submitted: { + let c = Counter::new( + "substrate_sync_import_queue_blocks_submitted", + "Number of blocks submitted to the import queue.", + )?; + register(c, r)? + }, + import_queue_justifications_submitted: { + let c = Counter::new( + "substrate_sync_import_queue_justifications_submitted", + "Number of justifications submitted to the import queue.", + )?; + register(c, r)? + }, }) } } @@ -277,6 +317,21 @@ pub struct SyncingEngine { /// Instant when the last notification was sent or received. last_notification_io: Instant, + + /// Pending responses + pending_responses: PendingResponses, + + /// Block downloader + block_downloader: Arc>, + + /// Protocol name used to send out state requests + state_request_protocol_name: ProtocolName, + + /// Protocol name used to send out warp sync requests + warp_sync_protocol_name: Option, + + /// Handle to import queue. + import_queue: Box>, } impl SyncingEngine @@ -381,24 +436,30 @@ where let warp_sync_target_block_header_rx = warp_sync_target_block_header_rx .map_or(futures::future::pending().boxed().fuse(), |rx| rx.boxed().fuse()); - let (chain_sync, block_announce_config) = ChainSync::new( - mode, - client.clone(), + let block_announce_config = Self::get_block_announce_proto_config( protocol_id, fork_id, roles, + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); + let block_announce_protocol_name = block_announce_config.notifications_protocol.clone(); + + let chain_sync = ChainSync::new( + mode, + client.clone(), + block_announce_protocol_name.clone(), max_parallel_downloads, max_blocks_per_request, warp_sync_config, - metrics_registry, network_service.clone(), - import_queue, - block_downloader, - state_request_protocol_name, - warp_sync_protocol_name, )?; - let block_announce_protocol_name = block_announce_config.notifications_protocol.clone(); let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); @@ -455,6 +516,11 @@ where } else { None }, + pending_responses: PendingResponses::new(), + block_downloader, + state_request_protocol_name, + warp_sync_protocol_name, + import_queue, }, SyncingService::new(tx, num_connected, is_major_syncing), block_announce_config, @@ -682,11 +748,23 @@ where ToServiceCommand::BlocksProcessed(imported, count, results) => { for result in self.chain_sync.on_blocks_processed(imported, count, results) { match result { - Ok((id, req)) => self.chain_sync.send_block_request(id, req), - Err(BadPeer(id, repu)) => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - self.network_service.report_peer(id, repu) + Ok(action) => match action { + BlockRequestAction::SendRequest { peer_id, request } => { + // drop obsolete pending response first + self.pending_responses.remove(&peer_id); + self.send_block_request(peer_id, request); + }, + BlockRequestAction::RemoveStale { peer_id } => { + self.pending_responses.remove(&peer_id); + }, + }, + Err(BadPeer(peer_id, repu)) => { + self.pending_responses.remove(&peer_id); + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + self.network_service.report_peer(peer_id, repu) }, } } @@ -715,7 +793,7 @@ where let _ = tx.send(status); }, ToServiceCommand::NumActivePeers(tx) => { - let _ = tx.send(self.chain_sync.num_active_peers()); + let _ = tx.send(self.num_active_peers()); }, ToServiceCommand::SyncState(tx) => { let _ = tx.send(self.chain_sync.status()); @@ -817,8 +895,13 @@ where Poll::Pending => {}, } - // Drive `ChainSync`. - while let Poll::Ready(()) = self.chain_sync.poll(cx) {} + // Send outbound requests on `ChanSync`'s behalf. + self.send_chain_sync_requests(); + + // Poll & process pending responses. + while let Poll::Ready(Some(event)) = self.pending_responses.poll_next_unpin(cx) { + self.process_response_event(event); + } // Poll block announce validations last, because if a block announcement was received // through the event stream between `SyncingEngine` and `Protocol` and the validation @@ -859,7 +942,11 @@ where } } - self.chain_sync.peer_disconnected(&peer_id); + if let Some(import_blocks_action) = self.chain_sync.peer_disconnected(&peer_id) { + self.import_blocks(import_blocks_action) + } + + self.pending_responses.remove(&peer_id); self.event_streams.retain(|stream| { stream.unbounded_send(SyncEvent::PeerDisconnected(peer_id)).is_ok() }); @@ -991,7 +1078,7 @@ where } if let Some(req) = req { - self.chain_sync.send_block_request(peer_id, req); + self.send_block_request(peer_id, req); } self.event_streams @@ -999,4 +1086,306 @@ where Ok(()) } + + fn send_chain_sync_requests(&mut self) { + for (peer_id, request) in self.chain_sync.block_requests() { + self.send_block_request(peer_id, request); + } + + if let Some((peer_id, request)) = self.chain_sync.state_request() { + self.send_state_request(peer_id, request); + } + + for (peer_id, request) in self.chain_sync.justification_requests() { + self.send_block_request(peer_id, request); + } + + if let Some((peer_id, request)) = self.chain_sync.warp_sync_request() { + self.send_warp_sync_request(peer_id, request); + } + } + + fn send_block_request(&mut self, peer_id: PeerId, request: BlockRequest) { + if !self.chain_sync.is_peer_known(&peer_id) { + trace!(target: LOG_TARGET, "Cannot send block request to unknown peer {peer_id}"); + debug_assert!(false); + return + } + + let downloader = self.block_downloader.clone(); + + self.pending_responses.insert( + peer_id, + PeerRequest::Block(request.clone()), + async move { downloader.download_blocks(peer_id, request).await }.boxed(), + ); + } + + fn send_state_request(&mut self, peer_id: PeerId, request: OpaqueStateRequest) { + if !self.chain_sync.is_peer_known(&peer_id) { + trace!(target: LOG_TARGET, "Cannot send state request to unknown peer {peer_id}"); + debug_assert!(false); + return + } + + let (tx, rx) = oneshot::channel(); + + self.pending_responses.insert(peer_id, PeerRequest::State, rx.boxed()); + + match Self::encode_state_request(&request) { + Ok(data) => { + self.network_service.start_request( + peer_id, + self.state_request_protocol_name.clone(), + data, + tx, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: LOG_TARGET, + "Failed to encode state request {request:?}: {err:?}", + ); + }, + } + } + + fn send_warp_sync_request(&mut self, peer_id: PeerId, request: WarpProofRequest) { + if !self.chain_sync.is_peer_known(&peer_id) { + trace!(target: LOG_TARGET, "Cannot send warp proof request to unknown peer {peer_id}"); + debug_assert!(false); + return + } + + let (tx, rx) = oneshot::channel(); + + self.pending_responses.insert(peer_id, PeerRequest::WarpProof, rx.boxed()); + + match &self.warp_sync_protocol_name { + Some(name) => self.network_service.start_request( + peer_id, + name.clone(), + request.encode(), + tx, + IfDisconnected::ImmediateError, + ), + None => { + log::warn!( + target: LOG_TARGET, + "Trying to send warp sync request when no protocol is configured {request:?}", + ); + }, + } + } + + fn encode_state_request(request: &OpaqueStateRequest) -> Result, String> { + let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { + "Failed to downcast opaque state response during encoding, this is an \ + implementation bug." + .to_string() + })?; + + Ok(request.encode_to_vec()) + } + + fn decode_state_response(response: &[u8]) -> Result { + let response = StateResponse::decode(response) + .map_err(|error| format!("Failed to decode state response: {error}"))?; + + Ok(OpaqueStateResponse(Box::new(response))) + } + + fn process_response_event(&mut self, response_event: ResponseEvent) { + let ResponseEvent { peer_id, request, response } = response_event; + + match response { + Ok(Ok(resp)) => match request { + PeerRequest::Block(req) => { + match self.block_downloader.block_response_into_blocks(&req, resp) { + Ok(blocks) => { + match self.chain_sync.on_block_response(peer_id, req, blocks) { + OnBlockResponse::SendBlockRequest { peer_id, request } => + self.send_block_request(peer_id, request), + OnBlockResponse::ImportBlocks(import_blocks_action) => + self.import_blocks(import_blocks_action), + OnBlockResponse::ImportJustifications(action) => + self.import_justifications(action), + OnBlockResponse::Nothing => {}, + } + }, + Err(BlockResponseError::DecodeFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to decode block response from peer {:?}: {:?}.", + peer_id, + e + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + return + }, + Err(BlockResponseError::ExtractionFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to extract blocks from peer response {:?}: {:?}.", + peer_id, + e + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + return + }, + } + }, + PeerRequest::State => { + let response = match Self::decode_state_response(&resp[..]) { + Ok(proto) => proto, + Err(e) => { + debug!( + target: LOG_TARGET, + "Failed to decode state response from peer {peer_id:?}: {e:?}.", + ); + self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); + self.network_service.disconnect_peer( + peer_id, + self.block_announce_protocol_name.clone(), + ); + return + }, + }; + + if let Some(import_blocks_action) = + self.chain_sync.on_state_response(peer_id, response) + { + self.import_blocks(import_blocks_action); + } + }, + PeerRequest::WarpProof => { + self.chain_sync.on_warp_sync_response(peer_id, EncodedProof(resp)); + }, + }, + Ok(Err(e)) => { + debug!(target: LOG_TARGET, "Request to peer {peer_id:?} failed: {e:?}."); + + match e { + RequestFailure::Network(OutboundFailure::Timeout) => { + self.network_service.report_peer(peer_id, rep::TIMEOUT); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => { + self.network_service.report_peer(peer_id, rep::BAD_PROTOCOL); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::DialFailure) => { + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Refused => { + self.network_service.report_peer(peer_id, rep::REFUSED); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::Network(OutboundFailure::ConnectionClosed) | + RequestFailure::NotConnected => { + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + RequestFailure::UnknownProtocol => { + debug_assert!(false, "Block request protocol should always be known."); + }, + RequestFailure::Obsolete => { + debug_assert!( + false, + "Can not receive `RequestFailure::Obsolete` after dropping the \ + response receiver.", + ); + }, + } + }, + Err(oneshot::Canceled) => { + trace!( + target: LOG_TARGET, + "Request to peer {peer_id:?} failed due to oneshot being canceled.", + ); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, + } + } + + /// Returns the number of peers we're connected to and that are being queried. + fn num_active_peers(&self) -> usize { + self.pending_responses.len() + } + + /// Get config for the block announcement protocol + fn get_block_announce_proto_config( + protocol_id: ProtocolId, + fork_id: &Option, + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> NonDefaultSetConfig { + let block_announces_protocol = { + let genesis_hash = genesis_hash.as_ref(); + if let Some(ref fork_id) = fork_id { + format!( + "/{}/{}/block-announces/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) + } else { + format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) + } + }; + + NonDefaultSetConfig { + notifications_protocol: block_announces_protocol.into(), + fallback_names: iter::once( + format!("/{}/block-announces/1", protocol_id.as_ref()).into(), + ) + .collect(), + max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + roles, + best_number, + best_hash, + genesis_hash, + ))), + // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement + // protocol is still hardcoded into the peerset. + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } + + /// Import blocks. + fn import_blocks(&mut self, ImportBlocksAction { origin, blocks }: ImportBlocksAction) { + if let Some(metrics) = &self.metrics { + metrics.import_queue_blocks_submitted.inc(); + } + + self.import_queue.import_blocks(origin, blocks); + } + + /// Import justifications. + fn import_justifications(&mut self, action: ImportJustificationsAction) { + if let Some(metrics) = &self.metrics { + metrics.import_queue_justifications_submitted.inc(); + } + + let ImportJustificationsAction { peer_id, hash, number, justifications } = action; + + self.import_queue.import_justifications(peer_id, hash, number, justifications); + } } diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 20c0034966d5438b0b219c80e9721f6bde8df084..a291da4a90d58e66c8b904a3f53f171491a926ba 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -29,44 +29,29 @@ //! order to update it. use crate::{ - block_relay_protocol::{BlockDownloader, BlockResponseError}, blocks::BlockCollection, - schema::v1::{StateRequest, StateResponse}, + schema::v1::StateResponse, state::StateSync, warp::{WarpProofImportResult, WarpSync, WarpSyncConfig}, }; use codec::Encode; use extra_requests::ExtraRequests; -use futures::{channel::oneshot, task::Poll, Future, FutureExt}; -use libp2p::{request_response::OutboundFailure, PeerId}; +use libp2p::PeerId; use log::{debug, error, info, trace, warn}; -use prost::Message; -use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_client_api::{BlockBackend, ProofProvider}; -use sc_consensus::{ - import_queue::ImportQueueService, BlockImportError, BlockImportStatus, IncomingBlock, -}; -use sc_network::{ - config::{ - NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, - }, - request_responses::{IfDisconnected, RequestFailure}, - types::ProtocolName, -}; -use sc_network_common::{ - role::Roles, - sync::{ - message::{ - BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, - BlockResponse, Direction, FromBlock, - }, - warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress}, - BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, - OnStateData, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, PeerRequest, SyncMode, - SyncState, SyncStatus, +use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; +use sc_network::types::ProtocolName; +use sc_network_common::sync::{ + message::{ + BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, + FromBlock, }, + warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress}, + BadPeer, ChainSync as ChainSyncT, ImportBlocksAction, Metrics, OnBlockData, + OnBlockJustification, OnStateData, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, SyncMode, + SyncState, SyncStatus, }; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; @@ -81,9 +66,7 @@ use sp_runtime::{ use std::{ collections::{HashMap, HashSet}, - iter, ops::Range, - pin::Pin, sync::Arc, }; @@ -92,6 +75,7 @@ pub use service::chain_sync::SyncingService; mod block_announce_validator; mod extra_requests; mod futures_stream; +mod pending_responses; mod schema; pub mod block_relay_protocol; @@ -131,9 +115,6 @@ const MAJOR_SYNC_BLOCKS: u8 = 5; /// Number of peers that need to be connected before warp sync is started. const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; -/// Maximum allowed size for a block announce. -const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; - /// Maximum blocks per response. pub(crate) const MAX_BLOCKS_IN_RESPONSE: usize = 128; @@ -170,18 +151,6 @@ mod rep { /// Peer response data does not have requested bits. pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); - - /// Reputation change when a peer doesn't respond in time to our messages. - pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); - - /// Peer is on unsupported protocol version. - pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); - - /// Reputation change when a peer refuses a request. - pub const REFUSED: Rep = Rep::new(-(1 << 10), "Request refused"); - - /// We received a message that failed to decode. - pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); } enum AllowedRequests { @@ -229,49 +198,41 @@ impl Default for AllowedRequests { } } -struct SyncingMetrics { - pub import_queue_blocks_submitted: Counter, - pub import_queue_justifications_submitted: Counter, -} - -impl SyncingMetrics { - fn register(registry: &Registry) -> Result { - Ok(Self { - import_queue_blocks_submitted: register( - Counter::new( - "substrate_sync_import_queue_blocks_submitted", - "Number of blocks submitted to the import queue.", - )?, - registry, - )?, - import_queue_justifications_submitted: register( - Counter::new( - "substrate_sync_import_queue_justifications_submitted", - "Number of justifications submitted to the import queue.", - )?, - registry, - )?, - }) - } -} - struct GapSync { blocks: BlockCollection, best_queued_number: NumberFor, target: NumberFor, } -type PendingResponse = Pin< - Box< - dyn Future< - Output = ( - PeerId, - PeerRequest, - Result, RequestFailure>, oneshot::Canceled>, - ), - > + Send, - >, ->; +/// Action that [`engine::SyncingEngine`] should perform after reporting imported blocks with +/// [`ChainSync::on_blocks_processed`]. +enum BlockRequestAction { + /// Send block request to peer. Always implies dropping a stale block request to the same peer. + SendRequest { peer_id: PeerId, request: BlockRequest }, + /// Drop stale block request. + RemoveStale { peer_id: PeerId }, +} + +/// Action that [`engine::SyncingEngine`] should perform if we want to import justifications. +struct ImportJustificationsAction { + peer_id: PeerId, + hash: B::Hash, + number: NumberFor, + justifications: Justifications, +} + +/// Action that [`engine::SyncingEngine`] should perform on behalf of [`ChainSync`] +/// after reporting block response with [`ChainSync::on_block_response`]. +enum OnBlockResponse { + /// Nothing to do + Nothing, + /// Perform block request. + SendBlockRequest { peer_id: PeerId, request: BlockRequest }, + /// Import blocks. + ImportBlocks(ImportBlocksAction), + /// Import justifications. + ImportJustifications(ImportJustificationsAction), +} /// The main data structure which contains all the state for a chains /// active syncing strategy. @@ -322,18 +283,6 @@ pub struct ChainSync { network_service: service::network::NetworkServiceHandle, /// Protocol name used for block announcements block_announce_protocol_name: ProtocolName, - /// Block downloader stub - block_downloader: Arc>, - /// Protocol name used to send out state requests - state_request_protocol_name: ProtocolName, - /// Protocol name used to send out warp sync requests - warp_sync_protocol_name: Option, - /// Pending responses - pending_responses: HashMap>, - /// Handle to import queue. - import_queue: Box>, - /// Metrics. - metrics: Option, } /// All the data we have about a Peer that we are trying to sync with @@ -491,10 +440,7 @@ where self.peers.len() } - fn num_active_peers(&self) -> usize { - self.pending_responses.len() - } - + #[must_use] fn new_peer( &mut self, who: PeerId, @@ -688,6 +634,7 @@ where .extend(peers); } + #[must_use] fn on_block_data( &mut self, who: &PeerId, @@ -949,9 +896,10 @@ where return Err(BadPeer(*who, rep::NOT_REQUESTED)) }; - Ok(self.validate_and_queue_blocks(new_blocks, gap)) + Ok(OnBlockData::Import(self.validate_and_queue_blocks(new_blocks, gap))) } + #[must_use] fn on_block_justification( &mut self, who: PeerId, @@ -998,10 +946,10 @@ where None }; - if let Some((peer, hash, number, j)) = + if let Some((peer_id, hash, number, justifications)) = self.extra_justifications.on_response(who, justification) { - return Ok(OnBlockJustification::Import { peer, hash, number, justifications: j }) + return Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) } } @@ -1139,13 +1087,13 @@ where } } - fn peer_disconnected(&mut self, who: &PeerId) { + #[must_use] + fn peer_disconnected(&mut self, who: &PeerId) -> Option> { self.blocks.clear_peer_download(who); if let Some(gap_sync) = &mut self.gap_sync { gap_sync.blocks.clear_peer_download(who) } self.peers.remove(who); - self.pending_responses.remove(who); self.extra_justifications.peer_disconnected(who); self.allowed_requests.set_all(); self.fork_targets.retain(|_, target| { @@ -1154,11 +1102,8 @@ where }); let blocks = self.ready_blocks(); - if let Some(OnBlockData::Import(origin, blocks)) = - (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) - { - self.import_blocks(origin, blocks); - } + + (!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false)) } fn metrics(&self) -> Metrics { @@ -1168,36 +1113,6 @@ where justifications: self.extra_justifications.metrics(), } } - - fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { - self.process_outbound_requests(); - - while let Poll::Ready(result) = self.poll_pending_responses(cx) { - match result { - ImportResult::BlockImport(origin, blocks) => self.import_blocks(origin, blocks), - ImportResult::JustificationImport(who, hash, number, justifications) => - self.import_justifications(who, hash, number, justifications), - } - } - - Poll::Pending - } - - fn send_block_request(&mut self, who: PeerId, request: BlockRequest) { - if self.peers.contains_key(&who) { - let downloader = self.block_downloader.clone(); - self.pending_responses.insert( - who, - Box::pin(async move { - ( - who, - PeerRequest::Block(request.clone()), - downloader.download_blocks(who, request).await, - ) - }), - ); - } - } } impl ChainSync @@ -1216,32 +1131,12 @@ where pub fn new( mode: SyncMode, client: Arc, - protocol_id: ProtocolId, - fork_id: &Option, - roles: Roles, + block_announce_protocol_name: ProtocolName, max_parallel_downloads: u32, max_blocks_per_request: u32, warp_sync_config: Option>, - metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, - import_queue: Box>, - block_downloader: Arc>, - state_request_protocol_name: ProtocolName, - warp_sync_protocol_name: Option, - ) -> Result<(Self, NonDefaultSetConfig), ClientError> { - let block_announce_config = Self::get_block_announce_proto_config( - protocol_id, - fork_id, - roles, - client.info().best_number, - client.info().best_hash, - client - .block_hash(Zero::zero()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - ); - + ) -> Result { let mut sync = Self { client, peers: HashMap::new(), @@ -1261,35 +1156,13 @@ where import_existing: false, gap_sync: None, network_service, - block_downloader, - state_request_protocol_name, warp_sync_config, warp_sync_target_block_header: None, - warp_sync_protocol_name, - block_announce_protocol_name: block_announce_config - .notifications_protocol - .clone() - .into(), - pending_responses: HashMap::new(), - import_queue, - metrics: if let Some(r) = &metrics_registry { - match SyncingMetrics::register(r) { - Ok(metrics) => Some(metrics), - Err(err) => { - error!( - target: LOG_TARGET, - "Failed to register metrics for ChainSync: {err:?}", - ); - None - }, - } - } else { - None - }, + block_announce_protocol_name, }; sync.reset_sync_start_point()?; - Ok((sync, block_announce_config)) + Ok(sync) } /// Returns the median seen block number. @@ -1331,7 +1204,7 @@ where &mut self, mut new_blocks: Vec>, gap: bool, - ) -> OnBlockData { + ) -> ImportBlocksAction { let orig_len = new_blocks.len(); new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash)); if new_blocks.len() != orig_len { @@ -1362,7 +1235,8 @@ where self.on_block_queued(h, n) } self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); - OnBlockData::Import(origin, new_blocks) + + ImportBlocksAction { origin, blocks: new_blocks } } fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor) { @@ -1413,7 +1287,7 @@ where /// Restart the sync process. This will reset all pending block requests and return an iterator /// of new block requests to make to peers. Peers that were downloading finality data (i.e. /// their state was `DownloadingJustification`) are unaffected and will stay in the same state. - fn restart(&mut self) -> impl Iterator), BadPeer>> + '_ { + fn restart(&mut self) -> impl Iterator, BadPeer>> + '_ { self.blocks.clear(); if let Err(e) = self.reset_sync_start_point() { warn!(target: LOG_TARGET, "💔 Unable to restart sync: {e}"); @@ -1427,23 +1301,23 @@ where ); let old_peers = std::mem::take(&mut self.peers); - old_peers.into_iter().filter_map(move |(id, mut p)| { + old_peers.into_iter().filter_map(move |(peer_id, mut p)| { // peers that were downloading justifications // should be kept in that state. if let PeerSyncState::DownloadingJustification(_) = p.state { // We make sure our commmon number is at least something we have. p.common_number = self.best_queued_number; - self.peers.insert(id, p); + self.peers.insert(peer_id, p); return None } - // since the request is not a justification, remove it from pending responses - self.pending_responses.remove(&id); - // handle peers that were in other states. - match self.new_peer(id, p.best_hash, p.best_number) { - Ok(None) => None, - Ok(Some(x)) => Some(Ok((id, x))), + match self.new_peer(peer_id, p.best_hash, p.best_number) { + // since the request is not a justification, remove it from pending responses + Ok(None) => Some(Ok(BlockRequestAction::RemoveStale { peer_id })), + // update the request if the new one is available + Ok(Some(request)) => Some(Ok(BlockRequestAction::SendRequest { peer_id, request })), + // this implies that we need to drop pending response from the peer Err(e) => Some(Err(e)), } }) @@ -1524,10 +1398,34 @@ where .any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) } + /// Is the peer know to the sync state machine? + pub fn is_peer_known(&self, peer_id: &PeerId) -> bool { + self.peers.contains_key(peer_id) + } + /// Get the set of downloaded blocks that are ready to be queued for import. fn ready_blocks(&mut self) -> Vec> { + let start_block = self.best_queued_number + One::one(); + + // Verify that the parent of the first available block is in the chain. + // If not, we are downloading from a fork. In this case, wait until + // the start block has a parent on chain. + let parent_on_chain = + self.blocks.first_ready_block_header(start_block).map_or(false, |hdr| { + std::matches!( + self.block_status(hdr.parent_hash()).unwrap_or(BlockStatus::Unknown), + BlockStatus::InChainWithState | + BlockStatus::InChainPruned | + BlockStatus::Queued + ) + }); + + if !parent_on_chain { + return vec![] + } + self.blocks - .ready_blocks(self.best_queued_number + One::one()) + .ready_blocks(start_block) .into_iter() .map(|block_data| { let justifications = block_data @@ -1588,117 +1486,14 @@ where None } - /// Get config for the block announcement protocol - pub fn get_block_announce_proto_config( - protocol_id: ProtocolId, - fork_id: &Option, - roles: Roles, - best_number: NumberFor, - best_hash: B::Hash, - genesis_hash: B::Hash, - ) -> NonDefaultSetConfig { - let block_announces_protocol = { - let genesis_hash = genesis_hash.as_ref(); - if let Some(ref fork_id) = fork_id { - format!( - "/{}/{}/block-announces/1", - array_bytes::bytes2hex("", genesis_hash), - fork_id - ) - } else { - format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) - } - }; - - NonDefaultSetConfig { - notifications_protocol: block_announces_protocol.into(), - fallback_names: iter::once( - format!("/{}/block-announces/1", protocol_id.as_ref()).into(), - ) - .collect(), - max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( - roles, - best_number, - best_hash, - genesis_hash, - ))), - // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement - // protocol is still hardcoded into the peerset. - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, - }, - } - } - - fn decode_state_response(response: &[u8]) -> Result { - let response = StateResponse::decode(response) - .map_err(|error| format!("Failed to decode state response: {error}"))?; - - Ok(OpaqueStateResponse(Box::new(response))) - } - - fn send_state_request(&mut self, who: PeerId, request: OpaqueStateRequest) { - let (tx, rx) = oneshot::channel(); - - if self.peers.contains_key(&who) { - self.pending_responses - .insert(who, Box::pin(async move { (who, PeerRequest::State, rx.await) })); - } - - match self.encode_state_request(&request) { - Ok(data) => { - self.network_service.start_request( - who, - self.state_request_protocol_name.clone(), - data, - tx, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: LOG_TARGET, - "Failed to encode state request {request:?}: {err:?}", - ); - }, - } - } - - fn send_warp_sync_request(&mut self, who: PeerId, request: WarpProofRequest) { - let (tx, rx) = oneshot::channel(); - - if self.peers.contains_key(&who) { - self.pending_responses - .insert(who, Box::pin(async move { (who, PeerRequest::WarpProof, rx.await) })); - } - - match &self.warp_sync_protocol_name { - Some(name) => self.network_service.start_request( - who, - name.clone(), - request.encode(), - tx, - IfDisconnected::ImmediateError, - ), - None => { - log::warn!( - target: LOG_TARGET, - "Trying to send warp sync request when no protocol is configured {request:?}", - ); - }, - } - } - - fn on_block_response( + /// Process blocks received in a response. + #[must_use] + pub(crate) fn on_block_response( &mut self, peer_id: PeerId, request: BlockRequest, blocks: Vec>, - ) -> Option> { + ) -> OnBlockResponse { let block_response = BlockResponse:: { id: request.id, blocks }; let blocks_range = || match ( @@ -1723,47 +1518,47 @@ where if request.fields == BlockAttributes::JUSTIFICATION { match self.on_block_justification(peer_id, block_response) { - Ok(OnBlockJustification::Nothing) => None, - Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => { - self.import_justifications(peer, hash, number, justifications); - None - }, + Ok(OnBlockJustification::Nothing) => OnBlockResponse::Nothing, + Ok(OnBlockJustification::Import { peer_id, hash, number, justifications }) => + OnBlockResponse::ImportJustifications(ImportJustificationsAction { + peer_id, + hash, + number, + justifications, + }), Err(BadPeer(id, repu)) => { self.network_service .disconnect_peer(id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(id, repu); - None + OnBlockResponse::Nothing }, } } else { match self.on_block_data(&peer_id, Some(request), block_response) { - Ok(OnBlockData::Import(origin, blocks)) => { - self.import_blocks(origin, blocks); - None - }, - Ok(OnBlockData::Request(peer, req)) => { - self.send_block_request(peer, req); - None - }, - Ok(OnBlockData::Continue) => None, + Ok(OnBlockData::Import(action)) => OnBlockResponse::ImportBlocks(action), + Ok(OnBlockData::Request(peer_id, request)) => + OnBlockResponse::SendBlockRequest { peer_id, request }, + Ok(OnBlockData::Continue) => OnBlockResponse::Nothing, Err(BadPeer(id, repu)) => { self.network_service .disconnect_peer(id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(id, repu); - None + OnBlockResponse::Nothing }, } } } + /// Process state received in a response. + #[must_use] pub fn on_state_response( &mut self, peer_id: PeerId, response: OpaqueStateResponse, - ) -> Option> { + ) -> Option> { match self.on_state_data(&peer_id, response) { Ok(OnStateData::Import(origin, block)) => - Some(ImportResult::BlockImport(origin, vec![block])), + Some(ImportBlocksAction { origin, blocks: vec![block] }), Ok(OnStateData::Continue) => None, Err(BadPeer(id, repu)) => { self.network_service @@ -1782,165 +1577,10 @@ where } } - fn process_outbound_requests(&mut self) { - for (id, request) in self.block_requests() { - self.send_block_request(id, request); - } - - if let Some((id, request)) = self.state_request() { - self.send_state_request(id, request); - } - - for (id, request) in self.justification_requests().collect::>() { - self.send_block_request(id, request); - } - - if let Some((id, request)) = self.warp_sync_request() { - self.send_warp_sync_request(id, request); - } - } - - fn poll_pending_responses(&mut self, cx: &mut std::task::Context) -> Poll> { - let ready_responses = self - .pending_responses - .values_mut() - .filter_map(|future| match future.poll_unpin(cx) { - Poll::Pending => None, - Poll::Ready(result) => Some(result), - }) - .collect::>(); - - for (id, request, response) in ready_responses { - self.pending_responses - .remove(&id) - .expect("Logic error: peer id from pending response is missing in the map."); - - match response { - Ok(Ok(resp)) => match request { - PeerRequest::Block(req) => { - match self.block_downloader.block_response_into_blocks(&req, resp) { - Ok(blocks) => { - if let Some(import) = self.on_block_response(id, req, blocks) { - return Poll::Ready(import) - } - }, - Err(BlockResponseError::DecodeFailed(e)) => { - debug!( - target: LOG_TARGET, - "Failed to decode block response from peer {:?}: {:?}.", - id, - e - ); - self.network_service.report_peer(id, rep::BAD_MESSAGE); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - continue - }, - Err(BlockResponseError::ExtractionFailed(e)) => { - debug!( - target: LOG_TARGET, - "Failed to extract blocks from peer response {:?}: {:?}.", - id, - e - ); - self.network_service.report_peer(id, rep::BAD_MESSAGE); - continue - }, - } - }, - PeerRequest::State => { - let response = match Self::decode_state_response(&resp[..]) { - Ok(proto) => proto, - Err(e) => { - debug!( - target: LOG_TARGET, - "Failed to decode state response from peer {id:?}: {e:?}.", - ); - self.network_service.report_peer(id, rep::BAD_MESSAGE); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - continue - }, - }; - - if let Some(import) = self.on_state_response(id, response) { - return Poll::Ready(import) - } - }, - PeerRequest::WarpProof => { - self.on_warp_sync_response(id, EncodedProof(resp)); - }, - }, - Ok(Err(e)) => { - debug!(target: LOG_TARGET, "Request to peer {id:?} failed: {e:?}."); - - match e { - RequestFailure::Network(OutboundFailure::Timeout) => { - self.network_service.report_peer(id, rep::TIMEOUT); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => { - self.network_service.report_peer(id, rep::BAD_PROTOCOL); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - RequestFailure::Network(OutboundFailure::DialFailure) => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - RequestFailure::Refused => { - self.network_service.report_peer(id, rep::REFUSED); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - RequestFailure::Network(OutboundFailure::ConnectionClosed) | - RequestFailure::NotConnected => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - RequestFailure::UnknownProtocol => { - debug_assert!(false, "Block request protocol should always be known."); - }, - RequestFailure::Obsolete => { - debug_assert!( - false, - "Can not receive `RequestFailure::Obsolete` after dropping the \ - response receiver.", - ); - }, - } - }, - Err(oneshot::Canceled) => { - trace!( - target: LOG_TARGET, - "Request to peer {id:?} failed due to oneshot being canceled.", - ); - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); - }, - } - } - - Poll::Pending - } - - fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String> { - let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { - "Failed to downcast opaque state response during encoding, this is an \ - implementation bug." - .to_string() - })?; - - Ok(request.encode_to_vec()) - } - - fn justification_requests<'a>( - &'a mut self, - ) -> Box)> + 'a> { + fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); - Box::new(std::iter::from_fn(move || { + std::iter::from_fn(move || { if let Some((peer, request)) = matcher.next(peers) { peers .get_mut(&peer) @@ -1959,7 +1599,8 @@ where } else { None } - })) + }) + .collect() } fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest)> { @@ -2086,7 +1727,6 @@ where } }) .collect() - // Box::new(iter) } fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { @@ -2263,38 +1903,18 @@ where } } - fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { - if let Some(metrics) = &self.metrics { - metrics.import_queue_blocks_submitted.inc(); - } - - self.import_queue.import_blocks(origin, blocks); - } - - fn import_justifications( - &mut self, - peer: PeerId, - hash: B::Hash, - number: NumberFor, - justifications: Justifications, - ) { - if let Some(metrics) = &self.metrics { - metrics.import_queue_justifications_submitted.inc(); - } - - self.import_queue.import_justifications(peer, hash, number, justifications); - } - /// A batch of blocks have been processed, with or without errors. /// /// Call this when a batch of blocks have been processed by the import - /// queue, with or without errors. + /// queue, with or without errors. If an error is returned, the pending response + /// from the peer must be dropped. + #[must_use] fn on_blocks_processed( &mut self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) -> Box), BadPeer>>> { + ) -> Box, BadPeer>>> { trace!(target: LOG_TARGET, "Imported {imported} of {count}"); let mut output = Vec::new(); @@ -2799,13 +2419,10 @@ fn validate_blocks( #[cfg(test)] mod test { use super::*; - use crate::{mock::MockBlockDownloader, service::network::NetworkServiceProvider}; + use crate::service::network::NetworkServiceProvider; use futures::executor::block_on; use sc_block_builder::BlockBuilderProvider; - use sc_network_common::{ - role::Role, - sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}, - }; + use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; use sp_blockchain::HeaderBackend; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, @@ -2822,24 +2439,16 @@ mod test { let client = Arc::new(TestClientBuilder::new().build()); let peer_id = PeerId::random(); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 1, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -2857,7 +2466,8 @@ mod test { // the justification request should be scheduled to that peer assert!(sync .justification_requests() - .any(|(who, request)| { who == peer_id && request.from == FromBlock::Hash(a1_hash) })); + .iter() + .any(|(who, request)| { *who == peer_id && request.from == FromBlock::Hash(a1_hash) })); // there are no extra pending requests assert_eq!(sync.extra_justifications.pending_requests().count(), 0); @@ -2887,25 +2497,17 @@ mod test { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 1, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -2944,8 +2546,8 @@ mod test { // the justification request should be scheduled to the // new peer which is at the given block - assert!(sync.justification_requests().any(|(p, r)| { - p == peer_id3 && + assert!(sync.justification_requests().iter().any(|(p, r)| { + *p == peer_id3 && r.fields == BlockAttributes::JUSTIFICATION && r.from == FromBlock::Hash(b1_hash) })); @@ -2959,9 +2561,11 @@ mod test { let block_requests = sync.restart(); // which should make us send out block requests to the first two peers - assert!(block_requests - .map(|r| r.unwrap()) - .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); + assert!(block_requests.map(|r| r.unwrap()).all(|event| match event { + BlockRequestAction::SendRequest { peer_id, .. } => + peer_id == peer_id1 || peer_id == peer_id2, + BlockRequestAction::RemoveStale { .. } => false, + })); // peer 3 should be unaffected it was downloading finality data assert_eq!( @@ -3061,25 +2665,17 @@ mod test { sp_tracing::try_init_simple(); let mut client = Arc::new(TestClientBuilder::new().build()); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 5, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3141,7 +2737,9 @@ mod test { // We should not yet import the blocks, because there is still an open request for fetching // block `2` which blocks the import. - assert!(matches!(res, OnBlockData::Import(_, blocks) if blocks.is_empty())); + assert!( + matches!(res, OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) + ); let request3 = get_block_request(&mut sync, FromBlock::Number(2), 1, &peer_id2); @@ -3149,14 +2747,16 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request2), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.iter().all(|b| [2, 3, 4].contains(b.header.as_ref().unwrap().number())) )); let response = create_block_response(vec![block2.clone()]); let res = sync.on_block_data(&peer_id2, Some(request3), response).unwrap(); // Nothing to import - assert!(matches!(res, OnBlockData::Import(_, blocks) if blocks.is_empty())); + assert!( + matches!(res, OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty()) + ); } fn unwrap_from_block_number(from: FromBlock) -> u64 { @@ -3186,26 +2786,18 @@ mod test { }; let mut client = Arc::new(TestClientBuilder::new().build()); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let info = client.info(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 5, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3238,7 +2830,7 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == max_blocks_to_request as usize + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize ),); best_block_num += max_blocks_to_request as u32; @@ -3294,7 +2886,7 @@ mod test { let res = sync.on_block_data(&peer_id2, Some(peer2_req), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.is_empty() + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() ),); let peer1_from = unwrap_from_block_number(peer1_req.unwrap().from); @@ -3321,7 +2913,6 @@ mod test { fn can_sync_huge_fork() { sp_tracing::try_init_simple(); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); @@ -3348,21 +2939,14 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 5, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3420,7 +3004,7 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == sync.max_blocks_per_request as usize + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == sync.max_blocks_per_request as usize ),); best_block_num += sync.max_blocks_per_request as u32; @@ -3463,7 +3047,6 @@ mod test { fn syncs_fork_without_duplicate_requests() { sp_tracing::try_init_simple(); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); @@ -3490,21 +3073,14 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 5, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3563,7 +3139,7 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == max_blocks_to_request as usize + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == max_blocks_to_request as usize ),); best_block_num += max_blocks_to_request as u32; @@ -3628,27 +3204,19 @@ mod test { #[test] fn removes_target_fork_on_disconnect() { sp_tracing::try_init_simple(); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 1, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3664,14 +3232,13 @@ mod test { send_block_announce(header, peer_id1, &mut sync); assert!(sync.fork_targets.len() == 1); - sync.peer_disconnected(&peer_id1); + let _ = sync.peer_disconnected(&peer_id1); assert!(sync.fork_targets.len() == 0); } #[test] fn can_import_response_with_missing_blocks() { sp_tracing::try_init_simple(); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let mut client2 = Arc::new(TestClientBuilder::new().build()); @@ -3679,21 +3246,14 @@ mod test { let empty_client = Arc::new(TestClientBuilder::new().build()); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, empty_client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 1, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3728,24 +3288,16 @@ mod test { #[test] fn sync_restart_removes_block_but_not_justification_requests() { let mut client = Arc::new(TestClientBuilder::new().build()); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let mut sync = ChainSync::new( SyncMode::Full, client.clone(), - ProtocolId::from("test-protocol-name"), - &Some(String::from("test-fork-id")), - Roles::from(&Role::Full), + ProtocolName::from("test-block-announce-protocol"), 1, 64, None, - None, chain_sync_network_handle, - import_queue, - Arc::new(MockBlockDownloader::new()), - ProtocolName::from("state-request"), - None, ) .unwrap(); @@ -3766,10 +3318,14 @@ mod test { // add new peer and request blocks from them sync.new_peer(peers[0], Hash::random(), 42).unwrap(); + // we don't actually perform any requests, just keep track of peers waiting for a response + let mut pending_responses = HashSet::new(); + // we wil send block requests to these peers // for these blocks we don't know about - for (peer, request) in sync.block_requests() { - sync.send_block_request(peer, request); + for (peer, _request) in sync.block_requests() { + // "send" request + pending_responses.insert(peer); } // add a new peer at a known block @@ -3780,10 +3336,11 @@ mod test { // the justification request should be scheduled to the // new peer which is at the given block - let mut requests = sync.justification_requests().collect::>(); + let mut requests = sync.justification_requests(); assert_eq!(requests.len(), 1); - let (peer, request) = requests.remove(0); - sync.send_block_request(peer, request); + let (peer, _request) = requests.remove(0); + // "send" request + assert!(pending_responses.insert(peer)); assert!(!std::matches!( sync.peers.get(&peers[0]).unwrap().state, @@ -3793,18 +3350,413 @@ mod test { sync.peers.get(&peers[1]).unwrap().state, PeerSyncState::DownloadingJustification(b1_hash), ); - assert_eq!(sync.pending_responses.len(), 2); - - let requests = sync.restart().collect::>(); - assert!(requests.iter().any(|res| res.as_ref().unwrap().0 == peers[0])); + assert_eq!(pending_responses.len(), 2); + + // restart sync + let request_events = sync.restart().collect::>(); + for event in request_events.iter() { + match event.as_ref().unwrap() { + BlockRequestAction::RemoveStale { peer_id } => { + pending_responses.remove(&peer_id); + }, + BlockRequestAction::SendRequest { peer_id, .. } => { + // we drop obsolete response, but don't register a new request, it's checked in + // the `assert!` below + pending_responses.remove(&peer_id); + }, + } + } + assert!(request_events.iter().any(|event| { + match event.as_ref().unwrap() { + BlockRequestAction::RemoveStale { .. } => false, + BlockRequestAction::SendRequest { peer_id, .. } => peer_id == &peers[0], + } + })); - assert_eq!(sync.pending_responses.len(), 1); - assert!(sync.pending_responses.get(&peers[1]).is_some()); + assert_eq!(pending_responses.len(), 1); + assert!(pending_responses.contains(&peers[1])); assert_eq!( sync.peers.get(&peers[1]).unwrap().state, PeerSyncState::DownloadingJustification(b1_hash), ); - sync.peer_disconnected(&peers[1]); - assert_eq!(sync.pending_responses.len(), 0); + let _ = sync.peer_disconnected(&peers[1]); + pending_responses.remove(&peers[1]); + assert_eq!(pending_responses.len(), 0); + } + + #[test] + fn syncs_fork_with_partial_response_extends_tip() { + sp_tracing::try_init_simple(); + + // Set up: the two chains share the first 15 blocks before + // diverging. The other(canonical) chain fork is longer. + let max_blocks_per_request = 64; + let common_ancestor = 15; + let non_canonical_chain_length = common_ancestor + 3; + let canonical_chain_length = common_ancestor + max_blocks_per_request + 10; + + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + + // Blocks on the non-canonical chain. + let non_canonical_blocks = (0..non_canonical_chain_length) + .map(|_| build_block(&mut client, None, false)) + .collect::>(); + + // Blocks on the canonical chain. + let canonical_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let common_blocks = non_canonical_blocks[..common_ancestor as usize] + .into_iter() + .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) + .cloned() + .collect::>(); + + common_blocks + .into_iter() + .chain( + (0..(canonical_chain_length - common_ancestor as u32)) + .map(|_| build_block(&mut client, None, true)), + ) + .collect::>() + }; + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + max_blocks_per_request, + None, + chain_sync_network_handle, + ) + .unwrap(); + + // Connect the node we will sync from + let peer_id = PeerId::random(); + let canonical_tip = canonical_blocks.last().unwrap().clone(); + let mut request = sync + .new_peer(peer_id, canonical_tip.hash(), *canonical_tip.header().number()) + .unwrap() + .unwrap(); + assert_eq!(FromBlock::Number(client.info().best_number), request.from); + assert_eq!(Some(1), request.max); + + // Do the ancestor search + loop { + let block = + &canonical_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1]; + let response = create_block_response(vec![block.clone()]); + + let on_block_data = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { + // We found the ancestor + break + }; + + log::trace!(target: LOG_TARGET, "Request: {request:?}"); + } + + // The response for the 64 blocks is returned in two parts: + // part 1: last 61 blocks [19..79], part 2: first 3 blocks [16-18]. + // Even though the first part extends the current chain ending at 18, + // it should not result in an import yet. + let resp_1_from = common_ancestor as u64 + max_blocks_per_request as u64; + let resp_2_from = common_ancestor as u64 + 3; + + // No import expected. + let request = get_block_request( + &mut sync, + FromBlock::Number(resp_1_from), + max_blocks_per_request as u32, + &peer_id, + ); + + let from = unwrap_from_block_number(request.from.clone()); + let mut resp_blocks = canonical_blocks[18..from as usize].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() + ),); + + // Gap filled, expect max_blocks_per_request being imported now. + let request = get_block_request(&mut sync, FromBlock::Number(resp_2_from), 3, &peer_id); + let mut resp_blocks = canonical_blocks[common_ancestor as usize..18].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + let to_import: Vec<_> = match &res { + OnBlockData::Import(ImportBlocksAction { origin: _, blocks }) => { + assert_eq!(blocks.len(), sync.max_blocks_per_request as usize); + blocks + .iter() + .map(|b| { + let num = *b.header.as_ref().unwrap().number() as usize; + canonical_blocks[num - 1].clone() + }) + .collect() + }, + _ => { + panic!("Unexpected response: {res:?}"); + }, + }; + + let _ = sync.on_blocks_processed( + max_blocks_per_request as usize, + resp_blocks.len(), + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id), + )), + b.hash(), + ) + }) + .collect(), + ); + to_import.into_iter().for_each(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, b)).unwrap(); + }); + let expected_number = common_ancestor as u32 + max_blocks_per_request as u32; + assert_eq!(sync.best_queued_number as u32, expected_number); + assert_eq!(sync.best_queued_hash, canonical_blocks[expected_number as usize - 1].hash()); + // Sync rest of the chain. + let request = + get_block_request(&mut sync, FromBlock::Hash(canonical_tip.hash()), 10_u32, &peer_id); + let mut resp_blocks = canonical_blocks + [(canonical_chain_length - 10) as usize..canonical_chain_length as usize] + .to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 10 as usize + ),); + let _ = sync.on_blocks_processed( + max_blocks_per_request as usize, + resp_blocks.len(), + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id), + )), + b.hash(), + ) + }) + .collect(), + ); + resp_blocks.into_iter().rev().for_each(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, b)).unwrap(); + }); + let expected_number = canonical_chain_length as u32; + assert_eq!(sync.best_queued_number as u32, expected_number); + assert_eq!(sync.best_queued_hash, canonical_blocks[expected_number as usize - 1].hash()); + } + + #[test] + fn syncs_fork_with_partial_response_does_not_extend_tip() { + sp_tracing::try_init_simple(); + + // Set up: the two chains share the first 15 blocks before + // diverging. The other(canonical) chain fork is longer. + let max_blocks_per_request = 64; + let common_ancestor = 15; + let non_canonical_chain_length = common_ancestor + 3; + let canonical_chain_length = common_ancestor + max_blocks_per_request + 10; + + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let mut client = Arc::new(TestClientBuilder::new().build()); + + // Blocks on the non-canonical chain. + let non_canonical_blocks = (0..non_canonical_chain_length) + .map(|_| build_block(&mut client, None, false)) + .collect::>(); + + // Blocks on the canonical chain. + let canonical_blocks = { + let mut client = Arc::new(TestClientBuilder::new().build()); + let common_blocks = non_canonical_blocks[..common_ancestor as usize] + .into_iter() + .inspect(|b| block_on(client.import(BlockOrigin::Own, (*b).clone())).unwrap()) + .cloned() + .collect::>(); + + common_blocks + .into_iter() + .chain( + (0..(canonical_chain_length - common_ancestor as u32)) + .map(|_| build_block(&mut client, None, true)), + ) + .collect::>() + }; + + let mut sync = ChainSync::new( + SyncMode::Full, + client.clone(), + ProtocolName::from("test-block-announce-protocol"), + 1, + max_blocks_per_request, + None, + chain_sync_network_handle, + ) + .unwrap(); + + // Connect the node we will sync from + let peer_id = PeerId::random(); + let canonical_tip = canonical_blocks.last().unwrap().clone(); + let mut request = sync + .new_peer(peer_id, canonical_tip.hash(), *canonical_tip.header().number()) + .unwrap() + .unwrap(); + assert_eq!(FromBlock::Number(client.info().best_number), request.from); + assert_eq!(Some(1), request.max); + + // Do the ancestor search + loop { + let block = + &canonical_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1]; + let response = create_block_response(vec![block.clone()]); + + let on_block_data = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + request = if let OnBlockData::Request(_peer, request) = on_block_data { + request + } else { + // We found the ancestor + break + }; + + log::trace!(target: LOG_TARGET, "Request: {request:?}"); + } + + // The response for the 64 blocks is returned in two parts: + // part 1: last 62 blocks [18..79], part 2: first 2 blocks [16-17]. + // Even though the first part extends the current chain ending at 18, + // it should not result in an import yet. + let resp_1_from = common_ancestor as u64 + max_blocks_per_request as u64; + let resp_2_from = common_ancestor as u64 + 2; + + // No import expected. + let request = get_block_request( + &mut sync, + FromBlock::Number(resp_1_from), + max_blocks_per_request as u32, + &peer_id, + ); + + let from = unwrap_from_block_number(request.from.clone()); + let mut resp_blocks = canonical_blocks[17..from as usize].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.is_empty() + ),); + + // Gap filled, expect max_blocks_per_request being imported now. + let request = get_block_request(&mut sync, FromBlock::Number(resp_2_from), 2, &peer_id); + let mut resp_blocks = canonical_blocks[common_ancestor as usize..17].to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + let to_import: Vec<_> = match &res { + OnBlockData::Import(ImportBlocksAction { origin: _, blocks }) => { + assert_eq!(blocks.len(), sync.max_blocks_per_request as usize); + blocks + .iter() + .map(|b| { + let num = *b.header.as_ref().unwrap().number() as usize; + canonical_blocks[num - 1].clone() + }) + .collect() + }, + _ => { + panic!("Unexpected response: {res:?}"); + }, + }; + + let _ = sync.on_blocks_processed( + max_blocks_per_request as usize, + resp_blocks.len(), + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id), + )), + b.hash(), + ) + }) + .collect(), + ); + to_import.into_iter().for_each(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, b)).unwrap(); + }); + let expected_number = common_ancestor as u32 + max_blocks_per_request as u32; + assert_eq!(sync.best_queued_number as u32, expected_number); + assert_eq!(sync.best_queued_hash, canonical_blocks[expected_number as usize - 1].hash()); + // Sync rest of the chain. + let request = + get_block_request(&mut sync, FromBlock::Hash(canonical_tip.hash()), 10_u32, &peer_id); + let mut resp_blocks = canonical_blocks + [(canonical_chain_length - 10) as usize..canonical_chain_length as usize] + .to_vec(); + resp_blocks.reverse(); + let response = create_block_response(resp_blocks.clone()); + let res = sync.on_block_data(&peer_id, Some(request), response).unwrap(); + assert!(matches!( + res, + OnBlockData::Import(ImportBlocksAction{ origin: _, blocks }) if blocks.len() == 10 as usize + ),); + let _ = sync.on_blocks_processed( + max_blocks_per_request as usize, + resp_blocks.len(), + resp_blocks + .iter() + .rev() + .map(|b| { + ( + Ok(BlockImportStatus::ImportedUnknown( + *b.header().number(), + Default::default(), + Some(peer_id), + )), + b.hash(), + ) + }) + .collect(), + ); + resp_blocks.into_iter().rev().for_each(|b| { + assert!(matches!(client.block(*b.header.parent_hash()), Ok(Some(_)))); + block_on(client.import(BlockOrigin::Own, b)).unwrap(); + }); + let expected_number = canonical_chain_length as u32; + assert_eq!(sync.best_queued_number as u32, expected_number); + assert_eq!(sync.best_queued_hash, canonical_blocks[expected_number as usize - 1].hash()); } } diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index 859f9fb9c54b620f67fc2729043e8a9a145d97af..ed7c647c797732f0ff0c39828b52a9ec470f292e 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -20,13 +20,13 @@ use crate::block_relay_protocol::{BlockDownloader as BlockDownloaderT, BlockResponseError}; -use futures::{channel::oneshot, task::Poll}; +use futures::channel::oneshot; use libp2p::PeerId; use sc_network::RequestFailure; use sc_network_common::sync::{ message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, PeerInfo, - SyncStatus, + BadPeer, ChainSync as ChainSyncT, ImportBlocksAction, Metrics, OnBlockData, + OnBlockJustification, PeerInfo, SyncStatus, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -39,7 +39,6 @@ mockall::mock! { fn num_sync_requests(&self) -> usize; fn num_downloaded_blocks(&self) -> usize; fn num_peers(&self) -> usize; - fn num_active_peers(&self) -> usize; fn new_peer( &mut self, who: PeerId, @@ -79,17 +78,8 @@ mockall::mock! { who: PeerId, announce: &BlockAnnounce, ); - fn peer_disconnected(&mut self, who: &PeerId); + fn peer_disconnected(&mut self, who: &PeerId) -> Option>; fn metrics(&self) -> Metrics; - fn poll<'a>( - &mut self, - cx: &mut std::task::Context<'a>, - ) -> Poll<()>; - fn send_block_request( - &mut self, - who: PeerId, - request: BlockRequest, - ); } } diff --git a/substrate/client/network/sync/src/pending_responses.rs b/substrate/client/network/sync/src/pending_responses.rs new file mode 100644 index 0000000000000000000000000000000000000000..c863267e7808f13104eacd3d30f39987946443bf --- /dev/null +++ b/substrate/client/network/sync/src/pending_responses.rs @@ -0,0 +1,114 @@ +// 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 . + +//! [`PendingResponses`] is responsible for keeping track of pending responses and +//! polling them. + +use futures::{ + channel::oneshot, + future::BoxFuture, + stream::{BoxStream, Stream}, + FutureExt, StreamExt, +}; +use libp2p::PeerId; +use log::error; +use sc_network::request_responses::RequestFailure; +use sc_network_common::sync::PeerRequest; +use sp_runtime::traits::Block as BlockT; +use std::task::{Context, Poll}; +use tokio_stream::StreamMap; + +/// Response result. +type ResponseResult = Result, RequestFailure>, oneshot::Canceled>; + +/// A future yielding [`ResponseResult`]. +type ResponseFuture = BoxFuture<'static, ResponseResult>; + +/// An event we receive once a pending response future resolves. +pub(crate) struct ResponseEvent { + pub peer_id: PeerId, + pub request: PeerRequest, + pub response: ResponseResult, +} + +/// Stream taking care of polling pending responses. +pub(crate) struct PendingResponses { + /// Pending responses + pending_responses: StreamMap, ResponseResult)>>, +} + +impl PendingResponses { + pub fn new() -> Self { + Self { pending_responses: StreamMap::new() } + } + + pub fn insert( + &mut self, + peer_id: PeerId, + request: PeerRequest, + response_future: ResponseFuture, + ) { + let request_type = request.get_type(); + + if self + .pending_responses + .insert( + peer_id, + Box::pin(async move { (request, response_future.await) }.into_stream()), + ) + .is_some() + { + error!( + target: crate::LOG_TARGET, + "Discarded pending response from peer {peer_id}, request type: {request_type:?}.", + ); + debug_assert!(false); + } + } + + pub fn remove(&mut self, peer_id: &PeerId) -> bool { + self.pending_responses.remove(peer_id).is_some() + } + + pub fn len(&self) -> usize { + self.pending_responses.len() + } +} + +impl Unpin for PendingResponses {} + +impl Stream for PendingResponses { + type Item = ResponseEvent; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match futures::ready!(self.pending_responses.poll_next_unpin(cx)) { + Some((peer_id, (request, response))) => { + // We need to manually remove the stream, because `StreamMap` doesn't know yet that + // it's going to yield `None`, so may not remove it before the next request is made + // to the same peer. + self.pending_responses.remove(&peer_id); + + Poll::Ready(Some(ResponseEvent { peer_id, request, response })) + }, + None => Poll::Ready(None), + } + } +} diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index a2ee090b1c23994169dba9b1105c3972f0a83a07..9dca2e72fcdd5d5d3ce6deecbd794e5b2e1c02e4 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -19,6 +19,7 @@ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" thiserror = "1.0" sc-chain-spec = { path = "../chain-spec" } +sc-mixnet = { path = "../mixnet" } sc-transaction-pool-api = { path = "../transaction-pool/api" } sp-core = { path = "../../primitives/core" } sp-rpc = { path = "../../primitives/rpc" } diff --git a/substrate/client/rpc-api/src/error.rs b/substrate/client/rpc-api/src/error.rs index 72941e3145b94424bc16fdd77d0dc2117e89eecb..58b75b8fb1691f4dbbb93b9adc457bf5719c596b 100644 --- a/substrate/client/rpc-api/src/error.rs +++ b/substrate/client/rpc-api/src/error.rs @@ -25,4 +25,5 @@ pub mod base { pub const OFFCHAIN: i32 = 5000; pub const DEV: i32 = 6000; pub const STATEMENT: i32 = 7000; + pub const MIXNET: i32 = 8000; } diff --git a/substrate/client/rpc-api/src/lib.rs b/substrate/client/rpc-api/src/lib.rs index b99c237dc859bc1fd03a87c63b365956b7a6f5a1..32120d37902dd6718c2d95b5f36ef553dfc08ba1 100644 --- a/substrate/client/rpc-api/src/lib.rs +++ b/substrate/client/rpc-api/src/lib.rs @@ -31,6 +31,7 @@ pub mod author; pub mod chain; pub mod child_state; pub mod dev; +pub mod mixnet; pub mod offchain; pub mod state; pub mod statement; diff --git a/substrate/client/rpc-api/src/mixnet/error.rs b/substrate/client/rpc-api/src/mixnet/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..0dde5f32e6139acae2c867dbf24f53002dfffe56 --- /dev/null +++ b/substrate/client/rpc-api/src/mixnet/error.rs @@ -0,0 +1,48 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Mixnet RPC module errors. + +use jsonrpsee::types::error::{CallError, ErrorObject}; +use sc_mixnet::{PostErr, RemoteErr, TopologyErr}; + +/// Mixnet RPC error type. +pub struct Error(pub sc_mixnet::Error); + +/// Base code for all mixnet errors. +const BASE_ERROR: i32 = crate::error::base::MIXNET; + +impl From for jsonrpsee::core::Error { + fn from(err: Error) -> Self { + let code = match err.0 { + sc_mixnet::Error::ServiceUnavailable => BASE_ERROR + 1, + sc_mixnet::Error::NoReply => BASE_ERROR + 2, + sc_mixnet::Error::BadReply => BASE_ERROR + 3, + sc_mixnet::Error::Post(PostErr::TooManyFragments) => BASE_ERROR + 101, + sc_mixnet::Error::Post(PostErr::SessionMixnodesNotKnown(_)) => BASE_ERROR + 102, + sc_mixnet::Error::Post(PostErr::SessionDisabled(_)) => BASE_ERROR + 103, + sc_mixnet::Error::Post(PostErr::Topology(TopologyErr::NoConnectedGatewayMixnodes)) => + BASE_ERROR + 151, + sc_mixnet::Error::Post(PostErr::Topology(_)) => BASE_ERROR + 150, + sc_mixnet::Error::Post(_) => BASE_ERROR + 100, + sc_mixnet::Error::Remote(RemoteErr::Other(_)) => BASE_ERROR + 200, + sc_mixnet::Error::Remote(RemoteErr::Decode(_)) => BASE_ERROR + 201, + }; + CallError::Custom(ErrorObject::owned(code, err.0.to_string(), None::<()>)).into() + } +} diff --git a/substrate/client/rpc-api/src/mixnet/mod.rs b/substrate/client/rpc-api/src/mixnet/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..bc478cf3bf334db618b240193ae7c58d732f0cc9 --- /dev/null +++ b/substrate/client/rpc-api/src/mixnet/mod.rs @@ -0,0 +1,31 @@ +// 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 mixnet API. + +pub mod error; + +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sp_core::Bytes; + +#[rpc(client, server)] +pub trait MixnetApi { + /// Submit encoded extrinsic over the mixnet for inclusion in block. + #[method(name = "mixnet_submitExtrinsic")] + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<()>; +} diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 92b31937a0cbb1e018cacf17c5e19f418293877b..dc625c3d6c4cf44d37b865d9e022047066b34e58 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -145,6 +145,8 @@ fn hosts_filtering(enabled: bool, addrs: &[SocketAddr]) -> AllowHosts { 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 diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index c93006753afbbefedef3de6b27863aab0269fbfc..1eaed65706e049f0e1e4765334f76b26e723e088 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -31,12 +31,11 @@ serde = "1.0" hex = "0.4" futures = "0.3.21" parking_lot = "0.12.1" -tokio-stream = { version = "0.1", features = ["sync"] } +tokio-stream = { version = "0.1.14", features = ["sync"] } tokio = { version = "1.22.0", features = ["sync"] } array-bytes = "6.1" log = "0.4.17" futures-util = { version = "0.3.19", default-features = false } - [dev-dependencies] serde_json = "1.0" tokio = { version = "1.22.0", features = ["macros"] } diff --git a/substrate/client/rpc-spec-v2/src/archive/api.rs b/substrate/client/rpc-spec-v2/src/archive/api.rs new file mode 100644 index 0000000000000000000000000000000000000000..0583111cb488d1eeab5a175e13c6a592b2c7df3d --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/api.rs @@ -0,0 +1,91 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API trait of the archive methods. + +use crate::MethodResult; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(client, server)] +pub trait ArchiveApi { + /// Retrieves the body (list of transactions) of a given block hash. + /// + /// Returns an array of strings containing the hexadecimal-encoded SCALE-codec-encoded + /// transactions in that block. If no block with that hash is found, null. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_body")] + fn archive_unstable_body(&self, hash: Hash) -> RpcResult>>; + + /// Get the chain's genesis hash. + /// + /// Returns a string containing the hexadecimal-encoded hash of the genesis block of the chain. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_genesisHash")] + fn archive_unstable_genesis_hash(&self) -> RpcResult; + + /// Get the block's header. + /// + /// Returns a string containing the hexadecimal-encoded SCALE-codec encoding header of the + /// block. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_header")] + fn archive_unstable_header(&self, hash: Hash) -> RpcResult>; + + /// Get the height of the current finalized block. + /// + /// Returns an integer height of the current finalized block of the chain. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_finalizedHeight")] + fn archive_unstable_finalized_height(&self) -> RpcResult; + + /// Get the hashes of blocks from the given height. + /// + /// Returns an array (possibly empty) of strings containing an hexadecimal-encoded hash of a + /// block header. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_hashByHeight")] + fn archive_unstable_hash_by_height(&self, height: u64) -> RpcResult>; + + /// Call into the Runtime API at a specified block's state. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "archive_unstable_call")] + fn archive_unstable_call( + &self, + hash: Hash, + function: String, + call_parameters: String, + ) -> RpcResult; +} diff --git a/substrate/client/rpc-spec-v2/src/archive/archive.rs b/substrate/client/rpc-spec-v2/src/archive/archive.rs new file mode 100644 index 0000000000000000000000000000000000000000..bded842d8fd0de408b0d233af12010d41a9a7df7 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs @@ -0,0 +1,188 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API implementation for `archive`. + +use crate::{ + archive::{error::Error as ArchiveError, ArchiveApiServer}, + chain_head::hex_string, + MethodResult, +}; + +use codec::Encode; +use jsonrpsee::core::{async_trait, RpcResult}; +use sc_client_api::{ + Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, StorageProvider, +}; +use sp_api::{CallApiAt, CallContext, NumberFor}; +use sp_blockchain::{ + Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, +}; +use sp_core::Bytes; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT}, + SaturatedConversion, +}; +use std::{collections::HashSet, marker::PhantomData, sync::Arc}; + +/// An API for archive RPC calls. +pub struct Archive, Block: BlockT, Client> { + /// Substrate client. + client: Arc, + /// Backend of the chain. + backend: Arc, + /// The hexadecimal encoded hash of the genesis block. + genesis_hash: String, + /// Phantom member to pin the block type. + _phantom: PhantomData<(Block, BE)>, +} + +impl, Block: BlockT, Client> Archive { + /// Create a new [`Archive`]. + pub fn new>( + client: Arc, + backend: Arc, + genesis_hash: GenesisHash, + ) -> Self { + let genesis_hash = hex_string(&genesis_hash.as_ref()); + Self { client, backend, genesis_hash, _phantom: PhantomData } + } +} + +/// Parse hex-encoded string parameter as raw bytes. +/// +/// If the parsing fails, returns an error propagated to the RPC method. +fn parse_hex_param(param: String) -> Result, ArchiveError> { + // Methods can accept empty parameters. + if param.is_empty() { + return Ok(Default::default()) + } + + array_bytes::hex2bytes(¶m).map_err(|_| ArchiveError::InvalidParam(param)) +} + +#[async_trait] +impl ArchiveApiServer for Archive +where + Block: BlockT + 'static, + Block::Header: Unpin, + <::Header as HeaderT>::Number: From, + BE: Backend + 'static, + Client: BlockBackend + + ExecutorProvider + + HeaderBackend + + HeaderMetadata + + BlockchainEvents + + CallApiAt + + StorageProvider + + 'static, +{ + fn archive_unstable_body(&self, hash: Block::Hash) -> RpcResult>> { + let Ok(Some(signed_block)) = self.client.block(hash) else { return Ok(None) }; + + let extrinsics = signed_block + .block + .extrinsics() + .iter() + .map(|extrinsic| hex_string(&extrinsic.encode())) + .collect(); + + Ok(Some(extrinsics)) + } + + fn archive_unstable_genesis_hash(&self) -> RpcResult { + Ok(self.genesis_hash.clone()) + } + + fn archive_unstable_header(&self, hash: Block::Hash) -> RpcResult> { + let Ok(Some(header)) = self.client.header(hash) else { return Ok(None) }; + + Ok(Some(hex_string(&header.encode()))) + } + + fn archive_unstable_finalized_height(&self) -> RpcResult { + Ok(self.client.info().finalized_number.saturated_into()) + } + + fn archive_unstable_hash_by_height(&self, height: u64) -> RpcResult> { + let height: NumberFor = height.into(); + let finalized_num = self.client.info().finalized_number; + + if finalized_num >= height { + let Ok(Some(hash)) = self.client.block_hash(height.into()) else { return Ok(vec![]) }; + return Ok(vec![hex_string(&hash.as_ref())]) + } + + let blockchain = self.backend.blockchain(); + // Fetch all the leaves of the blockchain that are on a higher or equal height. + let mut headers: Vec<_> = blockchain + .leaves() + .map_err(|error| ArchiveError::FetchLeaves(error.to_string()))? + .into_iter() + .filter_map(|hash| { + let Ok(Some(header)) = self.client.header(hash) else { return None }; + + if header.number() < &height { + return None + } + + Some(header) + }) + .collect(); + + let mut result = Vec::new(); + let mut visited = HashSet::new(); + + while let Some(header) = headers.pop() { + if header.number() == &height { + result.push(hex_string(&header.hash().as_ref())); + continue + } + + let parent_hash = *header.parent_hash(); + + // Continue the iteration for unique hashes. + // Forks might intersect on a common chain that is not yet finalized. + if visited.insert(parent_hash) { + let Ok(Some(next_header)) = self.client.header(parent_hash) else { continue }; + headers.push(next_header); + } + } + + Ok(result) + } + + fn archive_unstable_call( + &self, + hash: Block::Hash, + function: String, + call_parameters: String, + ) -> RpcResult { + let call_parameters = Bytes::from(parse_hex_param(call_parameters)?); + + let result = + self.client + .executor() + .call(hash, &function, &call_parameters, CallContext::Offchain); + + Ok(match result { + Ok(result) => MethodResult::ok(hex_string(&result)), + Err(error) => MethodResult::err(error.to_string()), + }) + } +} diff --git a/substrate/client/rpc-spec-v2/src/archive/error.rs b/substrate/client/rpc-spec-v2/src/archive/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..b858212399ce713abbb76e2182f3ccd8cf8cd880 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/error.rs @@ -0,0 +1,66 @@ +// 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 . + +//! Error helpers for `archive` RPC module. + +use jsonrpsee::{ + core::Error as RpcError, + types::error::{CallError, ErrorObject}, +}; + +/// ChainHead RPC errors. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Invalid parameter provided to the RPC method. + #[error("Invalid parameter: {0}")] + InvalidParam(String), + /// Runtime call failed. + #[error("Runtime call: {0}")] + RuntimeCall(String), + /// Failed to fetch leaves. + #[error("Failed to fetch leaves of the chain: {0}")] + FetchLeaves(String), +} + +// Base code for all `archive` errors. +const BASE_ERROR: i32 = 3000; +/// Invalid parameter error. +const INVALID_PARAM_ERROR: i32 = BASE_ERROR + 1; +/// Runtime call error. +const RUNTIME_CALL_ERROR: i32 = BASE_ERROR + 2; +/// Failed to fetch leaves. +const FETCH_LEAVES_ERROR: i32 = BASE_ERROR + 3; + +impl From for ErrorObject<'static> { + fn from(e: Error) -> Self { + let msg = e.to_string(); + + match e { + Error::InvalidParam(_) => ErrorObject::owned(INVALID_PARAM_ERROR, msg, None::<()>), + Error::RuntimeCall(_) => ErrorObject::owned(RUNTIME_CALL_ERROR, msg, None::<()>), + Error::FetchLeaves(_) => ErrorObject::owned(FETCH_LEAVES_ERROR, msg, None::<()>), + } + .into() + } +} + +impl From for RpcError { + fn from(e: Error) -> Self { + CallError::Custom(e.into()).into() + } +} diff --git a/substrate/client/rpc-spec-v2/src/archive/mod.rs b/substrate/client/rpc-spec-v2/src/archive/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..eb7d71d702f616133ec037d75f97784b781307c7 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/mod.rs @@ -0,0 +1,32 @@ +// 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 archive API. +//! +//! # Note +//! +//! Methods are prefixed by `archive`. + +#[cfg(test)] +mod tests; + +pub mod api; +pub mod archive; +pub mod error; + +pub use api::ArchiveApiServer; diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..36f7716e393cee5f46d68f63e5b495ef1f98b5f7 --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -0,0 +1,258 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{chain_head::hex_string, MethodResult}; + +use super::{archive::Archive, *}; + +use assert_matches::assert_matches; +use codec::{Decode, Encode}; +use jsonrpsee::{ + core::error::Error, + types::{error::CallError, EmptyServerParams as EmptyParams}, + RpcModule, +}; +use sc_block_builder::BlockBuilderProvider; +use sp_blockchain::HeaderBackend; +use sp_consensus::BlockOrigin; +use sp_runtime::SaturatedConversion; +use std::sync::Arc; +use substrate_test_runtime::Transfer; +use substrate_test_runtime_client::{ + prelude::*, runtime, Backend, BlockBuilderExt, Client, ClientBlockImportExt, +}; + +const CHAIN_GENESIS: [u8; 32] = [0; 32]; +const INVALID_HASH: [u8; 32] = [1; 32]; + +type Header = substrate_test_runtime_client::runtime::Header; +type Block = substrate_test_runtime_client::runtime::Block; + +fn setup_api() -> (Arc>, RpcModule>>) { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = Archive::new(client.clone(), backend, CHAIN_GENESIS).into_rpc(); + + (client, api) +} + +#[tokio::test] +async fn archive_genesis() { + let (_client, api) = setup_api(); + + let genesis: String = + api.call("archive_unstable_genesisHash", EmptyParams::new()).await.unwrap(); + assert_eq!(genesis, hex_string(&CHAIN_GENESIS)); +} + +#[tokio::test] +async fn archive_body() { + let (mut client, api) = setup_api(); + + // Invalid block hash. + let invalid_hash = hex_string(&INVALID_HASH); + let res: Option> = api.call("archive_unstable_body", [invalid_hash]).await.unwrap(); + assert!(res.is_none()); + + // Import a new block with an extrinsic. + let mut builder = client.new_block(Default::default()).unwrap(); + builder + .push_transfer(runtime::Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 42, + nonce: 0, + }) + .unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let expected_tx = hex_string(&block.extrinsics[0].encode()); + + let body: Vec = api.call("archive_unstable_body", [block_hash]).await.unwrap(); + assert_eq!(vec![expected_tx], body); +} + +#[tokio::test] +async fn archive_header() { + let (mut client, api) = setup_api(); + + // Invalid block hash. + let invalid_hash = hex_string(&INVALID_HASH); + let res: Option = api.call("archive_unstable_header", [invalid_hash]).await.unwrap(); + assert!(res.is_none()); + + // Import a new block with an extrinsic. + let mut builder = client.new_block(Default::default()).unwrap(); + builder + .push_transfer(runtime::Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 42, + nonce: 0, + }) + .unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let header: String = api.call("archive_unstable_header", [block_hash]).await.unwrap(); + let bytes = array_bytes::hex2bytes(&header).unwrap(); + let header: Header = Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(header, block.header); +} + +#[tokio::test] +async fn archive_finalized_height() { + let (client, api) = setup_api(); + + let client_height: u32 = client.info().finalized_number.saturated_into(); + + let height: u32 = + api.call("archive_unstable_finalizedHeight", EmptyParams::new()).await.unwrap(); + + assert_eq!(client_height, height); +} + +#[tokio::test] +async fn archive_hash_by_height() { + let (mut client, api) = setup_api(); + + // Genesis height. + let hashes: Vec = api.call("archive_unstable_hashByHeight", [0]).await.unwrap(); + assert_eq!(hashes, vec![format!("{:?}", client.genesis_hash())]); + + // Block tree: + // genesis -> finalized -> block 1 -> block 2 -> block 3 + // -> block 1 -> block 4 + // + // ^^^ h = N + // ^^^ h = N + 1 + // ^^^ h = N + 2 + let finalized = client.new_block(Default::default()).unwrap().build().unwrap().block; + let finalized_hash = finalized.header.hash(); + client.import(BlockOrigin::Own, finalized.clone()).await.unwrap(); + client.finalize_block(finalized_hash, None).unwrap(); + + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_2_hash = block_2.header.hash(); + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + let block_3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + // Import block 4 fork. + let mut block_builder = client.new_block_at(block_1_hash, Default::default(), false).unwrap(); + // This push is required as otherwise block 3 has the same hash as block 1 and won't get + // imported + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_4 = block_builder.build().unwrap().block; + let block_4_hash = block_4.header.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + // Check finalized height. + let hashes: Vec = api.call("archive_unstable_hashByHeight", [1]).await.unwrap(); + assert_eq!(hashes, vec![format!("{:?}", finalized_hash)]); + + // Test nonfinalized heights. + // Height N must include block 1. + let mut height = block_1.header.number; + let hashes: Vec = api.call("archive_unstable_hashByHeight", [height]).await.unwrap(); + assert_eq!(hashes, vec![format!("{:?}", block_1_hash)]); + + // Height (N + 1) must include block 2 and 4. + height += 1; + let hashes: Vec = api.call("archive_unstable_hashByHeight", [height]).await.unwrap(); + assert_eq!(hashes, vec![format!("{:?}", block_4_hash), format!("{:?}", block_2_hash)]); + + // Height (N + 2) must include block 3. + height += 1; + let hashes: Vec = api.call("archive_unstable_hashByHeight", [height]).await.unwrap(); + assert_eq!(hashes, vec![format!("{:?}", block_3_hash)]); + + // Height (N + 3) has no blocks. + height += 1; + let hashes: Vec = api.call("archive_unstable_hashByHeight", [height]).await.unwrap(); + assert!(hashes.is_empty()); +} + +#[tokio::test] +async fn archive_call() { + let (mut client, api) = setup_api(); + let invalid_hash = hex_string(&INVALID_HASH); + + // Invalid parameter (non-hex). + let err = api + .call::<_, serde_json::Value>( + "archive_unstable_call", + [&invalid_hash, "BabeApi_current_epoch", "0x00X"], + ) + .await + .unwrap_err(); + assert_matches!(err, Error::Call(CallError::Custom(ref err)) if err.code() == 3001 && err.message().contains("Invalid parameter")); + + // Pass an invalid parameters that cannot be decode. + let err = api + .call::<_, serde_json::Value>( + "archive_unstable_call", + // 0x0 is invalid. + [&invalid_hash, "BabeApi_current_epoch", "0x0"], + ) + .await + .unwrap_err(); + assert_matches!(err, Error::Call(CallError::Custom(ref err)) if err.code() == 3001 && err.message().contains("Invalid parameter")); + + // Invalid hash. + let result: MethodResult = api + .call("archive_unstable_call", [&invalid_hash, "BabeApi_current_epoch", "0x00"]) + .await + .unwrap(); + assert_matches!(result, MethodResult::Err(_)); + + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + // Valid call. + let alice_id = AccountKeyring::Alice.to_account_id(); + // Hex encoded scale encoded bytes representing the call parameters. + let call_parameters = hex_string(&alice_id.encode()); + let result: MethodResult = api + .call( + "archive_unstable_call", + [&format!("{:?}", block_1_hash), "AccountNonceApi_account_nonce", &call_parameters], + ) + .await + .unwrap(); + let expected = MethodResult::ok("0x0000000000000000"); + assert_eq!(result, expected); +} 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 0fa995ce73a094f1fb9509847357d0712cbb3bbf..b981e69f2e473a6d3dfa44a08ced9702b86eb326 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 @@ -158,7 +158,7 @@ where let parent = match parent { Some(parent) => parent, // Nothing to compare against, always report. - None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })), + None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt.into() })), }; let parent_rt = match self.client.runtime_version_at(parent) { @@ -168,7 +168,7 @@ where // Report the runtime version change. if block_rt != parent_rt { - Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })) + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt.into() })) } else { None } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_storage.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_storage.rs index 7095548a2b16cd518e874a86acd44cc0fad26b73..6e19f59a5d68747dce1c9a9506dc4f36e662a5d3 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_storage.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_storage.rs @@ -71,8 +71,10 @@ impl ChainHeadStorage { /// Query to iterate over storage. struct QueryIter { - /// The next key from which the iteration should continue. - next_key: StorageKey, + /// The key from which the iteration was started. + query_key: StorageKey, + /// The key after which pagination should resume. + pagination_start_key: Option, /// The type of the query (either value or hash). ty: IterQueryType, } @@ -184,20 +186,27 @@ where hash: Block::Hash, child_key: Option<&ChildInfo>, ) -> QueryIterResult { - let QueryIter { next_key, ty } = query; + let QueryIter { ty, query_key, pagination_start_key } = query; let mut keys_iter = if let Some(child_key) = child_key { - self.client - .child_storage_keys(hash, child_key.to_owned(), Some(&next_key), None) + self.client.child_storage_keys( + hash, + child_key.to_owned(), + Some(&query_key), + pagination_start_key.as_ref(), + ) } else { - self.client.storage_keys(hash, Some(&next_key), None) + self.client.storage_keys(hash, Some(&query_key), pagination_start_key.as_ref()) } .map_err(|err| err.to_string())?; let mut ret = Vec::with_capacity(self.operation_max_storage_items); + let mut next_pagination_key = None; for _ in 0..self.operation_max_storage_items { let Some(key) = keys_iter.next() else { break }; + next_pagination_key = Some(key.clone()); + let result = match ty { IterQueryType::Value => self.query_storage_value(hash, &key, child_key), IterQueryType::Hash => self.query_storage_hash(hash, &key, child_key), @@ -209,7 +218,11 @@ where } // Save the next key if any to continue the iteration. - let maybe_next_query = keys_iter.next().map(|next_key| QueryIter { next_key, ty }); + let maybe_next_query = keys_iter.next().map(|_| QueryIter { + ty, + query_key, + pagination_start_key: next_pagination_key, + }); Ok((ret, maybe_next_query)) } @@ -325,12 +338,16 @@ where return }, }, - StorageQueryType::DescendantsValues => self - .iter_operations - .push_back(QueryIter { next_key: item.key, ty: IterQueryType::Value }), - StorageQueryType::DescendantsHashes => self - .iter_operations - .push_back(QueryIter { next_key: item.key, ty: IterQueryType::Hash }), + StorageQueryType::DescendantsValues => self.iter_operations.push_back(QueryIter { + query_key: item.key, + ty: IterQueryType::Value, + pagination_start_key: None, + }), + StorageQueryType::DescendantsHashes => self.iter_operations.push_back(QueryIter { + query_key: item.key, + ty: IterQueryType::Hash, + pagination_start_key: None, + }), }; } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index 3b2edb2b00c8cd63bd85d84cd01576b10c2e4ce0..811666428c5a56479ede3af21f9fadcbd305dce2 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -69,7 +69,6 @@ impl From for ErrorObject<'static> { Error::InvalidSubscriptionID => ErrorObject::owned(INVALID_SUB_ID, msg, None::<()>), Error::InvalidContinue => ErrorObject::owned(INVALID_CONTINUE, msg, None::<()>), } - .into() } } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/event.rs b/substrate/client/rpc-spec-v2/src/chain_head/event.rs index 65bc8b247c880d392e1c1ab62272f5dfa3a53acb..b5f9d6cc2fff44800ff70a690ae347820242aac8 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/event.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/event.rs @@ -21,6 +21,7 @@ use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; use sp_api::ApiError; use sp_version::RuntimeVersion; +use std::collections::BTreeMap; /// The operation could not be processed due to an error. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -35,11 +36,47 @@ pub struct ErrorEvent { /// This event is generated for: /// - the first announced block by the follow subscription /// - blocks that suffered a change in runtime compared with their parents -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RuntimeVersionEvent { /// The runtime version. - pub spec: RuntimeVersion, + pub spec: ChainHeadRuntimeVersion, +} + +/// Simplified type clone of `sp_version::RuntimeVersion`. Used instead of +/// `sp_version::RuntimeVersion` to conform to RPC spec V2. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ChainHeadRuntimeVersion { + /// Identifies the different Substrate runtimes. + pub spec_name: String, + /// Name of the implementation of the spec. + pub impl_name: String, + /// Version of the runtime specification. + pub spec_version: u32, + /// Version of the implementation of the specification. + pub impl_version: u32, + /// Map of all supported API "features" and their versions. + pub apis: BTreeMap, + /// Transaction version. + pub transaction_version: u32, +} + +impl From for ChainHeadRuntimeVersion { + fn from(val: RuntimeVersion) -> Self { + Self { + spec_name: val.spec_name.into(), + impl_name: val.impl_name.into(), + spec_version: val.spec_version, + impl_version: val.impl_version, + apis: val + .apis + .into_iter() + .map(|(api, version)| (sp_core::bytes::to_hex(api, false), *version)) + .collect(), + transaction_version: val.transaction_version, + } + } } /// The runtime event generated if the `follow` subscription @@ -380,7 +417,7 @@ mod tests { ..Default::default() }; - let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime }); + let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.into() }); let mut initialized = Initialized { finalized_block_hash: "0x1".into(), finalized_block_runtime: Some(runtime_event), @@ -391,8 +428,8 @@ mod tests { let ser = serde_json::to_string(&event).unwrap(); let exp = concat!( r#"{"event":"initialized","finalizedBlockHash":"0x1","#, - r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#, - r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#, + r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","#, + r#""specVersion":1,"implVersion":0,"apis":{},"transactionVersion":0}}}"#, ); assert_eq!(ser, exp); @@ -429,10 +466,11 @@ mod tests { spec_name: "ABC".into(), impl_name: "Impl".into(), spec_version: 1, + apis: vec![([0, 0, 0, 0, 0, 0, 0, 0], 2), ([1, 0, 0, 0, 0, 0, 0, 0], 3)].into(), ..Default::default() }; - let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime }); + let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.into() }); let mut new_block = NewBlock { block_hash: "0x1".into(), parent_block_hash: "0x2".into(), @@ -445,8 +483,8 @@ mod tests { let ser = serde_json::to_string(&event).unwrap(); let exp = concat!( r#"{"event":"newBlock","blockHash":"0x1","parentBlockHash":"0x2","#, - r#""newRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#, - r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#, + r#""newRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","#, + r#""specVersion":1,"implVersion":0,"apis":{"0x0000000000000000":2,"0x0100000000000000":3},"transactionVersion":0}}}"#, ); assert_eq!(ser, exp); 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 3ab47991c4e551456241707d4ad7ef828b042ce7..8aaeb413cdff9a6c797bc7ea4e975edb6808dd09 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -234,17 +234,17 @@ async fn follow_with_runtime() { let event: FollowEvent = get_next_event(&mut sub).await; // it is basically json-encoded substrate_test_runtime_client::runtime::VERSION - let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ + let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":0,\ \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\ [\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\ - [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":1}"; + [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":0}"; let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap(); let finalized_block_runtime = - Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() })); + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone().into() })); // Runtime must always be reported with the first event. let expected = FollowEvent::Initialized(Initialized { finalized_block_hash: format!("{:?}", finalized_hash), @@ -308,7 +308,8 @@ async fn follow_with_runtime() { let best_hash = block.header.hash(); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); - let new_runtime = Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() })); + let new_runtime = + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone().into() })); let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::NewBlock(NewBlock { block_hash: format!("{:?}", best_hash), @@ -2352,6 +2353,7 @@ async fn check_continue_operation() { builder.push_storage_change(b":m".to_vec(), Some(b"a".to_vec())).unwrap(); builder.push_storage_change(b":mo".to_vec(), Some(b"ab".to_vec())).unwrap(); builder.push_storage_change(b":moc".to_vec(), Some(b"abc".to_vec())).unwrap(); + builder.push_storage_change(b":moD".to_vec(), Some(b"abcmoD".to_vec())).unwrap(); builder.push_storage_change(b":mock".to_vec(), Some(b"abcd".to_vec())).unwrap(); let block = builder.build().unwrap().block; let block_hash = format!("{:?}", block.header.hash()); @@ -2430,6 +2432,25 @@ async fn check_continue_operation() { res.items[0].result == StorageResultType::Value(hex_string(b"ab")) ); + // Pagination event. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::OperationWaitingForContinue(res) if res.operation_id == operation_id + ); + does_not_produce_event::>( + &mut sub, + std::time::Duration::from_secs(DOES_NOT_PRODUCE_EVENTS_SECONDS), + ) + .await; + let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &operation_id]).await.unwrap(); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::OperationStorageItems(res) if res.operation_id == operation_id && + res.items.len() == 1 && + res.items[0].key == hex_string(b":moD") && + res.items[0].result == StorageResultType::Value(hex_string(b"abcmoD")) + ); + // Pagination event. assert_matches!( get_next_event::>(&mut sub).await, diff --git a/substrate/client/rpc-spec-v2/src/lib.rs b/substrate/client/rpc-spec-v2/src/lib.rs index 7c22ef5d523189f5a2d49b150c786976bf64c5a8..d202bfef4a74ced5a9f32d50705d596a4403db42 100644 --- a/substrate/client/rpc-spec-v2/src/lib.rs +++ b/substrate/client/rpc-spec-v2/src/lib.rs @@ -23,9 +23,83 @@ #![warn(missing_docs)] #![deny(unused_crate_dependencies)] +use serde::{Deserialize, Serialize}; + +pub mod archive; pub mod chain_head; pub mod chain_spec; pub mod transaction; /// Task executor that is being used by RPC subscriptions. pub type SubscriptionTaskExecutor = std::sync::Arc; + +/// The result of an RPC method. +#[derive(Debug, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum MethodResult { + /// Method generated a result. + Ok(MethodResultOk), + /// Method ecountered an error. + Err(MethodResultErr), +} + +impl MethodResult { + /// Constructs a successful result. + pub fn ok(result: impl Into) -> MethodResult { + MethodResult::Ok(MethodResultOk { success: true, result: result.into() }) + } + + /// Constructs an error result. + pub fn err(error: impl Into) -> MethodResult { + MethodResult::Err(MethodResultErr { success: false, error: error.into() }) + } +} + +/// The successful result of an RPC method. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MethodResultOk { + /// Method was successful. + success: bool, + /// The result of the method. + pub result: String, +} + +/// The error result of an RPC method. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MethodResultErr { + /// Method encountered an error. + success: bool, + /// The error of the method. + pub error: String, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn method_result_ok() { + let ok = MethodResult::ok("hello"); + + let ser = serde_json::to_string(&ok).unwrap(); + let exp = r#"{"success":true,"result":"hello"}"#; + assert_eq!(ser, exp); + + let ok_dec: MethodResult = serde_json::from_str(exp).unwrap(); + assert_eq!(ok_dec, ok); + } + + #[test] + fn method_result_error() { + let ok = MethodResult::err("hello"); + + let ser = serde_json::to_string(&ok).unwrap(); + let exp = r#"{"success":false,"error":"hello"}"#; + assert_eq!(ser, exp); + + let ok_dec: MethodResult = serde_json::from_str(exp).unwrap(); + assert_eq!(ok_dec, ok); + } +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/event.rs b/substrate/client/rpc-spec-v2/src/transaction/event.rs index bdc126366fb9249bdb5e9b8e577f8cc2c2ae010f..8b80fcda17beb22cece35c928f10d72175fa9458 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/event.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/event.rs @@ -34,7 +34,6 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "camelCase")] pub struct TransactionBroadcasted { /// The number of peers the transaction was broadcasted to. - #[serde(with = "as_string")] pub num_peers: usize, } @@ -45,7 +44,6 @@ pub struct TransactionBlock { /// The hash of the block the transaction was included into. pub hash: Hash, /// The index (zero-based) of the transaction within the body of the block. - #[serde(with = "as_string")] pub index: usize, } @@ -224,22 +222,6 @@ impl From> for TransactionEvent { } } -/// Serialize and deserialize helper as string. -mod as_string { - use super::*; - use serde::{Deserializer, Serializer}; - - pub fn serialize(data: &usize, serializer: S) -> Result { - data.to_string().serialize(serializer) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { - String::deserialize(deserializer)? - .parse() - .map_err(|e| serde::de::Error::custom(format!("Parsing failed: {}", e))) - } -} - #[cfg(test)] mod tests { use super::*; @@ -263,7 +245,7 @@ mod tests { TransactionEvent::Broadcasted(TransactionBroadcasted { num_peers: 2 }); let ser = serde_json::to_string(&event).unwrap(); - let exp = r#"{"event":"broadcasted","numPeers":"2"}"#; + let exp = r#"{"event":"broadcasted","numPeers":2}"#; assert_eq!(ser, exp); let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); @@ -288,7 +270,7 @@ mod tests { })); let ser = serde_json::to_string(&event).unwrap(); - let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"2"}}"#; + let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":2}}"#; assert_eq!(ser, exp); let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); @@ -303,7 +285,7 @@ mod tests { }); let ser = serde_json::to_string(&event).unwrap(); - let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"10"}}"#; + let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":10}}"#; assert_eq!(ser, exp); let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index 44f4bd36c8b8b655d9207f8687c5ad41144a8cda..fe16310aeffa126cb66ababe68c58f445d9611fe 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs @@ -46,7 +46,7 @@ use std::sync::Arc; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_runtime::{generic, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use codec::Decode; use futures::{FutureExt, StreamExt, TryFutureExt}; @@ -110,11 +110,7 @@ where let submit = self .pool - .submit_and_watch( - &generic::BlockId::hash(best_block_hash), - TX_SOURCE, - decoded_extrinsic, - ) + .submit_and_watch(best_block_hash, TX_SOURCE, decoded_extrinsic) .map_err(|e| { e.into_pool_error() .map(Error::from) diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 64aaa7c94aacb074bd577b94138c71b7f3fe3d7c..dd1120e5b0f86638ec0881716c0b7391097775ad 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -22,6 +22,7 @@ serde_json = "1.0.107" sc-block-builder = { path = "../block-builder" } sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } +sc-mixnet = { path = "../mixnet" } sc-rpc-api = { path = "../rpc-api" } sc-tracing = { path = "../tracing" } sc-transaction-pool-api = { path = "../transaction-pool/api" } diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index feee22641ef3469fa23d8b5bc048e985bf1f7bd7..55d0a504aa678b82a3327683b5d417d61c8ad4c5 100644 --- a/substrate/client/rpc/src/author/mod.rs +++ b/substrate/client/rpc/src/author/mod.rs @@ -41,7 +41,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_keystore::{KeystoreExt, KeystorePtr}; -use sp_runtime::{generic, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use sp_session::SessionKeys; use self::error::{Error, Result}; @@ -97,15 +97,12 @@ where Err(err) => return Err(Error::Client(Box::new(err)).into()), }; let best_block_hash = self.client.info().best_hash; - self.pool - .submit_one(&generic::BlockId::hash(best_block_hash), TX_SOURCE, xt) - .await - .map_err(|e| { - e.into_pool_error() - .map(|e| Error::Pool(e)) - .unwrap_or_else(|e| Error::Verification(Box::new(e))) - .into() - }) + self.pool.submit_one(best_block_hash, TX_SOURCE, xt).await.map_err(|e| { + e.into_pool_error() + .map(|e| Error::Pool(e)) + .unwrap_or_else(|e| Error::Verification(Box::new(e))) + .into() + }) } fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()> { @@ -191,14 +188,11 @@ where }, }; - let submit = self - .pool - .submit_and_watch(&generic::BlockId::hash(best_block_hash), TX_SOURCE, dxt) - .map_err(|e| { - e.into_pool_error() - .map(error::Error::from) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) - }); + let submit = self.pool.submit_and_watch(best_block_hash, TX_SOURCE, dxt).map_err(|e| { + e.into_pool_error() + .map(error::Error::from) + .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) + }); let fut = async move { let stream = match submit.await { diff --git a/substrate/client/rpc/src/lib.rs b/substrate/client/rpc/src/lib.rs index 475fc77a9b5bd37bbe9b271287e8bb806a826bd9..94fdb2d734ff01f5876ac92271f99b168d9c4ce3 100644 --- a/substrate/client/rpc/src/lib.rs +++ b/substrate/client/rpc/src/lib.rs @@ -34,6 +34,7 @@ pub use sc_rpc_api::DenyUnsafe; pub mod author; pub mod chain; pub mod dev; +pub mod mixnet; pub mod offchain; pub mod state; pub mod statement; diff --git a/substrate/client/rpc/src/mixnet/mod.rs b/substrate/client/rpc/src/mixnet/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..3f3d9c5aa4526e399a3263eb02624738f7233ebe --- /dev/null +++ b/substrate/client/rpc/src/mixnet/mod.rs @@ -0,0 +1,47 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate mixnet API. + +use jsonrpsee::core::{async_trait, RpcResult}; +use sc_mixnet::Api; +use sc_rpc_api::mixnet::error::Error; +pub use sc_rpc_api::mixnet::MixnetApiServer; +use sp_core::Bytes; + +/// Mixnet API. +pub struct Mixnet(futures::lock::Mutex); + +impl Mixnet { + /// Create a new mixnet API instance. + pub fn new(api: Api) -> Self { + Self(futures::lock::Mutex::new(api)) + } +} + +#[async_trait] +impl MixnetApiServer for Mixnet { + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<()> { + // We only hold the lock while pushing the request into the requests channel + let fut = { + let mut api = self.0.lock().await; + api.submit_extrinsic(extrinsic).await + }; + Ok(fut.await.map_err(Error)?) + } +} diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index ccf23bc8994b344fb66ac658b0f47ac1d8ad5a50..2386bebf24d26d9ec98ab51b1bdad7d078efc734 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -80,7 +80,7 @@ tracing-futures = { version = "0.2.4" } async-trait = "0.1.57" tokio = { version = "1.22.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" -directories = "4.0.1" +directories = "5.0.1" static_init = "1.0.3" [dev-dependencies] diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 26dcd0f9e21a6aa4299f3228321c1f2ba1ba1158..da4a4f66e2af16f85bad5f5b526956152f63d7ae 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -484,8 +484,7 @@ where CallExecutor::runtime_version(&self.executor, hash) } - /// Apply a checked and validated block to an operation. If a justification is provided - /// then `finalized` *must* be true. + /// Apply a checked and validated block to an operation. fn apply_block( &self, operation: &mut ClientImportOperation, @@ -1766,8 +1765,7 @@ where { type Error = ConsensusError; - /// Import a checked and validated block. If a justification is provided in - /// `BlockImportParams` then `finalized` *must* be true. + /// Import a checked and validated block. /// /// NOTE: only use this implementation when there are NO consensus-level BlockImport /// objects. Otherwise, importing blocks directly into the client would be bypassing diff --git a/substrate/client/service/src/error.rs b/substrate/client/service/src/error.rs index c871342c771ebfb91ea90032b85dd745ba49dee6..c0a2adf2d198cbdf5221a457c717f7a0b8c35cc9 100644 --- a/substrate/client/service/src/error.rs +++ b/substrate/client/service/src/error.rs @@ -54,10 +54,10 @@ pub enum Error { #[error("Tasks executor hasn't been provided.")] TaskExecutorRequired, - #[error("Prometheus metrics error")] + #[error("Prometheus metrics error: {0}")] Prometheus(#[from] prometheus_endpoint::PrometheusError), - #[error("Application")] + #[error("Application: {0}")] Application(#[from] Box), #[error("Other: {0}")] diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index cd720e1c1e096671a07fd849be40071cdfbea979..ff9eb982b862f9ebb36132c730835dc2087ef291 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -48,10 +48,7 @@ use sc_network_sync::SyncingService; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SyncOracle; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; pub use self::{ builder::{ @@ -481,10 +478,8 @@ where }, }; - let best_block_id = BlockId::hash(self.client.info().best_hash); - let import_future = self.pool.submit_one( - &best_block_id, + self.client.info().best_hash, sc_transaction_pool_api::TransactionSource::External, uxt, ); @@ -549,10 +544,9 @@ mod tests { to: AccountKeyring::Bob.into(), } .into_unchecked_extrinsic(); - block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone())) - .unwrap(); + block_on(pool.submit_one(best.hash(), source, transaction.clone())).unwrap(); block_on(pool.submit_one( - &BlockId::hash(best.hash()), + best.hash(), source, ExtrinsicBuilder::new_call_do_not_propagate().nonce(1).build(), )) diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index c40ac33da4bb9a7fe7f8f1dc512bd87426fa5ac7..f82008755874bdcba2e2d66c4edaff468c8bc648 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -39,7 +39,6 @@ use sp_runtime::{ }; use sp_state_machine::{backend::Backend as _, InMemoryBackend, OverlayedChanges, StateMachine}; use sp_storage::{ChildInfo, StorageKey}; -use sp_trie::{LayoutV0, TrieConfiguration}; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::TestAPI; use substrate_test_runtime_client::{ @@ -62,22 +61,17 @@ fn construct_block( backend: &InMemoryBackend, number: BlockNumber, parent_hash: Hash, - state_root: Hash, txs: Vec, -) -> (Vec, Hash) { +) -> Vec { let transactions = txs.into_iter().map(|tx| tx.into_unchecked_extrinsic()).collect::>(); - let iter = transactions.iter().map(Encode::encode); - let extrinsics_root = LayoutV0::::ordered_trie_root(iter).into(); - let mut header = Header { parent_hash, number, - state_root, - extrinsics_root, + state_root: Default::default(), + extrinsics_root: Default::default(), digest: Digest { logs: vec![] }, }; - let hash = header.hash(); let mut overlay = OverlayedChanges::default(); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); @@ -124,19 +118,16 @@ fn construct_block( .unwrap(); header = Header::decode(&mut &ret_data[..]).unwrap(); - (vec![].and(&Block { header, extrinsics: transactions }), hash) + vec![].and(&Block { header, extrinsics: transactions }) } -fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec, Hash) { +fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> Vec { construct_block( backend, 1, genesis_hash, - array_bytes::hex_n_into_unchecked( - "25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c", - ), vec![Transfer { - from: AccountKeyring::Alice.into(), + from: AccountKeyring::One.into(), to: AccountKeyring::Two.into(), amount: 69 * DOLLARS, nonce: 0, @@ -175,7 +166,7 @@ fn construct_genesis_should_work_with_native() { let genesis_hash = insert_genesis_block(&mut storage); let backend = InMemoryBackend::from((storage, StateVersion::default())); - let (b1data, _b1hash) = block1(genesis_hash, &backend); + let b1data = block1(genesis_hash, &backend); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); @@ -206,7 +197,7 @@ fn construct_genesis_should_work_with_wasm() { let genesis_hash = insert_genesis_block(&mut storage); let backend = InMemoryBackend::from((storage, StateVersion::default())); - let (b1data, _b1hash) = block1(genesis_hash, &backend); + let b1data = block1(genesis_hash, &backend); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs index 38a811acc7401986f3f4b1f07d53fae8f32d0e98..9700c7643c48514de6189fe619255516636a737a 100644 --- a/substrate/client/service/test/src/lib.rs +++ b/substrate/client/service/test/src/lib.rs @@ -34,7 +34,6 @@ use sc_service::{ RuntimeGenesis, SpawnTaskHandle, TaskManager, }; use sc_transaction_pool_api::TransactionPool; -use sp_api::BlockId; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use std::{iter, net::Ipv4Addr, pin::Pin, sync::Arc, task::Context, time::Duration}; @@ -501,15 +500,13 @@ pub fn sync( info!("Checking extrinsic propagation"); let first_service = network.full_nodes[0].1.clone(); let first_user_data = &network.full_nodes[0].2; - let best_block = BlockId::number(first_service.client().info().best_number); + let best_block = first_service.client().info().best_hash; let extrinsic = extrinsic_factory(&first_service, first_user_data); let source = sc_transaction_pool_api::TransactionSource::External; - futures::executor::block_on(first_service.transaction_pool().submit_one( - &best_block, - source, - extrinsic, - )) + futures::executor::block_on( + first_service.transaction_pool().submit_one(best_block, source, extrinsic), + ) .expect("failed to submit extrinsic"); network.run_until_all_full(|_index, service| service.transaction_pool().ready().count() == 1); diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index 6d425749a91bf6a99bbe79304639312dff4cbbea..021ee76240b980221602f0516afde1549e4e84b5 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -9,7 +9,7 @@ description = "Storage monitor service for substrate" homepage = "https://substrate.io" [dependencies] -clap = { version = "4.4.3", features = ["derive", "string"] } +clap = { version = "4.4.6", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.6.3" sc-client-db = { path = "../db", default-features = false} diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 270f34b6d04ba9ecd8e716c392816b36f3e1cf19..b134cbce3ccf4d4472680787838fd4ad6ebcd567 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.36", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index 73cc513708d2d8e55f85ac2b5c35e861c3383a65..a795917528f9cca0831068fc77dd346fd2390838 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -26,10 +26,7 @@ use codec::Codec; use futures::{Future, Stream}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_core::offchain::TransactionPoolExt; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Member, NumberFor}, -}; +use sp_runtime::traits::{Block as BlockT, Member, NumberFor}; use std::{collections::HashMap, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc}; const LOG_TARGET: &str = "txpool::api"; @@ -202,7 +199,7 @@ pub trait TransactionPool: Send + Sync { /// Returns a future that imports a bunch of unverified transactions to the pool. fn submit_at( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xts: Vec>, ) -> PoolFuture, Self::Error>>, Self::Error>; @@ -210,7 +207,7 @@ pub trait TransactionPool: Send + Sync { /// Returns a future that imports one unverified transaction to the pool. fn submit_one( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture, Self::Error>; @@ -219,7 +216,7 @@ pub trait TransactionPool: Send + Sync { /// pool. fn submit_and_watch( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture>>, Self::Error>; diff --git a/substrate/client/transaction-pool/benches/basics.rs b/substrate/client/transaction-pool/benches/basics.rs index d114acc343d500909ac3c64cae8580bcad922c66..0caf00bf29551d009d7c9164a9ad2067040de198 100644 --- a/substrate/client/transaction-pool/benches/basics.rs +++ b/substrate/client/transaction-pool/benches/basics.rs @@ -33,6 +33,7 @@ use sp_runtime::{ ValidTransaction, }, }; +use std::sync::Arc; use substrate_test_runtime::{AccountId, Block, Extrinsic, ExtrinsicBuilder, TransferData, H256}; #[derive(Clone, Debug, Default)] @@ -61,7 +62,7 @@ impl ChainApi for TestApi { fn validate_transaction( &self, - at: &BlockId, + at: ::Hash, _source: TransactionSource, uxt: ::Extrinsic, ) -> Self::ValidationFuture { @@ -70,7 +71,7 @@ impl ChainApi for TestApi { let nonce = transfer.nonce; let from = transfer.from; - match self.block_id_to_number(at) { + match self.block_id_to_number(&BlockId::Hash(at)) { Ok(Some(num)) if num > 5 => return ready(Ok(Err(InvalidTransaction::Stale.into()))), _ => {}, } @@ -94,6 +95,8 @@ impl ChainApi for TestApi { ) -> Result>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(*num), + BlockId::Hash(hash) if *hash == H256::from_low_u64_be(hash.to_low_u64_be()) => + Some(hash.to_low_u64_be()), BlockId::Hash(_) => None, }) } @@ -104,7 +107,7 @@ impl ChainApi for TestApi { ) -> Result::Hash>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), - BlockId::Hash(_) => None, + BlockId::Hash(hash) => Some(*hash), }) } @@ -137,7 +140,7 @@ fn uxt(transfer: TransferData) -> Extrinsic { ExtrinsicBuilder::new_bench_call(transfer).build() } -fn bench_configured(pool: Pool, number: u64) { +fn bench_configured(pool: Pool, number: u64, api: Arc) { let source = TransactionSource::External; let mut futures = Vec::new(); let mut tags = Vec::new(); @@ -151,7 +154,12 @@ fn bench_configured(pool: Pool, number: u64) { }); tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1)))); - futures.push(pool.submit_one(&BlockId::Number(1), source, xt)); + + futures.push(pool.submit_one( + api.block_id_to_hash(&BlockId::Number(1)).unwrap().unwrap(), + source, + xt, + )); } let res = block_on(futures::future::join_all(futures.into_iter())); @@ -162,7 +170,12 @@ fn bench_configured(pool: Pool, number: u64) { // Prune all transactions. let block_num = 6; - block_on(pool.prune_tags(&BlockId::Number(block_num), tags, vec![])).expect("Prune failed"); + block_on(pool.prune_tags( + api.block_id_to_hash(&BlockId::Number(block_num)).unwrap().unwrap(), + tags, + vec![], + )) + .expect("Prune failed"); // pool is empty assert_eq!(pool.validated_pool().status().ready, 0); @@ -172,19 +185,15 @@ fn bench_configured(pool: Pool, number: u64) { fn benchmark_main(c: &mut Criterion) { c.bench_function("sequential 50 tx", |b| { b.iter(|| { - bench_configured( - Pool::new(Default::default(), true.into(), TestApi::new_dependant().into()), - 50, - ); + let api = Arc::from(TestApi::new_dependant()); + bench_configured(Pool::new(Default::default(), true.into(), api.clone()), 50, api); }); }); c.bench_function("random 100 tx", |b| { b.iter(|| { - bench_configured( - Pool::new(Default::default(), true.into(), TestApi::default().into()), - 100, - ); + let api = Arc::from(TestApi::default()); + bench_configured(Pool::new(Default::default(), true.into(), api.clone()), 100, api); }); }); } diff --git a/substrate/client/transaction-pool/src/api.rs b/substrate/client/transaction-pool/src/api.rs index 871d8e9c81707b9fd3454ce201f898de692f76df..cccaad7c89949cb82e7f7576edf11dc48baab41c 100644 --- a/substrate/client/transaction-pool/src/api.rs +++ b/substrate/client/transaction-pool/src/api.rs @@ -133,13 +133,12 @@ where fn validate_transaction( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, uxt: graph::ExtrinsicFor, ) -> Self::ValidationFuture { let (tx, rx) = oneshot::channel(); let client = self.client.clone(); - let at = *at; let validation_pool = self.validation_pool.clone(); let metrics = self.metrics.clone(); @@ -151,7 +150,7 @@ where .await .send( async move { - let res = validate_transaction_blocking(&*client, &at, source, uxt); + let res = validate_transaction_blocking(&*client, at, source, uxt); let _ = tx.send(res); metrics.report(|m| m.validations_finished.inc()); } @@ -209,7 +208,7 @@ where /// This method will call into the runtime to perform the validation. fn validate_transaction_blocking( client: &Client, - at: &BlockId, + at: Block::Hash, source: TransactionSource, uxt: graph::ExtrinsicFor>, ) -> error::Result @@ -225,14 +224,10 @@ where { sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction"; { - let block_hash = client.to_hash(at) - .map_err(|e| Error::RuntimeApi(e.to_string()))? - .ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?; - let runtime_api = client.runtime_api(); let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version"; runtime_api - .api_version::>(block_hash) + .api_version::>(at) .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi( format!("Could not find `TaggedTransactionQueue` api for block `{:?}`.", at) @@ -245,31 +240,31 @@ where sp_tracing::Level::TRACE, "runtime::validate_transaction"; { if api_version >= 3 { - runtime_api.validate_transaction(block_hash, source, uxt, block_hash) + runtime_api.validate_transaction(at, source, uxt, at) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { - let block_number = client.to_number(at) + let block_number = client.to_number(&BlockId::Hash(at)) .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi(format!("Could not get number for block `{:?}`.", at)) )?; // The old versions require us to call `initialize_block` before. - runtime_api.initialize_block(block_hash, &sp_runtime::traits::Header::new( + runtime_api.initialize_block(at, &sp_runtime::traits::Header::new( block_number + sp_runtime::traits::One::one(), Default::default(), Default::default(), - block_hash, + at, Default::default()), ).map_err(|e| Error::RuntimeApi(e.to_string()))?; if api_version == 2 { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_3(block_hash, source, uxt) + runtime_api.validate_transaction_before_version_3(at, source, uxt) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_2(block_hash, uxt) + runtime_api.validate_transaction_before_version_2(at, uxt) .map_err(|e| Error::RuntimeApi(e.to_string())) } } @@ -294,7 +289,7 @@ where /// the runtime locally. pub fn validate_transaction_blocking( &self, - at: &BlockId, + at: Block::Hash, source: TransactionSource, uxt: graph::ExtrinsicFor, ) -> error::Result { diff --git a/substrate/client/transaction-pool/src/graph/pool.rs b/substrate/client/transaction-pool/src/graph/pool.rs index 4d34737a7ba704d72aaad67de60f6925499db6c3..5305b5f1c12ebe99668413f87e8becfe4ba45e82 100644 --- a/substrate/client/transaction-pool/src/graph/pool.rs +++ b/substrate/client/transaction-pool/src/graph/pool.rs @@ -71,7 +71,7 @@ pub trait ChainApi: Send + Sync { /// Verify extrinsic at given block. fn validate_transaction( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, uxt: ExtrinsicFor, ) -> Self::ValidationFuture; @@ -154,7 +154,7 @@ impl Pool { /// Imports a bunch of unverified extrinsics to the pool pub async fn submit_at( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xts: impl IntoIterator>, ) -> Result, B::Error>>, B::Error> { @@ -168,7 +168,7 @@ impl Pool { /// This does not check if a transaction is banned, before we verify it again. pub async fn resubmit_at( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xts: impl IntoIterator>, ) -> Result, B::Error>>, B::Error> { @@ -180,7 +180,7 @@ impl Pool { /// Imports one unverified extrinsic to the pool pub async fn submit_one( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: ExtrinsicFor, ) -> Result, B::Error> { @@ -191,11 +191,11 @@ impl Pool { /// Import a single extrinsic and starts to watch its progress in the pool. pub async fn submit_and_watch( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: ExtrinsicFor, ) -> Result, ExtrinsicHash>, B::Error> { - let block_number = self.resolve_block_number(at)?; + let block_number = self.resolve_block_number(&BlockId::Hash(at))?; let (_, tx) = self .verify_one(at, block_number, source, xt, CheckBannedBeforeVerify::Yes) .await; @@ -246,8 +246,8 @@ impl Pool { /// their provided tags from there. Otherwise we query the runtime at the `parent` block. pub async fn prune( &self, - at: &BlockId, - parent: &BlockId, + at: ::Hash, + parent: ::Hash, extrinsics: &[ExtrinsicFor], ) -> Result<(), B::Error> { log::debug!( @@ -324,7 +324,7 @@ impl Pool { /// prevent importing them in the (near) future. pub async fn prune_tags( &self, - at: &BlockId, + at: ::Hash, tags: impl IntoIterator, known_imported_hashes: impl IntoIterator> + Clone, ) -> Result<(), B::Error> { @@ -351,7 +351,7 @@ impl Pool { // And finally - submit reverified transactions back to the pool self.validated_pool.resubmit_pruned( - at, + &BlockId::Hash(at), known_imported_hashes, pruned_hashes, reverified_transactions.into_values().collect(), @@ -373,12 +373,12 @@ impl Pool { /// Returns future that validates a bunch of transactions at given block. async fn verify( &self, - at: &BlockId, + at: ::Hash, xts: impl IntoIterator)>, check: CheckBannedBeforeVerify, ) -> Result, ValidatedTransactionFor>, B::Error> { // we need a block number to compute tx validity - let block_number = self.resolve_block_number(at)?; + let block_number = self.resolve_block_number(&BlockId::Hash(at))?; let res = futures::future::join_all( xts.into_iter() @@ -394,7 +394,7 @@ impl Pool { /// Returns future that validates single transaction at given block. async fn verify_one( &self, - block_id: &BlockId, + block_hash: ::Hash, block_number: NumberFor, source: TransactionSource, xt: ExtrinsicFor, @@ -410,7 +410,7 @@ impl Pool { let validation_result = self .validated_pool .api() - .validate_transaction(block_id, source, xt.clone()) + .validate_transaction(block_hash, source, xt.clone()) .await; let status = match validation_result { @@ -458,6 +458,7 @@ mod tests { use super::{super::base_pool::Limit, *}; use crate::tests::{pool, uxt, TestApi, INVALID_NONCE}; use assert_matches::assert_matches; + use codec::Encode; use futures::executor::block_on; use parking_lot::Mutex; use sc_transaction_pool_api::TransactionStatus; @@ -471,11 +472,11 @@ mod tests { #[test] fn should_validate_and_import_transaction() { // given - let pool = pool(); + let (pool, api) = pool(); // when let hash = block_on(pool.submit_one( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -493,7 +494,7 @@ mod tests { #[test] fn should_reject_if_temporarily_banned() { // given - let pool = pool(); + let (pool, api) = pool(); let uxt = uxt(Transfer { from: Alice.into(), to: AccountId::from_h256(H256::from_low_u64_be(2)), @@ -503,7 +504,7 @@ mod tests { // when pool.validated_pool.ban(&Instant::now(), vec![pool.hash_of(&uxt)]); - let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt)); + let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt)); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); @@ -514,18 +515,19 @@ mod tests { #[test] fn should_reject_unactionable_transactions() { // given + let api = Arc::new(TestApi::default()); let pool = Pool::new( Default::default(), // the node does not author blocks false.into(), - TestApi::default().into(), + api.clone(), ); // after validation `IncludeData` will be set to non-propagable (validate_transaction mock) let uxt = ExtrinsicBuilder::new_include_data(vec![42]).build(); // when - let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt)); + let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt)); // then assert_matches!(res.unwrap_err(), error::Error::Unactionable); @@ -535,12 +537,13 @@ mod tests { fn should_notify_about_pool_events() { let (stream, hash0, hash1) = { // given - let pool = pool(); + let (pool, api) = pool(); + let hash_of_block0 = api.expect_hash_from_number(0); let stream = pool.validated_pool().import_notification_stream(); // when let hash0 = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -551,7 +554,7 @@ mod tests { )) .unwrap(); let hash1 = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -563,7 +566,7 @@ mod tests { .unwrap(); // future doesn't count let _hash = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -590,9 +593,10 @@ mod tests { #[test] fn should_clear_stale_transactions() { // given - let pool = pool(); + let (pool, api) = pool(); + let hash_of_block0 = api.expect_hash_from_number(0); let hash1 = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -603,7 +607,7 @@ mod tests { )) .unwrap(); let hash2 = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -614,7 +618,7 @@ mod tests { )) .unwrap(); let hash3 = block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -641,9 +645,9 @@ mod tests { #[test] fn should_ban_mined_transactions() { // given - let pool = pool(); + let (pool, api) = pool(); let hash1 = block_on(pool.submit_one( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -655,12 +659,12 @@ mod tests { .unwrap(); // when - block_on(pool.prune_tags(&BlockId::Number(1), vec![vec![0]], vec![hash1])).unwrap(); + block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![0]], vec![hash1])) + .unwrap(); // then assert!(pool.validated_pool.is_banned(&hash1)); } - use codec::Encode; #[test] fn should_limit_futures() { @@ -678,14 +682,15 @@ mod tests { let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; - let pool = Pool::new(options, true.into(), TestApi::default().into()); + let api = Arc::new(TestApi::default()); + let pool = Pool::new(options, true.into(), api.clone()); - let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap(); + let hash1 = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().future, 1); // when let hash2 = block_on(pool.submit_one( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Bob.into(), @@ -709,11 +714,12 @@ mod tests { let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; - let pool = Pool::new(options, true.into(), TestApi::default().into()); + let api = Arc::new(TestApi::default()); + let pool = Pool::new(options, true.into(), api.clone()); // when block_on(pool.submit_one( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -732,11 +738,11 @@ mod tests { #[test] fn should_reject_transactions_with_no_provides() { // given - let pool = pool(); + let (pool, api) = pool(); // when let err = block_on(pool.submit_one( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -759,9 +765,9 @@ mod tests { #[test] fn should_trigger_ready_and_finalized() { // given - let pool = pool(); + let (pool, api) = pool(); let watcher = block_on(pool.submit_and_watch( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -774,26 +780,25 @@ mod tests { assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 0); + let hash_of_block2 = api.expect_hash_from_number(2); + // when - block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![])).unwrap(); + block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![])).unwrap(); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!( - stream.next(), - Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), - ); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),); } #[test] fn should_trigger_ready_and_finalized_when_pruning_via_hash() { // given - let pool = pool(); + let (pool, api) = pool(); let watcher = block_on(pool.submit_and_watch( - &BlockId::Number(0), + api.expect_hash_from_number(0), SOURCE, uxt(Transfer { from: Alice.into(), @@ -806,8 +811,10 @@ mod tests { assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 0); + let hash_of_block2 = api.expect_hash_from_number(2); + // when - block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![*watcher.hash()])) + block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![*watcher.hash()])) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); @@ -815,18 +822,17 @@ mod tests { // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!( - stream.next(), - Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), - ); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),); } #[test] fn should_trigger_future_and_ready_after_promoted() { // given - let pool = pool(); + let (pool, api) = pool(); + let hash_of_block0 = api.expect_hash_from_number(0); + let watcher = block_on(pool.submit_and_watch( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -841,7 +847,7 @@ mod tests { // when block_on(pool.submit_one( - &BlockId::Number(0), + hash_of_block0, SOURCE, uxt(Transfer { from: Alice.into(), @@ -862,7 +868,7 @@ mod tests { #[test] fn should_trigger_invalid_and_ban() { // given - let pool = pool(); + let (pool, api) = pool(); let uxt = uxt(Transfer { from: Alice.into(), to: AccountId::from_h256(H256::from_low_u64_be(2)), @@ -870,7 +876,8 @@ mod tests { nonce: 0, }); let watcher = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt)) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // when @@ -886,7 +893,7 @@ mod tests { #[test] fn should_trigger_broadcasted() { // given - let pool = pool(); + let (pool, api) = pool(); let uxt = uxt(Transfer { from: Alice.into(), to: AccountId::from_h256(H256::from_low_u64_be(2)), @@ -894,7 +901,8 @@ mod tests { nonce: 0, }); let watcher = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt)) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // when @@ -916,7 +924,8 @@ mod tests { let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; - let pool = Pool::new(options, true.into(), TestApi::default().into()); + let api = Arc::new(TestApi::default()); + let pool = Pool::new(options, true.into(), api.clone()); let xt = uxt(Transfer { from: Alice.into(), @@ -924,7 +933,9 @@ mod tests { amount: 5, nonce: 0, }); - let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap(); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt)) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // when @@ -934,7 +945,7 @@ mod tests { amount: 4, nonce: 1, }); - block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // then @@ -951,12 +962,13 @@ mod tests { let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; - let pool = Pool::new(options, true.into(), TestApi::default().into()); + let api = Arc::new(TestApi::default()); + let pool = Pool::new(options, true.into(), api.clone()); // after validation `IncludeData` will have priority set to 9001 // (validate_transaction mock) let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build(); - block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // then @@ -968,7 +980,7 @@ mod tests { amount: 4, nonce: 1, }); - let result = block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)); + let result = block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)); assert!(matches!( result, Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped) @@ -980,12 +992,15 @@ mod tests { let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() }; - let pool = Pool::new(options, true.into(), TestApi::default().into()); + let api = Arc::new(TestApi::default()); + let pool = Pool::new(options, true.into(), api.clone()); + + let hash_of_block0 = api.expect_hash_from_number(0); // after validation `IncludeData` will have priority set to 9001 // (validate_transaction mock) let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build(); - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap(); + block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // after validation `Transfer` will have priority set to 4 (validate_transaction @@ -996,15 +1011,14 @@ mod tests { amount: 5, nonce: 0, }); - let watcher = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap(); + let watcher = block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); // when // after validation `Store` will have priority set to 9001 (validate_transaction // mock) let xt = ExtrinsicBuilder::new_indexed_call(Vec::new()).build(); - block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); // then @@ -1021,7 +1035,10 @@ mod tests { let (tx, rx) = std::sync::mpsc::sync_channel(1); let mut api = TestApi::default(); api.delay = Arc::new(Mutex::new(rx.into())); - let pool = Arc::new(Pool::new(Default::default(), true.into(), api.into())); + let api = Arc::new(api); + let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone())); + + let hash_of_block0 = api.expect_hash_from_number(0); // when let xt = uxt(Transfer { @@ -1034,7 +1051,7 @@ mod tests { // This transaction should go to future, since we use `nonce: 1` let pool2 = pool.clone(); std::thread::spawn(move || { - block_on(pool2.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap(); + block_on(pool2.submit_one(hash_of_block0, SOURCE, xt)).unwrap(); ready.send(()).unwrap(); }); @@ -1048,12 +1065,13 @@ mod tests { }); // The tag the above transaction provides (TestApi is using just nonce as u8) let provides = vec![0_u8]; - block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(hash_of_block0, SOURCE, xt)).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // Now block import happens before the second transaction is able to finish // verification. - block_on(pool.prune_tags(&BlockId::Number(1), vec![provides], vec![])).unwrap(); + block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![provides], vec![])) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 0); // so when we release the verification of the previous one it will have diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index ffaab89d982360b33d67efffac1255e11f9ad1e5..faa3f455a580c8713ced21b14818da874fd972a7 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -166,8 +166,11 @@ where finalized_hash: Block::Hash, ) -> (Self, Pin + Send>>) { let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone())); - let (revalidation_queue, background_task) = - revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone()); + let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background( + pool_api.clone(), + pool.clone(), + finalized_hash, + ); ( Self { api: pool_api, @@ -203,8 +206,11 @@ where RevalidationType::Light => (revalidation::RevalidationQueue::new(pool_api.clone(), pool.clone()), None), RevalidationType::Full => { - let (queue, background) = - revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone()); + let (queue, background) = revalidation::RevalidationQueue::new_background( + pool_api.clone(), + pool.clone(), + finalized_hash, + ); (queue, Some(background)) }, }; @@ -254,46 +260,43 @@ where fn submit_at( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xts: Vec>, ) -> PoolFuture, Self::Error>>, Self::Error> { let pool = self.pool.clone(); - let at = *at; self.metrics .report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64)); - async move { pool.submit_at(&at, source, xts).await }.boxed() + async move { pool.submit_at(at, source, xts).await }.boxed() } fn submit_one( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture, Self::Error> { let pool = self.pool.clone(); - let at = *at; self.metrics.report(|metrics| metrics.submitted_transactions.inc()); - async move { pool.submit_one(&at, source, xt).await }.boxed() + async move { pool.submit_one(at, source, xt).await }.boxed() } fn submit_and_watch( &self, - at: &BlockId, + at: ::Hash, source: TransactionSource, xt: TransactionFor, ) -> PoolFuture>>, Self::Error> { - let at = *at; let pool = self.pool.clone(); self.metrics.report(|metrics| metrics.submitted_transactions.inc()); async move { - let watcher = pool.submit_and_watch(&at, source, xt).await?; + let watcher = pool.submit_and_watch(at, source, xt).await?; Ok(watcher.into_stream().boxed()) } @@ -433,11 +436,7 @@ where let validity = self .api - .validate_transaction_blocking( - &BlockId::hash(at), - TransactionSource::Local, - xt.clone(), - )? + .validate_transaction_blocking(at, TransactionSource::Local, xt.clone())? .map_err(|e| { Self::Error::Pool(match e { TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i), @@ -577,10 +576,7 @@ async fn prune_known_txs_for_block { - at: NumberFor, + at: BlockHash, transactions: Vec>, } @@ -54,9 +52,9 @@ struct WorkerPayload { struct RevalidationWorker { api: Arc, pool: Arc>, - best_block: NumberFor, - block_ordered: BTreeMap, HashSet>>, - members: HashMap, NumberFor>, + best_block: BlockHash, + block_ordered: BTreeMap, HashSet>>, + members: HashMap, BlockHash>, } impl Unpin for RevalidationWorker {} @@ -68,15 +66,30 @@ impl Unpin for RevalidationWorker {} async fn batch_revalidate( pool: Arc>, api: Arc, - at: NumberFor, + at: BlockHash, batch: impl IntoIterator>, ) { + // This conversion should work. Otherwise, for unknown block the revalidation shall be skipped, + // all the transactions will be kept in the validated pool, and can be scheduled for + // revalidation with the next request. + let block_number = match api.block_id_to_number(&BlockId::Hash(at)) { + Ok(Some(n)) => n, + Ok(None) => { + log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}, could not get block number."); + return + }, + Err(e) => { + log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}: {e:?}."); + return + }, + }; + let mut invalid_hashes = Vec::new(); let mut revalidated = HashMap::new(); let validation_results = futures::future::join_all(batch.into_iter().filter_map(|ext_hash| { pool.validated_pool().ready_by_hash(&ext_hash).map(|ext| { - api.validate_transaction(&BlockId::Number(at), ext.source, ext.data.clone()) + api.validate_transaction(at, ext.source, ext.data.clone()) .map(move |validation_result| (validation_result, ext_hash, ext)) }) })) @@ -107,7 +120,7 @@ async fn batch_revalidate( revalidated.insert( ext_hash, ValidatedTransaction::valid_at( - at.saturated_into::(), + block_number.saturated_into::(), ext_hash, ext.source, ext.data.clone(), @@ -135,13 +148,13 @@ async fn batch_revalidate( } impl RevalidationWorker { - fn new(api: Arc, pool: Arc>) -> Self { + fn new(api: Arc, pool: Arc>, best_block: BlockHash) -> Self { Self { api, pool, + best_block, block_ordered: Default::default(), members: Default::default(), - best_block: Zero::zero(), } } @@ -303,10 +316,11 @@ where api: Arc, pool: Arc>, interval: Duration, + best_block: BlockHash, ) -> (Self, Pin + Send>>) { let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue", 100_000); - let worker = RevalidationWorker::new(api.clone(), pool.clone()); + let worker = RevalidationWorker::new(api.clone(), pool.clone(), best_block); let queue = Self { api, pool, background: Some(to_worker) }; @@ -317,8 +331,9 @@ where pub fn new_background( api: Arc, pool: Arc>, + best_block: BlockHash, ) -> (Self, Pin + Send>>) { - Self::new_with_interval(api, pool, BACKGROUND_REVALIDATION_INTERVAL) + Self::new_with_interval(api, pool, BACKGROUND_REVALIDATION_INTERVAL, best_block) } /// Queue some transaction for later revalidation. @@ -328,7 +343,7 @@ where /// revalidation is actually done. pub async fn revalidate_later( &self, - at: NumberFor, + at: BlockHash, transactions: Vec>, ) { if transactions.len() > 0 { @@ -360,9 +375,8 @@ mod tests { }; use futures::executor::block_on; use sc_transaction_pool_api::TransactionSource; - use sp_runtime::generic::BlockId; use substrate_test_runtime::{AccountId, Transfer, H256}; - use substrate_test_runtime_client::AccountKeyring::Alice; + use substrate_test_runtime_client::AccountKeyring::{Alice, Bob}; #[test] fn revalidation_queue_works() { @@ -376,18 +390,63 @@ mod tests { amount: 5, nonce: 0, }); - let uxt_hash = block_on(pool.submit_one( - &BlockId::number(0), - TransactionSource::External, - uxt.clone(), - )) - .expect("Should be valid"); - block_on(queue.revalidate_later(0, vec![uxt_hash])); + let hash_of_block0 = api.expect_hash_from_number(0); + + let uxt_hash = + block_on(pool.submit_one(hash_of_block0, TransactionSource::External, uxt.clone())) + .expect("Should be valid"); + + block_on(queue.revalidate_later(hash_of_block0, vec![uxt_hash])); // revalidated in sync offload 2nd time assert_eq!(api.validation_requests().len(), 2); // number of ready assert_eq!(pool.validated_pool().status().ready, 1); } + + #[test] + fn revalidation_queue_skips_revalidation_for_unknown_block_hash() { + let api = Arc::new(TestApi::default()); + let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone())); + let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone())); + + let uxt0 = uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }); + let uxt1 = uxt(Transfer { + from: Bob.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 4, + nonce: 1, + }); + + let hash_of_block0 = api.expect_hash_from_number(0); + let unknown_block = H256::repeat_byte(0x13); + + let uxt_hashes = + block_on(pool.submit_at(hash_of_block0, TransactionSource::External, vec![uxt0, uxt1])) + .expect("Should be valid") + .into_iter() + .map(|r| r.expect("Should be valid")) + .collect::>(); + + assert_eq!(api.validation_requests().len(), 2); + assert_eq!(pool.validated_pool().status().ready, 2); + + // revalidation works fine for block 0: + block_on(queue.revalidate_later(hash_of_block0, uxt_hashes.clone())); + assert_eq!(api.validation_requests().len(), 4); + assert_eq!(pool.validated_pool().status().ready, 2); + + // revalidation shall be skipped for unknown block: + block_on(queue.revalidate_later(unknown_block, uxt_hashes)); + // no revalidation shall be done + assert_eq!(api.validation_requests().len(), 4); + // number of ready shall not change + assert_eq!(pool.validated_pool().status().ready, 2); + } } diff --git a/substrate/client/transaction-pool/src/tests.rs b/substrate/client/transaction-pool/src/tests.rs index 62911d5cbb471e37f7075d5506d98b60f8f46b83..325add3fb1c5a81a56a4a2591ed12ac4630b0b06 100644 --- a/substrate/client/transaction-pool/src/tests.rs +++ b/substrate/client/transaction-pool/src/tests.rs @@ -32,7 +32,7 @@ use sp_runtime::{ }; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::{ - substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, Extrinsic, + substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, BlockNumber, Extrinsic, ExtrinsicBuilder, Hashing, RuntimeCall, Transfer, TransferData, H256, }; @@ -53,6 +53,11 @@ impl TestApi { pub fn validation_requests(&self) -> Vec { self.validation_requests.lock().clone() } + + /// Helper function for mapping block number to hash. Use if mapping shall not fail. + pub fn expect_hash_from_number(&self, n: BlockNumber) -> H256 { + self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap() + } } impl ChainApi for TestApi { @@ -64,13 +69,13 @@ impl ChainApi for TestApi { /// Verify extrinsic at given block. fn validate_transaction( &self, - at: &BlockId, + at: ::Hash, _source: TransactionSource, uxt: ExtrinsicFor, ) -> Self::ValidationFuture { self.validation_requests.lock().push(uxt.clone()); let hash = self.hash_and_length(&uxt).0; - let block_number = self.block_id_to_number(at).unwrap().unwrap(); + let block_number = self.block_id_to_number(&BlockId::Hash(at)).unwrap().unwrap(); let res = match uxt { Extrinsic { @@ -153,6 +158,8 @@ impl ChainApi for TestApi { ) -> Result>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(*num), + BlockId::Hash(hash) if *hash == H256::from_low_u64_be(hash.to_low_u64_be()) => + Some(hash.to_low_u64_be()), BlockId::Hash(_) => None, }) } @@ -164,7 +171,7 @@ impl ChainApi for TestApi { ) -> Result::Hash>, Self::Error> { Ok(match at { BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), - BlockId::Hash(_) => None, + BlockId::Hash(hash) => Some(*hash), }) } @@ -199,6 +206,7 @@ pub(crate) fn uxt(transfer: Transfer) -> Extrinsic { ExtrinsicBuilder::new_transfer(transfer).build() } -pub(crate) fn pool() -> Pool { - Pool::new(Default::default(), true.into(), TestApi::default().into()) +pub(crate) fn pool() -> (Pool, Arc) { + let api = Arc::new(TestApi::default()); + (Pool::new(Default::default(), true.into(), api.clone()), api) } diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index 4adf811b42521c165bcb777f45cc43e674940146..e5ab01ffbf09f73bb4f86632aeada334ec6dafc0 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -47,8 +47,9 @@ use substrate_test_runtime_transaction_pool::{uxt, TestApi}; const LOG_TARGET: &str = "txpool"; -fn pool() -> Pool { - Pool::new(Default::default(), true.into(), TestApi::with_alice_nonce(209).into()) +fn pool() -> (Pool, Arc) { + let api = Arc::new(TestApi::with_alice_nonce(209)); + (Pool::new(Default::default(), true.into(), api.clone()), api) } fn maintained_pool() -> (BasicPool, Arc, futures::executor::ThreadPool) { @@ -83,8 +84,8 @@ const SOURCE: TransactionSource = TransactionSource::External; #[test] fn submission_should_work() { - let pool = pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap(); + let (pool, api) = pool(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -96,9 +97,9 @@ fn submission_should_work() { #[test] fn multiple_submission_should_work() { - let pool = pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap(); + let (pool, api) = pool(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -111,8 +112,8 @@ fn multiple_submission_should_work() { #[test] fn early_nonce_should_be_culled() { sp_tracing::try_init_simple(); - let pool = pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 208))).unwrap(); + let (pool, api) = pool(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 208))).unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -124,9 +125,9 @@ fn early_nonce_should_be_culled() { #[test] fn late_nonce_should_be_queued() { - let pool = pool(); + let (pool, api) = pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() @@ -134,7 +135,7 @@ fn late_nonce_should_be_queued() { .collect(); assert_eq!(pending, Vec::::new()); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() @@ -145,9 +146,10 @@ fn late_nonce_should_be_queued() { #[test] fn prune_tags_should_work() { - let pool = pool(); - let hash209 = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap(); + let (pool, api) = pool(); + let hash209 = + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -157,7 +159,7 @@ fn prune_tags_should_work() { assert_eq!(pending, vec![209, 210]); pool.validated_pool().api().push_block(1, Vec::new(), true); - block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![hash209])) + block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![hash209])) .expect("Prune tags"); let pending: Vec<_> = pool @@ -170,11 +172,12 @@ fn prune_tags_should_work() { #[test] fn should_ban_invalid_transactions() { - let pool = pool(); + let (pool, api) = pool(); let uxt = uxt(Alice, 209); - let hash = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap(); + let hash = + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap(); pool.validated_pool().remove_invalid(&[hash]); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err(); // when let pending: Vec<_> = pool @@ -185,7 +188,7 @@ fn should_ban_invalid_transactions() { assert_eq!(pending, Vec::::new()); // then - block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err(); } #[test] @@ -193,9 +196,9 @@ fn only_prune_on_new_best() { let (pool, api, _) = maintained_pool(); let uxt = uxt(Alice, 209); - let _ = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, uxt.clone())) + let _ = block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt.clone())) .expect("1. Imported"); - pool.api().push_block(1, vec![uxt.clone()], true); + api.push_block(1, vec![uxt.clone()], true); assert_eq!(pool.status().ready, 1); let header = api.push_block(2, vec![uxt], true); @@ -212,13 +215,15 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() { })); let pool = Pool::new(Default::default(), true.into(), api.clone()); let xt = uxt(Alice, 209); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.validated_pool().status().ready, 1); // remove the transaction that just got imported. api.increment_nonce(Alice.into()); api.push_block(1, Vec::new(), true); - block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![])).expect("1. Pruned"); + block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![])) + .expect("1. Pruned"); assert_eq!(pool.validated_pool().status().ready, 0); // it's re-imported to future assert_eq!(pool.validated_pool().status().future, 1); @@ -227,7 +232,8 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() { api.increment_nonce(Alice.into()); api.push_block(2, Vec::new(), true); let xt = uxt(Alice, 211); - block_on(pool.submit_one(&BlockId::number(2), SOURCE, xt.clone())).expect("2. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(2), SOURCE, xt.clone())) + .expect("2. Imported"); assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 1); let pending: Vec<_> = pool @@ -240,7 +246,8 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() { // prune it and make sure the pool is empty api.increment_nonce(Alice.into()); api.push_block(3, Vec::new(), true); - block_on(pool.prune_tags(&BlockId::number(3), vec![vec![155]], vec![])).expect("2. Pruned"); + block_on(pool.prune_tags(api.expect_hash_from_number(3), vec![vec![155]], vec![])) + .expect("2. Pruned"); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 2); } @@ -270,7 +277,8 @@ fn should_prune_old_during_maintenance() { let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt.clone()], true); @@ -285,9 +293,11 @@ fn should_revalidate_during_maintenance() { let xt2 = uxt(Alice, 210); let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt2.clone())) - .expect("2. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone())) + .expect("1. Imported"); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt2.clone())) + .expect("2. Imported"); assert_eq!(pool.status().ready, 2); assert_eq!(api.validation_requests().len(), 2); @@ -311,7 +321,8 @@ fn should_resubmit_from_retracted_during_maintenance() { let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![], true); @@ -329,7 +340,8 @@ fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacte let (pool, api, _guard) = maintained_pool(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt.clone()], true); @@ -347,8 +359,9 @@ fn should_not_retain_invalid_hashes_from_retracted() { let (pool, api, _guard) = maintained_pool(); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) - .expect("1. Imported"); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![], true); @@ -374,15 +387,18 @@ fn should_revalidate_across_many_blocks() { let (pool, api, _guard) = maintained_pool(); - let watcher1 = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt1.clone())) + let watcher1 = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt1.clone())) + .expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt2.clone())) .expect("1. Imported"); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("1. Imported"); assert_eq!(pool.status().ready, 2); let header = api.push_block(1, vec![], true); block_on(pool.maintain(block_event(header))); - block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt3.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt3.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 3); let header = api.push_block(2, vec![xt1.clone()], true); @@ -409,19 +425,24 @@ fn should_push_watchers_during_maintenance() { let tx0 = alice_uxt(0); let watcher0 = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx0.clone())).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx0.clone())) + .unwrap(); let tx1 = alice_uxt(1); let watcher1 = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx1.clone())).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx1.clone())) + .unwrap(); let tx2 = alice_uxt(2); let watcher2 = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx2.clone())).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx2.clone())) + .unwrap(); let tx3 = alice_uxt(3); let watcher3 = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx3.clone())).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx3.clone())) + .unwrap(); let tx4 = alice_uxt(4); let watcher4 = - block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx4.clone())).unwrap(); + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx4.clone())) + .unwrap(); assert_eq!(pool.status().ready, 5); // when @@ -489,11 +510,13 @@ fn finalization() { let api = TestApi::with_alice_nonce(209); api.push_block(1, vec![], true); let pool = create_basic_pool(api); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) - .expect("1. Imported"); - pool.api().push_block(2, vec![xt.clone()], true); + let api = pool.api(); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, xt.clone())) + .expect("1. Imported"); + api.push_block(2, vec![xt.clone()], true); - let header = pool.api().chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone(); + let header = api.chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone(); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); @@ -515,16 +538,17 @@ fn fork_aware_finalization() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let mut canon_watchers = vec![]; let from_alice = uxt(Alice, 1); let from_dave = uxt(Dave, 2); let from_bob = uxt(Bob, 1); let from_charlie = uxt(Charlie, 1); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Dave.into()); - pool.api().increment_nonce(Charlie.into()); - pool.api().increment_nonce(Bob.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Dave.into()); + api.increment_nonce(Charlie.into()); + api.increment_nonce(Bob.into()); let from_dave_watcher; let from_bob_watcher; @@ -538,10 +562,13 @@ fn fork_aware_finalization() { // block B1 { - let watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(2, vec![from_alice.clone()], true); + let watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block(2, vec![from_alice.clone()], true); canon_watchers.push((watcher, header.hash())); assert_eq!(pool.status().ready, 1); @@ -556,10 +583,13 @@ fn fork_aware_finalization() { // block C2 { - let header = pool.api().push_block_with_parent(b1, vec![from_dave.clone()], true); - from_dave_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone())) - .expect("1. Imported"); + let header = api.push_block_with_parent(b1, vec![from_dave.clone()], true); + from_dave_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_dave.clone(), + )) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> C2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; @@ -570,11 +600,14 @@ fn fork_aware_finalization() { // block D2 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block_with_parent(c2, vec![from_bob.clone()], true); + let header = api.push_block_with_parent(c2, vec![from_bob.clone()], true); log::trace!(target: LOG_TARGET, ">> D2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; @@ -585,15 +618,18 @@ fn fork_aware_finalization() { // block C1 { - let watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) - .expect("1.Imported"); + let watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_charlie.clone(), + )) + .expect("1.Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block_with_parent(b1, vec![from_charlie.clone()], true); + let header = api.push_block_with_parent(b1, vec![from_charlie.clone()], true); log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); c1 = header.hash(); canon_watchers.push((watcher, header.hash())); - let event = block_event_with_retracted(header.clone(), d2, pool.api()); + let event = block_event_with_retracted(header.clone(), d2, api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); @@ -604,10 +640,10 @@ fn fork_aware_finalization() { // block D1 { let xt = uxt(Eve, 0); - let w = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) + let w = block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, xt.clone())) .expect("1. Imported"); assert_eq!(pool.status().ready, 3); - let header = pool.api().push_block_with_parent(c1, vec![xt.clone()], true); + let header = api.push_block_with_parent(c1, vec![xt.clone()], true); log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header); d1 = header.hash(); canon_watchers.push((w, header.hash())); @@ -623,7 +659,7 @@ fn fork_aware_finalization() { // block E1 { - let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true); + let header = api.push_block_with_parent(d1, vec![from_dave, from_bob], true); log::trace!(target: LOG_TARGET, ">> E1: {:?} {:?}", header.hash(), header); e1 = header.hash(); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; @@ -673,16 +709,18 @@ fn prune_and_retract_tx_at_same_time() { api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); - pool.api().increment_nonce(Alice.into()); + api.increment_nonce(Alice.into()); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); // Block B1 let b1 = { - let header = pool.api().push_block(2, vec![from_alice.clone()], true); + let header = api.push_block(2, vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; @@ -693,10 +731,10 @@ fn prune_and_retract_tx_at_same_time() { // Block B2 let b2 = { - let header = pool.api().push_block(2, vec![from_alice.clone()], true); + let header = api.push_block(2, vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 0); - let event = block_event_with_retracted(header.clone(), b1, pool.api()); + let event = block_event_with_retracted(header.clone(), b1, api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); @@ -739,19 +777,21 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Dave.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Dave.into()); let d0; // Block D0 { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(2, vec![tx0.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx0.clone())) + .expect("1. Imported"); + let header = api.push_block(2, vec![tx0.clone()], true); assert_eq!(pool.status().ready, 1); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; @@ -762,17 +802,18 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { // Block D1 { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone())) - .expect("1. Imported"); - pool.api().push_block(2, vec![tx1.clone()], false); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx1.clone())) + .expect("1. Imported"); + api.push_block(2, vec![tx1.clone()], false); assert_eq!(pool.status().ready, 1); } // Block D2 { //push new best block - let header = pool.api().push_block(2, vec![], true); - let event = block_event_with_retracted(header, d0, pool.api()); + let header = api.push_block(2, vec![], true); + let event = block_event_with_retracted(header, d0, api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); } @@ -786,6 +827,8 @@ fn resubmit_from_retracted_fork() { let pool = create_basic_pool(api); + let api = pool.api(); + let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); let tx2 = uxt(Bob, 3); @@ -795,18 +838,19 @@ fn resubmit_from_retracted_fork() { let tx4 = uxt(Ferdie, 2); let tx5 = uxt(One, 3); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Dave.into()); - pool.api().increment_nonce(Bob.into()); - pool.api().increment_nonce(Eve.into()); - pool.api().increment_nonce(Ferdie.into()); - pool.api().increment_nonce(One.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Dave.into()); + api.increment_nonce(Bob.into()); + api.increment_nonce(Eve.into()); + api.increment_nonce(Ferdie.into()); + api.increment_nonce(One.into()); // Block D0 { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(2, vec![tx0.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx0.clone())) + .expect("1. Imported"); + let header = api.push_block(2, vec![tx0.clone()], true); assert_eq!(pool.status().ready, 1); block_on(pool.maintain(block_event(header))); @@ -815,18 +859,20 @@ fn resubmit_from_retracted_fork() { // Block E0 { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(3, vec![tx1.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx1.clone())) + .expect("1. Imported"); + let header = api.push_block(3, vec![tx1.clone()], true); block_on(pool.maintain(block_event(header))); assert_eq!(pool.status().ready, 0); } // Block F0 let f0 = { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx2.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(4, vec![tx2.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx2.clone())) + .expect("1. Imported"); + let header = api.push_block(4, vec![tx2.clone()], true); block_on(pool.maintain(block_event(header.clone()))); assert_eq!(pool.status().ready, 0); header.hash() @@ -834,27 +880,30 @@ fn resubmit_from_retracted_fork() { // Block D1 let d1 = { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx3.clone())) - .expect("1. Imported"); - let header = pool.api().push_block(2, vec![tx3.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx3.clone())) + .expect("1. Imported"); + let header = api.push_block(2, vec![tx3.clone()], true); assert_eq!(pool.status().ready, 1); header.hash() }; // Block E1 let e1 = { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx4.clone())) - .expect("1. Imported"); - let header = pool.api().push_block_with_parent(d1, vec![tx4.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx4.clone())) + .expect("1. Imported"); + let header = api.push_block_with_parent(d1, vec![tx4.clone()], true); assert_eq!(pool.status().ready, 2); header.hash() }; // Block F1 let f1_header = { - let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx5.clone())) - .expect("1. Imported"); - let header = pool.api().push_block_with_parent(e1, vec![tx5.clone()], true); + let _ = + block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx5.clone())) + .expect("1. Imported"); + let header = api.push_block_with_parent(e1, vec![tx5.clone()], true); // Don't announce the block event to the pool directly, because we will // re-org to this block. assert_eq!(pool.status().ready, 3); @@ -865,7 +914,7 @@ fn resubmit_from_retracted_fork() { let expected_ready = vec![tx3, tx4, tx5].iter().map(Encode::encode).collect::>(); assert_eq!(expected_ready, ready); - let event = block_event_with_retracted(f1_header, f0, pool.api()); + let event = block_event_with_retracted(f1_header, f0, api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 3); @@ -876,9 +925,10 @@ fn resubmit_from_retracted_fork() { #[test] fn ready_set_should_not_resolve_before_block_update() { - let (pool, _api, _guard) = maintained_pool(); + let (pool, api, _guard) = maintained_pool(); let xt1 = uxt(Alice, 209); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone())) + .expect("1. Imported"); assert!(pool.ready_at(1).now_or_never().is_none()); } @@ -890,7 +940,8 @@ fn ready_set_should_resolve_after_block_update() { let xt1 = uxt(Alice, 209); - block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt1.clone())) + .expect("1. Imported"); block_on(pool.maintain(block_event(header))); assert!(pool.ready_at(1).now_or_never().is_some()); @@ -903,7 +954,8 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { let xt1 = uxt(Alice, 209); - block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt1.clone())) + .expect("1. Imported"); let noop_waker = futures::task::noop_waker(); let mut context = futures::task::Context::from_waker(&noop_waker); @@ -948,7 +1000,12 @@ fn import_notification_to_pool_maintain_works() { // Prepare the extrisic, push it to the pool and check that it was added. let xt = uxt(Alice, 0); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported"); + block_on(pool.submit_one( + pool.api().block_id_to_hash(&BlockId::Number(0)).unwrap().unwrap(), + SOURCE, + xt.clone(), + )) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let mut import_stream = block_on_stream(client.import_notification_stream()); @@ -973,7 +1030,8 @@ fn pruning_a_transaction_should_remove_it_from_best_transaction() { let xt1 = ExtrinsicBuilder::new_include_data(Vec::new()).build(); - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported"); + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt1.clone()], true); @@ -997,8 +1055,12 @@ fn stale_transactions_are_pruned() { let (pool, api, _guard) = maintained_pool(); xts.into_iter().for_each(|xt| { - block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.into_unchecked_extrinsic())) - .expect("1. Imported"); + block_on(pool.submit_one( + api.expect_hash_from_number(0), + SOURCE, + xt.into_unchecked_extrinsic(), + )) + .expect("1. Imported"); }); assert_eq!(pool.status().ready, 0); assert_eq!(pool.status().future, 3); @@ -1038,8 +1100,9 @@ fn finalized_only_handled_correctly() { let (pool, api, _guard) = maintained_pool(); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) - .expect("1. Imported"); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt], true); @@ -1066,8 +1129,9 @@ fn best_block_after_finalized_handled_correctly() { let (pool, api, _guard) = maintained_pool(); - let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) - .expect("1. Imported"); + let watcher = + block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone())) + .expect("1. Imported"); assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt], true); @@ -1096,11 +1160,12 @@ fn switching_fork_with_finalized_works() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); let from_bob = uxt(Bob, 2); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Bob.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Bob.into()); let from_alice_watcher; let from_bob_watcher; @@ -1109,12 +1174,13 @@ fn switching_fork_with_finalized_works() { // block B1 { - from_alice_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + from_alice_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; @@ -1122,10 +1188,13 @@ fn switching_fork_with_finalized_works() { // block B2 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); - let header = pool.api().push_block_with_parent( + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent( a_header.hash(), vec![from_alice.clone(), from_bob.clone()], true, @@ -1174,11 +1243,12 @@ fn switching_fork_multiple_times_works() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); let from_bob = uxt(Bob, 2); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Bob.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Bob.into()); let from_alice_watcher; let from_bob_watcher; @@ -1187,12 +1257,13 @@ fn switching_fork_multiple_times_works() { // block B1 { - from_alice_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + from_alice_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; @@ -1200,10 +1271,13 @@ fn switching_fork_multiple_times_works() { // block B2 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); - let header = pool.api().push_block_with_parent( + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent( a_header.hash(), vec![from_alice.clone(), from_bob.clone()], true, @@ -1223,14 +1297,14 @@ fn switching_fork_multiple_times_works() { { // phase-1 - let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), pool.api()); + let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 0); } { // phase-2 - let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), pool.api()); + let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), api); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 1); } @@ -1282,13 +1356,14 @@ fn two_blocks_delayed_finalization_works() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); let from_bob = uxt(Bob, 2); let from_charlie = uxt(Charlie, 3); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Bob.into()); - pool.api().increment_nonce(Charlie.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Bob.into()); + api.increment_nonce(Charlie.into()); let from_alice_watcher; let from_bob_watcher; @@ -1299,12 +1374,13 @@ fn two_blocks_delayed_finalization_works() { // block B1 { - from_alice_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + from_alice_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); @@ -1313,12 +1389,13 @@ fn two_blocks_delayed_finalization_works() { // block C1 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); assert_eq!(pool.status().ready, 2); log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); @@ -1327,12 +1404,13 @@ fn two_blocks_delayed_finalization_works() { // block D1 { - from_charlie_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true); + from_charlie_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_charlie.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true); assert_eq!(pool.status().ready, 3); log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header); @@ -1398,11 +1476,12 @@ fn delayed_finalization_does_not_retract() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); let from_bob = uxt(Bob, 2); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Bob.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Bob.into()); let from_alice_watcher; let from_bob_watcher; @@ -1411,12 +1490,13 @@ fn delayed_finalization_does_not_retract() { // block B1 { - from_alice_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + from_alice_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); @@ -1425,12 +1505,13 @@ fn delayed_finalization_does_not_retract() { // block C1 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); assert_eq!(pool.status().ready, 2); log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); @@ -1493,11 +1574,12 @@ fn best_block_after_finalization_does_not_retract() { let a_header = api.push_block(1, vec![], true); let pool = create_basic_pool(api); + let api = pool.api(); let from_alice = uxt(Alice, 1); let from_bob = uxt(Bob, 2); - pool.api().increment_nonce(Alice.into()); - pool.api().increment_nonce(Bob.into()); + api.increment_nonce(Alice.into()); + api.increment_nonce(Bob.into()); let from_alice_watcher; let from_bob_watcher; @@ -1506,12 +1588,13 @@ fn best_block_after_finalization_does_not_retract() { // block B1 { - from_alice_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + from_alice_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_alice.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 1); log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); @@ -1520,12 +1603,13 @@ fn best_block_after_finalization_does_not_retract() { // block C1 { - from_bob_watcher = - block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) - .expect("1. Imported"); - let header = - pool.api() - .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + from_bob_watcher = block_on(pool.submit_and_watch( + api.expect_hash_from_number(1), + SOURCE, + from_bob.clone(), + )) + .expect("1. Imported"); + let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); assert_eq!(pool.status().ready, 2); log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); diff --git a/substrate/docker/substrate_builder.Dockerfile b/substrate/docker/substrate_builder.Dockerfile index 03b6b46caf41f31c7e290741e4da67b585cd0b4c..b37acf4d2014d11b681d7bb85b16bf4a4f855e96 100644 --- a/substrate/docker/substrate_builder.Dockerfile +++ b/substrate/docker/substrate_builder.Dockerfile @@ -12,8 +12,8 @@ LABEL description="Multistage Docker image for Substrate: a platform for web3" \ io.parity.image.authors="chevdor@gmail.com, devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.description="Substrate is a next-generation framework for blockchain innovation 🚀" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/substrate_builder.Dockerfile" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/substrate/docker/substrate_builder.Dockerfile" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk" COPY --from=builder /substrate/target/release/substrate /usr/local/bin COPY --from=builder /substrate/target/release/subkey /usr/local/bin diff --git a/substrate/docs/Upgrading-2.0-to-3.0.md b/substrate/docs/Upgrading-2.0-to-3.0.md index 58066ce074de63c83ea1a1def1273e67d79be1b4..3f2a3e7c5be22ee738321c6589bb4ce644a6c9d4 100644 --- a/substrate/docs/Upgrading-2.0-to-3.0.md +++ b/substrate/docs/Upgrading-2.0-to-3.0.md @@ -261,6 +261,7 @@ impl pallet_tips::Config for Runtime { type TipCountdown = TipCountdown; type TipFindersFee = TipFindersFee; type TipReportDepositBase = TipReportDepositBase; + type MaxTipAmount = MaxTipAmount; type WeightInfo = pallet_tips::weights::SubstrateWeight; } ``` diff --git a/substrate/docs/node-template-release.md b/substrate/docs/node-template-release.md index 0acaf3bdc61100d1fc5311f95c15a7cf897dd4f2..2536d186b2d148317b0b7ce72deb4ebf105c417e 100644 --- a/substrate/docs/node-template-release.md +++ b/substrate/docs/node-template-release.md @@ -1,7 +1,7 @@ # Substrate Node Template Release Process ## This release process has to be run in a github checkout Substrate directory with your work committed into -`https://github.com/paritytech/substrate/`, because the build script will check the existence of your current git commit +`https://github.com/paritytech/polkadot-sdk/`, because the build script will check the existence of your current git commit ID in the remote repository. Assume you are in root directory of Substrate. Run: diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index eb32c6c466c91a9ae1ef5b9b380025af2c6731ce..77294c6b6646f26532e9952c485011ba7cdf8574 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -17,6 +17,8 @@ //! Alliance pallet benchmarking. +#![cfg(feature = "runtime-benchmarks")] + use sp_runtime::traits::{Bounded, Hash, StaticLookup}; use sp_std::{ cmp, @@ -25,7 +27,7 @@ use sp_std::{ prelude::*, }; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; +use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin as SystemOrigin}; @@ -94,32 +96,31 @@ fn set_members, I: 'static>() { T::InitializeMembers::initialize_members(&[fellows.as_slice()].concat()); } -benchmarks_instance_pallet! { - // This tests when proposal is created and queued as "proposed" - propose_proposed { - let b in 1 .. MAX_BYTES; - let m in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); +#[instance_benchmarks] +mod benchmarks { + use super::*; + // This tests when proposal is created and queued as "proposed" + #[benchmark] + fn propose_proposed( + b: Linear<1, MAX_BYTES>, + m: Linear<2, { T::MaxFellows::get() }>, + p: Linear<1, { T::MaxProposals::get() }>, + ) -> Result<(), BenchmarkError> { let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let proposer = fellows[0].clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; let threshold = m; // Add previous proposals. - for i in 0 .. p - 1 { + for i in 0..p - 1 { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; b as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -128,45 +129,45 @@ benchmarks_instance_pallet! { )?; } - let proposal: T::Proposal = AllianceCall::::set_rule { rule: rule(vec![p as u8; b as usize]) }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![p as u8; b as usize]) }.into(); + + #[extrinsic_call] + propose( + SystemOrigin::Signed(proposer.clone()), + threshold, + Box::new(proposal.clone()), + bytes_in_storage, + ); - }: propose(SystemOrigin::Signed(proposer.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage) - verify { - // New proposal is recorded let proposal_hash = T::Hashing::hash_of(&proposal); assert_eq!(T::ProposalProvider::proposal_of(proposal_hash), Some(proposal)); + Ok(()) } - vote { - // We choose 5 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let m in 5 .. T::MaxFellows::get(); - + #[benchmark] + fn vote(m: Linear<5, { T::MaxFellows::get() }>) -> Result<(), BenchmarkError> { let p = T::MaxProposals::get(); let b = MAX_BYTES; - let bytes_in_storage = b + size_of::() as u32 + 32; + let _bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let proposer = fellows[0].clone(); let members = fellows.clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; // Threshold is 1 less than the number of members so that one person can vote nay let threshold = m - 1; // Add previous proposals let mut last_hash = T::Hash::default(); - for i in 0 .. p { + for i in 0..p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; b as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -178,7 +179,7 @@ benchmarks_instance_pallet! { let index = p - 1; // Have almost everyone vote aye on last proposal, while keeping it from passing. - for j in 0 .. m - 3 { + for j in 0..m - 3 { let voter = &members[j as usize]; Alliance::::vote( SystemOrigin::Signed(voter.clone()).into(), @@ -203,28 +204,28 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: _(SystemOrigin::Signed(voter), last_hash.clone(), index, approve) - verify { - } - close_early_disapproved { - // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let m in 4 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); + #[extrinsic_call] + _(SystemOrigin::Signed(voter), last_hash.clone(), index, approve); + //nothing to verify + Ok(()) + } + + #[benchmark] + fn close_early_disapproved( + m: Linear<4, { T::MaxFellows::get() }>, + p: Linear<1, { T::MaxProposals::get() }>, + ) -> Result<(), BenchmarkError> { let bytes = 100; let bytes_in_storage = bytes + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let members = fellows.clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -234,11 +235,10 @@ benchmarks_instance_pallet! { // Add previous proposals let mut last_hash = T::Hash::default(); - for i in 0 .. p { + for i in 0..p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; bytes as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; bytes as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -251,7 +251,7 @@ benchmarks_instance_pallet! { let index = p - 1; // Have most everyone vote aye on last proposal, while keeping it from passing. - for j in 2 .. m - 1 { + for j in 2..m - 1 { let voter = &members[j as usize]; Alliance::::vote( SystemOrigin::Signed(voter.clone()).into(), @@ -280,44 +280,41 @@ benchmarks_instance_pallet! { // Whitelist voter account from further DB operations. let voter_key = frame_system::Account::::hashed_key_for(&voter); frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. + + #[extrinsic_call] + close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + Ok(()) } - close_early_approved { - let b in 1 .. MAX_BYTES; - // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let m in 4 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - + // We choose 4 as a minimum for param m, so we always trigger a vote in the voting loop (`for j + // in ...`) + #[benchmark] + fn close_early_approved( + b: Linear<1, MAX_BYTES>, + m: Linear<4, { T::MaxFellows::get() }>, + p: Linear<1, { T::MaxProposals::get() }>, + ) -> Result<(), BenchmarkError> { let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let members = fellows.clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; let proposer = members[0].clone(); - let voter = members[1].clone(); - // Threshold is 2 so any two ayes will approve the vote let threshold = 2; // Add previous proposals let mut last_hash = T::Hash::default(); - for i in 0 .. p { + for i in 0..p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; b as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -329,7 +326,8 @@ benchmarks_instance_pallet! { } let index = p - 1; - // Caller switches vote to nay on their own proposal, allowing them to be the deciding approval vote + // Caller switches vote to nay on their own proposal, allowing them to be the deciding + // approval vote Alliance::::vote( SystemOrigin::Signed(proposer.clone()).into(), last_hash.clone(), @@ -338,7 +336,7 @@ benchmarks_instance_pallet! { )?; // Have almost everyone vote nay on last proposal, while keeping it from failing. - for j in 2 .. m - 1 { + for j in 2..m - 1 { let voter = &members[j as usize]; Alliance::::vote( SystemOrigin::Signed(voter.clone()).into(), @@ -364,30 +362,28 @@ benchmarks_instance_pallet! { index, true, )?; - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. + + #[extrinsic_call] + close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + Ok(()) } - close_disapproved { - // We choose 4 as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let m in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - + #[benchmark] + fn close_disapproved( + m: Linear<2, { T::MaxFellows::get() }>, + p: Linear<1, { T::MaxProposals::get() }>, + ) -> Result<(), BenchmarkError> { let bytes = 100; let bytes_in_storage = bytes + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let members = fellows.clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; let proposer = members[0].clone(); let voter = members[1].clone(); @@ -397,11 +393,10 @@ benchmarks_instance_pallet! { // Add proposals let mut last_hash = T::Hash::default(); - for i in 0 .. p { + for i in 0..p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; bytes as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; bytes as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -415,7 +410,7 @@ benchmarks_instance_pallet! { let index = p - 1; // Have almost everyone vote aye on last proposal, while keeping it from passing. // A few abstainers will be the nay votes needed to fail the vote. - for j in 2 .. m - 1 { + for j in 2..m - 1 { let voter = &members[j as usize]; Alliance::::vote( SystemOrigin::Signed(voter.clone()).into(), @@ -434,44 +429,41 @@ benchmarks_instance_pallet! { System::::set_block_number(BlockNumberFor::::max_value()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { + #[extrinsic_call] + close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage); + // The last proposal is removed. assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + Ok(()) } - close_approved { - let b in 1 .. MAX_BYTES; - // We choose 4 fellows as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let m in 5 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - + // We choose 5 fellows as a minimum so we always trigger a vote in the voting loop (`for j in + // ...`) + #[benchmark] + fn close_approved( + b: Linear<1, MAX_BYTES>, + m: Linear<5, { T::MaxFellows::get() }>, + p: Linear<1, { T::MaxProposals::get() }>, + ) -> Result<(), BenchmarkError> { let bytes_in_storage = b + size_of::() as u32 + 32; // Construct `members`. - let fellows = (0 .. m).map(fellow::).collect::>(); + let fellows = (0..m).map(fellow::).collect::>(); let members = fellows.clone(); - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows, - vec![], - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows, vec![])?; let proposer = members[0].clone(); - let voter = members[1].clone(); - // Threshold is two, so any two ayes will pass the vote let threshold = 2; // Add proposals let mut last_hash = T::Hash::default(); - for i in 0 .. p { + for i in 0..p { // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); + let proposal: T::Proposal = + AllianceCall::::set_rule { rule: rule(vec![i as u8; b as usize]) }.into(); Alliance::::propose( SystemOrigin::Signed(proposer.clone()).into(), threshold, @@ -487,70 +479,71 @@ benchmarks_instance_pallet! { SystemOrigin::Signed(proposer.clone()).into(), last_hash.clone(), p - 1, - true // Vote aye. + true, // Vote aye. )?; let index = p - 1; // Have almost everyone vote nay on last proposal, while keeping it from failing. // A few abstainers will be the aye votes needed to pass the vote. - for j in 2 .. m - 1 { + for j in 2..m - 1 { let voter = &members[j as usize]; Alliance::::vote( SystemOrigin::Signed(voter.clone()).into(), last_hash.clone(), index, - false + false, )?; } // caller is prime, prime already votes aye by creating the proposal System::::set_block_number(BlockNumberFor::::max_value()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. + #[extrinsic_call] + close( + SystemOrigin::Signed(proposer), + last_hash.clone(), + index, + Weight::MAX, + bytes_in_storage, + ); + assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); + Ok(()) } - init_members { - // at least 1 fellow - let m in 1 .. T::MaxFellows::get(); - let z in 0 .. T::MaxAllies::get(); + #[benchmark] + fn init_members( + m: Linear<1, { T::MaxFellows::get() }>, + z: Linear<0, { T::MaxAllies::get() }>, + ) -> Result<(), BenchmarkError> { + let mut fellows = (0..m).map(fellow::).collect::>(); + let mut allies = (0..z).map(ally::).collect::>(); - let mut fellows = (0 .. m).map(fellow::).collect::>(); - let mut allies = (0 .. z).map(ally::).collect::>(); + #[extrinsic_call] + _(SystemOrigin::Root, fellows.clone(), allies.clone()); - }: _(SystemOrigin::Root, fellows.clone(), allies.clone()) - verify { fellows.sort(); allies.sort(); - assert_last_event::(Event::MembersInitialized { - fellows: fellows.clone(), - allies: allies.clone(), - }.into()); + assert_last_event::( + Event::MembersInitialized { fellows: fellows.clone(), allies: allies.clone() }.into(), + ); assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); assert_eq!(Alliance::::members(MemberRole::Ally), allies); + Ok(()) } - disband { - // at least 1 founders - let x in 1 .. T::MaxFellows::get(); - let y in 0 .. T::MaxAllies::get(); - let z in 0 .. T::MaxMembersCount::get() / 2; - - let fellows = (0 .. x).map(fellow::).collect::>(); - let allies = (0 .. y).map(ally::).collect::>(); - let witness = DisbandWitness{ - fellow_members: x, - ally_members: y, - }; + #[benchmark] + fn disband( + x: Linear<1, { T::MaxFellows::get() }>, + y: Linear<0, { T::MaxAllies::get() }>, + z: Linear<0, { T::MaxMembersCount::get() / 2 }>, + ) -> Result<(), BenchmarkError> { + let fellows = (0..x).map(fellow::).collect::>(); + let allies = (0..y).map(ally::).collect::>(); + let witness = DisbandWitness { fellow_members: x, ally_members: y }; // setting the Alliance to disband on the benchmark call - Alliance::::init_members( - SystemOrigin::Root.into(), - fellows.clone(), - allies.clone(), - )?; + Alliance::::init_members(SystemOrigin::Root.into(), fellows.clone(), allies.clone())?; // reserve deposits let deposit = T::AllyDeposit::get(); @@ -561,18 +554,25 @@ benchmarks_instance_pallet! { assert_eq!(Alliance::::voting_members_count(), x); assert_eq!(Alliance::::ally_members_count(), y); - }: _(SystemOrigin::Root, witness) - verify { - assert_last_event::(Event::AllianceDisbanded { - fellow_members: x, - ally_members: y, - unreserved: cmp::min(z, x + y), - }.into()); + + #[extrinsic_call] + _(SystemOrigin::Root, witness); + + assert_last_event::( + Event::AllianceDisbanded { + fellow_members: x, + ally_members: y, + unreserved: cmp::min(z, x + y), + } + .into(), + ); assert!(!Alliance::::is_initialized()); + Ok(()) } - set_rule { + #[benchmark] + fn set_rule() -> Result<(), BenchmarkError> { set_members::(); let rule = rule(b"hello world"); @@ -580,61 +580,86 @@ benchmarks_instance_pallet! { let call = Call::::set_rule { rule: rule.clone() }; let origin = T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } assert_eq!(Alliance::::rule(), Some(rule.clone())); assert_last_event::(Event::NewRuleSet { rule }.into()); + Ok(()) } - announce { + #[benchmark] + fn announce() -> Result<(), BenchmarkError> { set_members::(); let announcement = announcement(b"hello world"); let call = Call::::announce { announcement: announcement.clone() }; - let origin = - T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + assert!(Alliance::::announcements().contains(&announcement)); assert_last_event::(Event::Announced { announcement }.into()); + Ok(()) } - remove_announcement { + #[benchmark] + fn remove_announcement() -> Result<(), BenchmarkError> { set_members::(); let announcement = announcement(b"hello world"); - let announcements: BoundedVec<_, T::MaxAnnouncementsCount> = BoundedVec::try_from(vec![announcement.clone()]).unwrap(); + let announcements: BoundedVec<_, T::MaxAnnouncementsCount> = + BoundedVec::try_from(vec![announcement.clone()]).unwrap(); Announcements::::put(announcements); let call = Call::::remove_announcement { announcement: announcement.clone() }; - let origin = - T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert!(Alliance::::announcements().is_empty()); + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + + assert!(!Alliance::::announcements().contains(&announcement)); assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); + Ok(()) } - join_alliance { + #[benchmark] + fn join_alliance() -> Result<(), BenchmarkError> { set_members::(); let outsider = outsider::(1); assert!(!Alliance::::is_member(&outsider)); assert_eq!(DepositOf::::get(&outsider), None); - }: _(SystemOrigin::Signed(outsider.clone())) - verify { + + #[extrinsic_call] + _(SystemOrigin::Signed(outsider.clone())); + assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally assert_eq!(DepositOf::::get(&outsider), Some(T::AllyDeposit::get())); // with a deposit assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights - assert_last_event::(Event::NewAllyJoined { - ally: outsider, - nominator: None, - reserved: Some(T::AllyDeposit::get()) - }.into()); + assert_last_event::( + Event::NewAllyJoined { + ally: outsider, + nominator: None, + reserved: Some(T::AllyDeposit::get()), + } + .into(), + ); + Ok(()) } - nominate_ally { + #[benchmark] + fn nominate_ally() -> Result<(), BenchmarkError> { set_members::(); let fellow1 = fellow::(1); @@ -645,19 +670,23 @@ benchmarks_instance_pallet! { assert_eq!(DepositOf::::get(&outsider), None); let outsider_lookup = T::Lookup::unlookup(outsider.clone()); - }: _(SystemOrigin::Signed(fellow1.clone()), outsider_lookup) - verify { + + #[extrinsic_call] + _(SystemOrigin::Signed(fellow1.clone()), outsider_lookup); + assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally assert_eq!(DepositOf::::get(&outsider), None); // without a deposit assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights - assert_last_event::(Event::NewAllyJoined { - ally: outsider, - nominator: Some(fellow1), - reserved: None - }.into()); + assert_last_event::( + Event::NewAllyJoined { ally: outsider, nominator: Some(fellow1), reserved: None } + .into(), + ); + + Ok(()) } - elevate_ally { + #[benchmark] + fn elevate_ally() -> Result<(), BenchmarkError> { set_members::(); let ally1 = ally::(1); @@ -665,59 +694,69 @@ benchmarks_instance_pallet! { let ally1_lookup = T::Lookup::unlookup(ally1.clone()); let call = Call::::elevate_ally { ally: ally1_lookup }; - let origin = - T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { + let origin = T::MembershipManager::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + assert!(!Alliance::::is_ally(&ally1)); assert!(Alliance::::has_voting_rights(&ally1)); assert_last_event::(Event::AllyElevated { ally: ally1 }.into()); + Ok(()) } - give_retirement_notice { + #[benchmark] + fn give_retirement_notice() -> Result<(), BenchmarkError> { set_members::(); let fellow2 = fellow::(2); assert!(Alliance::::has_voting_rights(&fellow2)); - }: _(SystemOrigin::Signed(fellow2.clone())) - verify { + + #[extrinsic_call] + _(SystemOrigin::Signed(fellow2.clone())); + assert!(Alliance::::is_member_of(&fellow2, MemberRole::Retiring)); assert_eq!( RetiringMembers::::get(&fellow2), Some(System::::block_number() + T::RetirementPeriod::get()) ); - assert_last_event::( - Event::MemberRetirementPeriodStarted {member: fellow2}.into() - ); + assert_last_event::(Event::MemberRetirementPeriodStarted { member: fellow2 }.into()); + Ok(()) } - retire { + #[benchmark] + fn retire() -> Result<(), BenchmarkError> { set_members::(); let fellow2 = fellow::(2); assert!(Alliance::::has_voting_rights(&fellow2)); assert_eq!( - Alliance::::give_retirement_notice( - SystemOrigin::Signed(fellow2.clone()).into() - ), + Alliance::::give_retirement_notice(SystemOrigin::Signed(fellow2.clone()).into()), Ok(()) ); System::::set_block_number(System::::block_number() + T::RetirementPeriod::get()); assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); - }: _(SystemOrigin::Signed(fellow2.clone())) - verify { + + #[extrinsic_call] + _(SystemOrigin::Signed(fellow2.clone())); + assert!(!Alliance::::is_member(&fellow2)); assert_eq!(DepositOf::::get(&fellow2), None); - assert_last_event::(Event::MemberRetired { - member: fellow2, - unreserved: Some(T::AllyDeposit::get()) - }.into()); + assert_last_event::( + Event::MemberRetired { member: fellow2, unreserved: Some(T::AllyDeposit::get()) } + .into(), + ); + Ok(()) } - kick_member { + #[benchmark] + fn kick_member() -> Result<(), BenchmarkError> { set_members::(); let fellow2 = fellow::(2); @@ -726,58 +765,71 @@ benchmarks_instance_pallet! { let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); let call = Call::::kick_member { who: fellow2_lookup }; - let origin = - T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { + let origin = T::MembershipManager::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + assert!(!Alliance::::is_member(&fellow2)); assert_eq!(DepositOf::::get(&fellow2), None); - assert_last_event::(Event::MemberKicked { - member: fellow2, - slashed: Some(T::AllyDeposit::get()) - }.into()); + assert_last_event::( + Event::MemberKicked { member: fellow2, slashed: Some(T::AllyDeposit::get()) }.into(), + ); + Ok(()) } - add_unscrupulous_items { - let n in 0 .. T::MaxUnscrupulousItems::get(); - let l in 0 .. T::MaxWebsiteUrlLength::get(); - + #[benchmark] + fn add_scrupulous_items( + n: Linear<0, { T::MaxUnscrupulousItems::get() }>, + l: Linear<0, { T::MaxWebsiteUrlLength::get() }>, + ) -> Result<(), BenchmarkError> { set_members::(); - let accounts = (0 .. n) - .map(|i| generate_unscrupulous_account::(i)) + let accounts = (0..n).map(|i| generate_unscrupulous_account::(i)).collect::>(); + let websites = (0..n) + .map(|i| -> BoundedVec { + BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() + }) .collect::>(); - let websites = (0 .. n).map(|i| -> BoundedVec { - BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() - }).collect::>(); let mut unscrupulous_list = Vec::with_capacity(accounts.len() + websites.len()); unscrupulous_list.extend(accounts.into_iter().map(UnscrupulousItem::AccountId)); unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); let call = Call::::add_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = - T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + assert_last_event::(Event::UnscrupulousItemAdded { items: unscrupulous_list }.into()); + Ok(()) } - remove_unscrupulous_items { - let n in 0 .. T::MaxUnscrupulousItems::get(); - let l in 0 .. T::MaxWebsiteUrlLength::get(); - + #[benchmark] + fn remove_unscrupulous_items( + n: Linear<0, { T::MaxUnscrupulousItems::get() }>, + l: Linear<0, { T::MaxWebsiteUrlLength::get() }>, + ) -> Result<(), BenchmarkError> { set_members::(); - let mut accounts = (0 .. n) - .map(|i| generate_unscrupulous_account::(i)) - .collect::>(); + let mut accounts = + (0..n).map(|i| generate_unscrupulous_account::(i)).collect::>(); accounts.sort(); let accounts: BoundedVec<_, T::MaxUnscrupulousItems> = accounts.try_into().unwrap(); UnscrupulousAccounts::::put(accounts.clone()); - let mut websites = (0 .. n).map(|i| -> BoundedVec<_, T::MaxWebsiteUrlLength> - { BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() }).collect::>(); + let mut websites = (0..n) + .map(|i| -> BoundedVec<_, T::MaxWebsiteUrlLength> { + BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() + }) + .collect::>(); websites.sort(); let websites: BoundedVec<_, T::MaxUnscrupulousItems> = websites.try_into().unwrap(); UnscrupulousWebsites::::put(websites.clone()); @@ -787,24 +839,31 @@ benchmarks_instance_pallet! { unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = - T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); + let origin = T::AnnouncementOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; + + #[block] + { + call.dispatch_bypass_filter(origin)?; + } + + assert_last_event::( + Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into(), + ); + Ok(()) } - abdicate_fellow_status { + #[benchmark] + fn abdicate_fellow_status() -> Result<(), BenchmarkError> { set_members::(); let fellow2 = fellow::(2); assert!(Alliance::::has_voting_rights(&fellow2)); - }: _(SystemOrigin::Signed(fellow2.clone())) - verify { - assert!(Alliance::::is_member_of(&fellow2, MemberRole::Ally)); - assert_last_event::( - Event::FellowAbdicated {fellow: fellow2}.into() - ); + #[extrinsic_call] + _(SystemOrigin::Signed(fellow2.clone())); + + assert_last_event::(Event::FellowAbdicated { fellow: fellow2 }.into()); + Ok(()) } impl_benchmark_test_suite!(Alliance, crate::mock::new_bench_ext(), crate::mock::Test); diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index f04e7e414ed94dbaa930580189272cfb169c8d96..82dbbe9c0bb9102e1301001abfe9bc53e59a3b5e 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -26,7 +26,7 @@ pub use sp_runtime::{ use sp_std::convert::{TryFrom, TryInto}; pub use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{EitherOfDiverse, SortedMembers}, BoundedVec, }; @@ -45,30 +45,11 @@ parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::MAX); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/substrate/frame/asset-rate/src/lib.rs b/substrate/frame/asset-rate/src/lib.rs index c3dc551f876d0a64663fe8c17eef854865d67d63..d4afca8b73c4b2978bbed954c05aee4e2a645ee5 100644 --- a/substrate/frame/asset-rate/src/lib.rs +++ b/substrate/frame/asset-rate/src/lib.rs @@ -240,4 +240,9 @@ where .ok_or(pallet::Error::::UnknownAssetKind.into())?; Ok(rate.saturating_mul_int(balance)) } + /// Set a conversion rate to `1` for the `asset_id`. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(asset_id: AssetKindOf) { + pallet::ConversionRateToNative::::set(asset_id.clone(), Some(1.into())); + } } diff --git a/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs index 06d4ec1211737f368937a27141c21c5b562c1c0e..f1b116a0f4a0d4ec612aed393290f5f18adb8ddd 100644 --- a/substrate/frame/assets/src/tests.rs +++ b/substrate/frame/assets/src/tests.rs @@ -1328,7 +1328,7 @@ fn freezer_should_work() { #[test] fn imbalances_should_work() { - use frame_support::traits::tokens::fungibles::Balanced; + use frame_support::traits::fungibles::Balanced; new_test_ext().execute_with(|| { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); @@ -1591,7 +1591,7 @@ fn assets_from_genesis_should_exist() { #[test] fn querying_name_symbol_and_decimals_should_work() { new_test_ext().execute_with(|| { - use frame_support::traits::tokens::fungibles::metadata::Inspect; + use frame_support::traits::fungibles::metadata::Inspect; assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_set_metadata( RuntimeOrigin::root(), @@ -1610,7 +1610,7 @@ fn querying_name_symbol_and_decimals_should_work() { #[test] fn querying_allowance_should_work() { new_test_ext().execute_with(|| { - use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; + use frame_support::traits::fungibles::approvals::{Inspect, Mutate}; assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); @@ -1635,7 +1635,7 @@ fn transfer_large_asset() { #[test] fn querying_roles_should_work() { new_test_ext().execute_with(|| { - use frame_support::traits::tokens::fungibles::roles::Inspect; + use frame_support::traits::fungibles::roles::Inspect; assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::set_team( RuntimeOrigin::signed(1), diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index a9bd0c38cb67c0a84b142a50e3ca857fb84d0f25..56a516894dec2a430ccbbc193fe02c83adbb9597 100644 --- a/substrate/frame/authorship/src/lib.rs +++ b/substrate/frame/authorship/src/lib.rs @@ -97,16 +97,10 @@ mod tests { use super::*; use crate as pallet_authorship; use codec::{Decode, Encode}; - use frame_support::{ - traits::{ConstU32, ConstU64}, - ConsensusEngineId, - }; + use frame_support::{derive_impl, ConsensusEngineId}; use sp_core::H256; use sp_runtime::{ - generic::DigestItem, - testing::Header, - traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, - BuildStorage, + generic::DigestItem, testing::Header, traits::Header as HeaderT, BuildStorage, }; type Block = frame_system::mocking::MockBlock; @@ -119,30 +113,9 @@ mod tests { } ); + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet::Config for Test { diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 9549fac9fe2b629ce3968b80c8d2e424ae252dd5..4b99cd517968d8ddcf336cb5ccb022b611d57a5a 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -590,7 +590,6 @@ impl Pallet { if authorities.is_empty() { log::warn!(target: LOG_TARGET, "Ignoring empty epoch change."); - return } @@ -664,7 +663,7 @@ impl Pallet { let next_randomness = NextRandomness::::get(); let next_epoch = NextEpochDescriptor { - authorities: next_authorities.to_vec(), + authorities: next_authorities.into_inner(), randomness: next_randomness, }; Self::deposit_consensus(ConsensusLog::NextEpochData(next_epoch)); @@ -700,7 +699,7 @@ impl Pallet { epoch_index: EpochIndex::::get(), start_slot: Self::current_epoch_start(), duration: T::EpochDuration::get(), - authorities: Self::authorities().to_vec(), + authorities: Self::authorities().into_inner(), randomness: Self::randomness(), config: EpochConfig::::get() .expect("EpochConfig is initialized in genesis; we never `take` or `kill` it; qed"), @@ -725,7 +724,7 @@ impl Pallet { epoch_index: next_epoch_index, start_slot, duration: T::EpochDuration::get(), - authorities: NextAuthorities::::get().to_vec(), + authorities: NextAuthorities::::get().into_inner(), randomness: NextRandomness::::get(), config: NextEpochConfig::::get().unwrap_or_else(|| { EpochConfig::::get().expect( @@ -778,7 +777,7 @@ impl Pallet { // we use the same values as genesis because we haven't collected any // randomness yet. let next = NextEpochDescriptor { - authorities: Self::authorities().to_vec(), + authorities: Self::authorities().into_inner(), randomness: Self::randomness(), }; diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index dbffe9f312e60a25adfa67fc13b0562ca52590d7..a3f755902b598b7a55b005efcd675295991ad2a0 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -24,7 +24,7 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU128, ConstU32, ConstU64, KeyOwnerProofSystem, OnInitialize}, }; use pallet_session::historical as pallet_session_historical; @@ -32,14 +32,14 @@ use pallet_staking::FixedNominationsQuota; use sp_consensus_babe::{AuthorityId, AuthorityPair, Randomness, Slot, VrfSignature}; use sp_core::{ crypto::{KeyTypeId, Pair, VrfSecret}, - H256, U256, + U256, }; use sp_io; use sp_runtime::{ curve::PiecewiseLinear, impl_opaque_keys, testing::{Digest, DigestItem, Header, TestXt}, - traits::{Header as _, IdentityLookup, OpaqueKeys}, + traits::{Header as _, OpaqueKeys}, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; @@ -63,30 +63,10 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Version = (); - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = DummyValidatorId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index ae0c3e3873c5023f25c6ab6c6d3f1e4bdceb6d39..ec4e6fd972708a643d8daccbcf811866966fd37b 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -95,7 +95,7 @@ fn first_block_epoch_zero_start() { let consensus_log = sp_consensus_babe::ConsensusLog::NextEpochData( sp_consensus_babe::digests::NextEpochDescriptor { - authorities: Babe::authorities().to_vec(), + authorities: Babe::authorities().into_inner(), randomness: Babe::randomness(), }, ); diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 21cdb4f89830ecb7f1721b0853587a4858c61734..f4644890e2bafd4b9a25ec25dc81dddb020fae2e 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -27,7 +27,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau # third party log = { version = "0.4.17", default-features = false } -docify = "0.2.3" +docify = "0.2.4" aquamarine = { version = "0.3.2" } # Optional imports for benchmarking diff --git a/substrate/frame/bags-list/remote-tests/src/snapshot.rs b/substrate/frame/bags-list/remote-tests/src/snapshot.rs index 13922cd3ca61845937f8988eb3588a22eeba9340..81a8905e6b4b2c6e2f89f00c84cbc421bf3ae92b 100644 --- a/substrate/frame/bags-list/remote-tests/src/snapshot.rs +++ b/substrate/frame/bags-list/remote-tests/src/snapshot.rs @@ -42,8 +42,8 @@ where .to_string()], at: None, hashed_prefixes: vec![ - >::prefix_hash(), - >::prefix_hash(), + >::prefix_hash().to_vec(), + >::prefix_hash().to_vec(), >::map_storage_final_prefix(), >::map_storage_final_prefix(), ], diff --git a/substrate/frame/bags-list/remote-tests/src/try_state.rs b/substrate/frame/bags-list/remote-tests/src/try_state.rs index 338be50a93f79ac8fbcc65b09d3cddc817a7a219..83930024c89a51be8126caea07647784b8c1f66d 100644 --- a/substrate/frame/bags-list/remote-tests/src/try_state.rs +++ b/substrate/frame/bags-list/remote-tests/src/try_state.rs @@ -39,8 +39,8 @@ pub async fn execute( pallets: vec![pallet_bags_list::Pallet::::name() .to_string()], hashed_prefixes: vec![ - >::prefix_hash(), - >::prefix_hash(), + >::prefix_hash().to_vec(), + >::prefix_hash().to_vec(), ], ..Default::default() })) diff --git a/substrate/frame/bags-list/src/lib.rs b/substrate/frame/bags-list/src/lib.rs index a5d3257b734bb644b06967540a2435eec0236aa2..8e3d4cc1f012d7c5c8fa62c8eea903ea8fa522da 100644 --- a/substrate/frame/bags-list/src/lib.rs +++ b/substrate/frame/bags-list/src/lib.rs @@ -17,7 +17,7 @@ //! > Made with *Substrate*, for *Polkadot*. //! -//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) - +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/bags-list) - //! [![polkadot]](https://polkadot.network) //! //! [polkadot]: diff --git a/substrate/frame/bags-list/src/mock.rs b/substrate/frame/bags-list/src/mock.rs index ae50adabd508a8c5e429c452e9fde28159ee9f53..9946a2198ac4f94f1c9eb13104ba343f686b39dd 100644 --- a/substrate/frame/bags-list/src/mock.rs +++ b/substrate/frame/bags-list/src/mock.rs @@ -20,11 +20,11 @@ use super::*; use crate::{self as bags_list}; use frame_election_provider_support::VoteWeight; -use frame_support::parameter_types; +use frame_support::{derive_impl, parameter_types}; use sp_runtime::BuildStorage; use std::collections::HashMap; -pub type AccountId = u32; +pub type AccountId = ::AccountId; pub type Balance = u32; parameter_types! { @@ -48,30 +48,10 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { - type SS58Prefix = (); - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = sp_core::H256; - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = sp_runtime::traits::IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = (); - type DbWeight = (); - type BlockLength = (); - type BlockWeights = (); - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/substrate/frame/bags-list/src/tests.rs b/substrate/frame/bags-list/src/tests.rs index 9e8508698d8e8f613b1b78fb6472386d046d9c98..0b382a4fcefa98d437515ba36eccf2122b5e929d 100644 --- a/substrate/frame/bags-list/src/tests.rs +++ b/substrate/frame/bags-list/src/tests.rs @@ -163,7 +163,7 @@ mod pallet { assert_eq!(Bag::::get(10).unwrap(), Bag::new(Some(1), Some(3), 10)); assert_eq!(Bag::::get(1_000).unwrap(), Bag::new(Some(2), Some(2), 1_000)); - assert_eq!(get_list_as_ids(), vec![2u32, 1, 4, 3]); + assert_eq!(get_list_as_ids(), vec![2u64, 1, 4, 3]); // when StakingMock::set_score_of(&2, 10); @@ -272,10 +272,10 @@ mod pallet { // given assert_eq!(List::::get_bags(), vec![(20, vec![10, 11, 12])]); // 11 now has more weight than 10 and can be moved before it. - StakingMock::set_score_of(&11u32, 17); + StakingMock::set_score_of(&11u64, 17); // when - assert_ok!(BagsList::put_in_front_of_other(RuntimeOrigin::signed(42), 11u32, 10)); + assert_ok!(BagsList::put_in_front_of_other(RuntimeOrigin::signed(42), 11u64, 10)); // then assert_eq!(List::::get_bags(), vec![(20, vec![11, 10, 12])]); diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index c64a4929dd568d2fda1a941cd05e3dabd36efaab..1ac882ade70dfb92df8ae5bbe3897fa7799ae53f 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -100,6 +100,11 @@ mod imbalances { mem::forget(self); (Self(first), Self(second)) } + fn extract(&mut self, amount: T::Balance) -> Self { + let new = self.0.min(amount); + self.0 = self.0 - new; + Self(new) + } fn merge(mut self, other: Self) -> Self { self.0 = self.0.saturating_add(other.0); mem::forget(other); @@ -159,6 +164,11 @@ mod imbalances { mem::forget(self); (Self(first), Self(second)) } + fn extract(&mut self, amount: T::Balance) -> Self { + let new = self.0.min(amount); + self.0 = self.0 - new; + Self(new) + } fn merge(mut self, other: Self) -> Self { self.0 = self.0.saturating_add(other.0); mem::forget(other); diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 5da6600d8796780e19d85d383b58cdcf223caa9b..c294779a0e0800ff2b4d1eff5294cda4b9661f04 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -216,7 +216,7 @@ pub mod pallet { /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::*; - use frame_support::derive_impl; + use frame_support::{derive_impl, traits::ConstU64}; pub struct TestDefaultConfig; @@ -227,16 +227,21 @@ pub mod pallet { impl DefaultConfig for TestDefaultConfig { #[inject_runtime_type] type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeHoldReason = (); type Balance = u64; + type ExistentialDeposit = ConstU64<1>; type ReserveIdentifier = (); type FreezeIdentifier = (); - type MaxLocks = (); - type MaxReserves = (); - type MaxFreezes = (); - type MaxHolds = (); + type DustRemoval = (); + + type MaxLocks = ConstU32<100>; + type MaxReserves = ConstU32<100>; + type MaxFreezes = ConstU32<100>; + type MaxHolds = ConstU32<100>; type WeightInfo = (); } @@ -249,6 +254,10 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The overarching hold reason. + #[pallet::no_default_bounds] + type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Copy; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -266,7 +275,7 @@ pub mod pallet { + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. - #[pallet::no_default] + #[pallet::no_default_bounds] type DustRemoval: OnUnbalanced>; /// The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO! @@ -278,7 +287,7 @@ pub mod pallet { /// /// Bottom line: Do yourself a favour and make it at least one! #[pallet::constant] - #[pallet::no_default] + #[pallet::no_default_bounds] type ExistentialDeposit: Get; /// The means of storing the balances of an account. @@ -290,12 +299,8 @@ pub mod pallet { /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` type ReserveIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; - /// The overarching hold reason. - #[pallet::no_default] - type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Ord + Copy; - /// The ID type for freezes. - type FreezeIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; + type FreezeIdentifier: Parameter + Member + MaxEncodedLen + Copy; /// The maximum number of locks that should exist on an account. /// Not strictly enforced, but used for weight estimation. diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index d15f8e89118cc336cad226bfe1e16958cb653496..a0a3085c54f9021c84e4de6a20ed81cbd3429592 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -26,7 +26,7 @@ use frame_support::{ dispatch::{DispatchInfo, GetDispatchInfo}, parameter_types, traits::{ - tokens::fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, + fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, StorageMapShim, StoredMap, WhitelistedStorageKeys, }, weights::{IdentityFee, Weight}, diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs index b2d8758a04be6f74236d60488760292d1ac87ca8..b85096813decad50226eccf8b3f62be669327dd0 100644 --- a/substrate/frame/beefy-mmr/src/mock.rs +++ b/substrate/frame/beefy-mmr/src/mock.rs @@ -19,16 +19,15 @@ use std::vec; use codec::Encode; use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstU16, ConstU32, ConstU64}, + construct_runtime, derive_impl, parameter_types, + traits::{ConstU32, ConstU64}, }; use sp_consensus_beefy::mmr::MmrLeafVersion; -use sp_core::H256; use sp_io::TestExternalities; use sp_runtime::{ app_crypto::ecdsa::Public, impl_opaque_keys, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, Keccak256, OpaqueKeys}, + traits::{ConvertInto, Keccak256, OpaqueKeys}, BuildStorage, }; use sp_state_machine::BasicExternalities; @@ -58,30 +57,9 @@ construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl pallet_session::Config for Test { diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index b55a65dbd73aff5210dc6f74127aa8bbcea7c268..9480fd0406d785570ca49454d819117c1f7ad49f 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -22,19 +22,15 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, }; use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstU16, ConstU32, ConstU64, KeyOwnerProofSystem, OnFinalize, OnInitialize}, + construct_runtime, derive_impl, parameter_types, + traits::{ConstU32, ConstU64, KeyOwnerProofSystem, OnFinalize, OnInitialize}, }; use pallet_session::historical as pallet_session_historical; -use sp_core::{crypto::KeyTypeId, ConstU128, H256}; +use sp_core::{crypto::KeyTypeId, ConstU128}; use sp_io::TestExternalities; use sp_runtime::{ - app_crypto::ecdsa::Public, - curve::PiecewiseLinear, - impl_opaque_keys, - testing::TestXt, - traits::{BlakeTwo256, IdentityLookup, OpaqueKeys}, - BuildStorage, Perbill, + app_crypto::ecdsa::Public, curve::PiecewiseLinear, impl_opaque_keys, testing::TestXt, + traits::OpaqueKeys, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; use sp_state_machine::BasicExternalities; @@ -69,30 +65,10 @@ construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index c64a35672c7f728b6c528ebb1a99646a6c631c75..c099fc48b7a3bceb94e8b026386c84aed4edf818 100644 --- a/substrate/frame/bounties/src/lib.rs +++ b/substrate/frame/bounties/src/lib.rs @@ -291,6 +291,14 @@ pub mod pallet { BountyCanceled { index: BountyIndex }, /// A bounty expiry is extended. BountyExtended { index: BountyIndex }, + /// A bounty is approved. + BountyApproved { index: BountyIndex }, + /// A bounty curator is proposed. + CuratorProposed { bounty_id: BountyIndex, curator: T::AccountId }, + /// A bounty curator is unassigned. + CuratorUnassigned { bounty_id: BountyIndex }, + /// A bounty curator is accepted. + CuratorAccepted { bounty_id: BountyIndex, curator: T::AccountId }, } /// Number of bounty proposals that have been made. @@ -375,10 +383,12 @@ pub mod pallet { Ok(()) })?; + + Self::deposit_event(Event::::BountyApproved { index: bounty_id }); Ok(()) } - /// Assign a curator to a funded bounty. + /// Propose a curator to a funded bounty. /// /// May only be called from `T::SpendOrigin`. /// @@ -408,9 +418,11 @@ pub mod pallet { ensure!(fee < bounty.value, Error::::InvalidFee); - bounty.status = BountyStatus::CuratorProposed { curator }; + bounty.status = BountyStatus::CuratorProposed { curator: curator.clone() }; bounty.fee = fee; + Self::deposit_event(Event::::CuratorProposed { bounty_id, curator }); + Ok(()) })?; Ok(()) @@ -508,6 +520,8 @@ pub mod pallet { bounty.status = BountyStatus::Funded; Ok(()) })?; + + Self::deposit_event(Event::::CuratorUnassigned { bounty_id }); Ok(()) } @@ -542,6 +556,10 @@ pub mod pallet { bounty.status = BountyStatus::Active { curator: curator.clone(), update_due }; + Self::deposit_event(Event::::CuratorAccepted { + bounty_id, + curator: signer, + }); Ok(()) }, _ => Err(Error::::UnexpectedStatus.into()), diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index a6fb89bb8601228cdd6427b6f20bc89887775781..4083b05b629cd0bff61d0af62e2a940cc7e1c031 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -24,7 +24,10 @@ use crate as pallet_bounties; use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, OnInitialize}, + traits::{ + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstU32, ConstU64, OnInitialize, + }, PalletId, }; @@ -104,6 +107,8 @@ parameter_types! { pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2"); pub static SpendLimit: Balance = u64::MAX; pub static SpendLimit1: Balance = u64::MAX; + pub TreasuryAccount: u128 = Treasury::account_id(); + pub TreasuryInstance1Account: u128 = Treasury1::account_id(); } impl pallet_treasury::Config for Test { @@ -123,6 +128,14 @@ impl pallet_treasury::Config for Test { type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_system::EnsureRootWithSuccess; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<10>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_treasury::Config for Test { @@ -142,6 +155,14 @@ impl pallet_treasury::Config for Test { type SpendFunds = Bounties1; type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_system::EnsureRootWithSuccess; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<10>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { diff --git a/substrate/frame/broker/README.md b/substrate/frame/broker/README.md index a3c4b251a452752172c789bcfdab97fa5da6bc9c..eae0442dbf69be30f72ed74d96ef2b052279ed4f 100644 --- a/substrate/frame/broker/README.md +++ b/substrate/frame/broker/README.md @@ -2,7 +2,7 @@ Brokerage tool for managing Polkadot Core scheduling. -Properly described in RFC-0001 Agile Coretime. +Properly described in [RFC-0001 Agile Coretime](https://github.com/polkadot-fellows/RFCs/blob/main/text/0001-agile-coretime.md). ## Implementation Specifics diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 24a6410f29f78daf8e33edd8fe32fcbbd307d942..1fa3d944f3de153117b71817f9e5c5c17cde18e4 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -24,7 +24,10 @@ use crate as pallet_child_bounties; use frame_support::{ assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, OnInitialize}, + traits::{ + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstU32, ConstU64, OnInitialize, + }, weights::Weight, PalletId, }; @@ -104,6 +107,7 @@ parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: u128 = Treasury::account_id(); pub const SpendLimit: Balance = u64::MAX; } @@ -124,6 +128,14 @@ impl pallet_treasury::Config for Test { type SpendFunds = Bounties; type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_system::EnsureRootWithSuccess; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<10>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { // This will be 50% of the bounty fee. diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index ccc80a2eba4de3096fee69ad80d7526e427eb8be..3ada9e0c23dd9093aa1bb0f53b3211d46ac2eb46 100644 --- a/substrate/frame/contracts/proc-macro/Cargo.toml +++ b/substrate/frame/contracts/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full"] } +syn = { version = "2.0.38", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index b31403c29adfd10b570c068923f47974f636489e..ad9cd2dadecf93b1514fdb948509ba5318e973d9 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -608,7 +608,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) let not_deprecated = f.not_deprecated; // wrapped host function body call with host function traces - // see https://github.com/paritytech/substrate/tree/master/frame/contracts#host-function-tracing + // see https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/contracts#host-function-tracing let wrapped_body_with_trace = { let trace_fmt_args = params.clone().filter_map(|arg| match arg { syn::FnArg::Receiver(_) => None, diff --git a/substrate/frame/contracts/src/debug.rs b/substrate/frame/contracts/src/debug.rs index d92379a806ddaffa82f9d126abe4ebf6fe690d75..e22a841e6fb7f73a87c0afbd55fc24bc25129c57 100644 --- a/substrate/frame/contracts/src/debug.rs +++ b/substrate/frame/contracts/src/debug.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use crate::exec::ExportedFunction; -use crate::{CodeHash, Config, LOG_TARGET}; -use pallet_contracts_primitives::ExecReturnValue; +pub use crate::exec::{ExecResult, ExportedFunction}; +use crate::{Config, LOG_TARGET}; +pub use pallet_contracts_primitives::ExecReturnValue; /// Umbrella trait for all interfaces that serves for debugging. -pub trait Debugger: Tracing {} +pub trait Debugger: Tracing + CallInterceptor {} -impl Debugger for V where V: Tracing {} +impl Debugger for V where V: Tracing + CallInterceptor {} /// Defines methods to capture contract calls, enabling external observers to /// measure, trace, and react to contract interactions. @@ -37,11 +37,11 @@ pub trait Tracing { /// /// # Arguments /// - /// * `code_hash` - The code hash of the contract being called. + /// * `contract_address` - The address of the contract that is about to be executed. /// * `entry_point` - Describes whether the call is the constructor or a regular call. /// * `input_data` - The raw input data of the call. fn new_call_span( - code_hash: &CodeHash, + contract_address: &T::AccountId, entry_point: ExportedFunction, input_data: &[u8], ) -> Self::CallSpan; @@ -60,8 +60,12 @@ pub trait CallSpan { impl Tracing for () { type CallSpan = (); - fn new_call_span(code_hash: &CodeHash, entry_point: ExportedFunction, input_data: &[u8]) { - log::trace!(target: LOG_TARGET, "call {entry_point:?} hash: {code_hash:?}, input_data: {input_data:?}") + fn new_call_span( + contract_address: &T::AccountId, + entry_point: ExportedFunction, + input_data: &[u8], + ) { + log::trace!(target: LOG_TARGET, "call {entry_point:?} account: {contract_address:?}, input_data: {input_data:?}") } } @@ -70,3 +74,37 @@ impl CallSpan for () { log::trace!(target: LOG_TARGET, "call result {output:?}") } } + +/// Provides an interface for intercepting contract calls. +pub trait CallInterceptor { + /// Allows to intercept contract calls and decide whether they should be executed or not. + /// If the call is intercepted, the mocked result of the call is returned. + /// + /// # Arguments + /// + /// * `contract_address` - The address of the contract that is about to be executed. + /// * `entry_point` - Describes whether the call is the constructor or a regular call. + /// * `input_data` - The raw input data of the call. + /// + /// # Expected behavior + /// + /// This method should return: + /// * `Some(ExecResult)` - if the call should be intercepted and the mocked result of the call + /// is returned. + /// * `None` - otherwise, i.e. the call should be executed normally. + fn intercept_call( + contract_address: &T::AccountId, + entry_point: &ExportedFunction, + input_data: &[u8], + ) -> Option; +} + +impl CallInterceptor for () { + fn intercept_call( + _contract_address: &T::AccountId, + _entry_point: &ExportedFunction, + _input_data: &[u8], + ) -> Option { + None + } +} diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index f93e7a2b21a553405a02f3063ffa51482c943eb3..9090aa9cb112b39623db93c007c36fffa0e2770c 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::{ - debug::{CallSpan, Tracing}, + debug::{CallInterceptor, CallSpan, Tracing}, gas::GasMeter, storage::{self, meter::Diff, WriteOutcome}, BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, @@ -908,13 +908,16 @@ where // Every non delegate call or instantiate also optionally transfers the balance. self.initial_transfer()?; - let call_span = - T::Debug::new_call_span(executable.code_hash(), entry_point, &input_data); + let contract_address = &top_frame!(self).account_id; - // Call into the Wasm blob. - let output = executable - .execute(self, &entry_point, input_data) - .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; + let call_span = T::Debug::new_call_span(contract_address, entry_point, &input_data); + + let output = T::Debug::intercept_call(contract_address, &entry_point, &input_data) + .unwrap_or_else(|| { + executable + .execute(self, &entry_point, input_data) + .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee }) + })?; call_span.after_call(&output); diff --git a/substrate/frame/contracts/src/migration.rs b/substrate/frame/contracts/src/migration.rs index 3e3d6f37884c7a757285a79a22e79065b69fc5f7..2714620731201b225485805e67a5ccc431217a2c 100644 --- a/substrate/frame/contracts/src/migration.rs +++ b/substrate/frame/contracts/src/migration.rs @@ -328,6 +328,32 @@ impl OnRuntimeUpgrade for Migration) -> Result<(), TryRuntimeError> { + if !TEST_ALL_STEPS { + return Ok(()) + } + + log::info!(target: LOG_TARGET, "=== POST UPGRADE CHECKS ==="); + + // Ensure that the hashing algorithm is correct for each storage map. + if let Some(hash) = crate::CodeInfoOf::::iter_keys().next() { + crate::CodeInfoOf::::get(hash).expect("CodeInfo exists for hash; qed"); + } + if let Some(hash) = crate::PristineCode::::iter_keys().next() { + crate::PristineCode::::get(hash).expect("PristineCode exists for hash; qed"); + } + if let Some(account_id) = crate::ContractInfoOf::::iter_keys().next() { + crate::ContractInfoOf::::get(account_id) + .expect("ContractInfo exists for account_id; qed"); + } + if let Some(nonce) = crate::DeletionQueue::::iter_keys().next() { + crate::DeletionQueue::::get(nonce).expect("DeletionQueue exists for nonce; qed"); + } + + Ok(()) + } } /// The result of running the migration. diff --git a/substrate/frame/contracts/src/migration/v12.rs b/substrate/frame/contracts/src/migration/v12.rs index eb045aa42e9d70d1245384768ae2db62627757e1..4ddc57584b30eb74c0ed18f7da2989d3db2ff53c 100644 --- a/substrate/frame/contracts/src/migration/v12.rs +++ b/substrate/frame/contracts/src/migration/v12.rs @@ -96,7 +96,7 @@ where #[storage_alias] pub type CodeInfoOf = - StorageMap, Twox64Concat, CodeHash, CodeInfo>; + StorageMap, Identity, CodeHash, CodeInfo>; #[storage_alias] pub type PristineCode = StorageMap, Identity, CodeHash, Vec>; diff --git a/substrate/frame/contracts/src/migration/v14.rs b/substrate/frame/contracts/src/migration/v14.rs index efb49dff4f10ac2b8a27ebae1f58541b6e7f793b..94534d05fdf889d05227149efd57ede584ecb013 100644 --- a/substrate/frame/contracts/src/migration/v14.rs +++ b/substrate/frame/contracts/src/migration/v14.rs @@ -70,7 +70,7 @@ mod old { #[storage_alias] pub type CodeInfoOf = - StorageMap, Twox64Concat, CodeHash, CodeInfo>; + StorageMap, Identity, CodeHash, CodeInfo>; } #[cfg(feature = "runtime-benchmarks")] diff --git a/substrate/frame/contracts/src/tests/test_debug.rs b/substrate/frame/contracts/src/tests/test_debug.rs index c7862c7f03dd3d406e9e11bdd76f08e8f1ee0643..2d7ed4743657573469deff09630ff2b2bf3a51a2 100644 --- a/substrate/frame/contracts/src/tests/test_debug.rs +++ b/substrate/frame/contracts/src/tests/test_debug.rs @@ -16,7 +16,10 @@ // limitations under the License. use super::*; -use crate::debug::{CallSpan, ExportedFunction, Tracing}; +use crate::{ + debug::{CallInterceptor, CallSpan, ExecResult, ExportedFunction, Tracing}, + AccountIdOf, +}; use frame_support::traits::Currency; use pallet_contracts_primitives::ExecReturnValue; use pretty_assertions::assert_eq; @@ -24,7 +27,7 @@ use std::cell::RefCell; #[derive(Clone, PartialEq, Eq, Debug)] struct DebugFrame { - code_hash: CodeHash, + contract_account: AccountId32, call: ExportedFunction, input: Vec, result: Option>, @@ -32,11 +35,12 @@ struct DebugFrame { thread_local! { static DEBUG_EXECUTION_TRACE: RefCell> = RefCell::new(Vec::new()); + static INTERCEPTED_ADDRESS: RefCell> = RefCell::new(None); } pub struct TestDebug; pub struct TestCallSpan { - code_hash: CodeHash, + contract_account: AccountId32, call: ExportedFunction, input: Vec, } @@ -45,19 +49,39 @@ impl Tracing for TestDebug { type CallSpan = TestCallSpan; fn new_call_span( - code_hash: &CodeHash, + contract_account: &AccountIdOf, entry_point: ExportedFunction, input_data: &[u8], ) -> TestCallSpan { DEBUG_EXECUTION_TRACE.with(|d| { d.borrow_mut().push(DebugFrame { - code_hash: *code_hash, + contract_account: contract_account.clone(), call: entry_point, input: input_data.to_vec(), result: None, }) }); - TestCallSpan { code_hash: *code_hash, call: entry_point, input: input_data.to_vec() } + TestCallSpan { + contract_account: contract_account.clone(), + call: entry_point, + input: input_data.to_vec(), + } + } +} + +impl CallInterceptor for TestDebug { + fn intercept_call( + contract_address: &::AccountId, + _entry_point: &ExportedFunction, + _input_data: &[u8], + ) -> Option { + INTERCEPTED_ADDRESS.with(|i| { + if i.borrow().as_ref() == Some(contract_address) { + Some(Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![] })) + } else { + None + } + }) } } @@ -65,7 +89,7 @@ impl CallSpan for TestCallSpan { fn after_call(self, output: &ExecReturnValue) { DEBUG_EXECUTION_TRACE.with(|d| { d.borrow_mut().push(DebugFrame { - code_hash: self.code_hash, + contract_account: self.contract_account, call: self.call, input: self.input, result: Some(output.data.clone()), @@ -75,9 +99,9 @@ impl CallSpan for TestCallSpan { } #[test] -fn unsafe_debugging_works() { - let (wasm_caller, code_hash_caller) = compile_module::("call").unwrap(); - let (wasm_callee, code_hash_callee) = compile_module::("store_call").unwrap(); +fn debugging_works() { + let (wasm_caller, _) = compile_module::("call").unwrap(); + let (wasm_callee, _) = compile_module::("store_call").unwrap(); fn current_stack() -> Vec { DEBUG_EXECUTION_TRACE.with(|stack| stack.borrow().clone()) @@ -100,18 +124,18 @@ fn unsafe_debugging_works() { .account_id } - fn constructor_frame(hash: CodeHash, after: bool) -> DebugFrame { + fn constructor_frame(contract_account: &AccountId32, after: bool) -> DebugFrame { DebugFrame { - code_hash: hash, + contract_account: contract_account.clone(), call: ExportedFunction::Constructor, input: vec![], result: if after { Some(vec![]) } else { None }, } } - fn call_frame(hash: CodeHash, args: Vec, after: bool) -> DebugFrame { + fn call_frame(contract_account: &AccountId32, args: Vec, after: bool) -> DebugFrame { DebugFrame { - code_hash: hash, + contract_account: contract_account.clone(), call: ExportedFunction::Call, input: args, result: if after { Some(vec![]) } else { None }, @@ -129,19 +153,19 @@ fn unsafe_debugging_works() { assert_eq!( current_stack(), vec![ - constructor_frame(code_hash_caller, false), - constructor_frame(code_hash_caller, true), - constructor_frame(code_hash_callee, false), - constructor_frame(code_hash_callee, true), + constructor_frame(&addr_caller, false), + constructor_frame(&addr_caller, true), + constructor_frame(&addr_callee, false), + constructor_frame(&addr_callee, true), ] ); - let main_args = (100u32, &addr_callee).encode(); + let main_args = (100u32, &addr_callee.clone()).encode(); let inner_args = (100u32).encode(); assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), - addr_caller, + addr_caller.clone(), 0, GAS_LIMIT, None, @@ -152,11 +176,54 @@ fn unsafe_debugging_works() { assert_eq!( stack_top, vec![ - call_frame(code_hash_caller, main_args.clone(), false), - call_frame(code_hash_callee, inner_args.clone(), false), - call_frame(code_hash_callee, inner_args, true), - call_frame(code_hash_caller, main_args, true), + call_frame(&addr_caller, main_args.clone(), false), + call_frame(&addr_callee, inner_args.clone(), false), + call_frame(&addr_callee, inner_args, true), + call_frame(&addr_caller, main_args, true), ] ); }); } + +#[test] +fn call_interception_works() { + let (wasm, _) = compile_module::("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + let account_id = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm), + vec![], + // some salt to ensure that the address of this contract is unique among all tests + vec![0x41, 0x41, 0x41, 0x41], + DebugInfo::Skip, + CollectEvents::Skip, + ) + .result + .unwrap() + .account_id; + + // no interception yet + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + account_id.clone(), + 0, + GAS_LIMIT, + None, + vec![], + )); + + // intercept calls to this contract + INTERCEPTED_ADDRESS.with(|i| *i.borrow_mut() = Some(account_id.clone())); + + assert_err_ignore_postinfo!( + Contracts::call(RuntimeOrigin::signed(ALICE), account_id, 0, GAS_LIMIT, None, vec![],), + >::ContractReverted, + ); + }); +} diff --git a/substrate/frame/contracts/src/wasm/prepare.rs b/substrate/frame/contracts/src/wasm/prepare.rs index b129c17e13eca5cbef72c40387a9f86d81fa3515..dfe8c4f8f9b91fe5e7d73032282fe50effd51d38 100644 --- a/substrate/frame/contracts/src/wasm/prepare.rs +++ b/substrate/frame/contracts/src/wasm/prepare.rs @@ -79,8 +79,7 @@ impl LoadedModule { } let engine = Engine::new(&config); - let module = - Module::new(&engine, code.clone()).map_err(|_| "Can't load the module into wasmi!")?; + let module = Module::new(&engine, code).map_err(|_| "Can't load the module into wasmi!")?; // Return a `LoadedModule` instance with // __valid__ module. diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs index e4a21a4e1d9b8a1a82c7b45f96bba22264383ed5..b4aa17726b8d28869110f44acbd6d21895da5218 100644 --- a/substrate/frame/democracy/src/benchmarking.rs +++ b/substrate/frame/democracy/src/benchmarking.rs @@ -25,7 +25,6 @@ use frame_support::{ traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_core::H256; use sp_runtime::{traits::Bounded, BoundedVec}; use crate::Pallet as Democracy; @@ -46,7 +45,7 @@ fn make_proposal(n: u32) -> BoundedCallOf { ::Preimages::bound(call).unwrap() } -fn add_proposal(n: u32) -> Result { +fn add_proposal(n: u32) -> Result { let other = funded_account::("proposer", n); let value = T::MinimumDeposit::get(); let proposal = make_proposal::(n); @@ -55,7 +54,7 @@ fn add_proposal(n: u32) -> Result { } // add a referendum with a metadata. -fn add_referendum(n: u32) -> (ReferendumIndex, H256, PreimageHash) { +fn add_referendum(n: u32) -> (ReferendumIndex, T::Hash, T::Hash) { let vote_threshold = VoteThreshold::SimpleMajority; let proposal = make_proposal::(n); let hash = proposal.hash(); @@ -85,7 +84,7 @@ fn assert_has_event(generic_event: ::RuntimeEvent) { } // note a new preimage. -fn note_preimage() -> PreimageHash { +fn note_preimage() -> T::Hash { use core::sync::atomic::{AtomicU8, Ordering}; use sp_std::borrow::Cow; // note a new preimage on every function invoke. diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs index e538d31c6ad0312e9a81d155786fac16ab403c54..089556191cd14eee735d12976ba6b0ed471a4eac 100644 --- a/substrate/frame/democracy/src/lib.rs +++ b/substrate/frame/democracy/src/lib.rs @@ -159,9 +159,8 @@ use frame_support::{ traits::{ defensive_prelude::*, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, - LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, - WithdrawReasons, + Bounded, Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, OnUnbalanced, + QueryPreimage, ReservableCurrency, StorePreimage, WithdrawReasons, }, weights::Weight, }; @@ -203,7 +202,7 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; pub type CallOf = ::RuntimeCall; -pub type BoundedCallOf = Bounded>; +pub type BoundedCallOf = Bounded, ::Hashing>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] @@ -211,7 +210,6 @@ pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_core::H256; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -226,10 +224,15 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Scheduler. - type Scheduler: ScheduleNamed, CallOf, Self::PalletsOrigin>; + type Scheduler: ScheduleNamed< + BlockNumberFor, + CallOf, + Self::PalletsOrigin, + Hasher = Self::Hashing, + >; /// The Preimage provider. - type Preimages: QueryPreimage + StorePreimage; + type Preimages: QueryPreimage + StorePreimage; /// Currency type for this pallet. type Currency: ReservableCurrency @@ -421,22 +424,22 @@ pub mod pallet { pub type Blacklist = StorageMap< _, Identity, - H256, + T::Hash, (BlockNumberFor, BoundedVec), >; /// Record of all proposals that have been subject to emergency cancellation. #[pallet::storage] - pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; + pub type Cancellations = StorageMap<_, Identity, T::Hash, bool, ValueQuery>; /// General information concerning any proposal or referendum. - /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// The `Hash` refers to the preimage of the `Preimages` provider which can be a JSON /// dump or IPFS hash of a JSON file. /// /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) /// large preimages. #[pallet::storage] - pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; + pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, T::Hash>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] @@ -476,9 +479,9 @@ pub mod pallet { /// An account has cancelled a previous delegation operation. Undelegated { account: T::AccountId }, /// An external proposal has been vetoed. - Vetoed { who: T::AccountId, proposal_hash: H256, until: BlockNumberFor }, + Vetoed { who: T::AccountId, proposal_hash: T::Hash, until: BlockNumberFor }, /// A proposal_hash has been blacklisted permanently. - Blacklisted { proposal_hash: H256 }, + Blacklisted { proposal_hash: T::Hash }, /// An account has voted in a referendum Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, /// An account has secconded a proposal @@ -490,14 +493,14 @@ pub mod pallet { /// Metadata owner. owner: MetadataOwner, /// Preimage hash. - hash: PreimageHash, + hash: T::Hash, }, /// Metadata for a proposal or a referendum has been cleared. MetadataCleared { /// Metadata owner. owner: MetadataOwner, /// Preimage hash. - hash: PreimageHash, + hash: T::Hash, }, /// Metadata has been transferred to new owner. MetadataTransferred { @@ -506,7 +509,7 @@ pub mod pallet { /// New metadata owner. owner: MetadataOwner, /// Preimage hash. - hash: PreimageHash, + hash: T::Hash, }, } @@ -775,7 +778,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::fast_track())] pub fn fast_track( origin: OriginFor, - proposal_hash: H256, + proposal_hash: T::Hash, voting_period: BlockNumberFor, delay: BlockNumberFor, ) -> DispatchResult { @@ -827,7 +830,7 @@ pub mod pallet { /// Weight: `O(V + log(V))` where V is number of `existing vetoers` #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::veto_external())] - pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { + pub fn veto_external(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { let who = T::VetoOrigin::ensure_origin(origin)?; if let Some((ext_proposal, _)) = NextExternal::::get() { @@ -1042,7 +1045,7 @@ pub mod pallet { #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] pub fn blacklist( origin: OriginFor, - proposal_hash: H256, + proposal_hash: T::Hash, maybe_ref_index: Option, ) -> DispatchResult { T::BlacklistOrigin::ensure_origin(origin)?; @@ -1139,7 +1142,7 @@ pub mod pallet { pub fn set_metadata( origin: OriginFor, owner: MetadataOwner, - maybe_hash: Option, + maybe_hash: Option, ) -> DispatchResult { match owner { MetadataOwner::External => { @@ -1173,15 +1176,16 @@ pub mod pallet { } pub trait EncodeInto: Encode { - fn encode_into + Default>(&self) -> T { + fn encode_into + Default, H: sp_core::Hasher>(&self) -> T { let mut t = T::default(); self.using_encoded(|data| { if data.len() <= t.as_mut().len() { t.as_mut()[0..data.len()].copy_from_slice(data); } else { - // encoded self is too big to fit into a T. hash it and use the first bytes of that - // instead. - let hash = sp_io::hashing::blake2_256(data); + // encoded self is too big to fit into a T. + // hash it and use the first bytes of that instead. + let hash = H::hash(&data); + let hash = hash.as_ref(); let l = t.as_mut().len().min(hash.len()); t.as_mut()[0..l].copy_from_slice(&hash[0..l]); } @@ -1610,7 +1614,7 @@ impl Pallet { // Earliest it can be scheduled for is next block. let when = now.saturating_add(status.delay.max(One::one())); if T::Scheduler::schedule_named( - (DEMOCRACY_ID, index).encode_into(), + (DEMOCRACY_ID, index).encode_into::<_, T::Hashing>(), DispatchTime::At(when), None, 63, diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index 9b885fb5915b7a3d92f28d7a7220f5c5ddf7d7f5..ebccf32e342377a56999c49b6cdd6fa95504b943 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -277,7 +277,7 @@ fn tally(r: ReferendumIndex) -> Tally { } /// note a new preimage without registering. -fn note_preimage(who: u64) -> PreimageHash { +fn note_preimage(who: u64) -> ::Hash { use std::sync::atomic::{AtomicU8, Ordering}; // note a new preimage on every function invoke. static COUNTER: AtomicU8 = AtomicU8::new(0); diff --git a/substrate/frame/democracy/src/tests/metadata.rs b/substrate/frame/democracy/src/tests/metadata.rs index 5a36d80b72637dbae4d931016df11484f2228256..1b6d66a8bc4486c555a5f0e1241f76280b33eeb7 100644 --- a/substrate/frame/democracy/src/tests/metadata.rs +++ b/substrate/frame/democracy/src/tests/metadata.rs @@ -22,9 +22,8 @@ use super::*; #[test] fn set_external_metadata_works() { new_test_ext().execute_with(|| { - use frame_support::traits::Hash as PreimageHash; // invalid preimage hash. - let invalid_hash: PreimageHash = [1u8; 32].into(); + let invalid_hash: ::Hash = [1u8; 32].into(); // metadata owner is an external proposal. let owner = MetadataOwner::External; // fails to set metadata if an external proposal does not exist. @@ -83,9 +82,8 @@ fn clear_metadata_works() { #[test] fn set_proposal_metadata_works() { new_test_ext().execute_with(|| { - use frame_support::traits::Hash as PreimageHash; // invalid preimage hash. - let invalid_hash: PreimageHash = [1u8; 32].into(); + let invalid_hash: ::Hash = [1u8; 32].into(); // create an external proposal. assert_ok!(propose_set_balance(1, 2, 5)); // metadata owner is a public proposal. diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 8b6e0827c715834de9101dd1f061c9d362b1705c..05f9b24f8f9c53f833b5de3504645c40c1df6a6d 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -2365,7 +2365,7 @@ mod tests { assert_eq!(MultiPhase::desired_targets().unwrap(), 2); // mine seq_phragmen solution with 2 iters. - let (solution, witness) = MultiPhase::mine_solution().unwrap(); + let (solution, witness, _) = MultiPhase::mine_solution().unwrap(); // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); @@ -2647,7 +2647,7 @@ mod tests { // set the solution balancing to get the desired score. crate::mock::Balancing::set(Some(BalancingConfig { iterations: 2, tolerance: 0 })); - let (solution, _) = MultiPhase::mine_solution().unwrap(); + let (solution, _, _) = MultiPhase::mine_solution().unwrap(); // Default solution's score. assert!(matches!(solution.score, ElectionScore { minimal_stake: 50, .. })); diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index a5fe8ce55582064078882ff125e3f945ac1b895c..7e4b029ff8c80cff6a57c0868e335d11aa4a2cc6 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -1348,7 +1348,7 @@ mod tests { roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); - let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let (raw, witness, _) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( witness.voters, witness.targets, diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index f1c9e92a704e926bc5e2ccf1e18ec590f1c69fd6..e3d0ded97515b9cbac011956afebbc5d4f15e5d6 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -108,6 +108,27 @@ impl From for MinerError { } } +/// Reports the trimming result of a mined solution +#[derive(Debug, Clone)] +pub struct TrimmingStatus { + weight: usize, + length: usize, +} + +impl TrimmingStatus { + pub fn is_trimmed(&self) -> bool { + self.weight > 0 || self.length > 0 + } + + pub fn trimmed_weight(&self) -> usize { + self.weight + } + + pub fn trimmed_length(&self) -> usize { + self.length + } +} + /// Save a given call into OCW storage. fn save_solution(call: &Call) -> Result<(), MinerError> { log!(debug, "saving a call to the offchain storage."); @@ -162,16 +183,21 @@ impl Pallet { /// /// The Npos Solver type, `S`, must have the same AccountId and Error type as the /// [`crate::Config::Solver`] in order to create a unified return type. - pub fn mine_solution( - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { + pub fn mine_solution() -> Result< + (RawSolution>, SolutionOrSnapshotSize, TrimmingStatus), + MinerError, + > { let RoundSnapshot { voters, targets } = Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?; - let (solution, score, size) = Miner::::mine_solution_with_snapshot::< - T::Solver, - >(voters, targets, desired_targets)?; + let (solution, score, size, is_trimmed) = + Miner::::mine_solution_with_snapshot::( + voters, + targets, + desired_targets, + )?; let round = Self::round(); - Ok((RawSolution { solution, score, round }, size)) + Ok((RawSolution { solution, score, round }, size, is_trimmed)) } /// Attempt to restore a solution from cache. Otherwise, compute it fresh. Either way, submit @@ -232,7 +258,7 @@ impl Pallet { /// Mine a new solution as a call. Performs all checks. pub fn mine_checked_call() -> Result, MinerError> { // get the solution, with a load of checks to ensure if submitted, IT IS ABSOLUTELY VALID. - let (raw_solution, witness) = Self::mine_and_check()?; + let (raw_solution, witness, _) = Self::mine_and_check()?; let score = raw_solution.score; let call: Call = Call::submit_unsigned { raw_solution: Box::new(raw_solution), witness }; @@ -282,11 +308,13 @@ impl Pallet { /// If you want an unchecked solution, use [`Pallet::mine_solution`]. /// If you want a checked solution and submit it at the same time, use /// [`Pallet::mine_check_save_submit`]. - pub fn mine_and_check( - ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> { - let (raw_solution, witness) = Self::mine_solution()?; + pub fn mine_and_check() -> Result< + (RawSolution>, SolutionOrSnapshotSize, TrimmingStatus), + MinerError, + > { + let (raw_solution, witness, is_trimmed) = Self::mine_solution()?; Self::basic_checks(&raw_solution, "mined")?; - Ok((raw_solution, witness)) + Ok((raw_solution, witness, is_trimmed)) } /// Checks if an execution of the offchain worker is permitted at the given block number, or @@ -408,7 +436,7 @@ impl Miner { voters: Vec<(T::AccountId, VoteWeight, BoundedVec)>, targets: Vec, desired_targets: u32, - ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize), MinerError> + ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize, TrimmingStatus), MinerError> where S: NposSolver, { @@ -436,7 +464,8 @@ impl Miner { voters: Vec<(T::AccountId, VoteWeight, BoundedVec)>, targets: Vec, desired_targets: u32, - ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize), MinerError> { + ) -> Result<(SolutionOf, ElectionScore, SolutionOrSnapshotSize, TrimmingStatus), MinerError> + { // now make some helper closures. let cache = helpers::generate_voter_cache::(&voters); let voter_index = helpers::voter_index_fn::(&cache); @@ -495,13 +524,13 @@ impl Miner { // trim assignments list for weight and length. let size = SolutionOrSnapshotSize { voters: voters.len() as u32, targets: targets.len() as u32 }; - Self::trim_assignments_weight( + let weight_trimmed = Self::trim_assignments_weight( desired_targets, size, T::MaxWeight::get(), &mut index_assignments, ); - Self::trim_assignments_length( + let length_trimmed = Self::trim_assignments_length( T::MaxLength::get(), &mut index_assignments, &encoded_size_of, @@ -513,7 +542,9 @@ impl Miner { // re-calc score. let score = solution.clone().score(stake_of, voter_at, target_at)?; - Ok((solution, score, size)) + let is_trimmed = TrimmingStatus { weight: weight_trimmed, length: length_trimmed }; + + Ok((solution, score, size, is_trimmed)) } /// Greedily reduce the size of the solution to fit into the block w.r.t length. @@ -534,7 +565,7 @@ impl Miner { max_allowed_length: u32, assignments: &mut Vec>, encoded_size_of: impl Fn(&[IndexAssignmentOf]) -> Result, - ) -> Result<(), MinerError> { + ) -> Result { // Perform a binary search for the max subset of which can fit into the allowed // length. Having discovered that, we can truncate efficiently. let max_allowed_length: usize = max_allowed_length.saturated_into(); @@ -543,7 +574,7 @@ impl Miner { // not much we can do if assignments are already empty. if high == low { - return Ok(()) + return Ok(0) } while high - low > 1 { @@ -577,16 +608,18 @@ impl Miner { // after this point, we never error. // check before edit. + let remove = assignments.len().saturating_sub(maximum_allowed_voters); + log_no_system!( debug, "from {} assignments, truncating to {} for length, removing {}", assignments.len(), maximum_allowed_voters, - assignments.len().saturating_sub(maximum_allowed_voters), + remove ); assignments.truncate(maximum_allowed_voters); - Ok(()) + Ok(remove) } /// Greedily reduce the size of the solution to fit into the block w.r.t. weight. @@ -609,7 +642,7 @@ impl Miner { size: SolutionOrSnapshotSize, max_weight: Weight, assignments: &mut Vec>, - ) { + ) -> usize { let maximum_allowed_voters = Self::maximum_voter_for_weight(desired_targets, size, max_weight); let removing: usize = @@ -622,6 +655,8 @@ impl Miner { removing, ); assignments.truncate(maximum_allowed_voters as usize); + + removing } /// Find the maximum `len` that a solution can have in order to fit into the block weight. @@ -1230,7 +1265,7 @@ mod tests { assert_eq!(MultiPhase::desired_targets().unwrap(), 2); // mine seq_phragmen solution with 2 iters. - let (solution, witness) = MultiPhase::mine_solution().unwrap(); + let (solution, witness, _) = MultiPhase::mine_solution().unwrap(); // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); @@ -1268,7 +1303,7 @@ mod tests { roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); - let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let (raw, witness, t) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( witness.voters, witness.targets, @@ -1278,11 +1313,12 @@ mod tests { // default solution will have 5 edges (5 * 5 + 10) assert_eq!(solution_weight, Weight::from_parts(35, 0)); assert_eq!(raw.solution.voter_count(), 5); + assert_eq!(t.trimmed_weight(), 0); // now reduce the max weight ::set(Weight::from_parts(25, u64::MAX)); - let (raw, witness) = MultiPhase::mine_solution().unwrap(); + let (raw, witness, t) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( witness.voters, witness.targets, @@ -1292,6 +1328,7 @@ mod tests { // default solution will have 5 edges (5 * 5 + 10) assert_eq!(solution_weight, Weight::from_parts(25, 0)); assert_eq!(raw.solution.voter_count(), 3); + assert_eq!(t.trimmed_weight(), 2); }) } @@ -1303,7 +1340,7 @@ mod tests { assert!(MultiPhase::current_phase().is_unsigned()); // Force the number of winners to be bigger to fail - let (mut solution, _) = MultiPhase::mine_solution().unwrap(); + let (mut solution, _, _) = MultiPhase::mine_solution().unwrap(); solution.solution.votes1[0].1 = 4; assert_eq!( @@ -1342,7 +1379,7 @@ mod tests { let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap(); let desired_targets = MultiPhase::desired_targets().unwrap(); - let (raw, score, witness) = + let (raw, score, witness, _) = Miner::::prepare_election_result_with_snapshot( result, voters.clone(), @@ -1371,7 +1408,7 @@ mod tests { }, ], }; - let (raw, score, _) = Miner::::prepare_election_result_with_snapshot( + let (raw, score, _, _) = Miner::::prepare_election_result_with_snapshot( result, voters.clone(), targets.clone(), @@ -1400,7 +1437,7 @@ mod tests { }, ], }; - let (raw, score, witness) = + let (raw, score, witness, _) = Miner::::prepare_election_result_with_snapshot( result, voters.clone(), @@ -1769,7 +1806,7 @@ mod tests { let solution_clone = solution.clone(); // when - Miner::::trim_assignments_length( + let trimmed_len = Miner::::trim_assignments_length( encoded_len, &mut assignments, encoded_size_of, @@ -1779,6 +1816,7 @@ mod tests { // then let solution = SolutionOf::::try_from(assignments.as_slice()).unwrap(); assert_eq!(solution, solution_clone); + assert_eq!(trimmed_len, 0); }); } @@ -1794,7 +1832,7 @@ mod tests { let solution_clone = solution.clone(); // when - Miner::::trim_assignments_length( + let trimmed_len = Miner::::trim_assignments_length( encoded_len as u32 - 1, &mut assignments, encoded_size_of, @@ -1805,6 +1843,7 @@ mod tests { let solution = SolutionOf::::try_from(assignments.as_slice()).unwrap(); assert_ne!(solution, solution_clone); assert!(solution.encoded_size() < encoded_len); + assert_eq!(trimmed_len, 1); }); } 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 e40bac3e9fc44adb37b0d8e527d4ac6eae460ed2..1d3f4712b1d604988047f5643ddd86296f453878 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 @@ -338,7 +338,7 @@ fn ledger_consistency_active_balance_below_ed() { ExtBuilder::default().staking(StakingExtBuilder::default()).build_offchainify(); ext.execute_with(|| { - assert_eq!(Staking::ledger(&11).unwrap().active, 1000); + assert_eq!(Staking::ledger(11.into()).unwrap().active, 1000); // unbonding total of active stake fails because the active ledger balance would fall // below the `MinNominatorBond`. @@ -356,13 +356,13 @@ fn ledger_consistency_active_balance_below_ed() { // the active balance of the ledger entry is 0, while total balance is 1000 until // `withdraw_unbonded` is called. - assert_eq!(Staking::ledger(&11).unwrap().active, 0); - assert_eq!(Staking::ledger(&11).unwrap().total, 1000); + assert_eq!(Staking::ledger(11.into()).unwrap().active, 0); + assert_eq!(Staking::ledger(11.into()).unwrap().total, 1000); // trying to withdraw the unbonded balance won't work yet because not enough bonding // eras have passed. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); - assert_eq!(Staking::ledger(&11).unwrap().total, 1000); + assert_eq!(Staking::ledger(11.into()).unwrap().total, 1000); // tries to reap stash after chilling, which fails since the stash total balance is // above ED. @@ -384,6 +384,6 @@ fn ledger_consistency_active_balance_below_ed() { pool_state, ); assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); - assert_eq!(Staking::ledger(&11), None); + assert!(Staking::ledger(11.into()).is_err()); }); } 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 ec646c3119789ec1ea01ef08fa5514037060dc9d..2e3cb15f9a4345f1a2804109c290b95166779dcd 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 @@ -65,8 +65,7 @@ type Block = frame_system::mocking::MockBlockU32; type Extrinsic = testing::TestXt; frame_support::construct_runtime!( - pub enum Runtime - { + pub enum Runtime { System: frame_system, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, @@ -89,15 +88,8 @@ pub(crate) type Moment = u32; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; - type BlockHashCount = ConstU32<10>; - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); - type AccountData = pallet_balances::AccountData; + type BlockHashCount = ConstU32<10>; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 1b432204470abb6abb9d3fda5ae368e1fe2a7cc3..f4ea4ef6e361f13013a1f434b08ebcbdd6dfe37f 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.36", features = ["full", "visit"] } +syn = { version = "2.0.38", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" 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 fe84c4c0ef943993e118cc901367df839317df30..e485920145416dce3425b5e5942388c204b4d582 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/substrate/frame/elections-phragmen/src/benchmarking.rs b/substrate/frame/elections-phragmen/src/benchmarking.rs index 56ea19578c8f5425bc9f42029659d64ebf9cba84..9878f7fd41c068329574810c3fc8edff0e6b7b4a 100644 --- a/substrate/frame/elections-phragmen/src/benchmarking.rs +++ b/substrate/frame/elections-phragmen/src/benchmarking.rs @@ -379,7 +379,7 @@ benchmarks! { let root = RawOrigin::Root; }: _(root, v, d) verify { - assert_eq!(>::iter().count() as u32, 0); + assert_eq!(>::iter().count() as u32, v - d); } election_phragmen { diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 6912649bd122d8d66014b9f805f54732c01bc18b..93f9fc2b6d241df1dd75f1f47c171708f6857e08 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -591,15 +591,18 @@ pub mod pallet { /// ## Complexity /// - Check is_defunct_voter() details. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::clean_defunct_voters(*_num_voters, *_num_defunct))] + #[pallet::weight(T::WeightInfo::clean_defunct_voters(*num_voters, *num_defunct))] pub fn clean_defunct_voters( origin: OriginFor, - _num_voters: u32, - _num_defunct: u32, + num_voters: u32, + num_defunct: u32, ) -> DispatchResult { let _ = ensure_root(origin)?; + >::iter() + .take(num_voters as usize) .filter(|(_, x)| Self::is_defunct_voter(&x.votes)) + .take(num_defunct as usize) .for_each(|(dv, _)| Self::do_remove_voter(&dv)); Ok(()) diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index 31d20e07f5f74ea18815b37ef4e93ec4ed6136bc..5eff74922cabfa8e10b747ba186b7974e81c49f4 100644 --- a/substrate/frame/examples/basic/src/lib.rs +++ b/substrate/frame/examples/basic/src/lib.rs @@ -457,7 +457,7 @@ impl Pallet { // Note that a signed extension can also indicate that a particular data must be present in the // _signing payload_ of a transaction by providing an implementation for the `additional_signed` // method. This example will not cover this type of extension. See `CheckSpecVersion` in -// [FRAME System](https://github.com/paritytech/substrate/tree/master/frame/system#signed-extensions) +// [FRAME System](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/system#signed-extensions) // for an example. // // Using the extension, you can add some hooks to the life cycle of each transaction. Note that by diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index d2eade0ccff1eeab28ada5b4af9ed3b810d0bcb8..8a1f6f9d6a82cffbd557ab2d3f1e92ad966abad0 100644 --- a/substrate/frame/examples/default-config/src/lib.rs +++ b/substrate/frame/examples/default-config/src/lib.rs @@ -26,7 +26,7 @@ //! Study the following types: //! //! - [`pallet::DefaultConfig`], and how it differs from [`pallet::Config`]. -//! - [`pallet::config_preludes::TestDefaultConfig`] and how it implements +//! - [`struct@pallet::config_preludes::TestDefaultConfig`] and how it implements //! [`pallet::DefaultConfig`]. //! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`]. @@ -83,11 +83,12 @@ pub mod pallet { // This will help use not need to disambiguate anything when using `derive_impl`. use super::*; use frame_support::derive_impl; + use frame_system::config_preludes::TestDefaultConfig as SystemTestDefaultConfig; /// A type providing default configurations for this pallet in testing environment. pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(SystemTestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] @@ -109,7 +110,7 @@ pub mod pallet { /// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again. pub struct OtherDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(SystemTestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for OtherDefaultConfig {} #[frame_support::register_default_impl(OtherDefaultConfig)] diff --git a/substrate/frame/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 0fbffc971da6225180b1548b3f87c88b8231ca48..56117c59dc6d706393ccf5215e6b194c457307bc 100644 --- a/substrate/frame/examples/kitchensink/src/lib.rs +++ b/substrate/frame/examples/kitchensink/src/lib.rs @@ -74,7 +74,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// This is a normal Rust type, nothing specific to FRAME here. - type Currency: frame_support::traits::tokens::fungible::Inspect; + type Currency: frame_support::traits::fungible::Inspect; /// Similarly, let the runtime decide this. fn some_function() -> u32; diff --git a/substrate/frame/examples/kitchensink/src/tests.rs b/substrate/frame/examples/kitchensink/src/tests.rs index b2af7c8983f563e5ab636ab63a9e8da102167d8f..abded83e48201ef0b518ba9f6f7a1e2d11eb3418 100644 --- a/substrate/frame/examples/kitchensink/src/tests.rs +++ b/substrate/frame/examples/kitchensink/src/tests.rs @@ -39,15 +39,7 @@ frame_support::construct_runtime!( /// details. #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; type Block = Block; - type BlockHashCount = ConstU64<10>; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); - type AccountData = pallet_balances::AccountData; } diff --git a/substrate/frame/examples/split/src/mock.rs b/substrate/frame/examples/split/src/mock.rs index bee3633ef68f2c02856b70429370c34301577e32..caab4f1ae902f9be5bee10d324af96304db3a63f 100644 --- a/substrate/frame/examples/split/src/mock.rs +++ b/substrate/frame/examples/split/src/mock.rs @@ -17,7 +17,6 @@ use crate as pallet_template; use frame_support::{derive_impl, sp_runtime::BuildStorage}; -use sp_core::ConstU64; type Block = frame_system::mocking::MockBlock; @@ -35,13 +34,6 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type Block = Block; - type BlockHashCount = ConstU64<10>; - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); } impl pallet_template::Config for Test { diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 224067d4fa70aa7c3b4fb1ced5de8ba2ba8262c7..85548c6600db827f316549b91c4a120be406745d 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -27,7 +27,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} -docify = "0.2.3" +docify = "0.2.4" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/fast-unstake/src/lib.rs b/substrate/frame/fast-unstake/src/lib.rs index 39783271e6569381de242a92b6a7213e7c2d6227..2b99ad79a7dfdd16d0aae764c289d36f569011ab 100644 --- a/substrate/frame/fast-unstake/src/lib.rs +++ b/substrate/frame/fast-unstake/src/lib.rs @@ -17,7 +17,7 @@ //! > Made with *Substrate*, for *Polkadot*. //! -//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) - +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/fast-unstake) - //! [![polkadot]](https://polkadot.network) //! //! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index dc24a823c0db022ad0f625be9d6a51a3505f07b0..cf274c784f9f99b87150c1bde0845f2d867cd3a2 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -17,7 +17,7 @@ use crate::{self as fast_unstake}; use frame_support::{ - assert_ok, + assert_ok, derive_impl, pallet_prelude::*, parameter_types, traits::{ConstU64, Currency}, @@ -32,7 +32,6 @@ use pallet_staking::{Exposure, IndividualExposure, StakerStatus}; use sp_std::prelude::*; pub type AccountId = u128; -pub type Nonce = u32; pub type BlockNumber = u64; pub type Balance = u128; pub type T = Runtime; @@ -44,30 +43,13 @@ parameter_types! { ); } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = Nonce; - type RuntimeCall = RuntimeCall; - type Hash = sp_core::H256; - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type 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>; + // we use U128 account id in order to get a better iteration order out of a map. + type AccountId = AccountId; + type Lookup = IdentityLookup; } impl pallet_timestamp::Config for Runtime { diff --git a/substrate/frame/grandpa/src/lib.rs b/substrate/frame/grandpa/src/lib.rs index 2a0e707ac4148c81777a99014fb907a23ee0ca67..95d1c8aa609495f567e23a0650365c924bad040b 100644 --- a/substrate/frame/grandpa/src/lib.rs +++ b/substrate/frame/grandpa/src/lib.rs @@ -129,18 +129,16 @@ pub mod pallet { if let Some(pending_change) = >::get() { // emit signal if we're at the block that scheduled the change if block_number == pending_change.scheduled_at { + let next_authorities = pending_change.next_authorities.to_vec(); if let Some(median) = pending_change.forced { Self::deposit_log(ConsensusLog::ForcedChange( median, - ScheduledChange { - delay: pending_change.delay, - next_authorities: pending_change.next_authorities.to_vec(), - }, + ScheduledChange { delay: pending_change.delay, next_authorities }, )) } else { Self::deposit_log(ConsensusLog::ScheduledChange(ScheduledChange { delay: pending_change.delay, - next_authorities: pending_change.next_authorities.to_vec(), + next_authorities, })); } } @@ -149,7 +147,7 @@ pub mod pallet { if block_number == pending_change.scheduled_at + pending_change.delay { Self::set_grandpa_authorities(&pending_change.next_authorities); Self::deposit_event(Event::NewAuthorities { - authority_set: pending_change.next_authorities.to_vec(), + authority_set: pending_change.next_authorities.into_inner(), }); >::kill(); } diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index 4b51d23f6b34f99463e29bb8054628ff62bd2945..059de204bbf772fb28bd586a841bedee9c366bfb 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -22,7 +22,9 @@ use super::*; use crate::Pallet as Identity; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; +use frame_benchmarking::{ + account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, +}; use frame_support::{ ensure, traits::{EnsureOrigin, Get}, @@ -118,110 +120,128 @@ fn create_identity_info(num_fields: u32) -> IdentityInfo add_registrars::(r)?; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn add_registrar(r: Linear<1, { T::MaxRegistrars::get() - 1 }>) -> Result<(), BenchmarkError> { + add_registrars::(r)?; ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); let origin = T::RegistrarOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); - }: _(origin, account) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, account); + ensure!(Registrars::::get().len() as u32 == r + 1, "Registrars not added."); + Ok(()) } - set_identity { - let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 0 .. T::MaxAdditionalFields::get(); - let caller = { - // The target user - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - let caller_origin: ::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); - let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - - // Add an initial identity - let initial_info = create_identity_info::(1); - Identity::::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?; - - // User requests judgement from all the registrars, and they approve - for i in 0..r { - let registrar: T::AccountId = account("registrar", i, SEED); - let registrar_lookup = T::Lookup::unlookup(registrar.clone()); - let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); - let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); - - Identity::::request_judgement(caller_origin.clone(), i, 10u32.into())?; - Identity::::provide_judgement( - RawOrigin::Signed(registrar).into(), - i, - caller_lookup.clone(), - Judgement::Reasonable, - T::Hashing::hash_of(&initial_info), - )?; - } - caller - }; - }: _(RawOrigin::Signed(caller.clone()), Box::new(create_identity_info::(x))) - verify { + #[benchmark] + fn set_identity( + r: Linear<1, { T::MaxRegistrars::get() }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { + add_registrars::(r)?; + + let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let caller_origin: ::RuntimeOrigin = + RawOrigin::Signed(caller.clone()).into(); + let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + + // Add an initial identity + let initial_info = create_identity_info::(1); + Identity::::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?; + + // User requests judgement from all the registrars, and they approve + for i in 0..r { + let registrar: T::AccountId = account("registrar", i, SEED); + let _ = T::Lookup::unlookup(registrar.clone()); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); + + Identity::::request_judgement(caller_origin.clone(), i, 10u32.into())?; + Identity::::provide_judgement( + RawOrigin::Signed(registrar).into(), + i, + caller_lookup.clone(), + Judgement::Reasonable, + T::Hashing::hash_of(&initial_info), + )?; + } + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), Box::new(create_identity_info::(x))); + assert_last_event::(Event::::IdentitySet { who: caller }.into()); + Ok(()) } // We need to split `set_subs` into two benchmarks to accurately isolate the potential // writes caused by new or old sub accounts. The actual weight should simply be // the sum of these two weights. - set_subs_new { + #[benchmark] + fn set_subs_new(s: Linear<0, { T::MaxSubAccounts::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); - // Create a new subs vec with s sub accounts - let s in 0 .. T::MaxSubAccounts::get() => (); + + // Create a new subs vec with sub accounts let subs = create_sub_accounts::(&caller, s)?; ensure!(SubsOf::::get(&caller).1.len() == 0, "Caller already has subs"); - }: set_subs(RawOrigin::Signed(caller.clone()), subs) - verify { + + #[extrinsic_call] + set_subs(RawOrigin::Signed(caller.clone()), subs); + ensure!(SubsOf::::get(&caller).1.len() as u32 == s, "Subs not added"); + Ok(()) } - set_subs_old { + #[benchmark] + fn set_subs_old(p: Linear<0, { T::MaxSubAccounts::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); + // Give them p many previous sub accounts. - let p in 0 .. T::MaxSubAccounts::get() => { - let _ = add_sub_accounts::(&caller, p)?; - }; + let _ = add_sub_accounts::(&caller, p)?; + // Remove all subs. let subs = create_sub_accounts::(&caller, 0)?; - ensure!( - SubsOf::::get(&caller).1.len() as u32 == p, - "Caller does have subs", - ); - }: set_subs(RawOrigin::Signed(caller.clone()), subs) - verify { + ensure!(SubsOf::::get(&caller).1.len() as u32 == p, "Caller does have subs",); + + #[extrinsic_call] + set_subs(RawOrigin::Signed(caller.clone()), subs); + ensure!(SubsOf::::get(&caller).1.len() == 0, "Subs not removed"); + Ok(()) } - clear_identity { + #[benchmark] + fn clear_identity( + r: Linear<1, { T::MaxRegistrars::get() }>, + s: Linear<0, { T::MaxSubAccounts::get() }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = + ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let caller_lookup = ::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 0 .. T::MaxSubAccounts::get() => { - // Give them s many sub accounts - let caller: T::AccountId = whitelisted_caller(); - let _ = add_sub_accounts::(&caller, s)?; - }; - let x in 0 .. T::MaxAdditionalFields::get(); + // Register the registrars + add_registrars::(r)?; + + // Add sub accounts + let _ = add_sub_accounts::(&caller, s)?; // Create their main identity with x additional fields let info = create_identity_info::(x); - let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve for i in 0..r { let registrar: T::AccountId = account("registrar", i, SEED); - let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); Identity::::request_judgement(caller_origin.clone(), i, 10u32.into())?; @@ -233,111 +253,175 @@ benchmarks! { T::Hashing::hash_of(&info), )?; } + ensure!(IdentityOf::::contains_key(&caller), "Identity does not exist."); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + ensure!(!IdentityOf::::contains_key(&caller), "Identity not cleared."); + Ok(()) } - request_judgement { + #[benchmark] + fn request_judgement( + r: Linear<1, { T::MaxRegistrars::get() }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 0 .. T::MaxAdditionalFields::get() => { - // Create their main identity with x additional fields - let info = create_identity_info::(x); - let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); - Identity::::set_identity(caller_origin, Box::new(info))?; - }; - }: _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into()) - verify { - assert_last_event::(Event::::JudgementRequested { who: caller, registrar_index: r-1 }.into()); + // Register the registrars + add_registrars::(r)?; + + // Create their main identity with x additional fields + let info = create_identity_info::(x); + let caller_origin = + ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); + Identity::::set_identity(caller_origin.clone(), Box::new(info))?; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into()); + + assert_last_event::( + Event::::JudgementRequested { who: caller, registrar_index: r - 1 }.into(), + ); + + Ok(()) } - cancel_request { + #[benchmark] + fn cancel_request( + r: Linear<1, { T::MaxRegistrars::get() }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 0 .. T::MaxAdditionalFields::get() => { - // Create their main identity with x additional fields - let info = create_identity_info::(x); - let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); - Identity::::set_identity(caller_origin, Box::new(info))?; - }; - - Identity::::request_judgement(caller_origin, r - 1, 10u32.into())?; - }: _(RawOrigin::Signed(caller.clone()), r - 1) - verify { - assert_last_event::(Event::::JudgementUnrequested { who: caller, registrar_index: r-1 }.into()); + // Register the registrars + add_registrars::(r)?; + + // Create their main identity with x additional fields + let info = create_identity_info::(x); + let caller_origin = + ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); + Identity::::set_identity(caller_origin.clone(), Box::new(info))?; + + Identity::::request_judgement(caller_origin.clone(), r - 1, 10u32.into())?; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), r - 1); + + assert_last_event::( + Event::::JudgementUnrequested { who: caller, registrar_index: r - 1 }.into(), + ); + + Ok(()) } - set_fee { + #[benchmark] + fn set_fee(r: Linear<1, { T::MaxRegistrars::get() - 1 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; + add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::try_successful_origin() .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; + let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set."); - }: _(RawOrigin::Signed(caller), r, 100u32.into()) - verify { - let registrars = Registrars::::get(); - ensure!(registrars[r as usize].as_ref().unwrap().fee == 100u32.into(), "Fee not changed."); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), r, 100u32.into()); + + let updated_registrars = Registrars::::get(); + ensure!( + updated_registrars[r as usize].as_ref().unwrap().fee == 100u32.into(), + "Fee not changed." + ); + + Ok(()) } - set_account_id { + #[benchmark] + fn set_account_id(r: Linear<1, { T::MaxRegistrars::get() - 1 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; + add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::try_successful_origin() .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; + let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); + let new_account = T::Lookup::unlookup(account("new", 0, SEED)); - }: _(RawOrigin::Signed(caller), r, new_account) - verify { - let registrars = Registrars::::get(); - ensure!(registrars[r as usize].as_ref().unwrap().account == account("new", 0, SEED), "id not changed."); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), r, new_account); + + let updated_registrars = Registrars::::get(); + ensure!( + updated_registrars[r as usize].as_ref().unwrap().account == account("new", 0, SEED), + "id not changed." + ); + + Ok(()) } - set_fields { + #[benchmark] + fn set_fields(r: Linear<1, { T::MaxRegistrars::get() - 1 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; + add_registrars::(r)?; let registrar_origin = T::RegistrarOrigin::try_successful_origin() .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; - let fields = IdentityFields( - IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot - | IdentityField::Email | IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter - ); - let registrars = Registrars::::get(); - ensure!(registrars[r as usize].as_ref().unwrap().fields == Default::default(), "fields already set."); - }: _(RawOrigin::Signed(caller), r, fields) - verify { + + let fields = + IdentityFields( + IdentityField::Display | + IdentityField::Legal | IdentityField::Web | + IdentityField::Riot | IdentityField::Email | + IdentityField::PgpFingerprint | + IdentityField::Image | IdentityField::Twitter, + ); + let registrars = Registrars::::get(); - ensure!(registrars[r as usize].as_ref().unwrap().fields != Default::default(), "fields not set."); + ensure!( + registrars[r as usize].as_ref().unwrap().fields == Default::default(), + "fields already set." + ); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), r, fields); + + let updated_registrars = Registrars::::get(); + ensure!( + updated_registrars[r as usize].as_ref().unwrap().fields != Default::default(), + "fields not set." + ); + + Ok(()) } - provide_judgement { + #[benchmark] + fn provide_judgement( + r: Linear<1, { T::MaxRegistrars::get() - 1 }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { // The user let user: T::AccountId = account("user", r, SEED); - let user_origin = ::RuntimeOrigin::from(RawOrigin::Signed(user.clone())); + let user_origin = + ::RuntimeOrigin::from(RawOrigin::Signed(user.clone())); let user_lookup = ::unlookup(user.clone()); let _ = T::Currency::make_free_balance_be(&user, BalanceOf::::max_value()); @@ -345,8 +429,7 @@ benchmarks! { let caller_lookup = T::Lookup::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let x in 0 .. T::MaxAdditionalFields::get(); + add_registrars::(r)?; let info = create_identity_info::(x); let info_hash = T::Hashing::hash_of(&info); @@ -356,18 +439,28 @@ benchmarks! { .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; - }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash) - verify { - assert_last_event::(Event::::JudgementGiven { target: user, registrar_index: r }.into()) + + #[extrinsic_call] + _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash); + + assert_last_event::( + Event::::JudgementGiven { target: user, registrar_index: r }.into(), + ); + + Ok(()) } - kill_identity { - let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 0 .. T::MaxSubAccounts::get(); - let x in 0 .. T::MaxAdditionalFields::get(); + #[benchmark] + fn kill_identity( + r: Linear<1, { T::MaxRegistrars::get() }>, + s: Linear<0, { T::MaxSubAccounts::get() }>, + x: Linear<0, { T::MaxAdditionalFields::get() }>, + ) -> Result<(), BenchmarkError> { + add_registrars::(r)?; let target: T::AccountId = account("target", 0, SEED); - let target_origin: ::RuntimeOrigin = RawOrigin::Signed(target.clone()).into(); + let target_origin: ::RuntimeOrigin = + RawOrigin::Signed(target.clone()).into(); let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); @@ -378,7 +471,7 @@ benchmarks! { // User requests judgement from all the registrars, and they approve for i in 0..r { let registrar: T::AccountId = account("registrar", i, SEED); - let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); + let balance_to_use = T::Currency::minimum_balance() * 10u32.into(); let _ = T::Currency::make_free_balance_be(®istrar, balance_to_use); Identity::::request_judgement(target_origin.clone(), i, 10u32.into())?; @@ -390,62 +483,86 @@ benchmarks! { T::Hashing::hash_of(&info), )?; } + ensure!(IdentityOf::::contains_key(&target), "Identity not set"); + let origin = T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin, target_lookup) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, target_lookup); + ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); - } - add_sub { - let s in 0 .. T::MaxSubAccounts::get() - 1; + Ok(()) + } + #[benchmark] + fn add_sub(s: Linear<0, { T::MaxSubAccounts::get() - 1 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; let sub = account("new_sub", 0, SEED); let data = Data::Raw(vec![0; 32].try_into().unwrap()); + ensure!(SubsOf::::get(&caller).1.len() as u32 == s, "Subs not set."); - }: _(RawOrigin::Signed(caller.clone()), T::Lookup::unlookup(sub), data) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), T::Lookup::unlookup(sub), data); + ensure!(SubsOf::::get(&caller).1.len() as u32 == s + 1, "Subs not added."); - } - rename_sub { - let s in 1 .. T::MaxSubAccounts::get(); + Ok(()) + } + #[benchmark] + fn rename_sub(s: Linear<1, { T::MaxSubAccounts::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let (sub, _) = add_sub_accounts::(&caller, s)?.remove(0); let data = Data::Raw(vec![1; 32].try_into().unwrap()); + ensure!(SuperOf::::get(&sub).unwrap().1 != data, "data already set"); - }: _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone()), data.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone()), data.clone()); + ensure!(SuperOf::::get(&sub).unwrap().1 == data, "data not set"); - } - remove_sub { - let s in 1 .. T::MaxSubAccounts::get(); + Ok(()) + } + #[benchmark] + fn remove_sub(s: Linear<1, { T::MaxSubAccounts::get() }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let (sub, _) = add_sub_accounts::(&caller, s)?.remove(0); ensure!(SuperOf::::contains_key(&sub), "Sub doesn't exists"); - }: _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), T::Lookup::unlookup(sub.clone())); + ensure!(!SuperOf::::contains_key(&sub), "Sub not removed"); - } - quit_sub { - let s in 0 .. T::MaxSubAccounts::get() - 1; + Ok(()) + } + #[benchmark] + fn quit_sub(s: Linear<0, { T::MaxSubAccounts::get() - 1 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let sup = account("super", 0, SEED); let _ = add_sub_accounts::(&sup, s)?; let sup_origin = RawOrigin::Signed(sup).into(); - Identity::::add_sub(sup_origin, T::Lookup::unlookup(caller.clone()), Data::Raw(vec![0; 32].try_into().unwrap()))?; + Identity::::add_sub( + sup_origin, + T::Lookup::unlookup(caller.clone()), + Data::Raw(vec![0; 32].try_into().unwrap()), + )?; ensure!(SuperOf::::contains_key(&caller), "Sub doesn't exists"); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + ensure!(!SuperOf::::contains_key(&caller), "Sub not removed"); + + Ok(()) } impl_benchmark_test_suite!(Identity, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/substrate/frame/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs index ecc254278bf0fa1661d57e1fd2f1b97edbf181c1..d3cb4e57029727f395dcafb263a2033c5291dbe9 100644 --- a/substrate/frame/merkle-mountain-range/src/mock.rs +++ b/substrate/frame/merkle-mountain-range/src/mock.rs @@ -19,13 +19,9 @@ use crate as pallet_mmr; use crate::*; use codec::{Decode, Encode}; -use frame_support::{ - parameter_types, - traits::{ConstU32, ConstU64}, -}; -use sp_core::H256; +use frame_support::{derive_impl, parameter_types}; use sp_mmr_primitives::{Compact, LeafDataProvider}; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup, Keccak256}; +use sp_runtime::traits::Keccak256; type Block = frame_system::mocking::MockBlock; @@ -37,30 +33,9 @@ frame_support::construct_runtime!( } ); +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = sp_core::sr25519::Public; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; } impl Config for Test { diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..68ffdad20fcbb2478f0a47f6fccff514d9a8c85f --- /dev/null +++ b/substrate/frame/mixnet/Cargo.toml @@ -0,0 +1,57 @@ +[package] +description = "FRAME's mixnet pallet" +name = "pallet-mixnet" +version = "0.1.0-dev" +license = "Apache-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "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" } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.188", default-features = false, features = ["derive"] } +sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto" } +sp-arithmetic = { default-features = false, path = "../../primitives/arithmetic" } +sp-io = { default-features = false, path = "../../primitives/io" } +sp-mixnet = { default-features = false, path = "../../primitives/mixnet" } +sp-runtime = { default-features = false, path = "../../primitives/runtime" } +sp-std = { default-features = false, path = "../../primitives/std" } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "serde/std", + "sp-application-crypto/std", + "sp-arithmetic/std", + "sp-io/std", + "sp-mixnet/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/mixnet/README.md b/substrate/frame/mixnet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..59b81851ed11faa4020c49edbd74e412472e6259 --- /dev/null +++ b/substrate/frame/mixnet/README.md @@ -0,0 +1,4 @@ +This pallet is responsible for determining the current mixnet session and phase, and the mixnode +set for each session. + +License: Apache-2.0 diff --git a/substrate/frame/mixnet/src/lib.rs b/substrate/frame/mixnet/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..c7a5b624157b88610f6728fffc6f70daef59f9ad --- /dev/null +++ b/substrate/frame/mixnet/src/lib.rs @@ -0,0 +1,598 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This pallet is responsible for determining the current mixnet session and phase, and the +//! mixnode set for each session. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + traits::{EstimateNextSessionRotation, Get, OneSessionHandler}, + BoundedVec, +}; +use frame_system::{ + offchain::{SendTransactionTypes, SubmitTransaction}, + pallet_prelude::BlockNumberFor, +}; +pub use pallet::*; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_application_crypto::RuntimeAppPublic; +use sp_arithmetic::traits::{CheckedSub, Saturating, UniqueSaturatedInto, Zero}; +use sp_io::MultiRemovalResults; +use sp_mixnet::types::{ + AuthorityId, AuthoritySignature, KxPublic, Mixnode, MixnodesErr, PeerId, SessionIndex, + SessionPhase, SessionStatus, KX_PUBLIC_SIZE, +}; +use sp_runtime::RuntimeDebug; +use sp_std::{cmp::Ordering, vec::Vec}; + +const LOG_TARGET: &str = "runtime::mixnet"; + +/// Index of an authority in the authority list for a session. +pub type AuthorityIndex = u32; + +//////////////////////////////////////////////////////////////////////////////// +// Bounded mixnode type +//////////////////////////////////////////////////////////////////////////////// + +/// Like [`Mixnode`], but encoded size is bounded. +#[derive( + Clone, Decode, Encode, MaxEncodedLen, PartialEq, TypeInfo, RuntimeDebug, Serialize, Deserialize, +)] +pub struct BoundedMixnode { + /// Key-exchange public key for the mixnode. + pub kx_public: KxPublic, + /// libp2p peer ID of the mixnode. + pub peer_id: PeerId, + /// External addresses for the mixnode, in multiaddr format, UTF-8 encoded. + pub external_addresses: ExternalAddresses, +} + +impl Into + for BoundedMixnode, MaxExternalAddresses>> +{ + fn into(self) -> Mixnode { + Mixnode { + kx_public: self.kx_public, + peer_id: self.peer_id, + external_addresses: self + .external_addresses + .into_iter() + .map(BoundedVec::into_inner) + .collect(), + } + } +} + +impl, MaxExternalAddresses: Get> From + for BoundedMixnode, MaxExternalAddresses>> +{ + fn from(mixnode: Mixnode) -> Self { + Self { + kx_public: mixnode.kx_public, + peer_id: mixnode.peer_id, + external_addresses: mixnode + .external_addresses + .into_iter() + .flat_map(|addr| match addr.try_into() { + Ok(addr) => Some(addr), + Err(addr) => { + log::debug!( + target: LOG_TARGET, + "Mixnode external address {addr:x?} too long; discarding", + ); + None + }, + }) + .take(MaxExternalAddresses::get() as usize) + .collect::>() + .try_into() + .expect("Excess external addresses discarded with take()"), + } + } +} + +/// [`BoundedMixnode`] type for the given configuration. +pub type BoundedMixnodeFor = BoundedMixnode< + BoundedVec< + BoundedVec::MaxExternalAddressSize>, + ::MaxExternalAddressesPerMixnode, + >, +>; + +//////////////////////////////////////////////////////////////////////////////// +// Registration type +//////////////////////////////////////////////////////////////////////////////// + +/// A mixnode registration. A registration transaction is formed from one of these plus an +/// [`AuthoritySignature`]. +#[derive(Clone, Decode, Encode, PartialEq, TypeInfo, RuntimeDebug)] +pub struct Registration { + /// Block number at the time of creation. When a registration transaction fails to make it on + /// to the chain for whatever reason, we send out another one. We want this one to have a + /// different hash in case the earlier transaction got banned somewhere; including the block + /// number is a simple way of achieving this. + pub block_number: BlockNumber, + /// The session during which this registration should be processed. Note that on success the + /// mixnode is registered for the _following_ session. + pub session_index: SessionIndex, + /// The index in the next session's authority list of the authority registering the mixnode. + pub authority_index: AuthorityIndex, + /// Mixnode information to register for the following session. + pub mixnode: BoundedMixnode, +} + +/// [`Registration`] type for the given configuration. +pub type RegistrationFor = Registration, BoundedMixnodeFor>; + +//////////////////////////////////////////////////////////////////////////////// +// Misc helper funcs +//////////////////////////////////////////////////////////////////////////////// + +fn check_removed_all(res: MultiRemovalResults) { + debug_assert!(res.maybe_cursor.is_none()); +} + +fn twox>( + block_number: BlockNumber, + kx_public: &KxPublic, +) -> u64 { + let block_number: u64 = block_number.unique_saturated_into(); + let mut data = [0; 8 + KX_PUBLIC_SIZE]; + data[..8].copy_from_slice(&block_number.to_le_bytes()); + data[8..].copy_from_slice(kx_public); + u64::from_le_bytes(sp_io::hashing::twox_64(&data)) +} + +//////////////////////////////////////////////////////////////////////////////// +// The pallet +//////////////////////////////////////////////////////////////////////////////// + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + SendTransactionTypes> { + /// The maximum number of authorities per session. + #[pallet::constant] + type MaxAuthorities: Get; + + /// The maximum size of one of a mixnode's external addresses. + #[pallet::constant] + type MaxExternalAddressSize: Get; + + /// The maximum number of external addresses for a mixnode. + #[pallet::constant] + type MaxExternalAddressesPerMixnode: Get; + + /// Session progress/length estimation. Used to determine when to send registration + /// transactions and the longevity of these transactions. + type NextSessionRotation: EstimateNextSessionRotation>; + + /// Length of the first phase of each session (`CoverToCurrent`), in blocks. + #[pallet::constant] + type NumCoverToCurrentBlocks: Get>; + + /// Length of the second phase of each session (`RequestsToCurrent`), in blocks. + #[pallet::constant] + type NumRequestsToCurrentBlocks: Get>; + + /// Length of the third phase of each session (`CoverToPrev`), in blocks. + #[pallet::constant] + type NumCoverToPrevBlocks: Get>; + + /// The number of "slack" blocks at the start of each session, during which + /// [`maybe_register`](Pallet::maybe_register) will not attempt to post registration + /// transactions. + #[pallet::constant] + type NumRegisterStartSlackBlocks: Get>; + + /// The number of "slack" blocks at the end of each session. + /// [`maybe_register`](Pallet::maybe_register) will try to register before this slack + /// period, but may post registration transactions during the slack period as a last + /// resort. + #[pallet::constant] + type NumRegisterEndSlackBlocks: Get>; + + /// Priority of unsigned transactions used to register mixnodes. + #[pallet::constant] + type RegistrationPriority: Get; + + /// Minimum number of mixnodes. If there are fewer than this many mixnodes registered for a + /// session, the mixnet will not be active during the session. + #[pallet::constant] + type MinMixnodes: Get; + } + + /// Index of the current session. This may be offset relative to the session index tracked by + /// eg `pallet_session`; mixnet session indices are independent. + #[pallet::storage] + pub(crate) type CurrentSessionIndex = StorageValue<_, SessionIndex, ValueQuery>; + + /// Block in which the current session started. + #[pallet::storage] + pub(crate) type CurrentSessionStartBlock = StorageValue<_, BlockNumberFor, ValueQuery>; + + /// Authority list for the next session. + #[pallet::storage] + pub(crate) type NextAuthorityIds = StorageMap<_, Identity, AuthorityIndex, AuthorityId>; + + /// Mixnode sets by session index. Only the mixnode sets for the previous, current, and next + /// sessions are kept; older sets are discarded. + /// + /// The mixnodes in each set are keyed by authority index so we can easily check if an + /// authority has registered a mixnode. The authority indices should only be used during + /// registration; the authority indices for the very first session are made up. + #[pallet::storage] + pub(crate) type Mixnodes = + StorageDoubleMap<_, Identity, SessionIndex, Identity, AuthorityIndex, BoundedMixnodeFor>; + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + /// The mixnode set for the very first session. + pub mixnodes: BoundedVec, T::MaxAuthorities>, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + assert!( + Mixnodes::::iter_prefix_values(0).next().is_none(), + "Initial mixnodes already set" + ); + for (i, mixnode) in self.mixnodes.iter().enumerate() { + // We just make up authority indices here. This doesn't matter as authority indices + // are only used during registration to check an authority doesn't register twice. + Mixnodes::::insert(0, i as AuthorityIndex, mixnode); + } + } + } + + #[pallet::call] + impl Pallet { + /// Register a mixnode for the following session. + #[pallet::call_index(0)] + #[pallet::weight(1)] // TODO + pub fn register( + origin: OriginFor, + registration: RegistrationFor, + _signature: AuthoritySignature, + ) -> DispatchResult { + ensure_none(origin)?; + + // Checked by ValidateUnsigned + debug_assert_eq!(registration.session_index, CurrentSessionIndex::::get()); + debug_assert!(registration.authority_index < T::MaxAuthorities::get()); + + Mixnodes::::insert( + // Registering for the _following_ session + registration.session_index + 1, + registration.authority_index, + registration.mixnode, + ); + + Ok(()) + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + let Self::Call::register { registration, signature } = call else { + return InvalidTransaction::Call.into() + }; + + // Check session index matches + match registration.session_index.cmp(&CurrentSessionIndex::::get()) { + Ordering::Greater => return InvalidTransaction::Future.into(), + Ordering::Less => return InvalidTransaction::Stale.into(), + Ordering::Equal => (), + } + + // Check authority index is valid + if registration.authority_index >= T::MaxAuthorities::get() { + return InvalidTransaction::BadProof.into() + } + let Some(authority_id) = NextAuthorityIds::::get(registration.authority_index) + else { + return InvalidTransaction::BadProof.into() + }; + + // Check the authority hasn't registered a mixnode yet + if Self::already_registered(registration.session_index, registration.authority_index) { + return InvalidTransaction::Stale.into() + } + + // Check signature. Note that we don't use regular signed transactions for registration + // as we don't want validators to have to pay to register. Spam is prevented by only + // allowing one registration per session per validator (see above). + let signature_ok = registration.using_encoded(|encoded_registration| { + authority_id.verify(&encoded_registration, signature) + }); + if !signature_ok { + return InvalidTransaction::BadProof.into() + } + + ValidTransaction::with_tag_prefix("MixnetRegistration") + .priority(T::RegistrationPriority::get()) + // Include both authority index _and_ ID in tag in case of forks with different + // authority lists + .and_provides(( + registration.session_index, + registration.authority_index, + authority_id, + )) + .longevity( + (T::NextSessionRotation::average_session_length() / 2_u32.into()) + .try_into() + .unwrap_or(64_u64), + ) + .build() + } + } +} + +impl Pallet { + /// Returns the phase of the current session. + fn session_phase() -> SessionPhase { + let block_in_phase = frame_system::Pallet::::block_number() + .saturating_sub(CurrentSessionStartBlock::::get()); + let Some(block_in_phase) = block_in_phase.checked_sub(&T::NumCoverToCurrentBlocks::get()) + else { + return SessionPhase::CoverToCurrent + }; + let Some(block_in_phase) = + block_in_phase.checked_sub(&T::NumRequestsToCurrentBlocks::get()) + else { + return SessionPhase::RequestsToCurrent + }; + if block_in_phase < T::NumCoverToPrevBlocks::get() { + SessionPhase::CoverToPrev + } else { + SessionPhase::DisconnectFromPrev + } + } + + /// Returns the index and phase of the current session. + pub fn session_status() -> SessionStatus { + SessionStatus { + current_index: CurrentSessionIndex::::get(), + phase: Self::session_phase(), + } + } + + /// Returns the mixnode set for the given session (which should be either the previous or the + /// current session). + fn mixnodes(session_index: SessionIndex) -> Result, MixnodesErr> { + let mixnodes: Vec<_> = + Mixnodes::::iter_prefix_values(session_index).map(Into::into).collect(); + if mixnodes.len() < T::MinMixnodes::get() as usize { + Err(MixnodesErr::InsufficientRegistrations { + num: mixnodes.len() as u32, + min: T::MinMixnodes::get(), + }) + } else { + Ok(mixnodes) + } + } + + /// Returns the mixnode set for the previous session. + pub fn prev_mixnodes() -> Result, MixnodesErr> { + let Some(prev_session_index) = CurrentSessionIndex::::get().checked_sub(1) else { + return Err(MixnodesErr::InsufficientRegistrations { + num: 0, + min: T::MinMixnodes::get(), + }) + }; + Self::mixnodes(prev_session_index) + } + + /// Returns the mixnode set for the current session. + pub fn current_mixnodes() -> Result, MixnodesErr> { + Self::mixnodes(CurrentSessionIndex::::get()) + } + + /// Is now a good time to register, considering only session progress? + fn should_register_by_session_progress( + block_number: BlockNumberFor, + mixnode: &Mixnode, + ) -> bool { + // At the start of each session there are some "slack" blocks during which we avoid + // registering + let block_in_session = block_number.saturating_sub(CurrentSessionStartBlock::::get()); + if block_in_session < T::NumRegisterStartSlackBlocks::get() { + return false + } + + let (Some(end_block), _weight) = + T::NextSessionRotation::estimate_next_session_rotation(block_number) + else { + // Things aren't going to work terribly well in this case as all the authorities will + // just pile in after the slack period... + return true + }; + + let remaining_blocks = end_block + .saturating_sub(block_number) + .saturating_sub(T::NumRegisterEndSlackBlocks::get()); + if remaining_blocks.is_zero() { + // Into the slack time at the end of the session. Not necessarily too late; + // registrations are accepted right up until the session ends. + return true + } + + // Want uniform distribution over the remaining blocks, so pick this block with probability + // 1/remaining_blocks. maybe_register may be called multiple times per block; ensure the + // same decision gets made each time by using a hash of the block number and the mixnode's + // public key as the "random" source. This is slightly biased as remaining_blocks most + // likely won't divide into 2^64, but it doesn't really matter... + let random = twox(block_number, &mixnode.kx_public); + (random % remaining_blocks.try_into().unwrap_or(u64::MAX)) == 0 + } + + fn next_local_authority() -> Option<(AuthorityIndex, AuthorityId)> { + // In the case where multiple local IDs are in the next authority set, we just return the + // first one. There's (currently at least) no point in registering multiple times. + let mut local_ids = AuthorityId::all(); + local_ids.sort(); + NextAuthorityIds::::iter().find(|(_index, id)| local_ids.binary_search(id).is_ok()) + } + + /// `session_index` should be the index of the current session. `authority_index` is the + /// authority index in the _next_ session. + fn already_registered(session_index: SessionIndex, authority_index: AuthorityIndex) -> bool { + Mixnodes::::contains_key(session_index + 1, authority_index) + } + + /// Try to register a mixnode for the next session. + /// + /// If a registration extrinsic is submitted, `true` is returned. The caller should avoid + /// calling `maybe_register` again for a few blocks, to give the submitted extrinsic a chance + /// to get included. + /// + /// With the above exception, `maybe_register` is designed to be called every block. Most of + /// the time it will not do anything, for example: + /// + /// - If it is not an appropriate time to submit a registration extrinsic. + /// - If the local node has already registered a mixnode for the next session. + /// - If the local node is not permitted to register a mixnode for the next session. + /// + /// `session_index` should match `session_status().current_index`; if it does not, `false` is + /// returned immediately. + pub fn maybe_register(session_index: SessionIndex, mixnode: Mixnode) -> bool { + let current_session_index = CurrentSessionIndex::::get(); + if session_index != current_session_index { + log::trace!( + target: LOG_TARGET, + "Session {session_index} registration attempted, \ + but current session is {current_session_index}", + ); + return false + } + + let block_number = frame_system::Pallet::::block_number(); + if !Self::should_register_by_session_progress(block_number, &mixnode) { + log::trace!( + target: LOG_TARGET, + "Waiting for the session to progress further before registering", + ); + return false + } + + let Some((authority_index, authority_id)) = Self::next_local_authority() else { + log::trace!( + target: LOG_TARGET, + "Not an authority in the next session; cannot register a mixnode", + ); + return false + }; + + if Self::already_registered(session_index, authority_index) { + log::trace!( + target: LOG_TARGET, + "Already registered a mixnode for the next session", + ); + return false + } + + let registration = + Registration { block_number, session_index, authority_index, mixnode: mixnode.into() }; + let Some(signature) = authority_id.sign(®istration.encode()) else { + log::debug!(target: LOG_TARGET, "Failed to sign registration"); + return false + }; + let call = Call::register { registration, signature }; + match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + Ok(()) => true, + Err(()) => { + log::debug!( + target: LOG_TARGET, + "Failed to submit registration transaction", + ); + false + }, + } + } +} + +impl sp_runtime::BoundToRuntimeAppPublic for Pallet { + type Public = AuthorityId; +} + +impl OneSessionHandler for Pallet { + type Key = AuthorityId; + + fn on_genesis_session<'a, I: 'a>(validators: I) + where + I: Iterator, + { + assert!( + NextAuthorityIds::::iter().next().is_none(), + "Initial authority IDs already set" + ); + for (i, (_, authority_id)) in validators.enumerate() { + NextAuthorityIds::::insert(i as AuthorityIndex, authority_id); + } + } + + fn on_new_session<'a, I: 'a>(changed: bool, _validators: I, queued_validators: I) + where + I: Iterator, + { + let session_index = CurrentSessionIndex::::mutate(|index| { + *index += 1; + *index + }); + CurrentSessionStartBlock::::put(frame_system::Pallet::::block_number()); + + // Discard the previous previous mixnode set, which we don't need any more + if let Some(prev_prev_session_index) = session_index.checked_sub(2) { + check_removed_all(Mixnodes::::clear_prefix( + prev_prev_session_index, + T::MaxAuthorities::get(), + None, + )); + } + + if changed { + // Save authority set for the next session. Note that we don't care about the authority + // set for the current session; we just care about the key-exchange public keys that + // were registered and are stored in Mixnodes. + check_removed_all(NextAuthorityIds::::clear(T::MaxAuthorities::get(), None)); + for (i, (_, authority_id)) in queued_validators.enumerate() { + NextAuthorityIds::::insert(i as AuthorityIndex, authority_id); + } + } + } + + fn on_disabled(_i: u32) { + // For now, to keep things simple, just ignore + // TODO + } +} diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index 3be55080b2407478b015ecbca653bb7919c2a482..330613bb3dfda94224b223a2f3f1fdf6735179b0 100644 --- a/substrate/frame/multisig/src/migrations.rs +++ b/substrate/frame/multisig/src/migrations.rs @@ -43,16 +43,14 @@ pub mod v1 { impl OnRuntimeUpgrade for MigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - let onchain = Pallet::::on_chain_storage_version(); - - ensure!(onchain < 1, "this migration can be deleted"); - log!(info, "Number of calls to refund and delete: {}", Calls::::iter().count()); Ok(Vec::new()) } fn on_runtime_upgrade() -> Weight { + use sp_runtime::Saturating; + let current = Pallet::::current_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -61,20 +59,24 @@ pub mod v1 { return T::DbWeight::get().reads(1) } + let mut call_count = 0u64; Calls::::drain().for_each(|(_call_hash, (_data, caller, deposit))| { T::Currency::unreserve(&caller, deposit); + call_count.saturating_inc(); }); current.put::>(); - ::BlockWeights::get().max_block + T::DbWeight::get().reads_writes( + // Reads: Get Calls + Get Version + call_count.saturating_add(1), + // Writes: Drain Calls + Unreserves + Set version + call_count.saturating_mul(2).saturating_add(1), + ) } #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - let onchain = Pallet::::on_chain_storage_version(); - ensure!(onchain < 2, "this migration needs to be removed"); - ensure!(onchain == 1, "this migration needs to be run"); ensure!( Calls::::iter().count() == 0, "there are some dangling calls that need to be destroyed and refunded" diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index e7fc5b3e4aaea455be251d26e59877c0ec9e765a..1798272552910e57e2bf8e8f22e0a1731a5916f3 100644 --- a/substrate/frame/multisig/src/tests.rs +++ b/substrate/frame/multisig/src/tests.rs @@ -31,8 +31,7 @@ use sp_runtime::{BuildStorage, TokenError}; type Block = frame_system::mocking::MockBlockU32; frame_support::construct_runtime!( - pub enum Test - { + pub enum Test { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Multisig: pallet_multisig::{Pallet, Call, Storage, Event}, @@ -43,24 +42,15 @@ frame_support::construct_runtime!( impl frame_system::Config for Test { type Block = Block; type BlockHashCount = ConstU32<250>; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type BaseCallFilter = TestBaseCallFilter; - type PalletInfo = PalletInfo; - type OnSetCode = (); - type AccountData = pallet_balances::AccountData; + // This pallet wishes to overwrite this. + type BaseCallFilter = TestBaseCallFilter; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = (); type ReserveIdentifier = [u8; 8]; - type DustRemoval = (); type AccountStore = System; - type ExistentialDeposit = ConstU64<1>; } pub struct TestBaseCallFilter; diff --git a/substrate/frame/nfts/src/migration.rs b/substrate/frame/nfts/src/migration.rs index f90d332062a2cbd1f12e629518847394598efdb7..94635a96aeba991fb458f2cc7830922060727dd7 100644 --- a/substrate/frame/nfts/src/migration.rs +++ b/substrate/frame/nfts/src/migration.rs @@ -97,9 +97,6 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let current_version = Pallet::::current_storage_version(); - let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version == 0 && current_version == 1, "migration from version 0 to 1."); let prev_count = Collection::::iter().count(); Ok((prev_count as u32).encode()) } @@ -115,7 +112,7 @@ pub mod v1 { "the records count before and after the migration should be the same" ); - ensure!(Pallet::::on_chain_storage_version() == 1, "wrong storage version"); + ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); Ok(()) } diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index 6e264048f11a6e332447061b808a77d4927e3a2c..a82fcca0151211b5ea0bb642889a965158e7519a 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -17,7 +17,7 @@ //! Tests for Nfts pallet. -use crate::{mock::*, Event, *}; +use crate::{mock::*, Event, SystemConfig, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 45f0ca0ecfe6ef050953f484bf98a43a1f5dd2bb..fc86a6f56c0bed09cd86963cc4d26b97219f76e6 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -27,7 +27,10 @@ use frame_benchmarking::v1::{account, whitelist_account}; use frame_election_provider_support::SortedListProvider; use frame_support::{ assert_ok, ensure, - traits::{Currency, Get}, + traits::{ + fungible::{Inspect, Mutate, Unbalanced}, + Get, + }, }; use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ @@ -67,7 +70,7 @@ fn create_funded_user_with_balance( balance: BalanceOf, ) -> T::AccountId { let user = account(string, n, USER_SEED); - T::Currency::make_free_balance_be(&user, balance); + T::Currency::set_balance(&user, balance); user } @@ -148,8 +151,7 @@ impl ListScenario { ); // Burn the entire issuance. - let i = CurrencyOf::::burn(CurrencyOf::::total_issuance()); - sp_std::mem::forget(i); + CurrencyOf::::set_total_issuance(Zero::zero()); // Create accounts with the origin weight let (pool_creator1, pool_origin1) = @@ -206,7 +208,7 @@ impl ListScenario { let joiner: T::AccountId = account("joiner", USER_SEED, 0); self.origin1_member = Some(joiner.clone()); - CurrencyOf::::make_free_balance_be(&joiner, amount * 2u32.into()); + CurrencyOf::::set_balance(&joiner, amount * 2u32.into()); let original_bonded = T::Staking::active_stake(&self.origin1).unwrap(); @@ -254,7 +256,7 @@ frame_benchmarking::benchmarks! { whitelist_account!(joiner); }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) verify { - assert_eq!(CurrencyOf::::free_balance(&joiner), joiner_free - max_additional); + assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); assert_eq!( T::Staking::active_stake(&scenario.origin1).unwrap(), scenario.dest_weight @@ -289,7 +291,7 @@ frame_benchmarking::benchmarks! { // transfer exactly `extra` to the depositor of the src pool (1), let reward_account1 = Pools::::create_reward_account(1); assert!(extra >= CurrencyOf::::minimum_balance()); - CurrencyOf::::deposit_creating(&reward_account1, extra); + let _ = CurrencyOf::::mint_into(&reward_account1, extra); }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) verify { @@ -309,7 +311,7 @@ frame_benchmarking::benchmarks! { let reward_account = Pools::::create_reward_account(1); // Send funds to the reward account of the pool - CurrencyOf::::make_free_balance_be(&reward_account, ed + origin_weight); + CurrencyOf::::set_balance(&reward_account, ed + origin_weight); // set claim preferences to `PermissionlessAll` so any account can claim rewards on member's // behalf. @@ -317,7 +319,7 @@ frame_benchmarking::benchmarks! { // Sanity check assert_eq!( - CurrencyOf::::free_balance(&depositor), + CurrencyOf::::balance(&depositor), origin_weight ); @@ -325,11 +327,11 @@ frame_benchmarking::benchmarks! { }:claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()) verify { assert_eq!( - CurrencyOf::::free_balance(&depositor), + CurrencyOf::::balance(&depositor), origin_weight + commission * origin_weight ); assert_eq!( - CurrencyOf::::free_balance(&reward_account), + CurrencyOf::::balance(&reward_account), ed + commission * origin_weight ); } @@ -383,7 +385,7 @@ frame_benchmarking::benchmarks! { T::Staking::active_stake(&pool_account).unwrap(), min_create_bond + min_join_bond ); - assert_eq!(CurrencyOf::::free_balance(&joiner), 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(); @@ -403,7 +405,7 @@ frame_benchmarking::benchmarks! { }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) verify { // The joiners funds didn't change - assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); + 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); } @@ -426,7 +428,7 @@ frame_benchmarking::benchmarks! { T::Staking::active_stake(&pool_account).unwrap(), min_create_bond + min_join_bond ); - assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); + assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); // Unbond the new member pallet_staking::CurrentEra::::put(0); @@ -447,8 +449,7 @@ frame_benchmarking::benchmarks! { }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) verify { assert_eq!( - CurrencyOf::::free_balance(&joiner), - min_join_bond * 2u32.into() + 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); @@ -485,7 +486,7 @@ frame_benchmarking::benchmarks! { Zero::zero() ); assert_eq!( - CurrencyOf::::free_balance(&pool_account), + CurrencyOf::::balance(&pool_account), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -515,7 +516,7 @@ frame_benchmarking::benchmarks! { // Funds where transferred back correctly assert_eq!( - CurrencyOf::::free_balance(&depositor), + CurrencyOf::::balance(&depositor), // gets bond back + rewards collecting when unbonding min_create_bond * 2u32.into() + CurrencyOf::::minimum_balance() ); @@ -527,7 +528,7 @@ frame_benchmarking::benchmarks! { let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond - CurrencyOf::::make_free_balance_be(&depositor, min_create_bond * 2u32.into()); + 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); @@ -782,7 +783,7 @@ frame_benchmarking::benchmarks! { 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::::make_free_balance_be(&reward_account, ed + origin_weight); + CurrencyOf::::set_balance(&reward_account, ed + origin_weight); // member claims a payout to make some commission available. let _ = Pools::::claim_payout(RuntimeOrigin::Signed(claimer).into()); @@ -791,15 +792,29 @@ frame_benchmarking::benchmarks! { }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) verify { assert_eq!( - CurrencyOf::::free_balance(&depositor), + CurrencyOf::::balance(&depositor), origin_weight + commission * origin_weight ); assert_eq!( - CurrencyOf::::free_balance(&reward_account), + 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(), diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 2d75df63b518a698c5755cb12557e6aa7cb58b9e..1e6a5c249998bb5ef604eeda69828b0441f5ee99 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -74,8 +74,8 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); type MaxHolds = (); } @@ -160,6 +160,7 @@ impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; @@ -183,7 +184,7 @@ frame_support::construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, - Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, + Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event, FreezeReason}, } ); diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 485cdada7173b2c583b3cf49ab89ac05c9e026dd..909a930e3821f8611b30ed39415eaab3f4b38636 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -353,12 +353,16 @@ use codec::Codec; use frame_support::{ - defensive, ensure, + defensive, defensive_assert, ensure, pallet_prelude::{MaxEncodedLen, *}, storage::bounded_btree_map::BoundedBTreeMap, traits::{ - Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, - ExistenceRequirement, Get, + fungible::{ + Inspect as FunInspect, InspectFreeze, Mutate as FunMutate, + MutateFreeze as FunMutateFreeze, + }, + tokens::{Fortitude, Preservation}, + Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, Get, }, DefaultNoBound, PalletError, }; @@ -380,7 +384,6 @@ use sp_runtime::TryRuntimeError; /// The log target of this pallet. pub const LOG_TARGET: &str = "runtime::nomination-pools"; - // syntactic sugar for logging. #[macro_export] macro_rules! log { @@ -405,7 +408,7 @@ pub use weights::WeightInfo; /// The balance type used by the currency system. pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as FunInspect<::AccountId>>::Balance; /// Type used for unique identifier of each pool. pub type PoolId = u32; @@ -535,6 +538,31 @@ impl PoolMember { } } + /// Total balance of the member, both active and unbonding. + /// Doesn't mutate state. + #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))] + fn total_balance(&self) -> BalanceOf { + let pool = BondedPool::::get(self.pool_id).unwrap(); + let active_balance = pool.points_to_balance(self.active_points()); + + let sub_pools = match SubPoolsStorage::::get(self.pool_id) { + Some(sub_pools) => sub_pools, + None => return active_balance, + }; + + let unbonding_balance = self.unbonding_eras.iter().fold( + BalanceOf::::zero(), + |accumulator, (era, unlocked_points)| { + // if the `SubPools::with_era` has already been merged into the + // `SubPools::no_era` use this pool instead. + let era_pool = sub_pools.with_era.get(era).unwrap_or(&sub_pools.no_era); + accumulator + (era_pool.point_to_balance(*unlocked_points)) + }, + ); + + active_balance + unbonding_balance + } + /// Total points of this member, both active and unbonding. fn total_points(&self) -> BalanceOf { self.active_points().saturating_add(self.unbonding_points()) @@ -1005,10 +1033,15 @@ impl BondedPool { self } - /// The pools balance that is transferrable. - fn transferrable_balance(&self) -> BalanceOf { + /// The pools balance that is transferable provided it is expendable by staking pallet. + fn transferable_balance(&self) -> BalanceOf { let account = self.bonded_account(); - T::Currency::free_balance(&account) + // Note on why we can't use `Currency::reducible_balance`: Since pooled account has a + // provider (staking pallet), the account can not be set expendable by + // `pallet-nomination-pool`. This means reducible balance always returns balance preserving + // ED in the account. What we want though is transferable balance given the account can be + // dusted. + T::Currency::balance(&account) .saturating_sub(T::Staking::active_stake(&account).unwrap_or_default()) } @@ -1181,11 +1214,11 @@ impl BondedPool { Ok(()) } - /// Bond exactly `amount` from `who`'s funds into this pool. + /// Bond exactly `amount` from `who`'s funds into this pool. Increases the [`TotalValueLocked`] + /// by `amount`. /// - /// If the bond type is `Create`, `Staking::bond` is called, and `who` - /// is allowed to be killed. Otherwise, `Staking::bond_extra` is called and `who` - /// cannot be killed. + /// If the bond is [`BondType::Create`], [`Staking::bond`] is called, and `who` is allowed to be + /// killed. Otherwise, [`Staking::bond_extra`] is called and `who` cannot be killed. /// /// Returns `Ok(points_issues)`, `Err` otherwise. fn try_bond_funds( @@ -1201,8 +1234,8 @@ impl BondedPool { &bonded_account, amount, match ty { - BondType::Create => ExistenceRequirement::AllowDeath, - BondType::Later => ExistenceRequirement::KeepAlive, + BondType::Create => Preservation::Expendable, + BondType::Later => Preservation::Preserve, }, )?; // We must calculate the points issued *before* we bond who's funds, else points:balance @@ -1216,6 +1249,9 @@ impl BondedPool { // found, we exit early. BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?, } + TotalValueLocked::::mutate(|tvl| { + tvl.saturating_accrue(amount); + }); Ok(points_issued) } @@ -1231,6 +1267,27 @@ impl BondedPool { }); }; } + + /// Withdraw all the funds that are already unlocked from staking for the + /// [`BondedPool::bonded_account`]. + /// + /// Also reduces the [`TotalValueLocked`] by the difference of the + /// [`T::Staking::total_stake`] of the [`BondedPool::bonded_account`] that might occur by + /// [`T::Staking::withdraw_unbonded`]. + /// + /// Returns the result of [`T::Staking::withdraw_unbonded`] + fn withdraw_from_staking(&self, num_slashing_spans: u32) -> Result { + let bonded_account = self.bonded_account(); + + let prev_total = T::Staking::total_stake(&bonded_account.clone()).unwrap_or_default(); + let outcome = T::Staking::withdraw_unbonded(bonded_account.clone(), num_slashing_spans); + let diff = prev_total + .defensive_saturating_sub(T::Staking::total_stake(&bonded_account).unwrap_or_default()); + TotalValueLocked::::mutate(|tvl| { + tvl.saturating_reduce(diff); + }); + outcome + } } /// A reward pool. @@ -1300,13 +1357,22 @@ impl RewardPool { self.total_commission_pending = self.total_commission_pending.saturating_add(new_pending_commission); - // Store the total payouts at the time of this update. Total payouts are essentially the - // entire historical balance of the reward pool, equating to the current balance + the total - // rewards that have left the pool + the total commission that has left the pool. - self.last_recorded_total_payouts = balance + // Total payouts are essentially the entire historical balance of the reward pool, equating + // to the current balance + the total rewards that have left the pool + the total commission + // that has left the pool. + let last_recorded_total_payouts = balance .checked_add(&self.total_rewards_claimed.saturating_add(self.total_commission_claimed)) .ok_or(Error::::OverflowRisk)?; + // Store the total payouts at the time of this update. + // + // An increase in ED could cause `last_recorded_total_payouts` to decrease but we should not + // allow that to happen since an already paid out reward cannot decrease. The reward account + // might go in deficit temporarily in this exceptional case but it will be corrected once + // new rewards are added to the pool. + self.last_recorded_total_payouts = + self.last_recorded_total_payouts.max(last_recorded_total_payouts); + Ok(()) } @@ -1380,8 +1446,11 @@ impl RewardPool { /// /// This is sum of all the rewards that are claimable by pool members. fn current_balance(id: PoolId) -> BalanceOf { - T::Currency::free_balance(&Pallet::::create_reward_account(id)) - .saturating_sub(T::Currency::minimum_balance()) + T::Currency::reducible_balance( + &Pallet::::create_reward_account(id), + Preservation::Expendable, + Fortitude::Polite, + ) } } @@ -1417,9 +1486,7 @@ impl UnbondPool { } /// Dissolve some points from the unbonding pool, reducing the balance of the pool - /// proportionally. - /// - /// This is the opposite of `issue`. + /// proportionally. This is the opposite of `issue`. /// /// Returns the actual amount of `Balance` that was removed from the pool. fn dissolve(&mut self, points: BalanceOf) -> BalanceOf { @@ -1487,6 +1554,7 @@ impl SubPools { /// `no_era` pool. This is guaranteed to at least be equal to the staking `UnbondingDuration`. For /// improved UX [`Config::PostUnbondingPoolsWindow`] should be configured to a non-zero value. pub struct TotalUnbondingPools(PhantomData); + impl Get for TotalUnbondingPools { fn get() -> u32 { // NOTE: this may be dangerous in the scenario bonding_duration gets decreased because @@ -1504,7 +1572,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1518,8 +1586,12 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; - /// The nominating balance. - type Currency: Currency; + /// The currency type used for nomination pool. + type Currency: FunMutate + + FunMutateFreeze; + + /// The overarching freeze reason. + type RuntimeFreezeReason: From; /// The type that is used for reward counter. /// @@ -1577,6 +1649,14 @@ pub mod pallet { type MaxUnbonding: Get; } + /// The sum of funds across all pools. + /// + /// This might be lower but never higher than the sum of `total_balance` of all [`PoolMembers`] + /// because calling `pool_withdraw_unbonded` might decrease the total stake of the pool's + /// `bonded_account` without adjusting the pallet-internal `UnbondingPool`'s. + #[pallet::storage] + pub type TotalValueLocked = StorageValue<_, BalanceOf, ValueQuery>; + /// Minimum amount to bond to join a pool. #[pallet::storage] pub type MinJoinBond = StorageValue<_, BalanceOf, ValueQuery>; @@ -1685,6 +1765,7 @@ pub mod pallet { fn build(&self) { MinJoinBond::::put(self.min_join_bond); MinCreateBond::::put(self.min_create_bond); + if let Some(max_pools) = self.max_pools { MaxPools::::put(max_pools); } @@ -1770,6 +1851,10 @@ pub mod pallet { }, /// Pool commission has been claimed. PoolCommissionClaimed { pool_id: PoolId, commission: BalanceOf }, + /// Topped up deficit in frozen ED of the reward pool. + MinBalanceDeficitAdjusted { pool_id: PoolId, amount: BalanceOf }, + /// Claimed excess frozen ED of af the reward pool. + MinBalanceExcessAdjusted { pool_id: PoolId, amount: BalanceOf }, } #[pallet::error] @@ -1795,9 +1880,9 @@ pub mod pallet { CannotWithdrawAny, /// The amount does not meet the minimum bond to either join or create a pool. /// - /// The depositor can never unbond to a value less than - /// `Pallet::depositor_min_bond`. The caller does not have nominating - /// permissions for the pool. Members can never unbond to a value below `MinJoinBond`. + /// The depositor can never unbond to a value less than `Pallet::depositor_min_bond`. The + /// caller does not have nominating permissions for the pool. Members can never unbond to a + /// value below `MinJoinBond`. MinimumBondNotMet, /// The transaction could not be executed due to overflow risk for the pool. OverflowRisk, @@ -1845,6 +1930,8 @@ pub mod pallet { InvalidPoolId, /// Bonding extra is restricted to the exact pending reward amount. BondExtraRestricted, + /// No imbalance in the ED deposit for the pool. + NothingToAdjust, } #[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)] @@ -1868,6 +1955,14 @@ pub mod pallet { } } + /// A reason for freezing funds. + #[pallet::composite_enum] + pub enum FreezeReason { + /// Pool reward account is restricted from going below Existential Deposit. + #[codec(index = 0)] + PoolMinBalance, + } + #[pallet::call] impl Pallet { /// Stake funds with a pool. The amount to bond is transferred from the member to the @@ -2074,7 +2169,7 @@ pub mod pallet { /// Call `withdraw_unbonded` for the pools account. This call can be made by any account. /// - /// This is useful if their are too many unlocking chunks to call `unbond`, and some + /// This is useful if there are too many unlocking chunks to call `unbond`, and some /// can be cleared by withdrawing. In the case there are too many unlocking chunks, the user /// would probably see an error like `NoMoreChunks` emitted from the staking system when /// they attempt to unbond. @@ -2087,10 +2182,12 @@ pub mod pallet { ) -> DispatchResult { let _ = ensure_signed(origin)?; let pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool // is destroying then `withdraw_unbonded` can be used. ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); - T::Staking::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; + pool.withdraw_from_staking(num_slashing_spans)?; + Ok(()) } @@ -2141,8 +2238,7 @@ pub mod pallet { // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the // `transferrable_balance` is correct. - let stash_killed = - T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; + let stash_killed = bonded_pool.withdraw_from_staking(num_slashing_spans)?; // defensive-only: the depositor puts enough funds into the stash so that it will only // be destroyed when they are leaving. @@ -2175,13 +2271,13 @@ pub mod pallet { // don't exist. This check is also defensive in cases where the unbond pool does not // update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in // order to ensure members can leave the pool and it can be destroyed. - .min(bonded_pool.transferrable_balance()); + .min(bonded_pool.transferable_balance()); T::Currency::transfer( &bonded_pool.bonded_account(), &member_account, balance_to_unbond, - ExistenceRequirement::AllowDeath, + Preservation::Expendable, ) .defensive()?; @@ -2237,7 +2333,7 @@ pub mod pallet { /// # Note /// /// In addition to `amount`, the caller will transfer the existential deposit; so the caller - /// needs at have at least `amount + existential_deposit` transferrable. + /// needs at have at least `amount + existential_deposit` transferable. #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::create())] pub fn create( @@ -2631,6 +2727,20 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::do_claim_commission(who, pool_id) } + + /// Top up the deficit or withdraw the excess ED from the pool. + /// + /// When a pool is created, the pool depositor transfers ED to the reward account of the + /// pool. ED is subject to change and over time, the deposit in the reward account may be + /// insufficient to cover the ED deficit of the pool or vice-versa where there is excess + /// deposit to the pool. This call allows anyone to adjust the ED deposit of the + /// pool by either topping up the deficit or claiming the excess. + #[pallet::call_index(21)] + #[pallet::weight(T::WeightInfo::adjust_pool_deposit())] + pub fn adjust_pool_deposit(origin: OriginFor, pool_id: PoolId) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_adjust_pool_deposit(who, pool_id) + } } #[pallet::hooks] @@ -2681,6 +2791,9 @@ impl Pallet { RewardPools::::remove(bonded_pool.id); SubPoolsStorage::::remove(bonded_pool.id); + // remove the ED restriction from the pool reward account. + let _ = Self::unfreeze_pool_deposit(&bonded_pool.reward_account()).defensive(); + // Kill accounts from storage by making their balance go below ED. We assume that the // accounts have no references that would prevent destruction once we get to this point. We // don't work with the system pallet directly, but @@ -2688,26 +2801,44 @@ impl Pallet { // consumers anyway. // 2. the bonded account should become a 'killed stash' in the staking system, and all of // its consumers removed. - debug_assert_eq!(frame_system::Pallet::::consumers(&reward_account), 0); - debug_assert_eq!(frame_system::Pallet::::consumers(&bonded_account), 0); - debug_assert_eq!( - T::Staking::total_stake(&bonded_account).unwrap_or_default(), - Zero::zero() + defensive_assert!( + frame_system::Pallet::::consumers(&reward_account) == 0, + "reward account of dissolving pool should have no consumers" + ); + defensive_assert!( + frame_system::Pallet::::consumers(&bonded_account) == 0, + "bonded account of dissolving pool should have no consumers" + ); + defensive_assert!( + T::Staking::total_stake(&bonded_account).unwrap_or_default() == Zero::zero(), + "dissolving pool should not have any stake in the staking pallet" ); // This shouldn't fail, but if it does we don't really care. Remaining balance can consist - // of unclaimed pending commission, errorneous transfers to the reward account, etc. - let reward_pool_remaining = T::Currency::free_balance(&reward_account); + // of unclaimed pending commission, erroneous transfers to the reward account, etc. + let reward_pool_remaining = T::Currency::reducible_balance( + &reward_account, + Preservation::Expendable, + Fortitude::Polite, + ); let _ = T::Currency::transfer( &reward_account, &bonded_pool.roles.depositor, reward_pool_remaining, - ExistenceRequirement::AllowDeath, + Preservation::Expendable, ); - // NOTE: this is purely defensive. - T::Currency::make_free_balance_be(&reward_account, Zero::zero()); - T::Currency::make_free_balance_be(&bonded_pool.bonded_account(), Zero::zero()); + defensive_assert!( + T::Currency::total_balance(&reward_account) == Zero::zero(), + "could not transfer all amount to depositor while dissolving pool" + ); + defensive_assert!( + T::Currency::total_balance(&bonded_pool.bonded_account()) == Zero::zero(), + "dissolving pool should not have any balance" + ); + // NOTE: Defensively force set balance to zero. + T::Currency::set_balance(&reward_account, Zero::zero()); + T::Currency::set_balance(&bonded_pool.bonded_account(), Zero::zero()); Self::deposit_event(Event::::Destroyed { pool_id: bonded_pool.id }); // Remove bonded pool metadata. @@ -2771,12 +2902,9 @@ impl Pallet { }, (false, false) => { // Equivalent to (current_points / current_balance) * new_funds - balance( - u256(current_points) - .saturating_mul(u256(new_funds)) - // We check for zero above - .div(u256(current_balance)), - ) + balance(u256(current_points).saturating_mul(u256(new_funds))) + // We check for zero above + .div(current_balance) }, } } @@ -2796,9 +2924,12 @@ impl Pallet { } // Equivalent of (current_balance / current_points) * points - balance(u256(current_balance).saturating_mul(u256(points))) - // We check for zero above - .div(current_points) + balance( + u256(current_balance) + .saturating_mul(u256(points)) + // We check for zero above + .div(u256(current_points)), + ) } /// If the member has some rewards, transfer a payout from the reward pool to the member. @@ -2838,7 +2969,7 @@ impl Pallet { pending_rewards, // defensive: the depositor has put existential deposit into the pool and it stays // untouched, reward account shall not die. - ExistenceRequirement::KeepAlive, + Preservation::Preserve, )?; Self::deposit_event(Event::::PaidOut { @@ -2846,7 +2977,6 @@ impl Pallet { pool_id: member.pool_id, payout: pending_rewards, }); - Ok(pending_rewards) } @@ -2881,13 +3011,17 @@ impl Pallet { bonded_pool.try_inc_members()?; let points = bonded_pool.try_bond_funds(&who, amount, BondType::Create)?; + // Transfer the minimum balance for the reward account. T::Currency::transfer( &who, &bonded_pool.reward_account(), T::Currency::minimum_balance(), - ExistenceRequirement::AllowDeath, + Preservation::Expendable, )?; + // Restrict reward account balance from going below ED. + Self::freeze_pool_deposit(&bonded_pool.reward_account())?; + PoolMembers::::insert( who.clone(), PoolMember:: { @@ -2999,7 +3133,7 @@ impl Pallet { &bonded_pool.reward_account(), &payee, commission, - ExistenceRequirement::KeepAlive, + Preservation::Preserve, )?; // Add pending commission to total claimed counter. @@ -3007,7 +3141,6 @@ impl Pallet { reward_pool.total_commission_claimed.saturating_add(commission); // Reset total pending commission counter to zero. reward_pool.total_commission_pending = Zero::zero(); - // Commit reward pool updates RewardPools::::insert(pool_id, reward_pool); Self::deposit_event(Event::::PoolCommissionClaimed { pool_id, commission }); @@ -3029,6 +3162,55 @@ impl Pallet { Ok(()) } + fn do_adjust_pool_deposit(who: T::AccountId, pool: PoolId) -> DispatchResult { + let bonded_pool = BondedPool::::get(pool).ok_or(Error::::PoolNotFound)?; + let reward_acc = &bonded_pool.reward_account(); + let pre_frozen_balance = + T::Currency::balance_frozen(&FreezeReason::PoolMinBalance.into(), reward_acc); + let min_balance = T::Currency::minimum_balance(); + + if pre_frozen_balance == min_balance { + return Err(Error::::NothingToAdjust.into()) + } + + // Update frozen amount with current ED. + Self::freeze_pool_deposit(reward_acc)?; + + if pre_frozen_balance > min_balance { + // Transfer excess back to depositor. + let excess = pre_frozen_balance.saturating_sub(min_balance); + T::Currency::transfer(reward_acc, &who, excess, Preservation::Preserve)?; + Self::deposit_event(Event::::MinBalanceExcessAdjusted { + pool_id: pool, + amount: excess, + }); + } else { + // Transfer ED deficit from depositor to the pool + let deficit = min_balance.saturating_sub(pre_frozen_balance); + T::Currency::transfer(&who, reward_acc, deficit, Preservation::Expendable)?; + Self::deposit_event(Event::::MinBalanceDeficitAdjusted { + pool_id: pool, + amount: deficit, + }); + } + + Ok(()) + } + + /// Apply freeze on reward account to restrict it from going below ED. + pub(crate) fn freeze_pool_deposit(reward_acc: &T::AccountId) -> DispatchResult { + T::Currency::set_freeze( + &FreezeReason::PoolMinBalance.into(), + reward_acc, + T::Currency::minimum_balance(), + ) + } + + /// Removes the ED freeze on the reward account of `pool_id`. + pub fn unfreeze_pool_deposit(reward_acc: &T::AccountId) -> DispatchResult { + T::Currency::thaw(&FreezeReason::PoolMinBalance.into(), reward_acc) + } + /// Ensure the correctness of the state of this pallet. /// /// This should be valid before or after each state transition of this pallet. @@ -3094,14 +3276,20 @@ impl Pallet { for id in reward_pools { let account = Self::create_reward_account(id); - if T::Currency::free_balance(&account) < T::Currency::minimum_balance() { + if T::Currency::reducible_balance(&account, Preservation::Expendable, Fortitude::Polite) < + T::Currency::minimum_balance() + { log!( warn, "reward pool of {:?}: {:?} (ed = {:?}), should only happen because ED has \ changed recently. Pool operators should be notified to top up the reward \ account", id, - T::Currency::free_balance(&account), + T::Currency::reducible_balance( + &account, + Preservation::Expendable, + Fortitude::Polite + ), T::Currency::minimum_balance(), ) } @@ -3110,6 +3298,7 @@ impl Pallet { let mut pools_members = BTreeMap::::new(); let mut pools_members_pending_rewards = BTreeMap::>::new(); let mut all_members = 0u32; + let mut total_balance_members = Default::default(); PoolMembers::::iter().try_for_each(|(_, d)| -> Result<(), TryRuntimeError> { let bonded_pool = BondedPools::::get(d.pool_id).unwrap(); ensure!(!d.total_points().is_zero(), "No member should have zero points"); @@ -3125,6 +3314,7 @@ impl Pallet { let pending_rewards = d.pending_rewards(current_rc).unwrap(); *pools_members_pending_rewards.entry(d.pool_id).or_default() += pending_rewards; } // else this pool has been heavily slashed and cannot have any rewards anymore. + total_balance_members += d.total_balance(); Ok(()) })?; @@ -3135,9 +3325,8 @@ impl Pallet { let pending_rewards_lt_leftover_bal = RewardPool::::current_balance(id) >= pools_members_pending_rewards.get(&id).copied().unwrap_or_default(); - // this is currently broken in Kusama, a fix is being worked on in - // . until it is fixed, log a - // warning instead of panicing with an `ensure` statement. + // If this happens, this is most likely due to an old bug and not a recent code change. + // We warn about this in try-runtime checks but do not panic. if !pending_rewards_lt_leftover_bal { log::warn!( "pool {:?}, sum pending rewards = {:?}, remaining balance = {:?}", @@ -3149,6 +3338,7 @@ impl Pallet { Ok(()) })?; + let mut expected_tvl: BalanceOf = Default::default(); BondedPools::::iter().try_for_each(|(id, inner)| -> Result<(), TryRuntimeError> { let bonded_pool = BondedPool { id, inner }; ensure!( @@ -3169,13 +3359,28 @@ impl Pallet { "depositor must always have MinCreateBond stake in the pool, except for when the \ pool is being destroyed and the depositor is the last member", ); + + expected_tvl += + T::Staking::total_stake(&bonded_pool.bonded_account()).unwrap_or_default(); + Ok(()) })?; + ensure!( MaxPoolMembers::::get().map_or(true, |max| all_members <= max), Error::::MaxPoolMembers ); + ensure!( + TotalValueLocked::::get() == expected_tvl, + "TVL deviates from the actual sum of funds of all Pools." + ); + + ensure!( + TotalValueLocked::::get() <= total_balance_members, + "TVL must be equal to or less than the total balance of all PoolMembers." + ); + if level <= 1 { return Ok(()) } @@ -3199,9 +3404,39 @@ impl Pallet { ); } + // Warn if any pool has incorrect ED frozen. We don't want to fail hard as this could be a + // result of an intentional ED change. + let _ = Self::check_ed_imbalance()?; + Ok(()) } + /// Check if any pool have an incorrect amount of ED frozen. + /// + /// This can happen if the ED has changed since the pool was created. + #[cfg(any(feature = "try-runtime", feature = "runtime-benchmarks", test, debug_assertions))] + pub fn check_ed_imbalance() -> Result<(), DispatchError> { + let mut failed: u32 = 0; + BondedPools::::iter_keys().for_each(|id| { + let reward_acc = Self::create_reward_account(id); + let frozen_balance = + T::Currency::balance_frozen(&FreezeReason::PoolMinBalance.into(), &reward_acc); + + let expected_frozen_balance = T::Currency::minimum_balance(); + if frozen_balance != expected_frozen_balance { + failed += 1; + log::warn!( + "pool {:?} has incorrect ED frozen that can result from change in ED. Expected = {:?}, Actual = {:?}", + id, + expected_frozen_balance, + frozen_balance, + ); + } + }); + + ensure!(failed == 0, "Some pools do not have correct ED frozen"); + Ok(()) + } /// Fully unbond the shares of `member`, when executed from `origin`. /// /// This is useful for backwards compatibility with the majority of tests that only deal with @@ -3263,20 +3498,30 @@ impl Pallet { } impl sp_staking::OnStakingUpdate> for Pallet { + /// Reduces the balances of the [`SubPools`], that belong to the pool involved in the + /// slash, to the amount that is defined in the `slashed_unlocking` field of + /// [`sp_staking::OnStakingUpdate::on_slash`] + /// + /// Emits the `PoolsSlashed` event. fn on_slash( pool_account: &T::AccountId, // Bonded balance is always read directly from staking, therefore we don't need to update // anything here. slashed_bonded: BalanceOf, slashed_unlocking: &BTreeMap>, + total_slashed: BalanceOf, ) { - if let Some(pool_id) = ReversePoolIdLookup::::get(pool_account) { - let mut sub_pools = match SubPoolsStorage::::get(pool_id).defensive() { - Some(sub_pools) => sub_pools, - None => return, - }; - for (era, slashed_balance) in slashed_unlocking.iter() { - if let Some(pool) = sub_pools.with_era.get_mut(era) { + let Some(pool_id) = ReversePoolIdLookup::::get(pool_account) else { return }; + // As the slashed account belongs to a `BondedPool` the `TotalValueLocked` decreases and + // an event is emitted. + TotalValueLocked::::mutate(|tvl| { + tvl.defensive_saturating_reduce(total_slashed); + }); + + if let Some(mut sub_pools) = SubPoolsStorage::::get(pool_id) { + // set the reduced balance for each of the `SubPools` + slashed_unlocking.iter().for_each(|(era, slashed_balance)| { + if let Some(pool) = sub_pools.with_era.get_mut(era).defensive() { pool.balance = *slashed_balance; Self::deposit_event(Event::::UnbondingPoolSlashed { era: *era, @@ -3284,10 +3529,11 @@ impl sp_staking::OnStakingUpdate> for Pall balance: *slashed_balance, }); } - } - - Self::deposit_event(Event::::PoolSlashed { pool_id, balance: slashed_bonded }); + }); SubPoolsStorage::::insert(pool_id, sub_pools); + } else if !slashed_unlocking.is_empty() { + defensive!("Expected SubPools were not found"); } + Self::deposit_event(Event::::PoolSlashed { pool_id, balance: slashed_bonded }); } } diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 2ae4cd1b86857787ff98d72191785c8e8168339c..eef2a976f1a2550081fee5caa28ea36a9c52ee68 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -23,55 +23,338 @@ use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -pub mod v1 { +/// Exports for versioned migration `type`s for this pallet. +pub mod versioned_migrations { + use super::*; + + /// Migration V6 to V7 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring + /// the migration is only performed when on-chain version is 6. + pub type V6ToV7 = frame_support::migrations::VersionedMigration< + 6, + 7, + v7::VersionUncheckedMigrateV6ToV7, + crate::pallet::Pallet, + ::DbWeight, + >; + + /// Wrapper over `MigrateToV6` with convenience version checks. + pub type V5toV6 = frame_support::migrations::VersionedMigration< + 5, + 6, + v6::MigrateToV6, + crate::pallet::Pallet, + ::DbWeight, + >; +} + +/// This migration accumulates and initializes the [`TotalValueLocked`] for all pools. +/// +/// WARNING: This migration works under the assumption that the [`BondedPools`] cannot be inflated +/// arbitrarily. Otherwise this migration could fail due to too high weight. +mod v7 { + use super::*; + + pub struct VersionUncheckedMigrateV6ToV7(sp_std::marker::PhantomData); + impl VersionUncheckedMigrateV6ToV7 { + fn calculate_tvl_by_total_stake() -> BalanceOf { + BondedPools::::iter() + .map(|(id, inner)| { + T::Staking::total_stake( + &BondedPool { id, inner: inner.clone() }.bonded_account(), + ) + .unwrap_or_default() + }) + .reduce(|acc, total_balance| acc + total_balance) + .unwrap_or_default() + } + } + + impl OnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { + fn on_runtime_upgrade() -> Weight { + let migrated = BondedPools::::count(); + // The TVL should be the sum of all the funds that are actively staked and in the + // unbonding process of the account of each pool. + let tvl: BalanceOf = Self::calculate_tvl_by_total_stake(); + + TotalValueLocked::::set(tvl); + + log!(info, "Upgraded {} pools with a TVL of {:?}", migrated, tvl); + + // reads: migrated * (BondedPools + Staking::total_stake) + count + onchain + // version + // + // writes: current version + TVL + T::DbWeight::get().reads_writes(migrated.saturating_mul(2).saturating_add(2).into(), 2) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_data: Vec) -> Result<(), TryRuntimeError> { + // check that the `TotalValueLocked` written is actually the sum of `total_stake` of the + // `BondedPools`` + let tvl: BalanceOf = Self::calculate_tvl_by_total_stake(); + ensure!( + TotalValueLocked::::get() == tvl, + "TVL written is not equal to `Staking::total_stake` of all `BondedPools`." + ); + + // calculate the sum of `total_balance` of all `PoolMember` as the upper bound for the + // `TotalValueLocked`. + let total_balance_members: BalanceOf = PoolMembers::::iter() + .map(|(_, member)| member.total_balance()) + .reduce(|acc, total_balance| acc + total_balance) + .unwrap_or_default(); + + ensure!( + TotalValueLocked::::get() <= total_balance_members, + "TVL is greater than the balance of all PoolMembers." + ); + + ensure!( + Pallet::::on_chain_storage_version() >= 7, + "nomination-pools::migration::v7: wrong storage version" + ); + + Ok(()) + } + } +} + +mod v6 { + use super::*; + + /// This migration would restrict reward account of pools to go below ED by doing a named + /// freeze on all the existing pools. + pub struct MigrateToV6(sp_std::marker::PhantomData); + + impl MigrateToV6 { + fn freeze_ed(pool_id: PoolId) -> Result<(), ()> { + let reward_acc = Pallet::::create_reward_account(pool_id); + Pallet::::freeze_pool_deposit(&reward_acc).map_err(|e| { + log!(error, "Failed to freeze ED for pool {} with error: {:?}", pool_id, e); + () + }) + } + } + impl OnRuntimeUpgrade for MigrateToV6 { + fn on_runtime_upgrade() -> Weight { + let mut success = 0u64; + let mut fail = 0u64; + + BondedPools::::iter_keys().for_each(|p| { + if Self::freeze_ed(p).is_ok() { + success.saturating_inc(); + } else { + fail.saturating_inc(); + } + }); + + if fail > 0 { + log!(error, "Failed to freeze ED for {} pools", fail); + } else { + log!(info, "Freezing ED succeeded for {} pools", success); + } + + let total = success.saturating_add(fail); + // freeze_ed = r:2 w:2 + // reads: (freeze_ed + bonded pool key) * total + // writes: freeze_ed * total + T::DbWeight::get().reads_writes(3u64.saturating_mul(total), 2u64.saturating_mul(total)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_data: Vec) -> Result<(), TryRuntimeError> { + // there should be no ED imbalances anymore.. + Pallet::::check_ed_imbalance() + } + } +} +pub mod v5 { use super::*; #[derive(Decode)] - pub struct OldPoolRoles { - pub depositor: AccountId, - pub root: AccountId, - pub nominator: AccountId, - pub bouncer: AccountId, + pub struct OldRewardPool { + last_recorded_reward_counter: T::RewardCounter, + last_recorded_total_payouts: BalanceOf, + total_rewards_claimed: BalanceOf, } - impl OldPoolRoles { - fn migrate_to_v1(self) -> PoolRoles { - PoolRoles { - depositor: self.depositor, - root: Some(self.root), - nominator: Some(self.nominator), - bouncer: Some(self.bouncer), + impl OldRewardPool { + fn migrate_to_v5(self) -> RewardPool { + RewardPool { + last_recorded_reward_counter: self.last_recorded_reward_counter, + last_recorded_total_payouts: self.last_recorded_total_payouts, + total_rewards_claimed: self.total_rewards_claimed, + total_commission_pending: Zero::zero(), + total_commission_claimed: Zero::zero(), } } } + /// This migration adds `total_commission_pending` and `total_commission_claimed` field to every + /// `RewardPool`, if any. + pub struct MigrateToV5(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV5 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 5 && onchain == 4 { + let mut translated = 0u64; + RewardPools::::translate::, _>(|_id, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v5()) + }); + + current.put::>(); + log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); + + // reads: translated + onchain version. + // writes: translated + current.put. + T::DbWeight::get().reads_writes(translated + 1, translated + 1) + } else { + log!(info, "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let rpool_keys = RewardPools::::iter_keys().count(); + let rpool_values = RewardPools::::iter_values().count(); + if rpool_keys != rpool_values { + log!(info, "🔥 There are {} undecodable RewardPools in storage. This migration will try to correct them. keys: {}, values: {}", rpool_keys.saturating_sub(rpool_values), rpool_keys, rpool_values); + } + + ensure!( + PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), + "There are undecodable PoolMembers in storage. This migration will not fix that." + ); + ensure!( + BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), + "There are undecodable BondedPools in storage. This migration will not fix that." + ); + ensure!( + SubPoolsStorage::::iter_keys().count() == + SubPoolsStorage::::iter_values().count(), + "There are undecodable SubPools in storage. This migration will not fix that." + ); + ensure!( + Metadata::::iter_keys().count() == Metadata::::iter_values().count(), + "There are undecodable Metadata in storage. This migration will not fix that." + ); + + Ok((rpool_values as u64).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(data: Vec) -> Result<(), TryRuntimeError> { + let old_rpool_values: u64 = Decode::decode(&mut &data[..]).unwrap(); + let rpool_keys = RewardPools::::iter_keys().count() as u64; + let rpool_values = RewardPools::::iter_values().count() as u64; + ensure!( + rpool_keys == rpool_values, + "There are STILL undecodable RewardPools - migration failed" + ); + + if old_rpool_values != rpool_values { + log!( + info, + "🎉 Fixed {} undecodable RewardPools.", + rpool_values.saturating_sub(old_rpool_values) + ); + } + + // ensure all RewardPools items now contain `total_commission_pending` and + // `total_commission_claimed` field. + ensure!( + RewardPools::::iter().all(|(_, reward_pool)| reward_pool + .total_commission_pending >= + Zero::zero() && reward_pool + .total_commission_claimed >= + Zero::zero()), + "a commission value has been incorrectly set" + ); + ensure!( + Pallet::::on_chain_storage_version() >= 5, + "nomination-pools::migration::v5: wrong storage version" + ); + + // These should not have been touched - just in case. + ensure!( + PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), + "There are undecodable PoolMembers in storage." + ); + ensure!( + BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), + "There are undecodable BondedPools in storage." + ); + ensure!( + SubPoolsStorage::::iter_keys().count() == + SubPoolsStorage::::iter_values().count(), + "There are undecodable SubPools in storage." + ); + ensure!( + Metadata::::iter_keys().count() == Metadata::::iter_values().count(), + "There are undecodable Metadata in storage." + ); + + Ok(()) + } + } +} + +pub mod v4 { + use super::*; + #[derive(Decode)] pub struct OldBondedPoolInner { pub points: BalanceOf, pub state: PoolState, pub member_counter: u32, - pub roles: OldPoolRoles, + pub roles: PoolRoles, } impl OldBondedPoolInner { - fn migrate_to_v1(self) -> BondedPoolInner { - // Note: `commission` field not introduced to `BondedPoolInner` until - // migration 4. + fn migrate_to_v4(self) -> BondedPoolInner { BondedPoolInner { - points: self.points, commission: Commission::default(), member_counter: self.member_counter, + points: self.points, state: self.state, - roles: self.roles.migrate_to_v1(), + roles: self.roles, } } } - /// Trivial migration which makes the roles of each pool optional. + /// Migrates from `v3` directly to `v5` to avoid the broken `v4` migration. + #[allow(deprecated)] + pub type MigrateV3ToV5 = (v4::MigrateToV4, v5::MigrateToV5); + + /// # Warning /// - /// Note: The depositor is not optional since they can never change. - pub struct MigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { + /// To avoid mangled storage please use `MigrateV3ToV5` instead. + /// See: github.com/paritytech/substrate/pull/13715 + /// + /// This migration adds a `commission` field to every `BondedPoolInner`, if + /// any. + #[deprecated( + note = "To avoid mangled storage please use `MigrateV3ToV5` instead. See: github.com/paritytech/substrate/pull/13715" + )] + pub struct MigrateToV4(sp_std::marker::PhantomData<(T, U)>); + #[allow(deprecated)] + impl> OnRuntimeUpgrade for MigrateToV4 { fn on_runtime_upgrade() -> Weight { let current = Pallet::::current_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -83,33 +366,128 @@ pub mod v1 { onchain ); - if current == 1 && onchain == 0 { - // this is safe to execute on any runtime that has a bounded number of pools. + if onchain == 3 { + log!(warn, "Please run MigrateToV5 immediately after this migration. See github.com/paritytech/substrate/pull/13715"); + let initial_global_max_commission = U::get(); + GlobalMaxCommission::::set(Some(initial_global_max_commission)); + log!( + info, + "Set initial global max commission to {:?}.", + initial_global_max_commission + ); + let mut translated = 0u64; BondedPools::::translate::, _>(|_key, old_value| { translated.saturating_inc(); - Some(old_value.migrate_to_v1()) + Some(old_value.migrate_to_v4()) }); - current.put::>(); - + StorageVersion::new(4).put::>(); log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); - T::DbWeight::get().reads_writes(translated + 1, translated + 1) + // reads: translated + onchain version. + // writes: translated + current.put + initial global commission. + T::DbWeight::get().reads_writes(translated + 1, translated + 2) } else { - log!(info, "Migration did not executed. This probably should be removed"); + log!(info, "Migration did not execute. This probably should be removed"); T::DbWeight::get().reads(1) } } + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + #[cfg(feature = "try-runtime")] fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { - // new version must be set. + // ensure all BondedPools items now contain an `inner.commission: Commission` field. ensure!( - Pallet::::on_chain_storage_version() == 1, - "The onchain version must be updated after the migration." + BondedPools::::iter().all(|(_, inner)| + // Check current + (inner.commission.current.is_none() || + inner.commission.current.is_some()) && + // Check max + (inner.commission.max.is_none() || inner.commission.max.is_some()) && + // Check change_rate + (inner.commission.change_rate.is_none() || + inner.commission.change_rate.is_some()) && + // Check throttle_from + (inner.commission.throttle_from.is_none() || + inner.commission.throttle_from.is_some())), + "a commission value has not been set correctly" + ); + ensure!( + GlobalMaxCommission::::get() == Some(U::get()), + "global maximum commission error" + ); + ensure!( + Pallet::::on_chain_storage_version() >= 4, + "nomination-pools::migration::v4: wrong storage version" + ); + Ok(()) + } + } +} + +pub mod v3 { + use super::*; + + /// This migration removes stale bonded-pool metadata, if any. + pub struct MigrateToV3(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV3 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + if onchain == 2 { + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + let mut metadata_iterated = 0u64; + let mut metadata_removed = 0u64; + Metadata::::iter_keys() + .filter(|id| { + metadata_iterated += 1; + !BondedPools::::contains_key(&id) + }) + .collect::>() + .into_iter() + .for_each(|id| { + metadata_removed += 1; + Metadata::::remove(&id); + }); + StorageVersion::new(3).put::>(); + // metadata iterated + bonded pools read + a storage version read + let total_reads = metadata_iterated * 2 + 1; + // metadata removed + a storage version write + let total_writes = metadata_removed + 1; + T::DbWeight::get().reads_writes(total_reads, total_writes) + } else { + log!(info, "MigrateToV3 should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + ensure!( + Metadata::::iter_keys().all(|id| BondedPools::::contains_key(&id)), + "not all of the stale metadata has been removed" + ); + ensure!( + Pallet::::on_chain_storage_version() >= 3, + "nomination-pools::migration::v3: wrong storage version" ); - Pallet::::try_state(frame_system::Pallet::::block_number())?; Ok(()) } } @@ -127,7 +505,7 @@ pub mod v2 { use crate::mock::*; ExtBuilder::default().build_and_execute(|| { let join = |x| { - Balances::make_free_balance_be(&x, Balances::minimum_balance() + 10); + Currency::set_balance(&x, Balances::minimum_balance() + 10); frame_support::assert_ok!(Pools::join(RuntimeOrigin::signed(x), 10, 1)); }; @@ -279,7 +657,7 @@ pub mod v2 { &reward_account, &who, last_claim, - ExistenceRequirement::KeepAlive, + Preservation::Preserve, ); if let Err(reason) = outcome { @@ -304,7 +682,7 @@ pub mod v2 { &reward_account, &bonded_pool.roles.depositor, leftover, - ExistenceRequirement::KeepAlive, + Preservation::Preserve, ); log!(warn, "paying {:?} leftover to the depositor: {:?}", leftover, o); } @@ -330,185 +708,14 @@ pub mod v2 { total_value_locked, total_points_locked, current - ); - current.put::>(); - - T::DbWeight::get().reads_writes(members_translated + 1, reward_pools_translated + 1) - } - } - - impl OnRuntimeUpgrade for MigrateToV2 { - fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); - let onchain = Pallet::::on_chain_storage_version(); - - log!( - info, - "Running migration with current storage version {:?} / onchain {:?}", - current, - onchain - ); - - if current == 2 && onchain == 1 { - Self::run(current) - } else { - log!(info, "MigrateToV2 did not executed. This probably should be removed"); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - // all reward accounts must have more than ED. - RewardPools::::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> { - ensure!( - T::Currency::free_balance(&Pallet::::create_reward_account(id)) >= - T::Currency::minimum_balance(), - "Reward accounts must have greater balance than ED." - ); - Ok(()) - })?; - - Ok(Vec::new()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { - // new version must be set. - ensure!( - Pallet::::on_chain_storage_version() == 2, - "The onchain version must be updated after the migration." - ); - - // no reward or bonded pool has been skipped. - ensure!( - RewardPools::::iter().count() as u32 == RewardPools::::count(), - "The count of reward pools must remain the same after the migration." - ); - ensure!( - BondedPools::::iter().count() as u32 == BondedPools::::count(), - "The count of reward pools must remain the same after the migration." - ); - - // all reward pools must have exactly ED in them. This means no reward can be claimed, - // and that setting reward counters all over the board to zero will work henceforth. - RewardPools::::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> { - ensure!( - RewardPool::::current_balance(id) == Zero::zero(), - "Reward pool balance must be zero.", - ); - Ok(()) - })?; - - log!(info, "post upgrade hook for MigrateToV2 executed."); - Ok(()) - } - } -} - -pub mod v3 { - use super::*; - - /// This migration removes stale bonded-pool metadata, if any. - pub struct MigrateToV3(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV3 { - fn on_runtime_upgrade() -> Weight { - let current = Pallet::::current_storage_version(); - let onchain = Pallet::::on_chain_storage_version(); - - if onchain == 2 { - log!( - info, - "Running migration with current storage version {:?} / onchain {:?}", - current, - onchain - ); - - let mut metadata_iterated = 0u64; - let mut metadata_removed = 0u64; - Metadata::::iter_keys() - .filter(|id| { - metadata_iterated += 1; - !BondedPools::::contains_key(&id) - }) - .collect::>() - .into_iter() - .for_each(|id| { - metadata_removed += 1; - Metadata::::remove(&id); - }); - StorageVersion::new(3).put::>(); - // metadata iterated + bonded pools read + a storage version read - let total_reads = metadata_iterated * 2 + 1; - // metadata removed + a storage version write - let total_writes = metadata_removed + 1; - T::DbWeight::get().reads_writes(total_reads, total_writes) - } else { - log!(info, "MigrateToV3 should be removed"); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - Ok(Vec::new()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { - ensure!( - Metadata::::iter_keys().all(|id| BondedPools::::contains_key(&id)), - "not all of the stale metadata has been removed" - ); - ensure!( - Pallet::::on_chain_storage_version() >= 3, - "nomination-pools::migration::v3: wrong storage version" - ); - Ok(()) - } - } -} - -pub mod v4 { - use super::*; - - #[derive(Decode)] - pub struct OldBondedPoolInner { - pub points: BalanceOf, - pub state: PoolState, - pub member_counter: u32, - pub roles: PoolRoles, - } + ); + current.put::>(); - impl OldBondedPoolInner { - fn migrate_to_v4(self) -> BondedPoolInner { - BondedPoolInner { - commission: Commission::default(), - member_counter: self.member_counter, - points: self.points, - state: self.state, - roles: self.roles, - } + T::DbWeight::get().reads_writes(members_translated + 1, reward_pools_translated + 1) } } - /// Migrates from `v3` directly to `v5` to avoid the broken `v4` migration. - #[allow(deprecated)] - pub type MigrateV3ToV5 = (v4::MigrateToV4, v5::MigrateToV5); - - /// # Warning - /// - /// To avoid mangled storage please use `MigrateV3ToV5` instead. - /// See: github.com/paritytech/substrate/pull/13715 - /// - /// This migration adds a `commission` field to every `BondedPoolInner`, if - /// any. - #[deprecated( - note = "To avoid mangled storage please use `MigrateV3ToV5` instead. See: github.com/paritytech/substrate/pull/13715" - )] - pub struct MigrateToV4(sp_std::marker::PhantomData<(T, U)>); - #[allow(deprecated)] - impl> OnRuntimeUpgrade for MigrateToV4 { + impl OnRuntimeUpgrade for MigrateToV2 { fn on_runtime_upgrade() -> Weight { let current = Pallet::::current_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -520,96 +727,112 @@ pub mod v4 { onchain ); - if onchain == 3 { - log!(warn, "Please run MigrateToV5 immediately after this migration. See github.com/paritytech/substrate/pull/13715"); - let initial_global_max_commission = U::get(); - GlobalMaxCommission::::set(Some(initial_global_max_commission)); - log!( - info, - "Set initial global max commission to {:?}.", - initial_global_max_commission - ); - - let mut translated = 0u64; - BondedPools::::translate::, _>(|_key, old_value| { - translated.saturating_inc(); - Some(old_value.migrate_to_v4()) - }); - - StorageVersion::new(4).put::>(); - log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); - - // reads: translated + onchain version. - // writes: translated + current.put + initial global commission. - T::DbWeight::get().reads_writes(translated + 1, translated + 2) + if current == 2 && onchain == 1 { + Self::run(current) } else { - log!(info, "Migration did not execute. This probably should be removed"); + log!(info, "MigrateToV2 did not executed. This probably should be removed"); T::DbWeight::get().reads(1) } } #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { + // all reward accounts must have more than ED. + RewardPools::::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> { + ensure!( + >::balance(&Pallet::::create_reward_account(id)) >= + T::Currency::minimum_balance(), + "Reward accounts must have greater balance than ED." + ); + Ok(()) + })?; + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { - // ensure all BondedPools items now contain an `inner.commission: Commission` field. + // new version must be set. ensure!( - BondedPools::::iter().all(|(_, inner)| - // Check current - (inner.commission.current.is_none() || - inner.commission.current.is_some()) && - // Check max - (inner.commission.max.is_none() || inner.commission.max.is_some()) && - // Check change_rate - (inner.commission.change_rate.is_none() || - inner.commission.change_rate.is_some()) && - // Check throttle_from - (inner.commission.throttle_from.is_none() || - inner.commission.throttle_from.is_some())), - "a commission value has not been set correctly" + Pallet::::on_chain_storage_version() == 2, + "The onchain version must be updated after the migration." ); + + // no reward or bonded pool has been skipped. ensure!( - GlobalMaxCommission::::get() == Some(U::get()), - "global maximum commission error" + RewardPools::::iter().count() as u32 == RewardPools::::count(), + "The count of reward pools must remain the same after the migration." ); ensure!( - Pallet::::on_chain_storage_version() >= 4, - "nomination-pools::migration::v4: wrong storage version" + BondedPools::::iter().count() as u32 == BondedPools::::count(), + "The count of reward pools must remain the same after the migration." ); + + // all reward pools must have exactly ED in them. This means no reward can be claimed, + // and that setting reward counters all over the board to zero will work henceforth. + RewardPools::::iter().try_for_each(|(id, _)| -> Result<(), TryRuntimeError> { + ensure!( + RewardPool::::current_balance(id) == Zero::zero(), + "Reward pool balance must be zero.", + ); + Ok(()) + })?; + + log!(info, "post upgrade hook for MigrateToV2 executed."); Ok(()) } } } -pub mod v5 { +pub mod v1 { use super::*; #[derive(Decode)] - pub struct OldRewardPool { - last_recorded_reward_counter: T::RewardCounter, - last_recorded_total_payouts: BalanceOf, - total_rewards_claimed: BalanceOf, + pub struct OldPoolRoles { + pub depositor: AccountId, + pub root: AccountId, + pub nominator: AccountId, + pub bouncer: AccountId, } - impl OldRewardPool { - fn migrate_to_v5(self) -> RewardPool { - RewardPool { - last_recorded_reward_counter: self.last_recorded_reward_counter, - last_recorded_total_payouts: self.last_recorded_total_payouts, - total_rewards_claimed: self.total_rewards_claimed, - total_commission_pending: Zero::zero(), - total_commission_claimed: Zero::zero(), + impl OldPoolRoles { + fn migrate_to_v1(self) -> PoolRoles { + PoolRoles { + depositor: self.depositor, + root: Some(self.root), + nominator: Some(self.nominator), + bouncer: Some(self.bouncer), } } } - /// This migration adds `total_commission_pending` and `total_commission_claimed` field to every - /// `RewardPool`, if any. - pub struct MigrateToV5(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV5 { + #[derive(Decode)] + pub struct OldBondedPoolInner { + pub points: BalanceOf, + pub state: PoolState, + pub member_counter: u32, + pub roles: OldPoolRoles, + } + + impl OldBondedPoolInner { + fn migrate_to_v1(self) -> BondedPoolInner { + // Note: `commission` field not introduced to `BondedPoolInner` until + // migration 4. + BondedPoolInner { + points: self.points, + commission: Commission::default(), + member_counter: self.member_counter, + state: self.state, + roles: self.roles.migrate_to_v1(), + } + } + } + + /// Trivial migration which makes the roles of each pool optional. + /// + /// Note: The depositor is not optional since they can never change. + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { let current = Pallet::::current_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -621,106 +844,33 @@ pub mod v5 { onchain ); - if current == 5 && onchain == 4 { + if current == 1 && onchain == 0 { + // this is safe to execute on any runtime that has a bounded number of pools. let mut translated = 0u64; - RewardPools::::translate::, _>(|_id, old_value| { + BondedPools::::translate::, _>(|_key, old_value| { translated.saturating_inc(); - Some(old_value.migrate_to_v5()) + Some(old_value.migrate_to_v1()) }); current.put::>(); + log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); - // reads: translated + onchain version. - // writes: translated + current.put. T::DbWeight::get().reads_writes(translated + 1, translated + 1) } else { - log!(info, "Migration did not execute. This probably should be removed"); + log!(info, "Migration did not executed. This probably should be removed"); T::DbWeight::get().reads(1) } } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let rpool_keys = RewardPools::::iter_keys().count(); - let rpool_values = RewardPools::::iter_values().count(); - if rpool_keys != rpool_values { - log!(info, "🔥 There are {} undecodable RewardPools in storage. This migration will try to correct them. keys: {}, values: {}", rpool_keys.saturating_sub(rpool_values), rpool_keys, rpool_values); - } - - ensure!( - PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), - "There are undecodable PoolMembers in storage. This migration will not fix that." - ); - ensure!( - BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), - "There are undecodable BondedPools in storage. This migration will not fix that." - ); - ensure!( - SubPoolsStorage::::iter_keys().count() == - SubPoolsStorage::::iter_values().count(), - "There are undecodable SubPools in storage. This migration will not fix that." - ); - ensure!( - Metadata::::iter_keys().count() == Metadata::::iter_values().count(), - "There are undecodable Metadata in storage. This migration will not fix that." - ); - - Ok((rpool_values as u64).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(data: Vec) -> Result<(), TryRuntimeError> { - let old_rpool_values: u64 = Decode::decode(&mut &data[..]).unwrap(); - let rpool_keys = RewardPools::::iter_keys().count() as u64; - let rpool_values = RewardPools::::iter_values().count() as u64; - ensure!( - rpool_keys == rpool_values, - "There are STILL undecodable RewardPools - migration failed" - ); - - if old_rpool_values != rpool_values { - log!( - info, - "🎉 Fixed {} undecodable RewardPools.", - rpool_values.saturating_sub(old_rpool_values) - ); - } - - // ensure all RewardPools items now contain `total_commission_pending` and - // `total_commission_claimed` field. - ensure!( - RewardPools::::iter().all(|(_, reward_pool)| reward_pool - .total_commission_pending >= - Zero::zero() && reward_pool - .total_commission_claimed >= - Zero::zero()), - "a commission value has been incorrectly set" - ); - ensure!( - Pallet::::on_chain_storage_version() >= 5, - "nomination-pools::migration::v5: wrong storage version" - ); - - // These should not have been touched - just in case. - ensure!( - PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), - "There are undecodable PoolMembers in storage." - ); - ensure!( - BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), - "There are undecodable BondedPools in storage." - ); - ensure!( - SubPoolsStorage::::iter_keys().count() == - SubPoolsStorage::::iter_values().count(), - "There are undecodable SubPools in storage." - ); + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + // new version must be set. ensure!( - Metadata::::iter_keys().count() == Metadata::::iter_values().count(), - "There are undecodable Metadata in storage." + Pallet::::on_chain_storage_version() == 1, + "The onchain version must be updated after the migration." ); - + Pallet::::try_state(frame_system::Pallet::::block_number())?; Ok(()) } } diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 28c24c42803519c0aee797bda06e3038a89d098a..d806ba071bd41b5abe5a479c44093612dc3451aa 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -17,10 +17,10 @@ use super::*; use crate::{self as pools}; -use frame_support::{assert_ok, parameter_types, PalletId}; +use frame_support::{assert_ok, parameter_types, traits::fungible::Mutate, PalletId}; use frame_system::RawOrigin; use sp_runtime::{BuildStorage, FixedU128}; -use sp_staking::Stake; +use sp_staking::{OnStakingUpdate, Stake}; pub type BlockNumber = u64; pub type AccountId = u128; @@ -29,6 +29,7 @@ pub type RewardCounter = FixedU128; // This sneaky little hack allows us to write code exactly as we would do in the pallet in the tests // as well, e.g. `StorageItem::::get()`. pub type T = Runtime; +pub type Currency = ::Currency; // Ext builder creates a pool with id 1. pub fn default_bonded_account() -> AccountId { @@ -45,20 +46,34 @@ parameter_types! { pub static CurrentEra: EraIndex = 0; pub static BondingDuration: EraIndex = 3; pub storage BondedBalanceMap: BTreeMap = Default::default(); - pub storage UnbondingBalanceMap: BTreeMap = Default::default(); + // map from a user to a vec of eras and amounts being unlocked in each era. + pub storage UnbondingBalanceMap: BTreeMap> = Default::default(); #[derive(Clone, PartialEq)] pub static MaxUnbonding: u32 = 8; pub static StakingMinBond: Balance = 10; pub storage Nominations: Option> = None; } - pub struct StakingMock; + impl StakingMock { pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) { let mut x = BondedBalanceMap::get(); x.insert(who, bonded); BondedBalanceMap::set(&x) } + /// Mimics a slash towards a pool specified by `pool_id`. + /// This reduces the bonded balance of a pool by `amount` and calls [`Pools::on_slash`] to + /// enact changes in the nomination-pool pallet. + /// + /// Does not modify any [`SubPools`] of the pool as [`Default::default`] is passed for + /// `slashed_unlocking`. + pub fn slash_by(pool_id: PoolId, amount: Balance) { + let acc = Pools::create_bonded_account(pool_id); + let bonded = BondedBalanceMap::get(); + let pre_total = bonded.get(&acc).unwrap(); + Self::set_bonded_balance(acc, pre_total - amount); + Pools::on_slash(&acc, pre_total - amount, &Default::default(), amount); + } } impl sp_staking::StakingInterface for StakingMock { @@ -104,8 +119,11 @@ impl sp_staking::StakingInterface for StakingMock { let mut x = BondedBalanceMap::get(); *x.get_mut(who).unwrap() = x.get_mut(who).unwrap().saturating_sub(amount); BondedBalanceMap::set(&x); + + let era = Self::current_era(); + let unlocking_at = era + Self::bonding_duration(); let mut y = UnbondingBalanceMap::get(); - *y.entry(*who).or_insert(Self::Balance::zero()) += amount; + y.entry(*who).or_insert(Default::default()).push((unlocking_at, amount)); UnbondingBalanceMap::set(&y); Ok(()) } @@ -115,11 +133,13 @@ impl sp_staking::StakingInterface for StakingMock { } fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result { - // Simulates removing unlocking chunks and only having the bonded balance locked - let mut x = UnbondingBalanceMap::get(); - x.remove(&who); - UnbondingBalanceMap::set(&x); + let mut unbonding_map = UnbondingBalanceMap::get(); + let staker_map = unbonding_map.get_mut(&who).ok_or("Nothing to unbond")?; + + let current_era = Self::current_era(); + staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era); + UnbondingBalanceMap::set(&unbonding_map); Ok(UnbondingBalanceMap::get().is_empty() && BondedBalanceMap::get().is_empty()) } @@ -143,14 +163,17 @@ impl sp_staking::StakingInterface for StakingMock { } fn stake(who: &Self::AccountId) -> Result, DispatchError> { - match ( - UnbondingBalanceMap::get().get(who).copied(), - BondedBalanceMap::get().get(who).copied(), - ) { + match (UnbondingBalanceMap::get().get(who), BondedBalanceMap::get().get(who).copied()) { (None, None) => Err(DispatchError::Other("balance not found")), - (Some(v), None) => Ok(Stake { total: v, active: 0 }), + (Some(v), None) => Ok(Stake { + total: v.into_iter().fold(0u128, |acc, &x| acc.saturating_add(x.1)), + active: 0, + }), (None, Some(v)) => Ok(Stake { total: v, active: v }), - (Some(a), Some(b)) => Ok(Stake { total: a + b, active: b }), + (Some(a), Some(b)) => Ok(Stake { + total: a.into_iter().fold(0u128, |acc, &x| acc.saturating_add(x.1)) + b, + active: b, + }), } } @@ -221,8 +244,8 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); type MaxHolds = (); } @@ -251,6 +274,7 @@ impl pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; @@ -268,7 +292,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Storage, Event, Config}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Pools: pools::{Pallet, Call, Storage, Event}, + Pools: pools::{Pallet, Call, Storage, Event, FreezeReason}, } ); @@ -356,12 +380,12 @@ impl ExtBuilder { // make a pool let amount_to_bond = Pools::depositor_min_bond(); - Balances::make_free_balance_be(&10, amount_to_bond * 5); + Currency::set_balance(&10, amount_to_bond * 5); assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); let last_pool = LastPoolId::::get(); for (account_id, bonded) in self.members { - Balances::make_free_balance_be(&account_id, bonded * 2); + ::Currency::set_balance(&account_id, bonded * 2); assert_ok!(Pools::join(RawOrigin::Signed(account_id).into(), bonded, last_pool)); } }); @@ -440,6 +464,58 @@ pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult { Pools::unbond(RuntimeOrigin::signed(member), member, points) } +pub fn pending_rewards_for_delegator(delegator: AccountId) -> Balance { + let member = PoolMembers::::get(delegator).unwrap(); + let bonded_pool = BondedPools::::get(member.pool_id).unwrap(); + let reward_pool = RewardPools::::get(member.pool_id).unwrap(); + + assert!(!bonded_pool.points.is_zero()); + + let commission = bonded_pool.commission.current(); + let current_rc = reward_pool + .current_reward_counter(member.pool_id, bonded_pool.points, commission) + .unwrap() + .0; + + member.pending_rewards(current_rc).unwrap_or_default() +} + +#[derive(PartialEq, Debug)] +pub enum RewardImbalance { + // There is no reward deficit. + Surplus(Balance), + // There is a reward deficit. + Deficit(Balance), +} + +pub fn pool_pending_rewards(pool: PoolId) -> Result, sp_runtime::DispatchError> { + let bonded_pool = BondedPools::::get(pool).ok_or(Error::::PoolNotFound)?; + let reward_pool = RewardPools::::get(pool).ok_or(Error::::PoolNotFound)?; + + let current_rc = if !bonded_pool.points.is_zero() { + let commission = bonded_pool.commission.current(); + reward_pool.current_reward_counter(pool, bonded_pool.points, commission)?.0 + } else { + Default::default() + }; + + Ok(PoolMembers::::iter() + .filter(|(_, d)| d.pool_id == pool) + .map(|(_, d)| d.pending_rewards(current_rc).unwrap_or_default()) + .fold(0u32.into(), |acc: BalanceOf, x| acc.saturating_add(x))) +} + +pub fn reward_imbalance(pool: PoolId) -> RewardImbalance { + let pending_rewards = pool_pending_rewards(pool).expect("pool should exist"); + let current_balance = RewardPool::::current_balance(pool); + + if pending_rewards > current_balance { + RewardImbalance::Deficit(pending_rewards - current_balance) + } else { + RewardImbalance::Surplus(current_balance - pending_rewards) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index d0fe4e40a18b75d90b639271f90b249596208d84..2749e89ecff33659dc96d2ddae9f3195e557a645 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -40,13 +40,13 @@ pub const DEFAULT_ROLES: PoolRoles = PoolRoles { depositor: 10, root: Some(900), nominator: Some(901), bouncer: Some(902) }; fn deposit_rewards(r: u128) { - let b = Balances::free_balance(&default_reward_account()).checked_add(r).unwrap(); - Balances::make_free_balance_be(&default_reward_account(), b); + let b = Currency::free_balance(&default_reward_account()).checked_add(r).unwrap(); + Currency::set_balance(&default_reward_account(), b); } fn remove_rewards(r: u128) { - let b = Balances::free_balance(&default_reward_account()).checked_sub(r).unwrap(); - Balances::make_free_balance_be(&default_reward_account(), b); + let b = Currency::free_balance(&default_reward_account()).checked_sub(r).unwrap(); + Currency::set_balance(&default_reward_account(), b); } #[test] @@ -59,6 +59,9 @@ fn test_setup_works() { assert_eq!(StakingMock::bonding_duration(), 3); assert!(Metadata::::contains_key(1)); + // initial member. + assert_eq!(TotalValueLocked::::get(), 10); + let last_pool = LastPoolId::::get(); assert_eq!( BondedPool::::get(last_pool).unwrap(), @@ -99,7 +102,7 @@ fn test_setup_works() { assert!(Nominations::get().is_none()); // reward account should have an initial ED in it. - assert_eq!(Balances::free_balance(&reward_account), Balances::minimum_balance()); + assert_eq!(Currency::free_balance(&reward_account), Currency::minimum_balance()); }) } @@ -218,10 +221,7 @@ mod bonded_pool { // slash half of the pool's balance. expected result of `fn api_points_to_balance` // to be 1/2 of the pool's balance. - StakingMock::set_bonded_balance( - default_bonded_account(), - Pools::depositor_min_bond() / 2, - ); + StakingMock::slash_by(1, Pools::depositor_min_bond() / 2); assert_eq!(Pallet::::api_points_to_balance(1, 10), 5); // if pool does not exist, points to balance ratio is 0. @@ -238,10 +238,7 @@ mod bonded_pool { // slash half of the pool's balance. expect result of `fn api_balance_to_points` // to be 2 * of the balance to add to the pool. - StakingMock::set_bonded_balance( - default_bonded_account(), - Pools::depositor_min_bond() / 2, - ); + StakingMock::slash_by(1, Pools::depositor_min_bond() / 2); assert_eq!(Pallet::::api_balance_to_points(1, 10), 20); // if pool does not exist, balance to points ratio is 0. @@ -298,30 +295,168 @@ mod bonded_pool { } mod reward_pool { + use super::*; + use crate::mock::RewardImbalance::{Deficit, Surplus}; + #[test] - fn current_balance_only_counts_balance_over_existential_deposit() { - use super::*; + fn ed_change_causes_reward_deficit() { + ExtBuilder::default().max_members_per_pool(Some(5)).build_and_execute(|| { + // original ED + ExistentialDeposit::set(5); - ExtBuilder::default().build_and_execute(|| { - let reward_account = Pools::create_reward_account(2); + // 11 joins the pool + Currency::set_balance(&11, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 90, 1)); - // Given - assert_eq!(Balances::free_balance(&reward_account), 0); + // new delegator does not have any pending rewards + assert_eq!(pending_rewards_for_delegator(11), 0); - // Then - assert_eq!(RewardPool::::current_balance(2), 0); + // give the pool some rewards + deposit_rewards(100); - // Given - Balances::make_free_balance_be(&reward_account, Balances::minimum_balance()); + // all existing delegator has pending rewards + assert_eq!(pending_rewards_for_delegator(11), 90); + assert_eq!(pending_rewards_for_delegator(10), 10); + assert_eq!(reward_imbalance(1), Surplus(0)); - // Then - assert_eq!(RewardPool::::current_balance(2), 0); + // 12 joins the pool. + Currency::set_balance(&12, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(12), 100, 1)); - // Given - Balances::make_free_balance_be(&reward_account, Balances::minimum_balance() + 1); + // Current reward balance is committed to last recorded reward counter of + // the pool before the increase in ED. + let bonded_pool = BondedPools::::get(1).unwrap(); + let reward_pool = RewardPools::::get(1).unwrap(); + assert_eq!( + reward_pool.last_recorded_reward_counter, + reward_pool + .current_reward_counter(1, bonded_pool.points, Perbill::zero()) + .unwrap() + .0 + ); - // Then - assert_eq!(RewardPool::::current_balance(2), 1); + // reward pool before ED increase and reward counter getting committed. + let reward_pool_1 = RewardPools::::get(1).unwrap(); + + // increase ED from 5 to 50 + ExistentialDeposit::set(50); + + // There is now an expected deficit of ed_diff + assert_eq!(reward_imbalance(1), Deficit(45)); + + // 13 joins the pool which commits the reward counter to reward pool. + Currency::set_balance(&13, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(13), 100, 1)); + + // still a deficit + assert_eq!(reward_imbalance(1), Deficit(45)); + + // reward pool after ED increase + let reward_pool_2 = RewardPools::::get(1).unwrap(); + + // last recorded total payout does not decrease even as ED increases. + assert_eq!( + reward_pool_1.last_recorded_total_payouts, + reward_pool_2.last_recorded_total_payouts + ); + + // Topping up pool decreases deficit + deposit_rewards(10); + assert_eq!(reward_imbalance(1), Deficit(35)); + + // top up the pool to remove the deficit + deposit_rewards(35); + // No deficit anymore + assert_eq!(reward_imbalance(1), Surplus(0)); + + // fix the ed deficit + assert_ok!(Currency::mint_into(&10, 45)); + assert_ok!(Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1)); + }); + } + + #[test] + fn ed_adjust_fixes_reward_deficit() { + ExtBuilder::default().max_members_per_pool(Some(5)).build_and_execute(|| { + // Given: pool has a reward deficit + + // original ED + ExistentialDeposit::set(5); + + // 11 joins the pool + Currency::set_balance(&11, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 90, 1)); + + // Pool some rewards + deposit_rewards(100); + + // 12 joins the pool. + Currency::set_balance(&12, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(12), 10, 1)); + + // When: pool ends up in reward deficit + // increase ED + ExistentialDeposit::set(50); + assert_eq!(reward_imbalance(1), Deficit(45)); + + // clear events + pool_events_since_last_call(); + + // Then: Anyone can permissionlessly can adjust ED deposit. + + // make sure caller has enough funds.. + assert_ok!(Currency::mint_into(&99, 100)); + let pre_balance = Currency::free_balance(&99); + // adjust ED + assert_ok!(Pools::adjust_pool_deposit(RuntimeOrigin::signed(99), 1)); + // depositor's balance should decrease by 45 + assert_eq!(Currency::free_balance(&99), pre_balance - 45); + assert_eq!(reward_imbalance(1), Surplus(0)); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::MinBalanceDeficitAdjusted { pool_id: 1, amount: 45 },] + ); + + // Trying to top up again does not work + assert_err!( + Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1), + Error::::NothingToAdjust + ); + + // When: ED is decreased and reward account has excess ED frozen + ExistentialDeposit::set(5); + + // And:: adjust ED deposit is called + let pre_balance = Currency::free_balance(&100); + assert_ok!(Pools::adjust_pool_deposit(RuntimeOrigin::signed(100), 1)); + + // Then: excess ED is claimed by the caller + assert_eq!(Currency::free_balance(&100), pre_balance + 45); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::MinBalanceExcessAdjusted { pool_id: 1, amount: 45 },] + ); + }); + } + + #[test] + fn topping_up_does_not_work_for_pools_with_no_deficit() { + ExtBuilder::default().max_members_per_pool(Some(5)).build_and_execute(|| { + // 11 joins the pool + Currency::set_balance(&11, 500); + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 90, 1)); + + // Pool some rewards + deposit_rewards(100); + assert_eq!(reward_imbalance(1), Surplus(0)); + + // Topping up fails + assert_err!( + Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1), + Error::::NothingToAdjust + ); }); } } @@ -497,14 +632,14 @@ mod join { }; ExtBuilder::default().with_check(0).build_and_execute(|| { // Given - Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); + Currency::set_balance(&11, ExistentialDeposit::get() + 2); assert!(!PoolMembers::::contains_key(11)); + assert_eq!(TotalValueLocked::::get(), 10); // When assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); // Then - assert_eq!( pool_events_since_last_call(), vec![ @@ -513,6 +648,7 @@ mod join { Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, ] ); + assert_eq!(TotalValueLocked::::get(), 12); assert_eq!( PoolMembers::::get(11).unwrap(), @@ -522,10 +658,10 @@ mod join { // Given // The bonded balance is slashed in half - StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 6); + StakingMock::slash_by(1, 6); // And - Balances::make_free_balance_be(&12, ExistentialDeposit::get() + 12); + Currency::set_balance(&12, ExistentialDeposit::get() + 12); assert!(!PoolMembers::::contains_key(12)); // When @@ -534,8 +670,12 @@ mod join { // Then assert_eq!( pool_events_since_last_call(), - vec![Event::Bonded { member: 12, pool_id: 1, bonded: 12, joined: true }] + vec![ + Event::PoolSlashed { pool_id: 1, balance: 6 }, + Event::Bonded { member: 12, pool_id: 1, bonded: 12, joined: true } + ] ); + assert_eq!(TotalValueLocked::::get(), 18); assert_eq!( PoolMembers::::get(12).unwrap(), @@ -661,12 +801,12 @@ mod join { assert_eq!(MaxPoolMembersPerPool::::get(), Some(3)); for i in 1..3 { let account = i + 100; - Balances::make_free_balance_be(&account, 100 + Balances::minimum_balance()); + Currency::set_balance(&account, 100 + Currency::minimum_balance()); assert_ok!(Pools::join(RuntimeOrigin::signed(account), 100, 1)); } - Balances::make_free_balance_be(&103, 100 + Balances::minimum_balance()); + Currency::set_balance(&103, 100 + Currency::minimum_balance()); // Then assert_eq!( @@ -688,7 +828,7 @@ mod join { assert_eq!(PoolMembers::::count(), 3); assert_eq!(MaxPoolMembers::::get(), Some(4)); - Balances::make_free_balance_be(&104, 100 + Balances::minimum_balance()); + Currency::set_balance(&104, 100 + Currency::minimum_balance()); assert_ok!(Pools::create(RuntimeOrigin::signed(104), 100, 104, 104, 104)); let pool_account = BondedPools::::iter() @@ -754,13 +894,13 @@ mod claim_payout { .add_members(vec![(40, 40), (50, 50)]) .build_and_execute(|| { // Given each member currently has a free balance of - Balances::make_free_balance_be(&10, 0); - Balances::make_free_balance_be(&40, 0); - Balances::make_free_balance_be(&50, 0); - let ed = Balances::minimum_balance(); + Currency::set_balance(&10, 0); + Currency::set_balance(&40, 0); + Currency::set_balance(&50, 0); + let ed = Currency::minimum_balance(); // and the reward pool has earned 100 in rewards - assert_eq!(Balances::free_balance(default_reward_account()), ed); + assert_eq!(Currency::free_balance(&default_reward_account()), ed); deposit_rewards(100); let _ = pool_events_since_last_call(); @@ -778,8 +918,8 @@ mod claim_payout { // pool's 'last_recorded_reward_counter' and 'last_recorded_total_payouts' don't // really change unless if someone bonds/unbonds. assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 10)); - assert_eq!(Balances::free_balance(&10), 10); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); + assert_eq!(Currency::free_balance(&10), 10); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 90); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); @@ -791,8 +931,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 1)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 50)); - assert_eq!(Balances::free_balance(&40), 40); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); + assert_eq!(Currency::free_balance(&40), 40); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 50); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); @@ -804,8 +944,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 1)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 100)); - assert_eq!(Balances::free_balance(&50), 50); - assert_eq!(Balances::free_balance(&default_reward_account()), ed); + assert_eq!(Currency::free_balance(&50), 50); + assert_eq!(Currency::free_balance(&default_reward_account()), ed); // Given the reward pool has some new rewards deposit_rewards(50); @@ -820,8 +960,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 1.5)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 105)); - assert_eq!(Balances::free_balance(&10), 10 + 5); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); + assert_eq!(Currency::free_balance(&10), 10 + 5); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 45); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); @@ -833,12 +973,12 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 1.5)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 125)); - assert_eq!(Balances::free_balance(&40), 40 + 20); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + assert_eq!(Currency::free_balance(&40), 40 + 20); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 25); // Given del 50 hasn't claimed and the reward pools has just earned 50 deposit_rewards(50); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 75); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); @@ -850,8 +990,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 2.0)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 175)); - assert_eq!(Balances::free_balance(&50), 50 + 50); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); + assert_eq!(Currency::free_balance(&50), 50 + 50); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 25); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -863,12 +1003,12 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 2)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 180)); - assert_eq!(Balances::free_balance(&10), 15 + 5); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 20); + assert_eq!(Currency::free_balance(&10), 15 + 5); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 20); // Given del 40 hasn't claimed and the reward pool has just earned 400 deposit_rewards(400); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 420); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -882,12 +1022,12 @@ mod claim_payout { // We expect a payout of 40 assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 6)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 220)); - assert_eq!(Balances::free_balance(&10), 20 + 40); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 380); + assert_eq!(Currency::free_balance(&10), 20 + 40); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 380); // Given del 40 + del 50 haven't claimed and the reward pool has earned 20 deposit_rewards(20); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 400); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -899,8 +1039,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 6.2)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 222)); - assert_eq!(Balances::free_balance(&10), 60 + 2); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); + assert_eq!(Currency::free_balance(&10), 60 + 2); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 398); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); @@ -912,8 +1052,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 6.2)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 410)); - assert_eq!(Balances::free_balance(&40), 60 + 188); - assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); + assert_eq!(Currency::free_balance(&40), 60 + 188); + assert_eq!(Currency::free_balance(&default_reward_account()), ed + 210); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); @@ -925,8 +1065,8 @@ mod claim_payout { ); assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 6.2)); assert_eq!(RewardPools::::get(1).unwrap(), rew(0, 0, 620)); - assert_eq!(Balances::free_balance(&50), 100 + 210); - assert_eq!(Balances::free_balance(&default_reward_account()), ed); + assert_eq!(Currency::free_balance(&50), 100 + 210); + assert_eq!(Currency::free_balance(&default_reward_account()), ed); }); } @@ -960,7 +1100,7 @@ mod claim_payout { Pools::get_member_with_pools(&10).unwrap(); // top up commission payee account to existential deposit - let _ = Balances::deposit_creating(&2, 5); + let _ = Currency::set_balance(&2, 5); // Set a commission pool 1 to 75%, with a payee set to `2` assert_ok!(Pools::set_commission( @@ -1010,7 +1150,7 @@ mod claim_payout { ExtBuilder::default().build_and_execute(|| { let (mut member, mut bonded_pool, mut reward_pool) = Pools::get_member_with_pools(&10).unwrap(); - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); let payout = Pools::do_reward_payout(&10, &mut member, &mut bonded_pool, &mut reward_pool) @@ -1060,7 +1200,7 @@ mod claim_payout { assert_eq!(member, del(1.5)); // Given the pool has earned no new rewards - Balances::make_free_balance_be(&default_reward_account(), ed); + Currency::set_balance(&default_reward_account(), ed); // When let payout = @@ -1267,7 +1407,7 @@ mod claim_payout { deposit_rewards(10); // 20 joins afterwards. - Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); + Currency::set_balance(&20, Currency::minimum_balance() + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); // reward by another 20 @@ -1310,7 +1450,7 @@ mod claim_payout { ExtBuilder::default().build_and_execute(|| { deposit_rewards(3); - Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); + Currency::set_balance(&20, Currency::minimum_balance() + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); deposit_rewards(6); @@ -1363,16 +1503,16 @@ mod claim_payout { #[test] fn rewards_distribution_is_fair_3() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); deposit_rewards(30); - Balances::make_free_balance_be(&20, ed + 10); + Currency::set_balance(&20, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); deposit_rewards(100); - Balances::make_free_balance_be(&30, ed + 10); + Currency::set_balance(&30, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); deposit_rewards(60); @@ -1416,14 +1556,14 @@ mod claim_payout { #[test] fn pending_rewards_per_member_works() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); assert_eq!(Pools::api_pending_rewards(10), Some(0)); deposit_rewards(30); assert_eq!(Pools::api_pending_rewards(10), Some(30)); assert_eq!(Pools::api_pending_rewards(20), None); - Balances::make_free_balance_be(&20, ed + 10); + Currency::set_balance(&20, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); assert_eq!(Pools::api_pending_rewards(10), Some(30)); @@ -1435,7 +1575,7 @@ mod claim_payout { assert_eq!(Pools::api_pending_rewards(20), Some(50)); assert_eq!(Pools::api_pending_rewards(30), None); - Balances::make_free_balance_be(&30, ed + 10); + Currency::set_balance(&30, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); @@ -1469,11 +1609,11 @@ mod claim_payout { #[test] fn rewards_distribution_is_fair_bond_extra() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); - Balances::make_free_balance_be(&20, ed + 20); + Currency::set_balance(&20, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - Balances::make_free_balance_be(&30, ed + 20); + Currency::set_balance(&30, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); deposit_rewards(40); @@ -1521,9 +1661,9 @@ mod claim_payout { #[test] fn rewards_distribution_is_fair_unbond() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); - Balances::make_free_balance_be(&20, ed + 20); + Currency::set_balance(&20, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); deposit_rewards(30); @@ -1566,11 +1706,11 @@ mod claim_payout { #[test] fn unclaimed_reward_is_safe() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); - Balances::make_free_balance_be(&20, ed + 20); + Currency::set_balance(&20, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - Balances::make_free_balance_be(&30, ed + 20); + Currency::set_balance(&30, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 @@ -1635,9 +1775,9 @@ mod claim_payout { #[test] fn bond_extra_and_delayed_claim() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); - Balances::make_free_balance_be(&20, ed + 200); + Currency::set_balance(&20, ed + 200); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 @@ -1710,7 +1850,7 @@ mod claim_payout { deposit_rewards(60); // create pool 2 - Balances::make_free_balance_be(&20, 100); + Currency::set_balance(&20, 100); assert_ok!(Pools::create(RuntimeOrigin::signed(20), 10, 20, 20, 20)); // has no impact -- initial @@ -1723,17 +1863,17 @@ mod claim_payout { assert_eq!(member_20.last_recorded_reward_counter, 0.into()); // pre-fund the reward account of pool id 3 with some funds. - Balances::make_free_balance_be(&Pools::create_reward_account(3), 10); + Currency::set_balance(&Pools::create_reward_account(3), 10); // create pool 3 - Balances::make_free_balance_be(&30, 100); + Currency::set_balance(&30, 100); assert_ok!(Pools::create(RuntimeOrigin::signed(30), 10, 30, 30, 30)); // reward counter is still the same. let (member_30, _, reward_pool_30) = Pools::get_member_with_pools(&30).unwrap(); assert_eq!( - Balances::free_balance(&Pools::create_reward_account(3)), - 10 + Balances::minimum_balance() + Currency::free_balance(&Pools::create_reward_account(3)), + 10 + Currency::minimum_balance() ); assert_eq!(reward_pool_30.last_recorded_total_payouts, 0); @@ -1766,7 +1906,7 @@ mod claim_payout { MaxPoolMembers::::set(None); MaxPoolMembersPerPool::::set(None); let join = |x, y| { - Balances::make_free_balance_be(&x, y + Balances::minimum_balance()); + Currency::set_balance(&x, y + Currency::minimum_balance()); assert_ok!(Pools::join(RuntimeOrigin::signed(x), y, 1)); }; @@ -1844,8 +1984,8 @@ mod claim_payout { assert_eq!(member_10.last_recorded_reward_counter, 0.into()); } - Balances::make_free_balance_be(&10, 100); - Balances::make_free_balance_be(&20, 100); + Currency::set_balance(&10, 100); + Currency::set_balance(&20, 100); // 10 bonds extra without any rewards. { @@ -2063,10 +2203,10 @@ mod claim_payout { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { // initial balance of 10. - assert_eq!(Balances::free_balance(&10), 35); + assert_eq!(Currency::free_balance(&10), 35); assert_eq!( - Balances::free_balance(&default_reward_account()), - Balances::minimum_balance() + Currency::free_balance(&default_reward_account()), + Currency::minimum_balance() ); // some rewards come in. @@ -2115,7 +2255,7 @@ mod claim_payout { assert!(!Metadata::::contains_key(1)); // original ed + ed put into reward account + reward + bond + dust. - assert_eq!(Balances::free_balance(&10), 35 + 5 + 13 + 10 + 1); + assert_eq!(Currency::free_balance(&10), 35 + 5 + 13 + 10 + 1); }) } @@ -2131,7 +2271,7 @@ mod claim_payout { .add_members(vec![(20, 1500 * unit), (21, 2500 * unit), (22, 5000 * unit)]) .build_and_execute(|| { // some rewards come in. - assert_eq!(Balances::free_balance(&default_reward_account()), unit); + assert_eq!(Currency::free_balance(&default_reward_account()), unit); deposit_rewards(unit / 1000); // everyone claims @@ -2180,14 +2320,14 @@ mod claim_payout { #[test] fn claim_payout_other_works() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { - Balances::make_free_balance_be(&default_reward_account(), 8); + Currency::set_balance(&default_reward_account(), 8); // ... of which only 3 are claimable to make sure the reward account does not die. let claimable_reward = 8 - ExistentialDeposit::get(); // NOTE: easier to read if we use 3, so let's use the number instead of variable. assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); // given - assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Currency::free_balance(&10), 35); // Permissioned by default assert_noop!( @@ -2202,8 +2342,8 @@ mod claim_payout { assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); // then - assert_eq!(Balances::free_balance(10), 36); - assert_eq!(Balances::free_balance(&default_reward_account()), 7); + assert_eq!(Currency::free_balance(&10), 36); + assert_eq!(Currency::free_balance(&default_reward_account()), 7); }) } } @@ -2221,11 +2361,15 @@ mod unbond { .min_join_bond(10) .add_members(vec![(20, 20)]) .build_and_execute(|| { + assert_eq!(TotalValueLocked::::get(), 30); // can unbond to above limit assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 5); + // tvl remains unchanged. + assert_eq!(TotalValueLocked::::get(), 30); + // cannot go to below 10: assert_noop!( Pools::unbond(RuntimeOrigin::signed(20), 20, 10), @@ -2530,11 +2674,12 @@ mod unbond { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { - let ed = Balances::minimum_balance(); - // Given a slash from 600 -> 100 - StakingMock::set_bonded_balance(default_bonded_account(), 100); + let ed = Currency::minimum_balance(); + // Given a slash from 600 -> 500 + StakingMock::slash_by(1, 500); + // and unclaimed rewards of 600. - Balances::make_free_balance_be(&default_reward_account(), ed + 600); + Currency::set_balance(&default_reward_account(), ed + 600); // When assert_ok!(fully_unbond_permissioned(40)); @@ -2564,8 +2709,9 @@ mod unbond { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::PoolSlashed { pool_id: 1, balance: 100 }, Event::PaidOut { member: 40, pool_id: 1, payout: 40 }, - Event::Unbonded { member: 40, pool_id: 1, points: 6, balance: 6, era: 3 } + Event::Unbonded { member: 40, pool_id: 1, balance: 6, points: 6, era: 3 } ] ); @@ -2574,7 +2720,7 @@ mod unbond { PoolMembers::::get(40).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6) ); - assert_eq!(Balances::free_balance(&40), 40 + 40); // We claim rewards when unbonding + assert_eq!(Currency::free_balance(&40), 40 + 40); // We claim rewards when unbonding // When unsafe_set_state(1, PoolState::Destroying); @@ -2603,7 +2749,7 @@ mod unbond { PoolMembers::::get(550).unwrap().unbonding_eras, member_unbonding_eras!(3 => 92) ); - assert_eq!(Balances::free_balance(&550), 550 + 550); + assert_eq!(Currency::free_balance(&550), 550 + 550); assert_eq!( pool_events_since_last_call(), vec![ @@ -2644,7 +2790,7 @@ mod unbond { ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!(Balances::free_balance(&550), 550 + 550 + 92); + assert_eq!(Currency::free_balance(&550), 550 + 550 + 92); assert_eq!( pool_events_since_last_call(), vec![ @@ -2725,6 +2871,7 @@ mod unbond { ); // When the root kicks then its ok + // Account with ID 100 is kicked. assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(900), 100)); assert_eq!( @@ -2745,6 +2892,7 @@ mod unbond { ); // When the bouncer kicks then its ok + // Account with ID 200 is kicked. assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(902), 200)); assert_eq!( @@ -2783,7 +2931,7 @@ mod unbond { ); assert_eq!( *UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), - 100 + 200 + vec![(3, 100), (3, 200)], ); }); } @@ -2882,7 +3030,10 @@ mod unbond { } ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!(*UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), 10); + assert_eq!( + *UnbondingBalanceMap::get().get(&default_bonded_account()).unwrap(), + vec![(6, 10)] + ); }); } @@ -3160,7 +3311,7 @@ mod unbond { assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); // slash the default pool - StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 5); + StakingMock::slash_by(1, 5); // cannot unbond even 7, because the value of shares is now less. assert_noop!( @@ -3173,14 +3324,11 @@ mod unbond { #[test] fn every_unbonding_triggers_payout() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { - let initial_reward_account = Balances::free_balance(default_reward_account()); - assert_eq!(initial_reward_account, Balances::minimum_balance()); + let initial_reward_account = Currency::free_balance(&default_reward_account()); + assert_eq!(initial_reward_account, Currency::minimum_balance()); assert_eq!(initial_reward_account, 5); - Balances::make_free_balance_be( - &default_reward_account(), - 4 * Balances::minimum_balance(), - ); + Currency::set_balance(&default_reward_account(), 4 * Currency::minimum_balance()); assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!( @@ -3196,10 +3344,7 @@ mod unbond { ); CurrentEra::set(1); - Balances::make_free_balance_be( - &default_reward_account(), - 4 * Balances::minimum_balance(), - ); + Currency::set_balance(&default_reward_account(), 4 * Currency::minimum_balance()); assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 3)); assert_eq!( @@ -3212,10 +3357,7 @@ mod unbond { ); CurrentEra::set(2); - Balances::make_free_balance_be( - &default_reward_account(), - 4 * Balances::minimum_balance(), - ); + Currency::set_balance(&default_reward_account(), 4 * Currency::minimum_balance()); assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!( @@ -3239,21 +3381,58 @@ mod pool_withdraw_unbonded { #[test] fn pool_withdraw_unbonded_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().add_members(vec![(20, 10)]).build_and_execute(|| { // Given 10 unbond'ed directly against the pool account - assert_ok!(StakingMock::unbond(&default_bonded_account(), 5)); - // and the pool account only has 10 balance - assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(5)); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(10)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 20); // When + CurrentEra::set(StakingMock::current_era() + StakingMock::bonding_duration() + 1); assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); - // Then there unbonding balance is no longer locked - assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(5)); - assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(5)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + // Then their unbonding balance is no longer locked + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + }); + } + #[test] + fn pool_withdraw_unbonded_creates_tvl_diff() { + ExtBuilder::default().add_members(vec![(20, 10)]).build_and_execute(|| { + // Given 10 unbond'ed directly against the pool account + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); + assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(TotalValueLocked::::get(), 20); + + // When + CurrentEra::set(StakingMock::current_era() + StakingMock::bonding_duration() + 1); + assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); + assert_eq!(TotalValueLocked::::get(), 15); + + let member_balance = PoolMembers::::iter() + .map(|(_, member)| member.total_balance()) + .reduce(|acc, total_balance| acc + total_balance) + .unwrap_or_default(); + + // Then their unbonding balance is no longer locked + assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); + assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); + assert_eq!(Currency::free_balance(&default_bonded_account()), 20); + + // The difference between TVL and member_balance is exactly the difference between + // `total_stake` and the `free_balance`. + // This relation is not guaranteed in the wild as arbitrary transfers towards + // `free_balance` can be made to the pool that are not accounted for. + let non_locked_balance = Balances::free_balance(&default_bonded_account()) - + StakingMock::total_stake(&default_bonded_account()).unwrap(); + assert_eq!(member_balance, TotalValueLocked::::get() + non_locked_balance); }); } } @@ -3274,7 +3453,7 @@ mod withdraw_unbonded { assert_eq!(StakingMock::bonding_duration(), 3); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550)); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 600); + assert_eq!(Currency::free_balance(&default_bonded_account()), 600); let mut current_era = 1; CurrentEra::set(current_era); @@ -3283,24 +3462,33 @@ mod withdraw_unbonded { let unbond_pool = sub_pools.with_era.get_mut(&3).unwrap(); // Sanity check assert_eq!(*unbond_pool, UnbondPool { points: 550 + 40, balance: 550 + 40 }); + assert_eq!(TotalValueLocked::::get(), 600); // Simulate a slash to the pool with_era(current_era), decreasing the balance by // half { unbond_pool.balance /= 2; // 295 SubPoolsStorage::::insert(1, sub_pools); + + // Adjust the TVL for this non-api usage (direct sub-pool modification) + TotalValueLocked::::mutate(|x| *x -= 295); + // Update the equivalent of the unbonding chunks for the `StakingMock` let mut x = UnbondingBalanceMap::get(); - *x.get_mut(&default_bonded_account()).unwrap() /= 5; + x.get_mut(&default_bonded_account()) + .unwrap() + .get_mut(current_era as usize) + .unwrap() + .1 /= 2; UnbondingBalanceMap::set(&x); - Balances::make_free_balance_be( + + Currency::set_balance( &default_bonded_account(), - Balances::free_balance(&default_bonded_account()) / 2, // 300 - ); - StakingMock::set_bonded_balance( - default_bonded_account(), - StakingMock::active_stake(&default_bonded_account()).unwrap() / 2, + Currency::free_balance(&default_bonded_account()) / 2, // 300 ); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 10); + StakingMock::slash_by(1, 5); + assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 5); }; // Advance the current_era to ensure all `with_era` pools will be merged into @@ -3336,11 +3524,12 @@ mod withdraw_unbonded { era: 3 }, Event::Unbonded { member: 40, pool_id: 1, points: 40, balance: 40, era: 3 }, + Event::PoolSlashed { pool_id: 1, balance: 5 } ] ); assert_eq!( balances_events_since_last_call(), - vec![BEvent::BalanceSet { who: default_bonded_account(), free: 300 }] + vec![BEvent::Burned { who: default_bonded_account(), amount: 300 }] ); // When @@ -3407,6 +3596,7 @@ mod withdraw_unbonded { balances_events_since_last_call(), vec![ BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, + BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] ); @@ -3422,8 +3612,8 @@ mod withdraw_unbonded { // Given // current bond is 600, we slash it all to 300. - StakingMock::set_bonded_balance(default_bonded_account(), 300); - Balances::make_free_balance_be(&default_bonded_account(), 300); + StakingMock::slash_by(1, 300); + Currency::set_balance(&default_bonded_account(), 300); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300)); assert_ok!(fully_unbond_permissioned(40)); @@ -3442,6 +3632,7 @@ mod withdraw_unbonded { Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, Event::Bonded { member: 40, pool_id: 1, bonded: 40, joined: true }, Event::Bonded { member: 550, pool_id: 1, bonded: 550, joined: true }, + Event::PoolSlashed { pool_id: 1, balance: 300 }, Event::Unbonded { member: 40, pool_id: 1, balance: 20, points: 20, era: 3 }, Event::Unbonded { member: 550, @@ -3454,7 +3645,7 @@ mod withdraw_unbonded { ); assert_eq!( balances_events_since_last_call(), - vec![BEvent::BalanceSet { who: default_bonded_account(), free: 300 },] + vec![BEvent::Burned { who: default_bonded_account(), amount: 300 },] ); CurrentEra::set(StakingMock::bonding_duration()); @@ -3517,8 +3708,8 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then - assert_eq!(Balances::free_balance(&10), 10 + 35); - assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + assert_eq!(Currency::free_balance(&10), 10 + 35); + assert_eq!(Currency::free_balance(&default_bonded_account()), 0); // in this test 10 also gets a fair share of the slash, because the slash was // applied to the bonded account. @@ -3536,6 +3727,7 @@ mod withdraw_unbonded { balances_events_since_last_call(), vec![ BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, + BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] ); @@ -3546,14 +3738,14 @@ mod withdraw_unbonded { fn withdraw_unbonded_handles_faulty_sub_pool_accounting() { ExtBuilder::default().build_and_execute(|| { // Given - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Balances::free_balance(&10), 35); - assert_eq!(Balances::free_balance(&default_bonded_account()), 10); + assert_eq!(Currency::minimum_balance(), 5); + assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(Currency::free_balance(&default_bonded_account()), 10); unsafe_set_state(1, PoolState::Destroying); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); // Simulate a slash that is not accounted for in the sub pools. - Balances::make_free_balance_be(&default_bonded_account(), 5); + Currency::set_balance(&default_bonded_account(), 5); assert_eq!( SubPoolsStorage::::get(1).unwrap().with_era, //------------------------------balance decrease is not account for @@ -3566,8 +3758,8 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // Then - assert_eq!(Balances::free_balance(10), 10 + 35); - assert_eq!(Balances::free_balance(&default_bonded_account()), 0); + assert_eq!(Currency::free_balance(&10), 10 + 35); + assert_eq!(Currency::free_balance(&default_bonded_account()), 0); }); } @@ -3673,8 +3865,8 @@ mod withdraw_unbonded { // Can kick as bouncer assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 200, 0)); - assert_eq!(Balances::free_balance(100), 100 + 100); - assert_eq!(Balances::free_balance(200), 200 + 200); + assert_eq!(Currency::free_balance(&100), 100 + 100); + assert_eq!(Currency::free_balance(&200), 200 + 200); assert!(!PoolMembers::::contains_key(100)); assert!(!PoolMembers::::contains_key(200)); assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default()); @@ -3709,7 +3901,7 @@ mod withdraw_unbonded { } ); CurrentEra::set(StakingMock::bonding_duration()); - assert_eq!(Balances::free_balance(100), 100); + assert_eq!(Currency::free_balance(&100), 100); // Cannot permissionlessly withdraw assert_noop!( @@ -3720,11 +3912,11 @@ mod withdraw_unbonded { // Given unsafe_set_state(1, PoolState::Destroying); - // Can permissionlesly withdraw a member that is not the depositor + // Can permissionlessly withdraw a member that is not the depositor assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(420), 100, 0)); assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); - assert_eq!(Balances::free_balance(100), 100 + 100); + assert_eq!(Currency::free_balance(&100), 100 + 100); assert!(!PoolMembers::::contains_key(100)); assert_eq!( pool_events_since_last_call(), @@ -3920,6 +4112,7 @@ mod withdraw_unbonded { #[test] fn full_multi_step_withdrawing_non_depositor() { ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { + assert_eq!(TotalValueLocked::::get(), 110); // given assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 75)); assert_eq!( @@ -3927,6 +4120,9 @@ mod withdraw_unbonded { member_unbonding_eras!(3 => 75) ); + // tvl unchanged. + assert_eq!(TotalValueLocked::::get(), 110); + // progress one era and unbond the leftover. CurrentEra::set(1); assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 25)); @@ -3939,6 +4135,8 @@ mod withdraw_unbonded { Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0), Error::::CannotWithdrawAny ); + // tvl unchanged. + assert_eq!(TotalValueLocked::::get(), 110); // now the 75 should be free. CurrentEra::set(3); @@ -3958,6 +4156,8 @@ mod withdraw_unbonded { PoolMembers::::get(100).unwrap().unbonding_eras, member_unbonding_eras!(4 => 25) ); + // tvl updated + assert_eq!(TotalValueLocked::::get(), 35); // the 25 should be free now, and the member removed. CurrentEra::set(4); @@ -4258,20 +4458,22 @@ mod withdraw_unbonded { mod create { use super::*; + use frame_support::traits::fungible::InspectFreeze; #[test] fn create_works() { ExtBuilder::default().build_and_execute(|| { // next pool id is 2. let next_pool_stash = Pools::create_bonded_account(2); - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); + assert_eq!(TotalValueLocked::::get(), 10); assert!(!BondedPools::::contains_key(2)); assert!(!RewardPools::::contains_key(2)); assert!(!PoolMembers::::contains_key(11)); assert_err!(StakingMock::active_stake(&next_pool_stash), "balance not found"); - Balances::make_free_balance_be(&11, StakingMock::minimum_nominator_bond() + ed); + Currency::set_balance(&11, StakingMock::minimum_nominator_bond() + ed); assert_ok!(Pools::create( RuntimeOrigin::signed(11), StakingMock::minimum_nominator_bond(), @@ -4279,8 +4481,9 @@ mod create { 456, 789 )); + assert_eq!(TotalValueLocked::::get(), 10 + StakingMock::minimum_nominator_bond()); - assert_eq!(Balances::free_balance(&11), 0); + assert_eq!(Currency::free_balance(&11), 0); assert_eq!( PoolMembers::::get(11).unwrap(), PoolMember { @@ -4316,6 +4519,15 @@ mod create { RewardPool { ..Default::default() } ); + // make sure ED is frozen on pool creation. + assert_eq!( + Currency::balance_frozen( + &FreezeReason::PoolMinBalance.into(), + &default_reward_account() + ), + Currency::minimum_balance() + ); + assert_eq!( pool_events_since_last_call(), vec![ @@ -4380,10 +4592,10 @@ mod create { assert_eq!(PoolMembers::::count(), 1); MaxPools::::put(3); MaxPoolMembers::::put(1); - Balances::make_free_balance_be(&11, 5 + 20); + Currency::set_balance(&11, 5 + 20); // Then - let create = RuntimeCall::Pools(crate::Call::::create { + let create = RuntimeCall::Pools(Call::::create { amount: 20, root: 11, nominator: 11, @@ -4399,9 +4611,9 @@ mod create { #[test] fn create_with_pool_id_works() { ExtBuilder::default().build_and_execute(|| { - let ed = Balances::minimum_balance(); + let ed = Currency::minimum_balance(); - Balances::make_free_balance_be(&11, StakingMock::minimum_nominator_bond() + ed); + Currency::set_balance(&11, StakingMock::minimum_nominator_bond() + ed); assert_ok!(Pools::create( RuntimeOrigin::signed(11), StakingMock::minimum_nominator_bond(), @@ -4410,7 +4622,7 @@ mod create { 789 )); - assert_eq!(Balances::free_balance(&11), 0); + assert_eq!(Currency::free_balance(&11), 0); // delete the initial pool created, then pool_Id `1` will be free assert_noop!( @@ -4439,7 +4651,7 @@ mod create { fn set_claimable_actor_works() { ExtBuilder::default().build_and_execute(|| { // Given - Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); + Currency::set_balance(&11, ExistentialDeposit::get() + 2); assert!(!PoolMembers::::contains_key(11)); // When @@ -4560,16 +4772,17 @@ mod set_state { // Given unsafe_set_state(1, PoolState::Open); - let mut bonded_pool = BondedPool::::get(1).unwrap(); - bonded_pool.points = 100; - bonded_pool.put(); + // slash the pool to the point that `max_points_to_balance` ratio is + // surpassed. Making this pool destroyable by anyone. + StakingMock::slash_by(1, 10); + // When assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); // Given - Balances::make_free_balance_be(&default_bonded_account(), Balance::max_value() / 10); + Currency::set_balance(&default_bonded_account(), Balance::MAX / 10); unsafe_set_state(1, PoolState::Open); // When assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); @@ -4588,6 +4801,7 @@ mod set_state { pool_events_since_last_call(), vec![ Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + Event::PoolSlashed { pool_id: 1, balance: 0 }, Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, Event::StateChanged { pool_id: 1, new_state: PoolState::Destroying } ] @@ -4693,18 +4907,18 @@ mod bond_extra { fn bond_extra_from_free_balance_creator() { ExtBuilder::default().build_and_execute(|| { // 10 is the owner and a member in pool 1, give them some more funds. - Balances::make_free_balance_be(&10, 100); + Currency::set_balance(&10, 100); // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Balances::free_balance(10), 100); + assert_eq!(Currency::free_balance(&10), 100); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // then - assert_eq!(Balances::free_balance(10), 90); + assert_eq!(Currency::free_balance(&10), 90); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 20); @@ -4721,7 +4935,7 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20))); // then - assert_eq!(Balances::free_balance(10), 70); + assert_eq!(Currency::free_balance(&10), 70); assert_eq!(PoolMembers::::get(10).unwrap().points, 40); assert_eq!(BondedPools::::get(1).unwrap().points, 40); @@ -4737,20 +4951,20 @@ mod bond_extra { ExtBuilder::default().build_and_execute(|| { // put some money in the reward account, all of which will belong to 10 as the only // member of the pool. - Balances::make_free_balance_be(&default_reward_account(), 7); + Currency::set_balance(&default_reward_account(), 7); // ... if which only 2 is claimable to make sure the reward account does not die. let claimable_reward = 7 - ExistentialDeposit::get(); // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Currency::free_balance(&10), 35); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then - assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Currency::free_balance(&10), 35); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); @@ -4776,7 +4990,7 @@ mod bond_extra { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { // put some money in the reward account, all of which will belong to 10 as the only // member of the pool. - Balances::make_free_balance_be(&default_reward_account(), 8); + Currency::set_balance(&default_reward_account(), 8); // ... if which only 3 is claimable to make sure the reward account does not die. let claimable_reward = 8 - ExistentialDeposit::get(); // NOTE: easier to read of we use 3, so let's use the number instead of variable. @@ -4786,15 +5000,19 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Balances::free_balance(10), 35); - assert_eq!(Balances::free_balance(20), 20); + + assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(TotalValueLocked::::get(), 30); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); - assert_eq!(Balances::free_balance(&default_reward_account()), 7); + assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(TotalValueLocked::::get(), 31); + // 10's share of the reward is 1/3, since they gave 10/30 of the total shares. assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); @@ -4803,7 +5021,9 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); // then - assert_eq!(Balances::free_balance(20), 20); + assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(TotalValueLocked::::get(), 33); + // 20's share of the rewards is the other 2/3 of the rewards, since they have 20/30 of // the shares assert_eq!(PoolMembers::::get(20).unwrap().points, 20 + 2); @@ -4827,7 +5047,7 @@ mod bond_extra { #[test] fn bond_extra_other() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { - Balances::make_free_balance_be(&default_reward_account(), 8); + Currency::set_balance(&default_reward_account(), 8); // ... of which only 3 are claimable to make sure the reward account does not die. let claimable_reward = 8 - ExistentialDeposit::get(); // NOTE: easier to read if we use 3, so let's use the number instead of variable. @@ -4837,8 +5057,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Balances::free_balance(10), 35); - assert_eq!(Balances::free_balance(20), 20); + assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(Currency::free_balance(&20), 20); // Permissioned by default assert_noop!( @@ -4851,10 +5071,10 @@ mod bond_extra { ClaimPermission::PermissionlessAll )); assert_ok!(Pools::bond_extra_other(RuntimeOrigin::signed(50), 10, BondExtra::Rewards)); - assert_eq!(Balances::free_balance(&default_reward_account()), 7); + assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Currency::free_balance(&10), 35); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); @@ -4872,8 +5092,8 @@ mod bond_extra { )); // then - assert_eq!(Balances::free_balance(20), 12); - assert_eq!(Balances::free_balance(&default_reward_account()), 5); + assert_eq!(Currency::free_balance(&20), 12); + assert_eq!(Currency::free_balance(&default_reward_account()), 5); assert_eq!(PoolMembers::::get(20).unwrap().points, 30); assert_eq!(BondedPools::::get(1).unwrap().points, 41); }) @@ -5107,7 +5327,7 @@ mod reward_counter_precision { ] ); - Balances::make_free_balance_be(&20, tiny_bond); + Currency::set_balance(&20, tiny_bond); assert_ok!(Pools::join(RuntimeOrigin::signed(20), tiny_bond / 2, 1)); // Suddenly, add a shit ton of rewards. @@ -5154,7 +5374,7 @@ mod reward_counter_precision { // some whale now joins with the other half ot the total issuance. This will bloat all // the calculation regarding current reward counter. - Balances::make_free_balance_be(&20, pool_bond * 2); + Currency::set_balance(&20, pool_bond * 2); assert_ok!(Pools::join(RuntimeOrigin::signed(20), pool_bond, 1)); assert_eq!( @@ -5176,7 +5396,7 @@ mod reward_counter_precision { ); // now let a small member join with 10 DOTs. - Balances::make_free_balance_be(&30, 20 * DOT); + Currency::set_balance(&30, 20 * DOT); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10 * DOT, 1)); // and give a reasonably small reward to the pool. @@ -5213,13 +5433,13 @@ mod reward_counter_precision { ); // slash this pool by 99% of that. - StakingMock::set_bonded_balance(default_bonded_account(), DOT + pool_bond / 100); + StakingMock::slash_by(1, pool_bond * 99 / 100); // some whale now joins with the other half ot the total issuance. This will trigger an // overflow. This test is actually a bit too lenient because all the reward counters are // set to zero. In other tests that we want to assert a scenario won't fail, we should // also set the reward counters to some large value. - Balances::make_free_balance_be(&20, pool_bond * 2); + Currency::set_balance(&20, pool_bond * 2); assert_err!( Pools::join(RuntimeOrigin::signed(20), pool_bond, 1), Error::::OverflowRisk @@ -5248,7 +5468,7 @@ mod reward_counter_precision { ); // and have a tiny fish join the pool as well.. - Balances::make_free_balance_be(&20, 20 * DOT); + Currency::set_balance(&20, 20 * DOT); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards @@ -5316,7 +5536,7 @@ mod reward_counter_precision { ); // and have a tiny fish join the pool as well.. - Balances::make_free_balance_be(&20, 20 * DOT); + Currency::set_balance(&20, 20 * DOT); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards @@ -5602,7 +5822,7 @@ mod commission { let member = 10; // Set the pool commission to 10% to test commission shares. Pool is topped up 40 points - // and `member` immediately claims their pending rewards. Reward pooll should still have + // and `member` immediately claims their pending rewards. Reward pool should still have // 10% share. // Given: @@ -6352,7 +6572,7 @@ mod commission { let pool_id = 1; // top up commission payee account to existential deposit - let _ = Balances::deposit_creating(&2, 5); + let _ = Currency::set_balance(&2, 5); // Set a commission pool 1 to 33%, with a payee set to `2` assert_ok!(Pools::set_commission( @@ -6566,7 +6786,7 @@ mod commission { Pools::get_member_with_pools(&10).unwrap(); // top up commission payee account to existential deposit - let _ = Balances::deposit_creating(&2, 5); + let _ = Currency::set_balance(&2, 5); // Set a commission pool 1 to 100%, with a payee set to `2` assert_ok!(Pools::set_commission( @@ -6609,7 +6829,7 @@ mod commission { Pools::get_member_with_pools(&10).unwrap(); // top up the commission payee account to existential deposit - let _ = Balances::deposit_creating(&2, 5); + let _ = Currency::set_balance(&2, 5); // Set a commission pool 1 to 100% fails. assert_noop!( @@ -6667,7 +6887,7 @@ mod commission { ExtBuilder::default().build_and_execute(|| { let pool_id = 1; - let _ = Balances::deposit_creating(&900, 5); + let _ = Currency::set_balance(&900, 5); assert_ok!(Pools::set_commission( RuntimeOrigin::signed(900), pool_id, @@ -6727,3 +6947,73 @@ mod commission { }) } } +mod slash { + use super::*; + + #[test] + fn slash_no_subpool_is_tracked() { + let bonded = |points, member_counter| BondedPool:: { + id: 1, + inner: BondedPoolInner { + commission: Commission::default(), + member_counter, + points, + roles: DEFAULT_ROLES, + state: PoolState::Open, + }, + }; + ExtBuilder::default().with_check(0).build_and_execute(|| { + // Given + Currency::set_balance(&11, ExistentialDeposit::get() + 2); + assert!(!PoolMembers::::contains_key(11)); + assert_eq!(TotalValueLocked::::get(), 10); + + // When + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); + + // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, + ] + ); + assert_eq!(TotalValueLocked::::get(), 12); + + assert_eq!( + PoolMembers::::get(11).unwrap(), + PoolMember:: { pool_id: 1, points: 2, ..Default::default() } + ); + assert_eq!(BondedPool::::get(1).unwrap(), bonded(12, 2)); + + // Given + // The bonded balance is slashed in half + StakingMock::slash_by(1, 6); + + // And + Currency::set_balance(&12, ExistentialDeposit::get() + 12); + assert!(!PoolMembers::::contains_key(12)); + + // When + assert_ok!(Pools::join(RuntimeOrigin::signed(12), 12, 1)); + + // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PoolSlashed { pool_id: 1, balance: 6 }, + Event::Bonded { member: 12, pool_id: 1, bonded: 12, joined: true } + ] + ); + assert_eq!(TotalValueLocked::::get(), 18); + + assert_eq!( + PoolMembers::::get(12).unwrap(), + PoolMember:: { pool_id: 1, points: 24, ..Default::default() } + ); + assert_eq!(BondedPool::::get(1).unwrap(), bonded(12 + 24, 3)); + }); + } +} diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index eb33c9adbbf9657a7ab71f9f33632d6e41499d4d..2cb414fc2a07f76f97a3c460c3db2a7450d10591 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -15,32 +15,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_nomination_pools +//! Autogenerated weights for `pallet_nomination_pools` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-guclnr1q-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_nomination_pools -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nomination-pools/src/weights.rs -// --header=./HEADER-APACHE2 -// --template=./.maintain/frame-weight-template.hbs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_nomination_pools +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/nomination-pools/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +47,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_nomination_pools. +/// Weight functions needed for `pallet_nomination_pools`. pub trait WeightInfo { fn join() -> Weight; fn bond_extra_transfer() -> Weight; @@ -72,1068 +69,1107 @@ pub trait WeightInfo { fn set_commission_change_rate() -> Weight; fn set_claim_permission() -> Weight; fn claim_commission() -> Weight; + fn adjust_pool_deposit() -> Weight; } -/// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. +/// Weights for `pallet_nomination_pools` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3300` + // Measured: `3388` // Estimated: `8877` - // Minimum execution time: 200_966_000 picoseconds. - Weight::from_parts(208_322_000, 8877) + // Minimum execution time: 203_377_000 picoseconds. + Weight::from_parts(206_359_000, 8877) .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3310` + // Measured: `3398` // Estimated: `8877` - // Minimum execution time: 197_865_000 picoseconds. - Weight::from_parts(203_085_000, 8877) + // Minimum execution time: 199_792_000 picoseconds. + Weight::from_parts(206_871_000, 8877) .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3375` + // Measured: `3463` // Estimated: `8877` - // Minimum execution time: 235_496_000 picoseconds. - Weight::from_parts(242_104_000, 8877) + // Minimum execution time: 246_362_000 picoseconds. + Weight::from_parts(253_587_000, 8877) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_payout() -> Weight { // Proof Size summary in bytes: // Measured: `1171` // Estimated: `3702` - // Minimum execution time: 81_813_000 picoseconds. - Weight::from_parts(83_277_000, 3702) + // Minimum execution time: 81_115_000 picoseconds. + Weight::from_parts(83_604_000, 3702) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3586` + // Measured: `3674` // Estimated: `27847` - // Minimum execution time: 183_935_000 picoseconds. - Weight::from_parts(186_920_000, 27847) + // Minimum execution time: 187_210_000 picoseconds. + Weight::from_parts(189_477_000, 27847) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687` + // Measured: `1743` // Estimated: `4764` - // Minimum execution time: 64_962_000 picoseconds. - Weight::from_parts(67_936_216, 4764) - // Standard Error: 1_780 - .saturating_add(Weight::from_parts(36_110, 0).saturating_mul(s.into())) + // Minimum execution time: 66_384_000 picoseconds. + Weight::from_parts(69_498_267, 4764) + // Standard Error: 2_566 + .saturating_add(Weight::from_parts(34_528, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2115` + // Measured: `2171` // Estimated: `27847` - // Minimum execution time: 136_073_000 picoseconds. - Weight::from_parts(141_448_439, 27847) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(75_893, 0).saturating_mul(s.into())) + // Minimum execution time: 137_474_000 picoseconds. + Weight::from_parts(142_341_215, 27847) + // Standard Error: 3_468 + .saturating_add(Weight::from_parts(66_597, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:1 w:0) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2470` + // Measured: `2526` // Estimated: `27847` - // Minimum execution time: 230_871_000 picoseconds. - Weight::from_parts(239_533_976, 27847) - .saturating_add(T::DbWeight::get().reads(21_u64)) - .saturating_add(T::DbWeight::get().writes(18_u64)) + // Minimum execution time: 249_135_000 picoseconds. + Weight::from_parts(263_632_571, 27847) + .saturating_add(T::DbWeight::get().reads(23_u64)) + .saturating_add(T::DbWeight::get().writes(19_u64)) } - /// Storage: NominationPools LastPoolId (r:1 w:1) - /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:1 w:0) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:1 w:0) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `NominationPools::LastPoolId` (r:1 w:1) + /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:1 w:0) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1289` - // Estimated: `6196` - // Minimum execution time: 194_272_000 picoseconds. - Weight::from_parts(197_933_000, 6196) - .saturating_add(T::DbWeight::get().reads(22_u64)) - .saturating_add(T::DbWeight::get().writes(15_u64)) + // Estimated: `8538` + // Minimum execution time: 214_207_000 picoseconds. + Weight::from_parts(221_588_000, 8538) + .saturating_add(T::DbWeight::get().reads(24_u64)) + .saturating_add(T::DbWeight::get().writes(16_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) + /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:17 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1849` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 70_256_000 picoseconds. - Weight::from_parts(71_045_351, 4556) - // Standard Error: 9_898 - .saturating_add(Weight::from_parts(1_592_597, 0).saturating_mul(n.into())) + // Minimum execution time: 70_626_000 picoseconds. + Weight::from_parts(73_830_182, 4556) + // Standard Error: 24_496 + .saturating_add(Weight::from_parts(1_561_416, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_state() -> Weight { // Proof Size summary in bytes: // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 36_233_000 picoseconds. - Weight::from_parts(37_114_000, 4556) + // Minimum execution time: 36_542_000 picoseconds. + Weight::from_parts(37_644_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForMetadata (r:1 w:1) - /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForMetadata` (r:1 w:1) + /// Proof: `NominationPools::CounterForMetadata` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3735` - // Minimum execution time: 14_494_000 picoseconds. - Weight::from_parts(15_445_658, 3735) - // Standard Error: 211 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(n.into())) + // Minimum execution time: 15_130_000 picoseconds. + Weight::from_parts(16_319_671, 3735) + // Standard Error: 351 + .saturating_add(Weight::from_parts(2_024, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: NominationPools MinJoinBond (r:0 w:1) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:0 w:1) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:0 w:1) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:0 w:1) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:0 w:1) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:0 w:1) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:0 w:1) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:0 w:1) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_configs() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_776_000 picoseconds. - Weight::from_parts(7_033_000, 0) + // Minimum execution time: 6_819_000 picoseconds. + Weight::from_parts(7_253_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 19_586_000 picoseconds. - Weight::from_parts(20_287_000, 3685) + // Minimum execution time: 19_596_000 picoseconds. + Weight::from_parts(20_828_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `2012` // Estimated: `4556` - // Minimum execution time: 68_086_000 picoseconds. - Weight::from_parts(70_784_000, 4556) + // Minimum execution time: 68_551_000 picoseconds. + Weight::from_parts(71_768_000, 4556) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn set_commission() -> Weight { // Proof Size summary in bytes: // Measured: `770` // Estimated: `3685` - // Minimum execution time: 33_353_000 picoseconds. - Weight::from_parts(34_519_000, 3685) + // Minimum execution time: 36_128_000 picoseconds. + Weight::from_parts(38_547_000, 3685) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_commission_max() -> Weight { // Proof Size summary in bytes: // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_020_000 picoseconds. - Weight::from_parts(19_630_000, 3685) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 20_067_000 picoseconds. + Weight::from_parts(21_044_000, 3685) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 19_693_000 picoseconds. - Weight::from_parts(20_114_000, 3685) + // Minimum execution time: 19_186_000 picoseconds. + Weight::from_parts(20_189_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:0) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:1 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_810_000 picoseconds. - Weight::from_parts(15_526_000, 3702) + // Minimum execution time: 15_275_000 picoseconds. + Weight::from_parts(15_932_000, 3702) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_commission() -> Weight { // Proof Size summary in bytes: // Measured: `968` // Estimated: `3685` - // Minimum execution time: 66_400_000 picoseconds. - Weight::from_parts(67_707_000, 3685) + // Minimum execution time: 67_931_000 picoseconds. + Weight::from_parts(72_202_000, 3685) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + fn adjust_pool_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `900` + // Estimated: `4764` + // Minimum execution time: 72_783_000 picoseconds. + Weight::from_parts(75_841_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3300` + // Measured: `3388` // Estimated: `8877` - // Minimum execution time: 200_966_000 picoseconds. - Weight::from_parts(208_322_000, 8877) + // Minimum execution time: 203_377_000 picoseconds. + Weight::from_parts(206_359_000, 8877) .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3310` + // Measured: `3398` // Estimated: `8877` - // Minimum execution time: 197_865_000 picoseconds. - Weight::from_parts(203_085_000, 8877) + // Minimum execution time: 199_792_000 picoseconds. + Weight::from_parts(206_871_000, 8877) .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3375` + // Measured: `3463` // Estimated: `8877` - // Minimum execution time: 235_496_000 picoseconds. - Weight::from_parts(242_104_000, 8877) + // Minimum execution time: 246_362_000 picoseconds. + Weight::from_parts(253_587_000, 8877) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } - /// Storage: NominationPools ClaimPermissions (r:1 w:0) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:0) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_payout() -> Weight { // Proof Size summary in bytes: // Measured: `1171` // Estimated: `3702` - // Minimum execution time: 81_813_000 picoseconds. - Weight::from_parts(83_277_000, 3702) + // Minimum execution time: 81_115_000 picoseconds. + Weight::from_parts(83_604_000, 3702) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3586` + // Measured: `3674` // Estimated: `27847` - // Minimum execution time: 183_935_000 picoseconds. - Weight::from_parts(186_920_000, 27847) + // Minimum execution time: 187_210_000 picoseconds. + Weight::from_parts(189_477_000, 27847) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687` + // Measured: `1743` // Estimated: `4764` - // Minimum execution time: 64_962_000 picoseconds. - Weight::from_parts(67_936_216, 4764) - // Standard Error: 1_780 - .saturating_add(Weight::from_parts(36_110, 0).saturating_mul(s.into())) + // Minimum execution time: 66_384_000 picoseconds. + Weight::from_parts(69_498_267, 4764) + // Standard Error: 2_566 + .saturating_add(Weight::from_parts(34_528, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2115` + // Measured: `2171` // Estimated: `27847` - // Minimum execution time: 136_073_000 picoseconds. - Weight::from_parts(141_448_439, 27847) - // Standard Error: 2_472 - .saturating_add(Weight::from_parts(75_893, 0).saturating_mul(s.into())) + // Minimum execution time: 137_474_000 picoseconds. + Weight::from_parts(142_341_215, 27847) + // Standard Error: 3_468 + .saturating_add(Weight::from_parts(66_597, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools SubPoolsStorage (r:1 w:1) - /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:0) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) - /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::SubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::SubPoolsStorage` (`max_values`: None, `max_size`: Some(24382), added: 26857, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::SlashingSpans` (r:1 w:0) + /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForSubPoolsStorage` (r:1 w:1) + /// Proof: `NominationPools::CounterForSubPoolsStorage` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2470` + // Measured: `2526` // Estimated: `27847` - // Minimum execution time: 230_871_000 picoseconds. - Weight::from_parts(239_533_976, 27847) - .saturating_add(RocksDbWeight::get().reads(21_u64)) - .saturating_add(RocksDbWeight::get().writes(18_u64)) + // Minimum execution time: 249_135_000 picoseconds. + Weight::from_parts(263_632_571, 27847) + .saturating_add(RocksDbWeight::get().reads(23_u64)) + .saturating_add(RocksDbWeight::get().writes(19_u64)) } - /// Storage: NominationPools LastPoolId (r:1 w:1) - /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:1 w:0) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MinJoinBond (r:1 w:0) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:1 w:0) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForBondedPools (r:1 w:1) - /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools PoolMembers (r:1 w:1) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:1 w:0) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) - /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForRewardPools (r:1 w:1) - /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) - /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: `NominationPools::LastPoolId` (r:1 w:1) + /// Proof: `NominationPools::LastPoolId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:1 w:0) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForBondedPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForBondedPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:1) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:1 w:0) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) + /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:2 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForRewardPools` (r:1 w:1) + /// Proof: `NominationPools::CounterForRewardPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:0 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1289` - // Estimated: `6196` - // Minimum execution time: 194_272_000 picoseconds. - Weight::from_parts(197_933_000, 6196) - .saturating_add(RocksDbWeight::get().reads(22_u64)) - .saturating_add(RocksDbWeight::get().writes(15_u64)) + // Estimated: `8538` + // Minimum execution time: 214_207_000 picoseconds. + Weight::from_parts(221_588_000, 8538) + .saturating_add(RocksDbWeight::get().reads(24_u64)) + .saturating_add(RocksDbWeight::get().writes(16_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) + /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:17 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1849` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 70_256_000 picoseconds. - Weight::from_parts(71_045_351, 4556) - // Standard Error: 9_898 - .saturating_add(Weight::from_parts(1_592_597, 0).saturating_mul(n.into())) + // Minimum execution time: 70_626_000 picoseconds. + Weight::from_parts(73_830_182, 4556) + // Standard Error: 24_496 + .saturating_add(Weight::from_parts(1_561_416, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_state() -> Weight { // Proof Size summary in bytes: // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 36_233_000 picoseconds. - Weight::from_parts(37_114_000, 4556) + // Minimum execution time: 36_542_000 picoseconds. + Weight::from_parts(37_644_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools Metadata (r:1 w:1) - /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) - /// Storage: NominationPools CounterForMetadata (r:1 w:1) - /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::Metadata` (r:1 w:1) + /// Proof: `NominationPools::Metadata` (`max_values`: None, `max_size`: Some(270), added: 2745, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::CounterForMetadata` (r:1 w:1) + /// Proof: `NominationPools::CounterForMetadata` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3735` - // Minimum execution time: 14_494_000 picoseconds. - Weight::from_parts(15_445_658, 3735) - // Standard Error: 211 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(n.into())) + // Minimum execution time: 15_130_000 picoseconds. + Weight::from_parts(16_319_671, 3735) + // Standard Error: 351 + .saturating_add(Weight::from_parts(2_024, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: NominationPools MinJoinBond (r:0 w:1) - /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembers (r:0 w:1) - /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) - /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MinCreateBond (r:0 w:1) - /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools MaxPools (r:0 w:1) - /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::MinJoinBond` (r:0 w:1) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembers` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPoolMembersPerPool` (r:0 w:1) + /// Proof: `NominationPools::MaxPoolMembersPerPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:0 w:1) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:0 w:1) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MaxPools` (r:0 w:1) + /// Proof: `NominationPools::MaxPools` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_configs() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_776_000 picoseconds. - Weight::from_parts(7_033_000, 0) + // Minimum execution time: 6_819_000 picoseconds. + Weight::from_parts(7_253_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn update_roles() -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 19_586_000 picoseconds. - Weight::from_parts(20_287_000, 3685) + // Minimum execution time: 19_596_000 picoseconds. + Weight::from_parts(20_828_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1 w:1) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:1 w:1) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `2012` // Estimated: `4556` - // Minimum execution time: 68_086_000 picoseconds. - Weight::from_parts(70_784_000, 4556) + // Minimum execution time: 68_551_000 picoseconds. + Weight::from_parts(71_768_000, 4556) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn set_commission() -> Weight { // Proof Size summary in bytes: // Measured: `770` // Estimated: `3685` - // Minimum execution time: 33_353_000 picoseconds. - Weight::from_parts(34_519_000, 3685) + // Minimum execution time: 36_128_000 picoseconds. + Weight::from_parts(38_547_000, 3685) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn set_commission_max() -> Weight { // Proof Size summary in bytes: // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_020_000 picoseconds. - Weight::from_parts(19_630_000, 3685) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 20_067_000 picoseconds. + Weight::from_parts(21_044_000, 3685) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:1) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 19_693_000 picoseconds. - Weight::from_parts(20_114_000, 3685) + // Minimum execution time: 19_186_000 picoseconds. + Weight::from_parts(20_189_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: NominationPools PoolMembers (r:1 w:0) - /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:1 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ClaimPermissions` (r:1 w:1) + /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_810_000 picoseconds. - Weight::from_parts(15_526_000, 3702) + // Minimum execution time: 15_275_000 picoseconds. + Weight::from_parts(15_932_000, 3702) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) - /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) - /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) - /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::RewardPools` (r:1 w:1) + /// Proof: `NominationPools::RewardPools` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::GlobalMaxCommission` (r:1 w:0) + /// Proof: `NominationPools::GlobalMaxCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_commission() -> Weight { // Proof Size summary in bytes: // Measured: `968` // Estimated: `3685` - // Minimum execution time: 66_400_000 picoseconds. - Weight::from_parts(67_707_000, 3685) + // Minimum execution time: 67_931_000 picoseconds. + Weight::from_parts(72_202_000, 3685) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `NominationPools::BondedPools` (r:1 w:0) + /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(220), added: 2695, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + fn adjust_pool_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `900` + // Estimated: `4764` + // Minimum execution time: 72_783_000 picoseconds. + Weight::from_parts(75_841_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index 02c253e62c018914687467b3a55d2e317f6bf6d7..54f578f861e87085902573dabd7439c7b1be850e 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -85,8 +85,8 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; type RuntimeHoldReason = (); type MaxHolds = (); } @@ -174,6 +174,7 @@ impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; @@ -195,7 +196,7 @@ frame_support::construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, - Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, + Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event, FreezeReason}, } ); diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 9fbc3fdb2c627fd2233d1378af3802389e39a9b6..eee099fff5f062b54085094050f55990018a7890 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } -docify = "0.2.3" +docify = "0.2.4" scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true} diff --git a/substrate/frame/paged-list/src/paged_list.rs b/substrate/frame/paged-list/src/paged_list.rs index 3597c3dea682313f0b56c2ae11bdfa4a85ccfebc..beea8ecc64409f9f199a94b1f8c3e0a2782e4a11 100644 --- a/substrate/frame/paged-list/src/paged_list.rs +++ b/substrate/frame/paged-list/src/paged_list.rs @@ -53,7 +53,7 @@ pub type ValueIndex = u32; /// [`Page`]s. /// /// Each [`Page`] holds at most `ValuesPerNewPage` values in its `values` vector. The last page is -/// the only one that could have less than `ValuesPerNewPage` values. +/// the only one that could have less than `ValuesPerNewPage` values. /// **Iteration** happens by starting /// at [`first_page`][StoragePagedListMeta::first_page]/ /// [`first_value_offset`][StoragePagedListMeta::first_value_offset] and incrementing these indices @@ -373,11 +373,11 @@ where /// that are completely useless for prefix calculation. struct StoragePagedListPrefix(PhantomData); -impl frame_support::storage::StoragePrefixedContainer for StoragePagedListPrefix +impl StoragePrefixedContainer for StoragePagedListPrefix where Prefix: StorageInstance, { - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { Prefix::pallet_prefix().as_bytes() } @@ -386,15 +386,15 @@ where } } -impl frame_support::storage::StoragePrefixedContainer +impl StoragePrefixedContainer for StoragePagedList where Prefix: StorageInstance, Value: FullCodec, ValuesPerNewPage: Get, { - fn module_prefix() -> &'static [u8] { - StoragePagedListPrefix::::module_prefix() + fn pallet_prefix() -> &'static [u8] { + StoragePagedListPrefix::::pallet_prefix() } fn storage_prefix() -> &'static [u8] { diff --git a/substrate/frame/preimage/src/benchmarking.rs b/substrate/frame/preimage/src/benchmarking.rs index d7c643ff90427b6e348a1751d06d218db3dfd3f3..d0c3404f40a911cf32d620858b97652b242f2be8 100644 --- a/substrate/frame/preimage/src/benchmarking.rs +++ b/substrate/frame/preimage/src/benchmarking.rs @@ -216,7 +216,7 @@ benchmarks! { } ensure_updated { - let n in 0..MAX_HASH_UPGRADE_BULK_COUNT; + let n in 1..MAX_HASH_UPGRADE_BULK_COUNT; let caller = funded_account::(); let hashes = (0..n).map(|i| insert_old_unrequested::(i)).collect::>(); diff --git a/substrate/frame/preimage/src/lib.rs b/substrate/frame/preimage/src/lib.rs index e603f1a32e6a4aaa3a1c38232be9bc423a7f919c..e344bdfe2d8feff5a25ed686d7301f462fa41189 100644 --- a/substrate/frame/preimage/src/lib.rs +++ b/substrate/frame/preimage/src/lib.rs @@ -49,8 +49,8 @@ use frame_support::{ ensure, pallet_prelude::Get, traits::{ - Consideration, Currency, Defensive, FetchResult, Footprint, Hash as PreimageHash, - PreimageProvider, PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, + Consideration, Currency, Defensive, FetchResult, Footprint, PreimageProvider, + PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, }, BoundedSlice, BoundedVec, }; @@ -156,6 +156,8 @@ pub mod pallet { NotRequested, /// More than `MAX_HASH_UPGRADE_BULK_COUNT` hashes were requested to be upgraded at once. TooMany, + /// Too few hashes were requested to be upgraded (i.e. zero). + TooFew, } /// A reason for this pallet placing a hold on funds. @@ -242,6 +244,7 @@ pub mod pallet { hashes: Vec, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; + ensure!(hashes.len() > 0, Error::::TooFew); ensure!(hashes.len() <= MAX_HASH_UPGRADE_BULK_COUNT as usize, Error::::TooMany); let updated = hashes.iter().map(Self::do_ensure_updated).filter(|b| *b).count() as u32; @@ -528,7 +531,9 @@ impl PreimageRecipient for Pallet { } } -impl> QueryPreimage for Pallet { +impl QueryPreimage for Pallet { + type H = T::Hashing; + fn len(hash: &T::Hash) -> Option { Pallet::::len(hash) } @@ -552,7 +557,7 @@ impl> QueryPreimage for Pallet { } } -impl> StorePreimage for Pallet { +impl StorePreimage for Pallet { const MAX_LENGTH: usize = MAX_SIZE as usize; fn note(bytes: Cow<[u8]>) -> Result { diff --git a/substrate/frame/preimage/src/migration.rs b/substrate/frame/preimage/src/migration.rs index 821cb01bbaae5784352bec53eecc89ea65dfd3d6..a86109f892a4f5b84b6aa48e89bc869f521bf74c 100644 --- a/substrate/frame/preimage/src/migration.rs +++ b/substrate/frame/preimage/src/migration.rs @@ -133,7 +133,7 @@ pub mod v1 { None => OldRequestStatus::Requested { deposit: None, count: 1, len: Some(len) }, }, - v0::OldRequestStatus::Requested(count) if count == 0 => { + v0::OldRequestStatus::Requested(0) => { log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash); continue }, diff --git a/substrate/frame/preimage/src/tests.rs b/substrate/frame/preimage/src/tests.rs index a473a0ae8e25f51aeb5d825eae497bba68cfc4b2..7609ec83e9039a66ce22b1fbcd4c49a591c86187 100644 --- a/substrate/frame/preimage/src/tests.rs +++ b/substrate/frame/preimage/src/tests.rs @@ -24,25 +24,32 @@ use crate::mock::*; use frame_support::{ assert_err, assert_noop, assert_ok, assert_storage_noop, - traits::{fungible::InspectHold, Bounded, BoundedInline, Hash as PreimageHash}, + traits::{fungible::InspectHold, Bounded, BoundedInline}, StorageNoopGuard, }; -use sp_core::{blake2_256, H256}; use sp_runtime::{bounded_vec, TokenError}; /// Returns one `Inline`, `Lookup` and `Legacy` item each with different data and hash. -pub fn make_bounded_values() -> (Bounded>, Bounded>, Bounded>) { +pub fn make_bounded_values() -> ( + Bounded, ::Hashing>, + Bounded, ::Hashing>, + Bounded, ::Hashing>, +) { let data: BoundedInline = bounded_vec![1]; - let inline = Bounded::>::Inline(data); + let inline = Bounded::, ::Hashing>::Inline(data); let data = vec![1, 2]; - let hash: H256 = blake2_256(&data[..]).into(); + let hash = ::Hashing::hash(&data[..]).into(); let len = data.len() as u32; - let lookup = Bounded::>::unrequested(hash, len); + let lookup = + Bounded::, ::Hashing>::unrequested(hash, len); let data = vec![1, 2, 3]; - let hash: H256 = blake2_256(&data[..]).into(); - let legacy = Bounded::>::Legacy { hash, dummy: Default::default() }; + let hash = ::Hashing::hash(&data[..]).into(); + let legacy = Bounded::, ::Hashing>::Legacy { + hash, + dummy: Default::default(), + }; (inline, lookup, legacy) } @@ -303,7 +310,7 @@ fn query_and_store_preimage_workflow() { let bound = Preimage::bound(data.clone()).unwrap(); let (len, hash) = (bound.len().unwrap(), bound.hash()); - assert_eq!(hash, blake2_256(&encoded).into()); + assert_eq!(hash, ::Hashing::hash(&encoded).into()); assert_eq!(bound.len(), Some(len)); assert!(bound.lookup_needed(), "Should not be Inlined"); assert_eq!(bound.lookup_len(), Some(len)); @@ -364,7 +371,7 @@ fn query_preimage_request_works() { new_test_ext().execute_with(|| { let _guard = StorageNoopGuard::default(); let data: Vec = vec![1; 10]; - let hash: PreimageHash = blake2_256(&data[..]).into(); + let hash = ::Hashing::hash(&data[..]).into(); // Request the preimage. ::request(&hash); @@ -454,7 +461,7 @@ fn store_preimage_basic_works() { // Cleanup. ::unnote(&bound.hash()); - let data_hash = blake2_256(&data); + let data_hash = ::Hashing::hash(&data); ::unnote(&data_hash.into()); // No storage changes remain. Checked by `StorageNoopGuard`. diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 0667be6e1e52b87c89b887171fe4d418dc2f6412..89bd8b68f0918c1ce5ab561286102e62f19c2051 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -45,25 +45,14 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type Block = Block; - type BlockHashCount = ConstU64<250>; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); - type BaseCallFilter = BaseFilter; type AccountData = pallet_balances::AccountData; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = (); type ReserveIdentifier = [u8; 8]; - type DustRemoval = (); type AccountStore = System; - type ExistentialDeposit = ConstU64<1>; } impl pallet_utility::Config for Test { diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index e884a0bb6ec921edf3f3ff93818482941ee1abea..47d43cc0600c076b6fce0e541e0f78c97649921e 100644 --- a/substrate/frame/referenda/src/benchmarking.rs +++ b/substrate/frame/referenda/src/benchmarking.rs @@ -25,7 +25,7 @@ use frame_benchmarking::v1::{ }; use frame_support::{ assert_ok, - traits::{Bounded, Currency, EnsureOrigin, EnsureOriginWithArg, UnfilteredDispatchable}, + traits::{Currency, EnsureOrigin, EnsureOriginWithArg, UnfilteredDispatchable}, }; use frame_system::RawOrigin; use sp_runtime::traits::Bounded as ArithBounded; @@ -42,7 +42,7 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T caller } -fn dummy_call, I: 'static>() -> Bounded<>::RuntimeCall> { +fn dummy_call, I: 'static>() -> BoundedCallOf { let inner = frame_system::Call::remark { remark: vec![] }; let call = >::RuntimeCall::from(inner); T::Preimages::bound(call).unwrap() diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index d4dbbf8a3c998e845165fb7a3d2fa7132c1824d4..be21375f526f034d072318afefca1f99d0e99b3d 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -73,8 +73,8 @@ use frame_support::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, Hash as PreimageHash, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, - Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, + Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, + ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -163,8 +163,17 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The Scheduler. - type Scheduler: ScheduleAnon, CallOf, PalletsOriginOf> - + ScheduleNamed, CallOf, PalletsOriginOf>; + type Scheduler: ScheduleAnon< + BlockNumberFor, + CallOf, + PalletsOriginOf, + Hasher = Self::Hashing, + > + ScheduleNamed< + BlockNumberFor, + CallOf, + PalletsOriginOf, + Hasher = Self::Hashing, + >; /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. @@ -226,7 +235,7 @@ pub mod pallet { >; /// The preimage provider. - type Preimages: QueryPreimage + StorePreimage; + type Preimages: QueryPreimage + StorePreimage; } /// The next free referendum index, aka the number of referenda started so far. @@ -257,14 +266,14 @@ pub mod pallet { StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; /// The metadata is a general information concerning the referendum. - /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// The `Hash` refers to the preimage of the `Preimages` provider which can be a JSON /// dump or IPFS hash of a JSON file. /// /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) /// large preimages. #[pallet::storage] pub type MetadataOf, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, ReferendumIndex, PreimageHash>; + StorageMap<_, Blake2_128Concat, ReferendumIndex, T::Hash>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -376,14 +385,14 @@ pub mod pallet { /// Index of the referendum. index: ReferendumIndex, /// Preimage hash. - hash: PreimageHash, + hash: T::Hash, }, /// Metadata for a referendum has been cleared. MetadataCleared { /// Index of the referendum. index: ReferendumIndex, /// Preimage hash. - hash: PreimageHash, + hash: T::Hash, }, } @@ -691,7 +700,7 @@ pub mod pallet { pub fn set_metadata( origin: OriginFor, index: ReferendumIndex, - maybe_hash: Option, + maybe_hash: Option, ) -> DispatchResult { let who = ensure_signed(origin)?; if let Some(hash) = maybe_hash { diff --git a/substrate/frame/referenda/src/migration.rs b/substrate/frame/referenda/src/migration.rs index 281da83d6569ef83b348feaa18e487f9e4b26c72..a80897242eec67aad194f8deaf1cd6527533eab9 100644 --- a/substrate/frame/referenda/src/migration.rs +++ b/substrate/frame/referenda/src/migration.rs @@ -99,8 +99,6 @@ pub mod v1 { impl, I: 'static> OnRuntimeUpgrade for MigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version == 0, "migration from version 0 to 1."); let referendum_count = v0::ReferendumInfoFor::::iter().count(); log::info!( target: TARGET, diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index c23fa4609d4340dc92e712a439ab07b8b4ab7605..dce91f7dbfd780fbbac5d53afd0d58249853713a 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -473,7 +473,7 @@ impl RefState { } /// note a new preimage without registering. -pub fn note_preimage(who: u64) -> PreimageHash { +pub fn note_preimage(who: u64) -> ::Hash { use std::sync::atomic::{AtomicU8, Ordering}; // note a new preimage on every function invoke. static COUNTER: AtomicU8 = AtomicU8::new(0); diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs index d748c524605a839b5d9f5b4804cf0d799452bc0c..8f51136de0bfdb48df1a43e47dd0de63f7a0e21d 100644 --- a/substrate/frame/referenda/src/tests.rs +++ b/substrate/frame/referenda/src/tests.rs @@ -599,9 +599,8 @@ fn curve_handles_all_inputs() { #[test] fn set_metadata_works() { ExtBuilder::default().build_and_execute(|| { - use frame_support::traits::Hash as PreimageHash; // invalid preimage hash. - let invalid_hash: PreimageHash = [1u8; 32].into(); + let invalid_hash: ::Hash = [1u8; 32].into(); // fails to set metadata for a finished referendum. assert_ok!(Referenda::submit( RuntimeOrigin::signed(1), diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs index ba89383888a7d7062267875095bbe439c01bb36b..8d6a13ef27c981b3996425b18062e2ef04a2f68b 100644 --- a/substrate/frame/referenda/src/types.rs +++ b/substrate/frame/referenda/src/types.rs @@ -34,7 +34,8 @@ pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; pub type CallOf = >::RuntimeCall; -pub type BoundedCallOf = Bounded<>::RuntimeCall>; +pub type BoundedCallOf = + Bounded<>::RuntimeCall, ::Hashing>; pub type VotesOf = >::Votes; pub type TallyOf = >::Tally; pub type PalletsOriginOf = diff --git a/substrate/frame/root-testing/src/lib.rs b/substrate/frame/root-testing/src/lib.rs index e04c7bfa13d26f5e40a8d5625d234c0a7ae93de7..bbcda09c3065da2ad7b197c69b6ee7143dda1338 100644 --- a/substrate/frame/root-testing/src/lib.rs +++ b/substrate/frame/root-testing/src/lib.rs @@ -29,7 +29,7 @@ use sp_runtime::Perbill; pub use pallet::*; -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 7fa14e861e8c9fd693e61f50ebc8af6b151f72bc..e81b4dbeff78c53e645dd4988b86411193127ac7 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -20,7 +20,7 @@ sp-io = { path = "../../primitives/io", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} sp-weights = { path = "../../primitives/weights", default-features = false} -docify = "0.2.3" +docify = "0.2.4" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index 341a19cdb230223536621db424f0e300399279e8..cc86a17973780870970a7b604b4fd5d30cffe263 100644 --- a/substrate/frame/scheduler/src/benchmarking.rs +++ b/substrate/frame/scheduler/src/benchmarking.rs @@ -82,13 +82,13 @@ fn make_task( Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData } } -fn bounded(len: u32) -> Option::RuntimeCall>> { +fn bounded(len: u32) -> Option> { let call = <::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] }); T::Preimages::bound(call).ok() } -fn make_call(maybe_lookup_len: Option) -> Bounded<::RuntimeCall> { +fn make_call(maybe_lookup_len: Option) -> BoundedCallOf { let bound = BoundedInline::bound() as u32; let mut len = match maybe_lookup_len { Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3, diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 3da4aa03caeb040bea5c3fc2ac6e63d1ca958e1e..e94f154eee32f908dc449ba7ff9e54853cc4b915 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -17,7 +17,7 @@ //! > Made with *Substrate*, for *Polkadot*. //! -//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) - +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/scheduler) - //! [![polkadot]](https://polkadot.network) //! //! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white @@ -91,8 +91,8 @@ use frame_support::{ ensure, traits::{ schedule::{self, DispatchTime, MaybeHashed}, - Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait, - PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, + Bounded, CallerTrait, EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, + PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, }, weights::{Weight, WeightMeter}, }; @@ -119,6 +119,9 @@ pub type TaskAddress = (BlockNumber, u32); pub type CallOrHashOf = MaybeHashed<::RuntimeCall, ::Hash>; +pub type BoundedCallOf = + Bounded<::RuntimeCall, ::Hashing>; + #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] struct ScheduledV1 { @@ -165,7 +168,7 @@ pub type ScheduledV3Of = ScheduledV3< pub type ScheduledOf = Scheduled< TaskName, - Bounded<::RuntimeCall>, + BoundedCallOf, BlockNumberFor, ::PalletsOrigin, ::AccountId, @@ -254,7 +257,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type Preimages: QueryPreimage + StorePreimage; + type Preimages: QueryPreimage + StorePreimage; } #[pallet::storage] @@ -440,7 +443,7 @@ pub mod pallet { } } -impl> Pallet { +impl Pallet { /// Migrate storage format from V1 to V4. /// /// Returns the weight consumed by this migration. @@ -627,7 +630,7 @@ impl> Pallet { >(&bounded) { log::error!( - "Dropping undecodable call {}: {:?}", + "Dropping undecodable call {:?}: {:?}", &h, &err ); @@ -695,7 +698,7 @@ impl Pallet { Option< Scheduled< TaskName, - Bounded<::RuntimeCall>, + BoundedCallOf, BlockNumberFor, OldOrigin, T::AccountId, @@ -797,7 +800,7 @@ impl Pallet { maybe_periodic: Option>>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: Bounded<::RuntimeCall>, + call: BoundedCallOf, ) -> Result>, DispatchError> { let when = Self::resolve_time(when)?; @@ -886,7 +889,7 @@ impl Pallet { maybe_periodic: Option>>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: Bounded<::RuntimeCall>, + call: BoundedCallOf, ) -> Result>, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -1191,8 +1194,8 @@ impl Pallet { } } -impl> - schedule::v2::Anon, ::RuntimeCall, T::PalletsOrigin> for Pallet +impl schedule::v2::Anon, ::RuntimeCall, T::PalletsOrigin> + for Pallet { type Address = TaskAddress>; type Hash = T::Hash; @@ -1225,8 +1228,8 @@ impl> } } -impl> - schedule::v2::Named, ::RuntimeCall, T::PalletsOrigin> for Pallet +impl schedule::v2::Named, ::RuntimeCall, T::PalletsOrigin> + for Pallet { type Address = TaskAddress>; type Hash = T::Hash; @@ -1270,13 +1273,14 @@ impl schedule::v3::Anon, ::RuntimeCall for Pallet { type Address = TaskAddress>; + type Hasher = T::Hashing; fn schedule( when: DispatchTime>, maybe_periodic: Option>>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: Bounded<::RuntimeCall>, + call: BoundedCallOf, ) -> Result { Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -1308,6 +1312,7 @@ impl schedule::v3::Named, ::RuntimeCal for Pallet { type Address = TaskAddress>; + type Hasher = T::Hashing; fn schedule_named( id: TaskName, @@ -1315,7 +1320,7 @@ impl schedule::v3::Named, ::RuntimeCal maybe_periodic: Option>>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: Bounded<::RuntimeCall>, + call: BoundedCallOf, ) -> Result { Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call) } diff --git a/substrate/frame/scheduler/src/migration.rs b/substrate/frame/scheduler/src/migration.rs index 06259768f0aa1be7ef836284c3aecf8e5070b117..9c8b0da03fc0b6368b2734c07db164a4ccc3b683 100644 --- a/substrate/frame/scheduler/src/migration.rs +++ b/substrate/frame/scheduler/src/migration.rs @@ -83,7 +83,7 @@ pub mod v3 { /// Migrate the scheduler pallet from V3 to V4. pub struct MigrateToV4(sp_std::marker::PhantomData); - impl> OnRuntimeUpgrade for MigrateToV4 { + impl OnRuntimeUpgrade for MigrateToV4 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { ensure!(StorageVersion::get::>() == 3, "Can only upgrade from version 3"); diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 25a60732e060bcb535a1bed46fcb9cecd6041931..1bf8b3e5f3a03bd2c9d233a24351d1ae2d923c45 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1019,7 +1019,7 @@ fn test_migrate_origin() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); - let old: Vec, u64, u32, u64>>> = vec![ + let old: Vec, u64, u32, u64>>> = vec![ Some(Scheduled { maybe_id: None, priority: i as u8 + 10, diff --git a/substrate/frame/session/benchmarking/src/lib.rs b/substrate/frame/session/benchmarking/src/lib.rs index 722bb14fb56edcccf735b6554a50e8ece9023d2d..84258d84994f45233e47a1ca413cb5b89ccf306a 100644 --- a/substrate/frame/session/benchmarking/src/lib.rs +++ b/substrate/frame/session/benchmarking/src/lib.rs @@ -134,7 +134,7 @@ fn check_membership_proof_setup( use rand::{RngCore, SeedableRng}; let validator = T::Lookup::lookup(who).unwrap(); - let controller = pallet_staking::Pallet::::bonded(validator).unwrap(); + let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); let keys = { let mut keys = [0u8; 128]; diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 7646bbc9a55dd98ae6456eccbbd25ee07949c42a..0a725996115990b36e81b7f538f35e2f551dfe6d 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "visit"] } +syn = { version = "2.0.38", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/staking/reward-curve/src/lib.rs b/substrate/frame/staking/reward-curve/src/lib.rs index ecf3af55379145cc85dea57cc1be998dc4d07079..1986357edabe20cca94d0d0e26e1bee54e08a0ac 100644 --- a/substrate/frame/staking/reward-curve/src/lib.rs +++ b/substrate/frame/staking/reward-curve/src/lib.rs @@ -81,11 +81,12 @@ pub fn build(input: TokenStream) -> TokenStream { let imports = match crate_name("sp-runtime") { Ok(FoundCrate::Itself) => quote!( - extern crate sp_runtime as _sp_runtime; + #[doc(hidden)] + pub use sp_runtime as _sp_runtime; ), Ok(FoundCrate::Name(sp_runtime)) => { let ident = syn::Ident::new(&sp_runtime, Span::call_site()); - quote!( extern crate #ident as _sp_runtime; ) + quote!( #[doc(hidden)] pub use #ident as _sp_runtime; ) }, Err(e) => syn::Error::new(Span::call_site(), e).to_compile_error(), }; diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index ce5c35524c747af4fa9face89a2d79be3c90e301..f94d9bf4b328ab6e0635ebd24659ca437ff25477 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -29,7 +29,7 @@ use frame_support::{ }; use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, - Perbill, Percent, + Perbill, Percent, Saturating, }; use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex}; use sp_std::prelude::*; @@ -684,13 +684,11 @@ benchmarks! { let stash = scenario.origin_stash1; add_slashing_spans::(&stash, s); - let l = StakingLedger { - stash: stash.clone(), - active: T::Currency::minimum_balance() - One::one(), - total: T::Currency::minimum_balance() - One::one(), - unlocking: Default::default(), - claimed_rewards: Default::default(), - }; + let l = StakingLedger::::new( + stash.clone(), + T::Currency::minimum_balance() - One::one(), + Default::default(), + ); Ledger::::insert(&controller, l); assert!(Bonded::::contains_key(&stash)); diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs new file mode 100644 index 0000000000000000000000000000000000000000..cf9b4635bf55a307f9906bdc161fdd443e759d47 --- /dev/null +++ b/substrate/frame/staking/src/ledger.rs @@ -0,0 +1,259 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A Ledger implementation for stakers. +//! +//! A [`StakingLedger`] encapsulates all the state and logic related to the stake of bonded +//! stakers, namely, it handles the following storage items: +//! * [`Bonded`]: mutates and reads the state of the controller <> stash bond map (to be deprecated +//! soon); +//! * [`Ledger`]: mutates and reads the state of all the stakers. The [`Ledger`] storage item stores +//! instances of [`StakingLedger`] keyed by the staker's controller account and should be mutated +//! and read through the [`StakingLedger`] API; +//! * [`Payee`]: mutates and reads the reward destination preferences for a bonded stash. +//! * Staking locks: mutates the locks for staking. +//! +//! NOTE: All the storage operations related to the staking ledger (both reads and writes) *MUST* be +//! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure +//! state consistency. + +use frame_support::{ + defensive, + traits::{LockableCurrency, WithdrawReasons}, + BoundedVec, +}; +use sp_staking::{EraIndex, StakingAccount}; +use sp_std::prelude::*; + +use crate::{ + BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, +}; + +#[cfg(any(feature = "runtime-benchmarks", test))] +use sp_runtime::traits::Zero; + +impl StakingLedger { + #[cfg(any(feature = "runtime-benchmarks", test))] + pub fn default_from(stash: T::AccountId) -> Self { + Self { + stash: stash.clone(), + total: Zero::zero(), + active: Zero::zero(), + unlocking: Default::default(), + claimed_rewards: Default::default(), + controller: Some(stash), + } + } + + /// Returns a new instance of a staking ledger. + /// + /// The [`Ledger`] storage is not mutated. In order to store, `StakingLedger::update` must be + /// called on the returned staking ledger. + /// + /// Note: as the controller accounts are being deprecated, the stash account is the same as the + /// controller account. + pub fn new( + stash: T::AccountId, + stake: BalanceOf, + claimed_rewards: BoundedVec, + ) -> Self { + Self { + stash: stash.clone(), + active: stake, + total: stake, + unlocking: Default::default(), + claimed_rewards, + // controllers are deprecated and mapped 1-1 to stashes. + controller: Some(stash), + } + } + + /// Returns the paired account, if any. + /// + /// A "pair" refers to the tuple (stash, controller). If the input is a + /// [`StakingAccount::Stash`] variant, its pair account will be of type + /// [`StakingAccount::Controller`] and vice-versa. + /// + /// This method is meant to abstract from the runtime development the difference between stash + /// and controller. This will be deprecated once the controller is fully deprecated as well. + pub(crate) fn paired_account(account: StakingAccount) -> Option { + match account { + StakingAccount::Stash(stash) => >::get(stash), + StakingAccount::Controller(controller) => + >::get(&controller).map(|ledger| ledger.stash), + } + } + + /// Returns whether a given account is bonded. + pub(crate) fn is_bonded(account: StakingAccount) -> bool { + match account { + StakingAccount::Stash(stash) => >::contains_key(stash), + StakingAccount::Controller(controller) => >::contains_key(controller), + } + } + + /// Returns a staking ledger, if it is bonded and it exists in storage. + /// + /// This getter can be called with either a controller or stash account, provided that the + /// account is properly wrapped in the respective [`StakingAccount`] variant. This is meant to + /// abstract the concept of controller/stash accounts from the caller. + pub(crate) fn get(account: StakingAccount) -> Result, Error> { + let controller = match account { + StakingAccount::Stash(stash) => >::get(stash).ok_or(Error::::NotStash), + StakingAccount::Controller(controller) => Ok(controller), + }?; + + >::get(&controller) + .map(|mut ledger| { + ledger.controller = Some(controller.clone()); + ledger + }) + .ok_or(Error::::NotController) + } + + /// Returns the reward destination of a staking ledger, stored in [`Payee`]. + /// + /// Note: if the stash is not bonded and/or does not have an entry in [`Payee`], it returns the + /// default reward destination. + pub(crate) fn reward_destination( + account: StakingAccount, + ) -> RewardDestination { + let stash = match account { + StakingAccount::Stash(stash) => Some(stash), + StakingAccount::Controller(controller) => + Self::paired_account(StakingAccount::Controller(controller)), + }; + + if let Some(stash) = stash { + >::get(stash) + } else { + defensive!("fetched reward destination from unbonded stash {}", stash); + RewardDestination::default() + } + } + + /// Returns the controller account of a staking ledger. + /// + /// Note: it will fallback into querying the [`Bonded`] storage with the ledger stash if the + /// controller is not set in `self`, which most likely means that self was fetched directly from + /// [`Ledger`] instead of through the methods exposed in [`StakingLedger`]. If the ledger does + /// not exist in storage, it returns `None`. + pub(crate) fn controller(&self) -> Option { + self.controller.clone().or_else(|| { + defensive!("fetched a controller on a ledger instance without it."); + Self::paired_account(StakingAccount::Stash(self.stash.clone())) + }) + } + + /// Inserts/updates a staking ledger account. + /// + /// Bonds the ledger if it is not bonded yet, signalling that this is a new ledger. The staking + /// locks of the stash account are updated accordingly. + /// + /// Note: To ensure lock consistency, all the [`Ledger`] storage updates should be made through + /// this helper function. + pub(crate) fn update(self) -> Result<(), Error> { + if !>::contains_key(&self.stash) { + return Err(Error::::NotStash) + } + + T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); + Ledger::::insert( + &self.controller().ok_or_else(|| { + defensive!("update called on a ledger that is not bonded."); + Error::::NotController + })?, + &self, + ); + + Ok(()) + } + + /// Bonds a ledger. + /// + /// 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() + } + } + + /// 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(()) + } + } + + /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] + /// storage items and updates the stash staking lock. + pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { + 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); + + Ok(()) + })? + } +} + +#[cfg(test)] +use { + crate::UnlockChunk, + codec::{Decode, Encode, MaxEncodedLen}, + scale_info::TypeInfo, +}; + +// This structs makes it easy to write tests to compare staking ledgers fetched from storage. This +// is required because the controller field is not stored in storage and it is private. +#[cfg(test)] +#[derive(frame_support::DebugNoBound, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct StakingLedgerInspect { + pub stash: T::AccountId, + #[codec(compact)] + pub total: BalanceOf, + #[codec(compact)] + pub active: BalanceOf, + pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, + pub claimed_rewards: BoundedVec, +} + +#[cfg(test)] +impl PartialEq> for StakingLedger { + fn eq(&self, other: &StakingLedgerInspect) -> bool { + self.stash == other.stash && + self.total == other.total && + self.active == other.active && + self.unlocking == other.unlocking && + self.claimed_rewards == other.claimed_rewards + } +} + +#[cfg(test)] +impl codec::EncodeLike> for StakingLedgerInspect {} diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e59b2a3324a62b69aa2f0577a63e7f399076324e..227326763a9bd58a97400d8e7faf93ecaf1a552a 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -91,7 +91,7 @@ //! #### Nomination //! //! A **nominator** does not take any _direct_ role in maintaining the network, instead, it votes on -//! a set of validators to be elected. Once interest in nomination is stated by an account, it +//! a set of validators to be elected. Once interest in nomination is stated by an account, it //! takes effect at the next election round. The funds in the nominator's stash account indicate the //! _weight_ of its vote. Both the rewards and any punishment that a validator earns are shared //! between the validator and its nominators. This rule incentivizes the nominators to NOT vote for @@ -294,6 +294,7 @@ mod tests; pub mod election_size_tracker; pub mod inflation; +pub mod ledger; pub mod migrations; pub mod slashing; pub mod weights; @@ -302,26 +303,27 @@ mod pallet; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ - traits::{ConstU32, Currency, Defensive, Get}, + traits::{ConstU32, Currency, Defensive, Get, LockIdentifier}, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, - traits::{AtLeast32BitUnsigned, Convert, Saturating, StaticLookup, Zero}, - Perbill, Perquintill, Rounding, RuntimeDebug, + traits::{AtLeast32BitUnsigned, Convert, StaticLookup, Zero}, + Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, }; pub use sp_staking::StakerStatus; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, - EraIndex, OnStakingUpdate, SessionIndex, + EraIndex, OnStakingUpdate, SessionIndex, StakingAccount, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap}; +pub(crate) const STAKING_ID: LockIdentifier = *b"staking "; pub(crate) const LOG_TARGET: &str = "runtime::staking"; // syntactic sugar for logging. @@ -433,6 +435,14 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. +/// +/// Note: All the reads and mutations to the [`Ledger`], [`Bonded`] and [`Payee`] storage items +/// *MUST* be performed through the methods exposed by this struct, to ensure the consistency of +/// ledger's data and corresponding staking lock +/// +/// TODO: move struct definition and full implementation into `/src/ledger.rs`. Currently +/// leaving here to enforce a clean PR diff, given how critical this logic is. Tracking issue +/// . #[derive( PartialEqNoBound, EqNoBound, @@ -462,20 +472,15 @@ pub struct StakingLedger { /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. pub claimed_rewards: BoundedVec, + /// The controller associated with this ledger's stash. + /// + /// This is not stored on-chain, and is only bundled when the ledger is read from storage. + /// Use [`controller`] function to get the controller associated with the ledger. + #[codec(skip)] + controller: Option, } impl StakingLedger { - /// Initializes the default object using the given `validator`. - pub fn default_from(stash: T::AccountId) -> Self { - Self { - stash, - total: Zero::zero(), - active: Zero::zero(), - unlocking: Default::default(), - claimed_rewards: Default::default(), - } - } - /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. fn consolidate_unlocked(self, current_era: EraIndex) -> Self { @@ -503,6 +508,7 @@ impl StakingLedger { active: self.active, unlocking, claimed_rewards: self.claimed_rewards, + controller: self.controller, } } @@ -671,8 +677,14 @@ impl StakingLedger { // clean unlocking chunks that are set to zero. self.unlocking.retain(|c| !c.value.is_zero()); - T::EventListeners::on_slash(&self.stash, self.active, &slashed_unlocking); - pre_slash_total.saturating_sub(self.total) + let final_slashed_amount = pre_slash_total.saturating_sub(self.total); + T::EventListeners::on_slash( + &self.stash, + self.active, + &slashed_unlocking, + final_slashed_amount, + ); + final_slashed_amount } } @@ -921,7 +933,7 @@ pub struct StashOf(sp_std::marker::PhantomData); impl Convert> for StashOf { fn convert(controller: T::AccountId) -> Option { - >::ledger(&controller).map(|l| l.stash) + StakingLedger::::paired_account(StakingAccount::Controller(controller)) } } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index cf08f8be1f27dec6a2d29d9343360f0a6675a2ea..26d05d3a8c878f6dd899bff3e18b6b989aa54f11 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -39,7 +39,10 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, BuildStorage, }; -use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}; +use sp_staking::{ + offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + OnStakingUpdate, +}; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -77,7 +80,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { } pub fn is_disabled(controller: AccountId) -> bool { - let stash = Staking::ledger(&controller).unwrap().stash; + let stash = Ledger::::get(&controller).unwrap().stash; let validator_index = match Session::validators().iter().position(|v| *v == stash) { Some(index) => index as u32, None => return false, @@ -278,6 +281,7 @@ impl OnStakingUpdate for EventListenerMock { _pool_account: &AccountId, slashed_bonded: Balance, slashed_chunks: &BTreeMap, + _total_slashed: Balance, ) { LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); } @@ -777,6 +781,16 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { } } +pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> Result<(), String> { + >::get(&stash).map_or(Ok(()), |_| Err("stash already bonded"))?; + >::get(&controller).map_or(Ok(()), |_| Err("controller already bonded"))?; + + >::insert(stash, controller); + >::insert(controller, StakingLedger::::default_from(stash)); + + Ok(()) +} + #[macro_export] macro_rules! assert_session_era { ($session:expr, $era:expr) => { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 3d9b1157ca87afaaea80b260ecb8d71179ffe4df..ad2de1d59315a0826729324707c1b60aec103cb5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -27,8 +27,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveResult, EstimateNextNewSession, Get, Imbalance, - LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, + Currency, Defensive, DefensiveResult, EstimateNextNewSession, Get, Imbalance, OnUnbalanced, + TryCollect, UnixTime, }, weights::Weight, }; @@ -41,7 +41,9 @@ use sp_runtime::{ use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, Stake, StakingInterface, + EraIndex, SessionIndex, Stake, + StakingAccount::{self, Controller, Stash}, + StakingInterface, }; use sp_std::prelude::*; @@ -52,7 +54,7 @@ use crate::{ SessionInterface, StakingLedger, ValidatorPrefs, }; -use super::{pallet::*, STAKING_ID}; +use super::pallet::*; #[cfg(feature = "try-runtime")] use frame_support::ensure; @@ -68,10 +70,24 @@ use sp_runtime::TryRuntimeError; const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2; impl Pallet { + /// Fetches the ledger associated with a controller or stash account, if any. + pub fn ledger(account: StakingAccount) -> Result, Error> { + StakingLedger::::get(account) + } + + pub fn payee(account: StakingAccount) -> RewardDestination { + StakingLedger::::reward_destination(account) + } + + /// Fetches the controller bonded to a stash account, if any. + pub fn bonded(stash: &T::AccountId) -> Option { + StakingLedger::::paired_account(Stash(stash.clone())) + } + /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. - Self::bonded(stash).and_then(Self::ledger).map(|l| l.active).unwrap_or_default() + Self::ledger(Stash(stash.clone())).map(|l| l.active).unwrap_or_default() } /// Internal impl of [`Self::slashable_balance_of`] that returns [`VoteWeight`]. @@ -105,25 +121,24 @@ impl Pallet { controller: &T::AccountId, num_slashing_spans: u32, ) -> Result { - let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let mut ledger = Self::ledger(Controller(controller.clone()))?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); if let Some(current_era) = Self::current_era() { ledger = ledger.consolidate_unlocked(current_era) } + let new_total = ledger.total; let used_weight = if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { // 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. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); + Self::kill_stash(&ledger.stash, num_slashing_spans)?; T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans) } else { // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); + ledger.update()?; // This is only an update, so we use less overall weight. T::WeightInfo::withdraw_unbonded_update(num_slashing_spans) @@ -131,9 +146,9 @@ impl Pallet { // `old_total` should never be less than the new total because // `consolidate_unlocked` strictly subtracts balance. - if ledger.total < old_total { + if new_total < old_total { // Already checked that this won't overflow by entry condition. - let value = old_total - ledger.total; + let value = old_total - new_total; Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } @@ -163,10 +178,15 @@ impl Pallet { .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; - let controller = Self::bonded(&validator_stash).ok_or_else(|| { - Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + let account = StakingAccount::Stash(validator_stash.clone()); + let mut ledger = Self::ledger(account.clone()).or_else(|_| { + if StakingLedger::::is_bonded(account) { + Err(Error::::NotController.into()) + } else { + Err(Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) + } })?; - let mut ledger = >::get(&controller).ok_or(Error::::NotController)?; + let stash = ledger.stash.clone(); ledger .claimed_rewards @@ -185,11 +205,11 @@ impl Pallet { .defensive_map_err(|_| Error::::BoundNotMet)?, } - let exposure = >::get(&era, &ledger.stash); + let exposure = >::get(&era, &stash); // Input data seems good, no errors allowed after this point - >::insert(&controller, &ledger); + ledger.update()?; // Get Era reward points. It has TOTAL and INDIVIDUAL // Find the fraction of the era reward that belongs to the validator @@ -200,11 +220,8 @@ impl Pallet { let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; - let validator_reward_points = era_reward_points - .individual - .get(&ledger.stash) - .copied() - .unwrap_or_else(Zero::zero); + let validator_reward_points = + era_reward_points.individual.get(&stash).copied().unwrap_or_else(Zero::zero); // Nothing to do if they have no reward points. if validator_reward_points.is_zero() { @@ -231,19 +248,15 @@ impl Pallet { Self::deposit_event(Event::::PayoutStarted { era_index: era, - validator_stash: ledger.stash.clone(), + validator_stash: stash.clone(), }); let mut total_imbalance = PositiveImbalanceOf::::zero(); // We can now make total validator payout: if let Some((imbalance, dest)) = - Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout) + Self::make_payout(&stash, validator_staking_payout + validator_commission_payout) { - Self::deposit_event(Event::::Rewarded { - stash: ledger.stash, - dest, - amount: imbalance.peek(), - }); + Self::deposit_event(Event::::Rewarded { stash, dest, amount: imbalance.peek() }); total_imbalance.subsume(imbalance); } @@ -278,14 +291,6 @@ impl Pallet { Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } - /// Update the ledger for a controller. - /// - /// This will also update the stash lock. - pub(crate) fn update_ledger(controller: &T::AccountId, ledger: &StakingLedger) { - T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, WithdrawReasons::all()); - >::insert(controller, ledger); - } - /// Chill a stash account. pub(crate) fn chill_stash(stash: &T::AccountId) { let chilled_as_validator = Self::do_remove_validator(stash); @@ -301,24 +306,30 @@ impl Pallet { stash: &T::AccountId, amount: BalanceOf, ) -> Option<(PositiveImbalanceOf, RewardDestination)> { - let maybe_imbalance = match Self::payee(stash) { + let dest = Self::payee(StakingAccount::Stash(stash.clone())); + let maybe_imbalance = match dest { RewardDestination::Controller => Self::bonded(stash) .map(|controller| T::Currency::deposit_creating(&controller, amount)), RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), - RewardDestination::Staked => Self::bonded(stash) - .and_then(|c| Self::ledger(&c).map(|l| (c, l))) - .and_then(|(controller, mut l)| { - l.active += amount; - l.total += amount; + RewardDestination::Staked => Self::ledger(Stash(stash.clone())) + .and_then(|mut ledger| { + ledger.active += amount; + ledger.total += amount; let r = T::Currency::deposit_into_existing(stash, amount).ok(); - Self::update_ledger(&controller, &l); - r - }), + + let _ = ledger + .update() + .defensive_proof("ledger fetched from storage, so it exists; qed."); + + Ok(r) + }) + .unwrap_or_default(), RewardDestination::Account(dest_account) => Some(T::Currency::deposit_creating(&dest_account, amount)), RewardDestination::None => None, }; - maybe_imbalance.map(|imbalance| (imbalance, Self::payee(stash))) + maybe_imbalance + .map(|imbalance| (imbalance, Self::payee(StakingAccount::Stash(stash.clone())))) } /// Plan a new session potentially trigger a new era. @@ -407,7 +418,6 @@ impl Pallet { } /// Start a new era. It does: - /// /// * Increment `active_era.index`, /// * reset `active_era.start`, /// * update `BondedEras` and apply slashes. @@ -666,18 +676,16 @@ impl Pallet { /// - after a `withdraw_unbonded()` call that frees all of a stash's bonded balance. /// - through `reap_stash()` if the balance has fallen to zero (through slashing). pub(crate) fn kill_stash(stash: &T::AccountId, num_slashing_spans: u32) -> DispatchResult { - let controller = >::get(stash).ok_or(Error::::NotStash)?; - - slashing::clear_stash_metadata::(stash, num_slashing_spans)?; + slashing::clear_stash_metadata::(&stash, num_slashing_spans)?; - >::remove(stash); - >::remove(&controller); + // removes controller from `Bonded` and staking ledger from `Ledger`, as well as reward + // setting of the stash in `Payee`. + StakingLedger::::kill(&stash)?; - >::remove(stash); - Self::do_remove_validator(stash); - Self::do_remove_nominator(stash); + Self::do_remove_validator(&stash); + Self::do_remove_nominator(&stash); - frame_system::Pallet::::dec_consumers(stash); + frame_system::Pallet::::dec_consumers(&stash); Ok(()) } @@ -1123,13 +1131,7 @@ impl ElectionDataProvider for Pallet { >::insert(voter.clone(), voter.clone()); >::insert( voter.clone(), - StakingLedger { - stash: voter.clone(), - active: stake, - total: stake, - unlocking: Default::default(), - claimed_rewards: Default::default(), - }, + StakingLedger::::new(voter.clone(), stake, Default::default()), ); Self::do_add_nominator(&voter, Nominations { targets, submitted_in: 0, suppressed: false }); @@ -1141,13 +1143,7 @@ impl ElectionDataProvider for Pallet { >::insert(target.clone(), target.clone()); >::insert( target.clone(), - StakingLedger { - stash: target.clone(), - active: stake, - total: stake, - unlocking: Default::default(), - claimed_rewards: Default::default(), - }, + StakingLedger::::new(target.clone(), stake, Default::default()), ); Self::do_add_validator( &target, @@ -1182,13 +1178,7 @@ impl ElectionDataProvider for Pallet { >::insert(v.clone(), v.clone()); >::insert( v.clone(), - StakingLedger { - stash: v.clone(), - active: stake, - total: stake, - unlocking: Default::default(), - claimed_rewards: Default::default(), - }, + StakingLedger::::new(v.clone(), stake, Default::default()), ); Self::do_add_validator( &v, @@ -1203,13 +1193,7 @@ impl ElectionDataProvider for Pallet { >::insert(v.clone(), v.clone()); >::insert( v.clone(), - StakingLedger { - stash: v.clone(), - active: stake, - total: stake, - unlocking: Default::default(), - claimed_rewards: Default::default(), - }, + StakingLedger::::new(v.clone(), stake, Default::default()), ); Self::do_add_nominator( &v, @@ -1459,9 +1443,9 @@ impl ScoreProvider for Pallet { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. let active: BalanceOf = weight.try_into().map_err(|_| ()).unwrap(); - let mut ledger = match Self::ledger(who) { - None => StakingLedger::default_from(who.clone()), - Some(l) => l, + let mut ledger = match Self::ledger(StakingAccount::Stash(who.clone())) { + Ok(l) => l, + Err(_) => StakingLedger::default_from(who.clone()), }; ledger.active = active; @@ -1652,9 +1636,9 @@ impl StakingInterface for Pallet { } fn stash_by_ctrl(controller: &Self::AccountId) -> Result { - Self::ledger(controller) + Self::ledger(Controller(controller.clone())) .map(|l| l.stash) - .ok_or(Error::::NotController.into()) + .map_err(|e| e.into()) } fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { @@ -1672,10 +1656,9 @@ impl StakingInterface for Pallet { } fn stake(who: &Self::AccountId) -> Result>, DispatchError> { - Self::bonded(who) - .and_then(|c| Self::ledger(c)) + Self::ledger(Stash(who.clone())) .map(|l| Stake { total: l.total, active: l.active }) - .ok_or(Error::::NotStash.into()) + .map_err(|e| e.into()) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { @@ -1700,7 +1683,7 @@ impl StakingInterface for Pallet { who: Self::AccountId, num_slashing_spans: u32, ) -> Result { - let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; + let ctrl = Self::bonded(&who).ok_or(Error::::NotStash)?; Self::withdraw_unbonded(RawOrigin::Signed(ctrl.clone()).into(), num_slashing_spans) .map(|_| !Ledger::::contains_key(&ctrl)) .map_err(|with_post| with_post.error) @@ -1727,8 +1710,7 @@ impl StakingInterface for Pallet { fn status( who: &Self::AccountId, ) -> Result, DispatchError> { - let is_bonded = Self::bonded(who).is_some(); - if !is_bonded { + if !StakingLedger::::is_bonded(StakingAccount::Stash(who.clone())) { return Err(Error::::NotStash.into()) } @@ -1882,7 +1864,8 @@ impl Pallet { fn ensure_ledger_consistent(ctrl: T::AccountId) -> Result<(), TryRuntimeError> { // ensures ledger.total == ledger.active + sum(ledger.unlocking). - let ledger = Self::ledger(ctrl.clone()).ok_or("Not a controller.")?; + let ledger = Self::ledger(StakingAccount::Controller(ctrl.clone()))?; + let real_total: BalanceOf = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value); ensure!(real_total == ledger.total, "ledger.total corrupt"); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0bcf932d90b44d9233515bb312e470fcd4ef1480..f084299be8e13d88b9228d123fe75a0593640c34 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,8 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, - UnixTime, + EstimateNextNewSession, Get, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, BoundedVec, @@ -36,7 +35,10 @@ use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, }; -use sp_staking::{EraIndex, SessionIndex}; +use sp_staking::{ + EraIndex, SessionIndex, + StakingAccount::{self, Controller, Stash}, +}; use sp_std::prelude::*; mod impls; @@ -50,7 +52,6 @@ use crate::{ UnappliedSlash, UnlockChunk, ValidatorPrefs, }; -const STAKING_ID: LockIdentifier = *b"staking "; // The speculative number of spans are used as an input of the weight annotation of // [`Call::unbond`], as the post dipatch weight may depend on the number of slashing span on the // account which is not provided as an input. The value set should be conservative but sensible. @@ -295,7 +296,6 @@ pub mod pallet { /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] - #[pallet::getter(fn bonded)] pub type Bonded = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>; /// The minimum active bond to become and maintain the role of a nominator. @@ -317,15 +317,16 @@ pub mod pallet { pub type MinCommission = StorageValue<_, Perbill, ValueQuery>; /// Map from all (unlocked) "controller" accounts to the info regarding the staking. + /// + /// Note: All the reads and mutations to this storage *MUST* be done through the methods exposed + /// by [`StakingLedger`] to ensure data and lock consistency. #[pallet::storage] - #[pallet::getter(fn ledger)] pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; /// Where the reward payment should be made. Keyed by stash. /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] - #[pallet::getter(fn payee)] pub type Payee = StorageMap<_, Twox64Concat, T::AccountId, RewardDestination, ValueQuery>; @@ -841,16 +842,11 @@ pub mod pallet { payee: RewardDestination, ) -> DispatchResult { let stash = ensure_signed(origin)?; - let controller_to_be_deprecated = stash.clone(); - if >::contains_key(&stash) { + if StakingLedger::::is_bonded(StakingAccount::Stash(stash.clone())) { return Err(Error::::AlreadyBonded.into()) } - if >::contains_key(&controller_to_be_deprecated) { - return Err(Error::::AlreadyPaired.into()) - } - // Reject a bond which is considered to be _dust_. if value < T::Currency::minimum_balance() { return Err(Error::::InsufficientBond.into()) @@ -858,11 +854,6 @@ pub mod pallet { frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; - // You're auto-bonded forever, here. We might improve this by only bonding when - // you actually validate/nominate and remove once you unbond __everything__. - >::insert(&stash, &stash); - >::insert(&stash, payee); - let current_era = CurrentEra::::get().unwrap_or(0); let history_depth = T::HistoryDepth::get(); let last_reward_era = current_era.saturating_sub(history_depth); @@ -870,19 +861,21 @@ pub mod pallet { let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); - let item = StakingLedger { - stash: stash.clone(), - total: value, - active: value, - unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era) + let ledger = StakingLedger::::new( + stash.clone(), + value, + (last_reward_era..current_era) .try_collect() // Since last_reward_era is calculated as `current_era - // HistoryDepth`, following bound is always expected to be // satisfied. .defensive_map_err(|_| Error::::BoundNotMet)?, - }; - Self::update_ledger(&controller_to_be_deprecated, &item); + ); + + // You're auto-bonded forever, here. We might improve this by only bonding when + // you actually validate/nominate and remove once you unbond __everything__. + ledger.bond(payee)?; + Ok(()) } @@ -908,8 +901,7 @@ pub mod pallet { ) -> DispatchResult { let stash = ensure_signed(origin)?; - let controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; - let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + 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) { @@ -923,11 +915,10 @@ pub mod pallet { ); // NOTE: ledger must be updated prior to calling `Self::weight_of`. - Self::update_ledger(&controller, &ledger); + 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(&ledger.stash)).defensive(); + let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); } Self::deposit_event(Event::::Bonded { stash, amount: extra }); @@ -963,9 +954,8 @@ pub mod pallet { #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - let unlocking = Self::ledger(&controller) - .map(|l| l.unlocking.len()) - .ok_or(Error::::NotController)?; + let unlocking = + Self::ledger(Controller(controller.clone())).map(|l| l.unlocking.len())?; // if there are no unlocking chunks available, try to withdraw chunks older than // `BondingDuration` to proceed with the unbonding. @@ -981,8 +971,9 @@ pub mod pallet { // we need to fetch the ledger again because it may have been mutated in the call // to `Self::do_withdraw_unbonded` above. - let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let mut ledger = Self::ledger(Controller(controller))?; let mut value = value.min(ledger.active); + let stash = ledger.stash.clone(); ensure!( ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, @@ -998,9 +989,9 @@ pub mod pallet { ledger.active = Zero::zero(); } - let min_active_bond = if Nominators::::contains_key(&ledger.stash) { + let min_active_bond = if Nominators::::contains_key(&stash) { MinNominatorBond::::get() - } else if Validators::::contains_key(&ledger.stash) { + } else if Validators::::contains_key(&stash) { MinValidatorBond::::get() } else { Zero::zero() @@ -1024,15 +1015,14 @@ pub mod pallet { .map_err(|_| Error::::NoMoreChunks)?; }; // NOTE: ledger must be updated prior to calling `Self::weight_of`. - Self::update_ledger(&controller, &ledger); + ledger.update()?; // update this staker in the sorted list, if they exist in it. - if T::VoterList::contains(&ledger.stash) { - let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)) - .defensive(); + if T::VoterList::contains(&stash) { + let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); } - Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); + Self::deposit_event(Event::::Unbonded { stash, amount: value }); } let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight { @@ -1089,7 +1079,7 @@ pub mod pallet { pub fn validate(origin: OriginFor, prefs: ValidatorPrefs) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let ledger = Self::ledger(Controller(controller))?; ensure!(ledger.active >= MinValidatorBond::::get(), Error::::InsufficientBond); let stash = &ledger.stash; @@ -1135,7 +1125,8 @@ pub mod pallet { ) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?; + ensure!(ledger.active >= MinNominatorBond::::get(), Error::::InsufficientBond); let stash = &ledger.stash; @@ -1202,7 +1193,9 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::chill())] pub fn chill(origin: OriginFor) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + + let ledger = Self::ledger(StakingAccount::Controller(controller))?; + Self::chill_stash(&ledger.stash); Ok(()) } @@ -1226,9 +1219,11 @@ pub mod pallet { payee: RewardDestination, ) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - let stash = &ledger.stash; - >::insert(stash, payee); + let ledger = Self::ledger(Controller(controller))?; + let _ = ledger + .set_payee(payee) + .defensive_proof("ledger was retrieved from storage, thus its bonded; qed."); + Ok(()) } @@ -1250,18 +1245,24 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_controller())] pub fn set_controller(origin: OriginFor) -> DispatchResult { let stash = ensure_signed(origin)?; - let old_controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; - if >::contains_key(&stash) { - return Err(Error::::AlreadyPaired.into()) - } - if old_controller != stash { - >::insert(&stash, &stash); - if let Some(l) = >::take(&old_controller) { - >::insert(&stash, l); + // the bonded map and ledger are mutated directly as this extrinsic is related to a + // (temporary) passive migration. + Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| { + let controller = ledger.controller() + .defensive_proof("ledger was fetched used the StakingInterface, so controller field must exist; qed.") + .ok_or(Error::::NotController)?; + + if controller == stash { + // stash is already its own controller. + return Err(Error::::AlreadyPaired.into()) } - } - Ok(()) + // update bond and ledger. + >::remove(controller); + >::insert(&stash, &stash); + >::insert(&stash, ledger); + Ok(()) + })? } /// Sets the ideal number of validators. @@ -1409,11 +1410,9 @@ pub mod pallet { ) -> DispatchResult { ensure_root(origin)?; - // Remove all staking-related information. + // Remove all staking-related information and lock. Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); Ok(()) } @@ -1502,7 +1501,7 @@ pub mod pallet { #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let ledger = Self::ledger(Controller(controller))?; ensure!(!ledger.unlocking.is_empty(), Error::::NoUnlockChunk); let initial_unlocking = ledger.unlocking.len() as u32; @@ -1515,16 +1514,18 @@ pub mod pallet { amount: rebonded_value, }); + let stash = ledger.stash.clone(); + let final_unlocking = ledger.unlocking.len(); + // NOTE: ledger must be updated prior to calling `Self::weight_of`. - Self::update_ledger(&controller, &ledger); - if T::VoterList::contains(&ledger.stash) { - let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)) - .defensive(); + ledger.update()?; + if T::VoterList::contains(&stash) { + let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); } let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed .saturating_add(initial_unlocking) - .saturating_sub(ledger.unlocking.len() as u32); + .saturating_sub(final_unlocking as u32); Ok(Some(T::WeightInfo::rebond(removed_chunks)).into()) } @@ -1556,13 +1557,11 @@ pub mod pallet { let ed = T::Currency::minimum_balance(); let reapable = T::Currency::total_balance(&stash) < ed || - Self::ledger(Self::bonded(stash.clone()).ok_or(Error::::NotStash)?) - .map(|l| l.total) - .unwrap_or_default() < ed; + Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default() < ed; ensure!(reapable, Error::::FundedTarget); + // Remove all staking-related information and lock. Self::kill_stash(&stash, num_slashing_spans)?; - T::Currency::remove_lock(STAKING_ID, &stash); Ok(Pays::No.into()) } @@ -1582,7 +1581,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::kick(who.len() as u32))] pub fn kick(origin: OriginFor, who: Vec>) -> DispatchResult { let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let ledger = Self::ledger(Controller(controller))?; let stash = &ledger.stash; for nom_stash in who @@ -1691,7 +1690,7 @@ pub mod pallet { pub fn chill_other(origin: OriginFor, controller: T::AccountId) -> DispatchResult { // Anyone can call this function. let caller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let ledger = Self::ledger(Controller(controller.clone()))?; let stash = ledger.stash; // In order for one user to chill another user, the following conditions must be met: diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index bb02da73f6e5d5ddb96f23f61a7ac4ca463e0f03..0d84d503733e6451feb69f287d69f8655fe0b20e 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -597,15 +597,11 @@ pub fn do_slash( slashed_imbalance: &mut NegativeImbalanceOf, slash_era: EraIndex, ) { - let controller = match >::bonded(stash).defensive() { - None => return, - Some(c) => c, - }; - - let mut ledger = match >::ledger(&controller) { - Some(ledger) => ledger, - None => return, // nothing to do. - }; + let mut ledger = + match Pallet::::ledger(sp_staking::StakingAccount::Stash(stash.clone())).defensive() { + Ok(ledger) => ledger, + Err(_) => return, // nothing to do. + }; let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); @@ -618,7 +614,9 @@ pub fn do_slash( *reward_payout = reward_payout.saturating_sub(missing); } - >::update_ledger(&controller, &ledger); + let _ = ledger + .update() + .defensive_proof("ledger fetched from storage so it exists in storage; qed."); // trigger the event >::deposit_event(super::Event::::Slashed { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 78183cfde9296bdec25327b39c8fd6691a403296..cb620f89f12c01c3c1816717993fb9d7bb6d1fcc 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -18,6 +18,7 @@ //! Tests for the module. use super::{ConfigOp, Event, *}; +use crate::ledger::StakingLedgerInspect; use frame_election_provider_support::{ bounds::{DataProviderBounds, ElectionBoundsBuilder}, ElectionProvider, SortedListProvider, Support, @@ -33,7 +34,7 @@ use pallet_balances::Error as BalancesError; use sp_runtime::{ assert_eq_error_rate, bounded_vec, traits::{BadOrigin, Dispatchable}, - Perbill, Percent, Rounding, TokenError, + Perbill, Percent, Perquintill, Rounding, TokenError, }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, @@ -151,8 +152,8 @@ fn basic_setup_works() { // Account 11 controls its own stash, which is 100 * balance_factor units assert_eq!( - Staking::ledger(&11).unwrap(), - StakingLedger { + Ledger::get(&11).unwrap(), + StakingLedgerInspect:: { stash: 11, total: 1000, active: 1000, @@ -162,17 +163,17 @@ fn basic_setup_works() { ); // Account 21 controls its own stash, which is 200 * balance_factor units assert_eq!( - Staking::ledger(&21), - Some(StakingLedger { + Ledger::get(&21).unwrap(), + StakingLedgerInspect:: { stash: 21, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Account 1 does not control any stash - assert_eq!(Staking::ledger(&1), None); + assert!(Staking::ledger(1.into()).is_err()); // ValidatorPrefs are default assert_eq_uvec!( @@ -185,14 +186,14 @@ fn basic_setup_works() { ); assert_eq!( - Staking::ledger(101), - Some(StakingLedger { + Staking::ledger(101.into()).unwrap(), + StakingLedgerInspect { stash: 101, total: 500, active: 500, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -265,7 +266,7 @@ fn change_controller_works() { #[test] fn change_controller_already_paired_once_stash() { ExtBuilder::default().build_and_execute(|| { - // 10 and 11 are bonded as controller and stash respectively. + // 11 and 11 are bonded as controller and stash respectively. assert_eq!(Staking::bonded(&11), Some(11)); // 11 is initially a validator. @@ -460,14 +461,14 @@ fn staking_should_work() { // Note: the stashed value of 4 is still lock assert_eq!( - Staking::ledger(&3), - Some(StakingLedger { + Staking::ledger(3.into()).unwrap(), + StakingLedgerInspect { stash: 3, total: 1500, active: 1500, unlocking: Default::default(), claimed_rewards: bounded_vec![0], - }) + } ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 assert_noop!(Balances::reserve(&3, 501), BalancesError::::LiquidityRestrictions); @@ -717,9 +718,9 @@ fn nominators_also_get_slashed_pro_rata() { assert_eq!(initial_exposure.others.first().unwrap().who, 101); // staked values; - let nominator_stake = Staking::ledger(101).unwrap().active; + let nominator_stake = Staking::ledger(101.into()).unwrap().active; let nominator_balance = balances(&101).0; - let validator_stake = Staking::ledger(11).unwrap().active; + 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; @@ -732,8 +733,8 @@ fn nominators_also_get_slashed_pro_rata() { ); // both stakes must have been decreased. - assert!(Staking::ledger(101).unwrap().active < nominator_stake); - assert!(Staking::ledger(11).unwrap().active < validator_stake); + 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 = @@ -746,8 +747,8 @@ fn nominators_also_get_slashed_pro_rata() { assert!(nominator_share > 0); // both stakes must have been decreased pro-rata. - assert_eq!(Staking::ledger(101).unwrap().active, nominator_stake - nominator_share); - assert_eq!(Staking::ledger(11).unwrap().active, validator_stake - validator_share); + 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, @@ -1047,14 +1048,14 @@ fn reward_destination_works() { assert_eq!(Balances::free_balance(11), 1000); // Check how much is at stake assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Compute total payout now for whole duration as other parameter won't change @@ -1065,19 +1066,19 @@ fn reward_destination_works() { mock::make_all_reward_payment(0); // Check that RewardDestination is Staked (default) - assert_eq!(Staking::payee(&11), RewardDestination::Staked); + assert_eq!(Staking::payee(11.into()), RewardDestination::Staked); // Check that reward went to the stash account of validator assert_eq!(Balances::free_balance(11), 1000 + total_payout_0); // Check that amount at stake increased accordingly assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), claimed_rewards: bounded_vec![0], - }) + } ); // Change RewardDestination to Stash @@ -1091,19 +1092,19 @@ fn reward_destination_works() { mock::make_all_reward_payment(1); // Check that RewardDestination is Stash - assert_eq!(Staking::payee(&11), RewardDestination::Stash); + assert_eq!(Staking::payee(11.into()), RewardDestination::Stash); // Check that reward went to the stash account assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1); // Check that amount at stake is NOT increased assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), claimed_rewards: bounded_vec![0, 1], - }) + } ); // Change RewardDestination to Controller @@ -1120,19 +1121,19 @@ fn reward_destination_works() { mock::make_all_reward_payment(2); // Check that RewardDestination is Controller - assert_eq!(Staking::payee(&11), RewardDestination::Controller); + assert_eq!(Staking::payee(11.into()), RewardDestination::Controller); // Check that reward went to the controller account assert_eq!(Balances::free_balance(11), 23150 + total_payout_2); // Check that amount at stake is NOT increased assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), claimed_rewards: bounded_vec![0, 1, 2], - }) + } ); }); } @@ -1185,14 +1186,14 @@ fn bond_extra_works() { assert_eq!(Staking::bonded(&11), Some(11)); // Check how much is at stake assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Give account 11 some large free balance greater than total @@ -1202,28 +1203,28 @@ fn bond_extra_works() { assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); // There should be 100 more `total` and `active` in the ledger assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Call the bond_extra function with a large number, should handle it assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), Balance::max_value())); // The full amount of the funds should now be in the total and active assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000000, active: 1000000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); }); } @@ -1254,14 +1255,14 @@ fn bond_extra_and_withdraw_unbonded_works() { // Initial state of 11 assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); assert_eq!( Staking::eras_stakers(active_era(), 11), @@ -1272,14 +1273,14 @@ fn bond_extra_and_withdraw_unbonded_works() { Staking::bond_extra(RuntimeOrigin::signed(11), 100).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Exposure is a snapshot! only updated after the next era update. assert_ne!( @@ -1293,14 +1294,14 @@ fn bond_extra_and_withdraw_unbonded_works() { // ledger should be the same. assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Exposure is now updated. assert_eq!( @@ -1311,27 +1312,27 @@ fn bond_extra_and_withdraw_unbonded_works() { // Unbond almost all of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 1000).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: bounded_vec![], - }), + }, ); // Attempting to free the balances now will fail. 2 eras need to pass. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: bounded_vec![], - }), + }, ); // trigger next era. @@ -1340,14 +1341,14 @@ fn bond_extra_and_withdraw_unbonded_works() { // nothing yet assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], claimed_rewards: bounded_vec![], - }), + }, ); // trigger next era. @@ -1356,14 +1357,14 @@ fn bond_extra_and_withdraw_unbonded_works() { assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); // Now the value is free and the staking ledger is updated. assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 100, active: 100, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }), + }, ); }) } @@ -1390,7 +1391,7 @@ fn many_unbond_calls_should_work() { // `BondingDuration` == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1)); assert_eq!( - Staking::ledger(&11).map(|l| l.unlocking.len()).unwrap(), + Staking::ledger(11.into()).map(|l| l.unlocking.len()).unwrap(), <::MaxUnlockingChunks as Get>::get() as usize ); @@ -1405,7 +1406,7 @@ fn many_unbond_calls_should_work() { // only slots within last `BondingDuration` are filled. assert_eq!( - Staking::ledger(&11).map(|l| l.unlocking.len()).unwrap(), + Staking::ledger(11.into()).map(|l| l.unlocking.len()).unwrap(), <::BondingDuration>::get() as usize ); }) @@ -1459,14 +1460,14 @@ fn rebond_works() { // Initial state of 11 assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(2); @@ -1478,66 +1479,66 @@ fn rebond_works() { // Unbond almost all of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond all the funds unbonded. Staking::rebond(RuntimeOrigin::signed(11), 900).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Unbond almost all of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond part of the funds unbonded. Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond the remainder of the funds unbonded. Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Unbond parts of the funds in stash. @@ -1545,27 +1546,27 @@ fn rebond_works() { Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap(); Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond part of the funds unbonded. Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], claimed_rewards: bounded_vec![], - }) + } ); }) } @@ -1585,14 +1586,14 @@ fn rebond_is_fifo() { // Initial state of 10 assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(2); @@ -1600,14 +1601,14 @@ fn rebond_is_fifo() { // Unbond some of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 400).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(3); @@ -1615,8 +1616,8 @@ fn rebond_is_fifo() { // Unbond more of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 300, @@ -1625,7 +1626,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, ], claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(4); @@ -1633,8 +1634,8 @@ fn rebond_is_fifo() { // Unbond yet more of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 200).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 100, @@ -1644,14 +1645,14 @@ fn rebond_is_fifo() { UnlockChunk { value: 200, era: 4 + 3 }, ], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond half of the unbonding funds. Staking::rebond(RuntimeOrigin::signed(11), 400).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 500, @@ -1660,7 +1661,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 100, era: 3 + 3 }, ], claimed_rewards: bounded_vec![], - }) + } ); }) } @@ -1682,27 +1683,27 @@ fn rebond_emits_right_value_in_event() { // Unbond almost all of the funds in stash. Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], claimed_rewards: bounded_vec![], - }) + } ); // Re-bond less than the total Staking::rebond(RuntimeOrigin::signed(11), 100).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 200, unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], claimed_rewards: bounded_vec![], - }) + } ); // Event emitted should be correct assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 100 }); @@ -1710,14 +1711,14 @@ fn rebond_emits_right_value_in_event() { // Re-bond way more than available Staking::rebond(RuntimeOrigin::signed(11), 100_000).unwrap(); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); // Event emitted should be correct, only 800 assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 800 }); @@ -1747,7 +1748,7 @@ fn reward_to_stake_works() { ErasStakers::::insert(0, 21, Exposure { total: 69, own: 69, others: vec![] }); >::insert( &20, - StakingLedger { + StakingLedgerInspect { stash: 21, total: 69, active: 69, @@ -1806,16 +1807,7 @@ fn reap_stash_works() { // no easy way to cause an account to go below ED, we tweak their staking ledger // instead. - Ledger::::insert( - 11, - StakingLedger { - stash: 11, - total: 5, - active: 5, - unlocking: Default::default(), - claimed_rewards: bounded_vec![], - }, - ); + Ledger::::insert(11, StakingLedger::::new(11, 5, bounded_vec![])); // reap-able assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); @@ -1937,14 +1929,14 @@ fn bond_with_no_staked_value() { // unbonding even 1 will cause all to be unbonded. assert_ok!(Staking::unbond(RuntimeOrigin::signed(1), 1)); assert_eq!( - Staking::ledger(1), - Some(StakingLedger { + Staking::ledger(1.into()).unwrap(), + StakingLedgerInspect { stash: 1, active: 0, total: 5, unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(1); @@ -1952,14 +1944,14 @@ fn bond_with_no_staked_value() { // not yet removed. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); - assert!(Staking::ledger(1).is_some()); + assert!(Staking::ledger(1.into()).is_ok()); assert_eq!(Balances::locks(&1)[0].amount, 5); mock::start_active_era(3); // poof. Account 1 is removed from the staking system. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); - assert!(Staking::ledger(1).is_none()); + assert!(Staking::ledger(1.into()).is_err()); assert_eq!(Balances::locks(&1).len(), 0); }); } @@ -2044,7 +2036,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { // ensure all have equal stake. assert_eq!( >::iter() - .map(|(v, _)| (v, Staking::ledger(v).unwrap().total)) + .map(|(v, _)| (v, Staking::ledger(v.into()).unwrap().total)) .collect::>(), vec![(31, 1000), (21, 1000), (11, 1000)], ); @@ -2096,7 +2088,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { // ensure all have equal stake. assert_eq!( >::iter() - .map(|(v, _)| (v, Staking::ledger(v).unwrap().total)) + .map(|(v, _)| (v, Staking::ledger(v.into()).unwrap().total)) .collect::>(), vec![(31, 1000), (21, 1000), (11, 1000)], ); @@ -2982,7 +2974,7 @@ fn retroactive_deferred_slashes_one_before() { mock::start_active_era(4); - assert_eq!(Staking::ledger(11).unwrap().total, 1000); + assert_eq!(Staking::ledger(11.into()).unwrap().total, 1000); // slash happens after the next line. mock::start_active_era(5); @@ -2997,9 +2989,9 @@ fn retroactive_deferred_slashes_one_before() { )); // their ledger has already been slashed. - assert_eq!(Staking::ledger(11).unwrap().total, 900); + assert_eq!(Staking::ledger(11.into()).unwrap().total, 900); assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1000)); - assert_eq!(Staking::ledger(11).unwrap().total, 900); + assert_eq!(Staking::ledger(11.into()).unwrap().total, 900); }) } @@ -3032,7 +3024,7 @@ fn staker_cannot_bail_deferred_slash() { assert_eq!( Ledger::::get(101).unwrap(), - StakingLedger { + StakingLedgerInspect { active: 0, total: 500, stash: 101, @@ -3782,14 +3774,14 @@ fn test_payout_stakers() { // We track rewards in `claimed_rewards` vec assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![1] - }) + } ); for i in 3..16 { @@ -3813,14 +3805,14 @@ fn test_payout_stakers() { // We track rewards in `claimed_rewards` vec assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: (1..=14).collect::>().try_into().unwrap() - }) + } ); let last_era = 99; @@ -3846,14 +3838,14 @@ fn test_payout_stakers() { expected_last_reward_era )); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] - }) + } ); // Out of order claims works. @@ -3861,8 +3853,8 @@ fn test_payout_stakers() { assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23)); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42)); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, @@ -3874,7 +3866,7 @@ fn test_payout_stakers() { 69, expected_last_reward_era ] - }) + } ); }); } @@ -4073,26 +4065,26 @@ fn bond_during_era_correctly_populates_claimed_rewards() { // Era = None bond_validator(9, 1000); assert_eq!( - Staking::ledger(&9), - Some(StakingLedger { + Staking::ledger(9.into()).unwrap(), + StakingLedgerInspect { stash: 9, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: bounded_vec![], - }) + } ); mock::start_active_era(5); bond_validator(11, 1000); assert_eq!( - Staking::ledger(&11), - Some(StakingLedger { + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), claimed_rewards: (0..5).collect::>().try_into().unwrap(), - }) + } ); // make sure only era upto history depth is stored @@ -4101,8 +4093,8 @@ fn bond_during_era_correctly_populates_claimed_rewards() { mock::start_active_era(current_era); bond_validator(13, 1000); assert_eq!( - Staking::ledger(&13), - Some(StakingLedger { + Staking::ledger(13.into()).unwrap(), + StakingLedgerInspect { stash: 13, total: 1000, active: 1000, @@ -4111,7 +4103,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { .collect::>() .try_into() .unwrap(), - }) + } ); }); } @@ -4200,6 +4192,7 @@ fn payout_creates_controller() { false, ) .unwrap(); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); // kill controller @@ -4356,8 +4349,8 @@ fn cannot_rebond_to_lower_than_ed() { .build_and_execute(|| { // initial stuff. assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: 11 * 1000, active: 11 * 1000, @@ -4370,8 +4363,8 @@ fn cannot_rebond_to_lower_than_ed() { assert_ok!(Staking::chill(RuntimeOrigin::signed(21))); assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 11 * 1000)); assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: 11 * 1000, active: 0, @@ -4396,8 +4389,8 @@ fn cannot_bond_extra_to_lower_than_ed() { .build_and_execute(|| { // initial stuff. assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: 11 * 1000, active: 11 * 1000, @@ -4410,8 +4403,8 @@ fn cannot_bond_extra_to_lower_than_ed() { assert_ok!(Staking::chill(RuntimeOrigin::signed(21))); assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 11 * 1000)); assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: 11 * 1000, active: 0, @@ -4437,8 +4430,8 @@ fn do_not_die_when_active_is_ed() { .build_and_execute(|| { // given assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: 1000 * ed, active: 1000 * ed, @@ -4454,8 +4447,8 @@ fn do_not_die_when_active_is_ed() { // then assert_eq!( - Staking::ledger(&21).unwrap(), - StakingLedger { + Staking::ledger(21.into()).unwrap(), + StakingLedgerInspect { stash: 21, total: ed, active: ed, @@ -5530,15 +5523,14 @@ fn force_apply_min_commission_works() { #[test] fn proportional_slash_stop_slashing_if_remaining_zero() { let c = |era, value| UnlockChunk:: { era, value }; + + // we have some chunks, but they are not affected. + let unlocking = bounded_vec![c(1, 10), c(2, 10)]; + // Given - let mut ledger = StakingLedger:: { - stash: 123, - total: 40, - active: 20, - // we have some chunks, but they are not affected. - unlocking: bounded_vec![c(1, 10), c(2, 10)], - claimed_rewards: bounded_vec![], - }; + let mut ledger = StakingLedger::::new(123, 20, bounded_vec![]); + ledger.total = 40; + ledger.unlocking = unlocking; assert_eq!(BondingDuration::get(), 3); @@ -5550,13 +5542,7 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { fn proportional_ledger_slash_works() { let c = |era, value| UnlockChunk:: { era, value }; // Given - let mut ledger = StakingLedger:: { - stash: 123, - total: 10, - active: 10, - unlocking: bounded_vec![], - claimed_rewards: bounded_vec![], - }; + let mut ledger = StakingLedger::::new(123, 10, bounded_vec![]); assert_eq!(BondingDuration::get(), 3); // When we slash a ledger with no unlocking chunks @@ -5795,8 +5781,8 @@ fn pre_bonding_era_cannot_be_claimed() { let claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( - Staking::ledger(&3).unwrap(), - StakingLedger { + Staking::ledger(3.into()).unwrap(), + StakingLedgerInspect { stash: 3, total: 1500, active: 1500, @@ -5823,7 +5809,7 @@ fn pre_bonding_era_cannot_be_claimed() { // decoding will fail now since Staking Ledger is in corrupt state HistoryDepth::set(history_depth - 1); - assert_eq!(Staking::ledger(&4), None); + assert!(Staking::ledger(4.into()).is_err()); // make sure stakers still cannot claim rewards that they are not meant to assert_noop!( @@ -5861,8 +5847,8 @@ fn reducing_history_depth_abrupt() { let claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( - Staking::ledger(&3).unwrap(), - StakingLedger { + Staking::ledger(3.into()).unwrap(), + StakingLedgerInspect { stash: 3, total: 1500, active: 1500, @@ -5900,8 +5886,8 @@ fn reducing_history_depth_abrupt() { let claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( - Staking::ledger(&5).unwrap(), - StakingLedger { + Staking::ledger(5.into()).unwrap(), + StakingLedgerInspect { stash: 5, total: 1200, active: 1200, @@ -5924,7 +5910,7 @@ fn reducing_max_unlocking_chunks_abrupt() { MaxUnlockingChunks::set(2); start_active_era(10); assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 300, RewardDestination::Staked)); - assert!(matches!(Staking::ledger(3), Some(_))); + assert!(matches!(Staking::ledger(3.into()), Ok(_))); // when staker unbonds assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 20)); @@ -5933,8 +5919,8 @@ fn reducing_max_unlocking_chunks_abrupt() { // => 10 + 3 = 13 let expected_unlocking: BoundedVec, MaxUnlockingChunks> = bounded_vec![UnlockChunk { value: 20 as Balance, era: 13 as EraIndex }]; - assert!(matches!(Staking::ledger(3), - Some(StakingLedger { + assert!(matches!(Staking::ledger(3.into()), + Ok(StakingLedger { unlocking, .. }) if unlocking==expected_unlocking)); @@ -5945,8 +5931,8 @@ fn reducing_max_unlocking_chunks_abrupt() { // then another unlock chunk is added let expected_unlocking: BoundedVec, MaxUnlockingChunks> = bounded_vec![UnlockChunk { value: 20, era: 13 }, UnlockChunk { value: 50, era: 14 }]; - assert!(matches!(Staking::ledger(3), - Some(StakingLedger { + assert!(matches!(Staking::ledger(3.into()), + Ok(StakingLedger { unlocking, .. }) if unlocking==expected_unlocking)); @@ -6134,3 +6120,123 @@ mod staking_interface { }) } } + +mod ledger { + use super::*; + + #[test] + fn paired_account_works() { + ExtBuilder::default().build_and_execute(|| { + assert_ok!(Staking::bond( + RuntimeOrigin::signed(10), + 100, + RewardDestination::Controller + )); + + assert_eq!(>::get(&10), Some(10)); + assert_eq!( + StakingLedger::::paired_account(StakingAccount::Controller(10)), + Some(10) + ); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(10)), Some(10)); + + assert_eq!(>::get(&42), None); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Controller(42)), None); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(42)), None); + + // bond manually stash with different controller. This is deprecated but the migration + // has not been complete yet (controller: 100, stash: 200) + assert_ok!(bond_controller_stash(100, 200)); + assert_eq!(>::get(&200), Some(100)); + assert_eq!( + StakingLedger::::paired_account(StakingAccount::Controller(100)), + Some(200) + ); + assert_eq!( + StakingLedger::::paired_account(StakingAccount::Stash(200)), + Some(100) + ); + }) + } + + #[test] + fn get_ledger_works() { + ExtBuilder::default().build_and_execute(|| { + // stash does not exist + assert!(StakingLedger::::get(StakingAccount::Stash(42)).is_err()); + + // bonded and paired + assert_eq!(>::get(&11), Some(11)); + + match StakingLedger::::get(StakingAccount::Stash(11)) { + Ok(ledger) => { + assert_eq!(ledger.controller(), Some(11)); + assert_eq!(ledger.stash, 11); + }, + Err(_) => panic!("staking ledger must exist"), + }; + + // bond manually stash with different controller. This is deprecated but the migration + // has not been complete yet (controller: 100, stash: 200) + assert_ok!(bond_controller_stash(100, 200)); + assert_eq!(>::get(&200), Some(100)); + + match StakingLedger::::get(StakingAccount::Stash(200)) { + Ok(ledger) => { + assert_eq!(ledger.controller(), Some(100)); + assert_eq!(ledger.stash, 200); + }, + Err(_) => panic!("staking ledger must exist"), + }; + + match StakingLedger::::get(StakingAccount::Controller(100)) { + Ok(ledger) => { + assert_eq!(ledger.controller(), Some(100)); + assert_eq!(ledger.stash, 200); + }, + Err(_) => panic!("staking ledger must exist"), + }; + }) + } + + #[test] + fn bond_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(!StakingLedger::::is_bonded(StakingAccount::Stash(42))); + assert!(>::get(&42).is_none()); + + let mut ledger: StakingLedger = StakingLedger::default_from(42); + let reward_dest = RewardDestination::Account(10); + + assert_ok!(ledger.clone().bond(reward_dest)); + assert!(StakingLedger::::is_bonded(StakingAccount::Stash(42))); + assert!(>::get(&42).is_some()); + assert_eq!(>::get(&42), reward_dest); + + // cannot bond again. + assert!(ledger.clone().bond(reward_dest).is_err()); + + // once bonded, update works as expected. + ledger.claimed_rewards = bounded_vec![1]; + assert_ok!(ledger.update()); + }) + } + + #[test] + fn is_bonded_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(!StakingLedger::::is_bonded(StakingAccount::Stash(42))); + assert!(!StakingLedger::::is_bonded(StakingAccount::Controller(42))); + + // adds entry to Bonded without Ledger pair (should not happen). + >::insert(42, 42); + assert!(!StakingLedger::::is_bonded(StakingAccount::Controller(42))); + + assert_eq!(>::get(&11), Some(11)); + assert!(StakingLedger::::is_bonded(StakingAccount::Stash(11))); + assert!(StakingLedger::::is_bonded(StakingAccount::Controller(11))); + + >::remove(42); // ensures try-state checks pass. + }) + } +} diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index bdd4252414a6d0c25758bc0f29ed3eb98616145f..a4934346d5dec87d4c6f8df9a924bb1781b0039e 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -22,7 +22,7 @@ sp-io = { path = "../../primitives/io", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} -docify = "0.2.3" +docify = "0.2.4" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 0c869bec7f076f7cc2e240adda1eeb77b8409277..fb29c0da42a99d9f36c1470fabe2a51284f08750 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -204,14 +204,15 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(1)] - #[pallet::weight((*_weight, call.get_dispatch_info().class))] + #[pallet::weight((*weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, call: Box<::RuntimeCall>, - _weight: Weight, + weight: Weight, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; + let _ = weight; // We don't check the weight witness since it is a root call. ensure!(Self::key().map_or(false, |k| sender == k), Error::::RequireSudo); let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 62a7b5e41fe7b907c8905422e3aab5e96ad8d952..65f4885b1599958da031f13ea0726ee330a65588 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -30,7 +30,7 @@ sp-weights = { path = "../../primitives/weights", default-features = false} sp-debug-derive = { path = "../../primitives/debug-derive", default-features = false} sp-metadata-ir = { path = "../../primitives/metadata-ir", default-features = false} tt-call = "1.0.8" -macro_magic = "0.4.2" +macro_magic = "0.5.0" frame-support-procedural = { path = "procedural", default-features = false} paste = "1.0" sp-state-machine = { path = "../../primitives/state-machine", default-features = false, optional = true} @@ -43,7 +43,7 @@ k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features=false} serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] } -docify = "0.2.3" +docify = "0.2.4" static_assertions = "1.1.0" aquamarine = { version = "0.3.2" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index e16068546056692f340eead77138de6fe1c5d601..45ed1750a52871f0d43d6e040def2fa8867d4ddd 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,11 +21,12 @@ cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full"] } +syn = { version = "2.0.38", features = ["full"] } frame-support-procedural-tools = { path = "tools" } -proc-macro-warning = { version = "0.4.2", default-features = false } -macro_magic = { version = "0.4.2", features = ["proc_support"] } +macro_magic = { version = "0.5.0", features = ["proc_support"] } +proc-macro-warning = { version = "1.0.0", default-features = false } expander = "2.0.0" +sp-core-hashing = { path = "../../../primitives/core/hashing" } [features] default = [ "std" ] diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 6f8f1d155e1e5991038349597ee4e00516b92c0f..fb55e8c9f662cfd93a35e592e57bb2fc42f6f96f 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -18,7 +18,7 @@ //! Home of the parsing and expansion code for the new pallet benchmarking syntax use derive_syn_parse::Parse; -use frame_support_procedural_tools::generate_crate_access_2018; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro::TokenStream; use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; @@ -418,7 +418,8 @@ pub fn benchmarks( true => quote!(T: Config, I: 'static), }; - let krate = generate_crate_access_2018("frame-benchmarking")?; + let krate = generate_access_from_frame_or_crate("frame-benchmarking")?; + let frame_system = generate_access_from_frame_or_crate("frame-system")?; // benchmark name variables let benchmark_names_str: Vec = benchmark_names.iter().map(|n| n.to_string()).collect(); @@ -488,7 +489,7 @@ pub fn benchmarks( } #[cfg(any(feature = "runtime-benchmarks", test))] impl<#type_impl_generics> #krate::Benchmarking for Pallet<#type_use_generics> - where T: frame_system::Config, #where_clause + where T: #frame_system::Config, #where_clause { fn benchmarks( extra: bool, @@ -535,7 +536,7 @@ pub fn benchmarks( _ => return Err("Could not find extrinsic.".into()), }; let mut whitelist = whitelist.to_vec(); - let whitelisted_caller_key = as #krate::__private::storage::StorageMap<_, _,>>::hashed_key_for( #krate::whitelisted_caller::() @@ -571,8 +572,8 @@ pub fn benchmarks( >::instance(&selected_benchmark, c, verify)?; // Set the block number to at least 1 so events are deposited. - if #krate::__private::Zero::is_zero(&frame_system::Pallet::::block_number()) { - frame_system::Pallet::::set_block_number(1u32.into()); + if #krate::__private::Zero::is_zero(&#frame_system::Pallet::::block_number()) { + #frame_system::Pallet::::set_block_number(1u32.into()); } // Commit the externalities to the database, flushing the DB cache. @@ -654,7 +655,7 @@ pub fn benchmarks( } #[cfg(test)] - impl<#type_impl_generics> Pallet<#type_use_generics> where T: ::frame_system::Config, #where_clause { + impl<#type_impl_generics> Pallet<#type_use_generics> where T: #frame_system::Config, #where_clause { /// Test a particular benchmark by name. /// /// This isn't called `test_benchmark_by_name` just in case some end-user eventually @@ -719,10 +720,14 @@ fn expand_benchmark( where_clause: TokenStream2, ) -> TokenStream2 { // set up variables needed during quoting - let krate = match generate_crate_access_2018("frame-benchmarking") { + let krate = match generate_access_from_frame_or_crate("frame-benchmarking") { Ok(ident) => ident, Err(err) => return err.to_compile_error().into(), }; + let frame_system = match generate_access_from_frame_or_crate("frame-system") { + Ok(path) => path, + Err(err) => return err.to_compile_error().into(), + }; let codec = quote!(#krate::__private::codec); let traits = quote!(#krate::__private::traits); let setup_stmts = benchmark_def.setup_stmts; @@ -762,7 +767,7 @@ fn expand_benchmark( Expr::Cast(t) => { let ty = t.ty.clone(); quote! { - <::RuntimeOrigin as From<#ty>>::from(#origin); + <::RuntimeOrigin as From<#ty>>::from(#origin); } }, _ => quote! { @@ -932,7 +937,7 @@ fn expand_benchmark( } #[cfg(test)] - impl<#type_impl_generics> Pallet<#type_use_generics> where T: ::frame_system::Config, #where_clause { + impl<#type_impl_generics> Pallet<#type_use_generics> where T: #frame_system::Config, #where_clause { #[allow(unused)] fn #test_ident() -> Result<(), #krate::BenchmarkError> { let selected_benchmark = SelectedBenchmark::#name; @@ -951,8 +956,8 @@ fn expand_benchmark( >::instance(&selected_benchmark, &c, true)?; // Set the block number to at least 1 so events are deposited. - if #krate::__private::Zero::is_zero(&frame_system::Pallet::::block_number()) { - frame_system::Pallet::::set_block_number(1u32.into()); + if #krate::__private::Zero::is_zero(&#frame_system::Pallet::::block_number()) { + #frame_system::Pallet::::set_block_number(1u32.into()); } // Run execution + verification diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/composite_helper.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/composite_helper.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c81d2360cb7bec33b7da67de08bc24a34d5ea34 --- /dev/null +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/composite_helper.rs @@ -0,0 +1,70 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::parse::PalletPath; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub(crate) fn expand_conversion_fn( + composite_name: &str, + path: &PalletPath, + instance: Option<&Ident>, + variant_name: &Ident, +) -> TokenStream { + let composite_name = quote::format_ident!("{}", composite_name); + let runtime_composite_name = quote::format_ident!("Runtime{}", composite_name); + + if let Some(inst) = instance { + quote! { + impl From<#path::#composite_name<#path::#inst>> for #runtime_composite_name { + fn from(hr: #path::#composite_name<#path::#inst>) -> Self { + #runtime_composite_name::#variant_name(hr) + } + } + } + } else { + quote! { + impl From<#path::#composite_name> for #runtime_composite_name { + fn from(hr: #path::#composite_name) -> Self { + #runtime_composite_name::#variant_name(hr) + } + } + } + } +} + +pub(crate) fn expand_variant( + composite_name: &str, + index: u8, + path: &PalletPath, + instance: Option<&Ident>, + variant_name: &Ident, +) -> TokenStream { + let composite_name = quote::format_ident!("{}", composite_name); + + if let Some(inst) = instance { + quote! { + #[codec(index = #index)] + #variant_name(#path::#composite_name<#path::#inst>), + } + } else { + quote! { + #[codec(index = #index)] + #variant_name(#path::#composite_name), + } + } +} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs index b142f8e84c92f1fb9d09f33b710c724c5a84eff2..18790850d6b3c7f992b9ef74dcf8b62d74912951 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs @@ -15,8 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::construct_runtime::{parse::PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; +use super::composite_helper; +use crate::construct_runtime::Pallet; +use proc_macro2::TokenStream; use quote::quote; pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { @@ -27,17 +28,29 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) let variant_name = &decl.name; let path = &decl.path; let index = decl.index; + let instance = decl.instance.as_ref(); - conversion_fns.push(expand_conversion_fn(path, variant_name)); + conversion_fns.push(composite_helper::expand_conversion_fn( + "FreezeReason", + path, + instance, + variant_name, + )); - freeze_reason_variants.push(expand_variant(index, path, variant_name)); + freeze_reason_variants.push(composite_helper::expand_variant( + "FreezeReason", + index, + path, + instance, + variant_name, + )); } } quote! { /// A reason for placing a freeze on funds. #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + Copy, Clone, Eq, PartialEq, #scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen, #scrate::__private::scale_info::TypeInfo, #scrate::__private::RuntimeDebug, @@ -49,20 +62,3 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) #( #conversion_fns )* } } - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::FreezeReason> for RuntimeFreezeReason { - fn from(hr: #path::FreezeReason) -> Self { - RuntimeFreezeReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::FreezeReason), - } -} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs index ed7183c4a150d80dcc69ab0b06a4c4fd73ff765b..1bb7462133cddc748ccf4c2023a3f56f68923854 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs @@ -15,8 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::construct_runtime::{parse::PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; +use super::composite_helper; +use crate::construct_runtime::Pallet; +use proc_macro2::TokenStream; use quote::quote; pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { @@ -27,17 +28,29 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) - let variant_name = &decl.name; let path = &decl.path; let index = decl.index; + let instance = decl.instance.as_ref(); - conversion_fns.push(expand_conversion_fn(path, variant_name)); + conversion_fns.push(composite_helper::expand_conversion_fn( + "HoldReason", + path, + instance, + variant_name, + )); - hold_reason_variants.push(expand_variant(index, path, variant_name)); + hold_reason_variants.push(composite_helper::expand_variant( + "HoldReason", + index, + path, + instance, + variant_name, + )); } } quote! { /// A reason for placing a hold on funds. #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + Copy, Clone, Eq, PartialEq, #scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen, #scrate::__private::scale_info::TypeInfo, #scrate::__private::RuntimeDebug, @@ -49,20 +62,3 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) - #( #conversion_fns )* } } - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::HoldReason> for RuntimeHoldReason { - fn from(hr: #path::HoldReason) -> Self { - RuntimeHoldReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::HoldReason), - } -} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs index a77aad66dcfc2db3d25e27d422c60c5aa8a8e2a5..34b9d21d8ce84fafb7958278227a3f572d8d2f74 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -90,8 +90,7 @@ pub fn expand_outer_inherent( use #scrate::inherent::{ProvideInherent, IsFatalError}; use #scrate::traits::{IsSubType, ExtrinsicCall}; use #scrate::sp_runtime::traits::Block as _; - use #scrate::_private::sp_inherents::Error; - use #scrate::__private::log; + use #scrate::__private::{sp_inherents::Error, log}; let mut result = #scrate::inherent::CheckInherentsResult::new(); diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/lock_id.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/lock_id.rs index ba35147a051fbc7347be8cc45508b975b5245f25..e67c0da00ea15e42efd0bcdddab98be5844b3e3f 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/lock_id.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/lock_id.rs @@ -15,8 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::construct_runtime::{parse::PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; +use super::composite_helper; +use crate::construct_runtime::Pallet; +use proc_macro2::TokenStream; use quote::quote; pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { @@ -27,17 +28,29 @@ pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> To let variant_name = &decl.name; let path = &decl.path; let index = decl.index; + let instance = decl.instance.as_ref(); - conversion_fns.push(expand_conversion_fn(path, variant_name)); + conversion_fns.push(composite_helper::expand_conversion_fn( + "LockId", + path, + instance, + variant_name, + )); - lock_id_variants.push(expand_variant(index, path, variant_name)); + lock_id_variants.push(composite_helper::expand_variant( + "LockId", + index, + path, + instance, + variant_name, + )); } } quote! { /// An identifier for each lock placed on funds. #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + Copy, Clone, Eq, PartialEq, #scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen, #scrate::__private::scale_info::TypeInfo, #scrate::__private::RuntimeDebug, @@ -49,20 +62,3 @@ pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> To #( #conversion_fns )* } } - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::LockId> for RuntimeLockId { - fn from(hr: #path::LockId) -> Self { - RuntimeLockId::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::LockId), - } -} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs index 830338f9265ffa846aee7de1e01bc7175e908c3a..a0fc6b8130b3c0b5b8fc7ce76768bbc9b0dc9908 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -16,6 +16,7 @@ // limitations under the License mod call; +pub mod composite_helper; mod config; mod freeze_reason; mod hold_reason; diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs index 2a3283230ad84baa02d159c74b72ec63a38230e8..892b842b174872c1d15ab39bcf0c7cc5b509c961 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs @@ -15,8 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::construct_runtime::{parse::PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; +use super::composite_helper; +use crate::construct_runtime::Pallet; +use proc_macro2::TokenStream; use quote::quote; pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { @@ -27,17 +28,29 @@ pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) let variant_name = &decl.name; let path = &decl.path; let index = decl.index; + let instance = decl.instance.as_ref(); - conversion_fns.push(expand_conversion_fn(path, variant_name)); + conversion_fns.push(composite_helper::expand_conversion_fn( + "SlashReason", + path, + instance, + variant_name, + )); - slash_reason_variants.push(expand_variant(index, path, variant_name)); + slash_reason_variants.push(composite_helper::expand_variant( + "SlashReason", + index, + path, + instance, + variant_name, + )); } } quote! { /// A reason for slashing funds. #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + Copy, Clone, Eq, PartialEq, #scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen, #scrate::__private::scale_info::TypeInfo, #scrate::__private::RuntimeDebug, @@ -49,20 +62,3 @@ pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) #( #conversion_fns )* } } - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::SlashReason> for RuntimeSlashReason { - fn from(hr: #path::SlashReason) -> Self { - RuntimeSlashReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::SlashReason), - } -} diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index f42dd837e3a95978db83912d6b8298ec70ae778a..ce34694275b386e029ef5c928569220c770752cf 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -211,9 +211,10 @@ mod expand; mod parse; +use crate::pallet::parse::helper::two128_str; use cfg_expr::Predicate; use frame_support_procedural_tools::{ - generate_crate_access, generate_crate_access_2018, generate_hidden_includes, + generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes, }; use itertools::Itertools; use parse::{ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration}; @@ -271,7 +272,7 @@ fn construct_runtime_implicit_to_explicit( input: TokenStream2, definition: ImplicitRuntimeDeclaration, ) -> Result { - let frame_support = generate_crate_access_2018("frame-support")?; + let frame_support = generate_access_from_frame_or_crate("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } ); @@ -282,7 +283,7 @@ fn construct_runtime_implicit_to_explicit( expansion = quote::quote!( #frame_support::__private::tt_call! { macro = [{ #pallet_path::tt_default_parts }] - 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 }] @@ -307,7 +308,7 @@ fn construct_runtime_explicit_to_explicit_expanded( input: TokenStream2, definition: ExplicitRuntimeDeclaration, ) -> Result { - let frame_support = generate_crate_access_2018("frame-support")?; + let frame_support = generate_access_from_frame_or_crate("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } ); @@ -318,7 +319,7 @@ fn construct_runtime_explicit_to_explicit_expanded( expansion = quote::quote!( #frame_support::__private::tt_call! { macro = [{ #pallet_path::tt_extra_parts }] - 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 }] @@ -371,7 +372,7 @@ fn construct_runtime_final_expansion( let scrate = generate_crate_access(hidden_crate_name, "frame-support"); let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); - let frame_system = generate_crate_access_2018("frame-system")?; + let frame_system = generate_access_from_frame_or_crate("frame-system")?; let block = quote!(<#name as #frame_system::Config>::Block); let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); @@ -403,17 +404,19 @@ fn construct_runtime_final_expansion( let integrity_test = decl_integrity_test(&scrate); let static_assertions = decl_static_assertions(&name, &pallets, &scrate); - let warning = - where_section.map_or(None, |where_section| { - Some(proc_macro_warning::Warning::new_deprecated("WhereSection") - .old("use a `where` clause in `construct_runtime`") - .new("use `frame_system::Config` to set the `Block` type and delete this clause. - It is planned to be removed in December 2023") - .help_links(&["https://github.com/paritytech/substrate/pull/14437"]) - .span(where_section.span) - .build(), + let warning = where_section.map_or(None, |where_section| { + Some( + proc_macro_warning::Warning::new_deprecated("WhereSection") + .old("use a `where` clause in `construct_runtime`") + .new( + "use `frame_system::Config` to set the `Block` type and delete this clause. + It is planned to be removed in December 2023", + ) + .help_links(&["https://github.com/paritytech/substrate/pull/14437"]) + .span(where_section.span) + .build_or_panic(), ) - }); + }); let res = quote!( #warning @@ -659,7 +662,6 @@ fn decl_all_pallets<'a>( #( #all_pallets_reversed_with_system_first )* ) } - fn decl_pallet_runtime_setup( runtime: &Ident, pallet_declarations: &[Pallet], @@ -667,6 +669,7 @@ fn decl_pallet_runtime_setup( ) -> TokenStream2 { let names = pallet_declarations.iter().map(|d| &d.name).collect::>(); let name_strings = pallet_declarations.iter().map(|d| d.name.to_string()); + let name_hashes = pallet_declarations.iter().map(|d| two128_str(&d.name.to_string())); let module_names = pallet_declarations.iter().map(|d| d.path.module_name()); let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize); let pallet_structs = pallet_declarations @@ -699,6 +702,7 @@ fn decl_pallet_runtime_setup( pub struct PalletInfo; impl #scrate::traits::PalletInfo for PalletInfo { + fn index() -> Option { let type_id = #scrate::__private::sp_std::any::TypeId::of::

(); #( @@ -723,6 +727,18 @@ fn decl_pallet_runtime_setup( None } + fn name_hash() -> Option<[u8; 16]> { + let type_id = #scrate::__private::sp_std::any::TypeId::of::

(); + #( + #pallet_attrs + if type_id == #scrate::__private::sp_std::any::TypeId::of::<#names>() { + return Some(#name_hashes) + } + )* + + None + } + fn module_name() -> Option<&'static str> { let type_id = #scrate::__private::sp_std::any::TypeId::of::

(); #( @@ -783,7 +799,7 @@ fn decl_static_assertions( quote! { #scrate::__private::tt_call! { macro = [{ #path::tt_error_token }] - frame_support = [{ #scrate }] + your_tt_return = [{ #scrate::__private::tt_return }] ~~> #scrate::assert_error_encoded_size! { path = [{ #path }] runtime = [{ #runtime }] diff --git a/substrate/frame/support/procedural/src/crate_version.rs b/substrate/frame/support/procedural/src/crate_version.rs index 3f728abdb0b03ef5c3c2f6aca5746e8bac8a1e66..8c8975a425971978596702af98617d93f5bfb31a 100644 --- a/substrate/frame/support/procedural/src/crate_version.rs +++ b/substrate/frame/support/procedural/src/crate_version.rs @@ -18,7 +18,7 @@ //! Implementation of macros related to crate versioning. use super::get_cargo_env_var; -use frame_support_procedural_tools::generate_crate_access_2018; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro2::{Span, TokenStream}; use syn::{Error, Result}; @@ -42,7 +42,7 @@ pub fn crate_to_crate_version(input: proc_macro::TokenStream) -> Result("CARGO_PKG_VERSION_PATCH") .map_err(|_| create_error("Patch version needs to fit into `u8`"))?; - let crate_ = generate_crate_access_2018("frame-support")?; + let crate_ = generate_access_from_frame_or_crate("frame-support")?; Ok(quote::quote! { #crate_::traits::CrateVersion { diff --git a/substrate/frame/support/procedural/src/key_prefix.rs b/substrate/frame/support/procedural/src/key_prefix.rs index 6f793d0e37bde1a72e1cda44b30ca98a3c771a4c..7f1ab6866d1e869a23623b25c51e5bbb6f297887 100644 --- a/substrate/frame/support/procedural/src/key_prefix.rs +++ b/substrate/frame/support/procedural/src/key_prefix.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens}; use syn::{Ident, Result}; @@ -27,6 +28,7 @@ pub fn impl_key_prefix_for_tuples(input: proc_macro::TokenStream) -> Result Result),* > HasReversibleKeyPrefix<( #( #kargs, )* )> for ( #( Key<#hashers, #current_tuple>, )* ) { - fn decode_partial_key(key_material: &[u8]) -> Result { + fn decode_partial_key(key_material: &[u8]) -> Result< + Self::Suffix, + #frame_support::__private::codec::Error, + > { <#suffix_keygen>::decode_final_key(key_material).map(|k| k.0) } } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 9957cf1cff85c821b50d132d92762eac4a70b7ac..9c551b9f23067c5402bea788791c8c6f827eb73f 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -33,8 +33,8 @@ mod storage_alias; mod transactional; mod tt_macro; -use frame_support_procedural_tools::generate_crate_access_2018; -use macro_magic::import_tokens_attr; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; +use macro_magic::{import_tokens_attr, import_tokens_attr_verbatim}; use proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::{cell::RefCell, str::FromStr}; @@ -442,8 +442,8 @@ pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream { quote::quote!( const _: () = { - impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + impl #impl_generics ::core::fmt::Debug for #name #ty_generics #where_clause { + fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> core::fmt::Result { fmt.write_str("") } } @@ -473,7 +473,7 @@ pub fn derive_eq_no_bound(input: TokenStream) -> TokenStream { quote::quote_spanned!(name.span() => const _: () = { - impl #impl_generics core::cmp::Eq for #name #ty_generics #where_clause {} + impl #impl_generics ::core::cmp::Eq for #name #ty_generics #where_clause {} }; ) .into() @@ -751,12 +751,12 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream /// Items that lack a `syn::Ident` for whatever reason are first checked to see if they exist, /// verbatim, in the local/destination trait before they are copied over, so you should not need to /// worry about collisions between identical unnamed items. -#[import_tokens_attr { +#[import_tokens_attr_verbatim { format!( "{}::macro_magic", - match generate_crate_access_2018("frame-support") { + match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_crate_access_2018("frame"), + Err(_) => generate_access_from_frame_or_crate("frame"), } .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") .to_token_stream() @@ -864,7 +864,12 @@ pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenSt let item_impl = syn::parse_macro_input!(tokens as ItemImpl); // internally wrap macro_magic's `#[export_tokens]` macro - match macro_magic::mm_core::export_tokens_internal(attrs, item_impl.to_token_stream(), true) { + match macro_magic::mm_core::export_tokens_internal( + attrs, + item_impl.to_token_stream(), + true, + false, + ) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -877,6 +882,8 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { if item.ident != "RuntimeCall" && item.ident != "RuntimeEvent" && item.ident != "RuntimeOrigin" && + item.ident != "RuntimeHoldReason" && + item.ident != "RuntimeFreezeReason" && item.ident != "PalletInfo" { return syn::Error::new_spanned( @@ -1417,57 +1424,15 @@ pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration -/// for the pallet. -/// -/// Item is defined as either an enum or a struct. It needs to be public and implement the -/// trait `GenesisBuild` with [`#[pallet::genesis_build]`](`macro@genesis_build`). The type -/// generics are constrained to be either none, or `T` or `T: Config`. -/// -/// E.g: -/// -/// ```ignore -/// #[pallet::genesis_config] -/// pub struct GenesisConfig { -/// _myfield: BalanceOf, -/// } -/// ``` +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::genesis_config`. #[proc_macro_attribute] pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` -/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's -/// initial state. -/// -/// The impl must be defined as: -/// -/// ```ignore -/// #[pallet::genesis_build] -/// impl GenesisBuild for GenesisConfig<$maybe_generics> { -/// fn build(&self) { $expr } -/// } -/// ``` -/// -/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on -/// type `GenesisConfig` with generics none or `T`. -/// -/// E.g.: -/// -/// ```ignore -/// #[pallet::genesis_build] -/// impl GenesisBuild for GenesisConfig { -/// fn build(&self) {} -/// } -/// ``` -/// -/// ## Macro expansion -/// -/// The macro will add the following attribute: -/// * `#[cfg(feature = "std")]` -/// -/// The macro will implement `sp_runtime::BuildStorage`. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::genesis_build`. #[proc_macro_attribute] pub fn genesis_build(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() @@ -1605,7 +1570,7 @@ pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { let _mod = parse_macro_input!(tokens_clone as ItemMod); // use macro_magic's export_tokens as the internal implementation otherwise - match macro_magic::mm_core::export_tokens_internal(attr, tokens, false) { + match macro_magic::mm_core::export_tokens_internal(attr, tokens, false, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } @@ -1647,9 +1612,9 @@ pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { #[import_tokens_attr { format!( "{}::macro_magic", - match generate_crate_access_2018("frame-support") { + match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_crate_access_2018("frame"), + Err(_) => generate_access_from_frame_or_crate("frame"), } .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") .to_token_stream() diff --git a/substrate/frame/support/procedural/src/no_bound/clone.rs b/substrate/frame/support/procedural/src/no_bound/clone.rs index bbea2feffa96fc52763c97cd812abc66a4c0c495..2c9037984f59437cf74af7f40948214fad6ccb7c 100644 --- a/substrate/frame/support/procedural/src/no_bound/clone.rs +++ b/substrate/frame/support/procedural/src/no_bound/clone.rs @@ -32,7 +32,7 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke syn::Fields::Named(named) => { let fields = named.named.iter().map(|i| &i.ident).map(|i| { quote::quote_spanned!(i.span() => - #i: core::clone::Clone::clone(&self.#i) + #i: ::core::clone::Clone::clone(&self.#i) ) }); @@ -42,7 +42,7 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke let fields = unnamed.unnamed.iter().enumerate().map(|(i, _)| syn::Index::from(i)).map(|i| { quote::quote_spanned!(i.span() => - core::clone::Clone::clone(&self.#i) + ::core::clone::Clone::clone(&self.#i) ) }); @@ -59,8 +59,8 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke syn::Fields::Named(named) => { let captured = named.named.iter().map(|i| &i.ident); let cloned = captured.clone().map(|i| { - quote::quote_spanned!(i.span() => - #i: core::clone::Clone::clone(#i) + ::quote::quote_spanned!(i.span() => + #i: ::core::clone::Clone::clone(#i) ) }); quote::quote!( @@ -75,7 +75,7 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke .map(|(i, f)| syn::Ident::new(&format!("_{}", i), f.span())); let cloned = captured.clone().map(|i| { quote::quote_spanned!(i.span() => - core::clone::Clone::clone(#i) + ::core::clone::Clone::clone(#i) ) }); quote::quote!( @@ -98,7 +98,7 @@ pub fn derive_clone_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke quote::quote!( const _: () = { - impl #impl_generics core::clone::Clone for #name #ty_generics #where_clause { + impl #impl_generics ::core::clone::Clone for #name #ty_generics #where_clause { fn clone(&self) -> Self { #impl_ } diff --git a/substrate/frame/support/procedural/src/no_bound/debug.rs b/substrate/frame/support/procedural/src/no_bound/debug.rs index ae182829a49eb14513acc3b7a6e3763af6a8db6b..88f5dfe7bec47bc90cb106d5855c6b9ae8294f3e 100644 --- a/substrate/frame/support/procedural/src/no_bound/debug.rs +++ b/substrate/frame/support/procedural/src/no_bound/debug.rs @@ -112,8 +112,8 @@ pub fn derive_debug_no_bound(input: proc_macro::TokenStream) -> proc_macro::Toke quote::quote!( const _: () = { - impl #impl_generics core::fmt::Debug for #input_ident #ty_generics #where_clause { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + impl #impl_generics ::core::fmt::Debug for #input_ident #ty_generics #where_clause { + fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { #impl_ } } diff --git a/substrate/frame/support/procedural/src/no_bound/default.rs b/substrate/frame/support/procedural/src/no_bound/default.rs index da05f19e0f817d3b1a3c8709bee87dd39f67277d..ddaab26c44159843c3282e0e26f9f095144ad20a 100644 --- a/substrate/frame/support/procedural/src/no_bound/default.rs +++ b/substrate/frame/support/procedural/src/no_bound/default.rs @@ -32,7 +32,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To Fields::Named(named) => { let fields = named.named.iter().map(|field| &field.ident).map(|ident| { quote_spanned! {ident.span() => - #ident: core::default::Default::default() + #ident: ::core::default::Default::default() } }); @@ -41,7 +41,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To Fields::Unnamed(unnamed) => { let fields = unnamed.unnamed.iter().map(|field| { quote_spanned! {field.span()=> - core::default::Default::default() + ::core::default::Default::default() } }); @@ -66,15 +66,12 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To .collect::>(); match &*default_variants { - [] => { - return syn::Error::new( - name.clone().span(), - // writing this as a regular string breaks rustfmt for some reason - r#"no default declared, make a variant default by placing `#[default]` above it"#, - ) - .into_compile_error() - .into() - }, + [] => return syn::Error::new( + name.clone().span(), + "no default declared, make a variant default by placing `#[default]` above it", + ) + .into_compile_error() + .into(), // only one variant with the #[default] attribute set [default_variant] => { let variant_attrs = default_variant @@ -108,7 +105,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To let fields = named.named.iter().map(|field| &field.ident).map(|ident| { quote_spanned! {ident.span()=> - #ident: core::default::Default::default() + #ident: ::core::default::Default::default() } }); @@ -117,7 +114,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To Fields::Unnamed(unnamed) => { let fields = unnamed.unnamed.iter().map(|field| { quote_spanned! {field.span()=> - core::default::Default::default() + ::core::default::Default::default() } }); @@ -152,7 +149,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To quote!( const _: () = { - impl #impl_generics core::default::Default for #name #ty_generics #where_clause { + impl #impl_generics ::core::default::Default for #name #ty_generics #where_clause { fn default() -> Self { #impl_ } diff --git a/substrate/frame/support/procedural/src/no_bound/partial_eq.rs b/substrate/frame/support/procedural/src/no_bound/partial_eq.rs index 27f5e98810ec3aa209f9a4030cfd4f2527ba724a..1a4a4e50b39e0d6224e2f1108c682f2a4b7ccd0d 100644 --- a/substrate/frame/support/procedural/src/no_bound/partial_eq.rs +++ b/substrate/frame/support/procedural/src/no_bound/partial_eq.rs @@ -128,7 +128,7 @@ pub fn derive_partial_eq_no_bound(input: proc_macro::TokenStream) -> proc_macro: quote::quote!( const _: () = { - impl #impl_generics core::cmp::PartialEq for #name #ty_generics #where_clause { + impl #impl_generics ::core::cmp::PartialEq for #name #ty_generics #where_clause { fn eq(&self, other: &Self) -> bool { #impl_ } diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index 3ed5509863e91f940145bf41e2407da08a4e471a..ed6335159cd6edae4bf435ed60b00da655d5bda0 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -17,12 +17,14 @@ use crate::{ pallet::{ + expand::warnings::{weight_constant_warning, weight_witness_warning}, parse::call::{CallVariantDef, CallWeightDef}, Def, }, COUNTER, }; use proc_macro2::TokenStream as TokenStream2; +use proc_macro_warning::Warning; use quote::{quote, ToTokens}; use syn::spanned::Spanned; @@ -68,7 +70,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { continue } - let warning = proc_macro_warning::Warning::new_deprecated("ImplicitCallIndex") + let warning = Warning::new_deprecated("ImplicitCallIndex") .index(call_index_warnings.len()) .old("use implicit call indices") .new("ensure that all calls have a `pallet::call_index` attribute or put the pallet into `dev` mode") @@ -77,7 +79,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { "https://github.com/paritytech/substrate/pull/11381" ]) .span(method.name.span()) - .build(); + .build_or_panic(); call_index_warnings.push(warning); } @@ -86,18 +88,12 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { for method in &methods { match &method.weight { CallWeightDef::DevModeDefault => fn_weight.push(syn::parse_quote!(0)), - CallWeightDef::Immediate(e @ syn::Expr::Lit(lit)) if !def.dev_mode => { - let warning = proc_macro_warning::Warning::new_deprecated("ConstantWeight") - .index(weight_warnings.len()) - .old("use hard-coded constant as call weight") - .new("benchmark all calls or put the pallet into `dev` mode") - .help_link("https://github.com/paritytech/substrate/pull/13798") - .span(lit.span()) - .build(); - weight_warnings.push(warning); + CallWeightDef::Immediate(e) => { + weight_constant_warning(e, def.dev_mode, &mut weight_warnings); + weight_witness_warning(method, def.dev_mode, &mut weight_warnings); + fn_weight.push(e.into_token_stream()); }, - CallWeightDef::Immediate(e) => fn_weight.push(e.into_token_stream()), CallWeightDef::Inherited => { let pallet_weight = def .call diff --git a/substrate/frame/support/procedural/src/pallet/expand/error.rs b/substrate/frame/support/procedural/src/pallet/expand/error.rs index d3aa0b762bc52df2af97079574eb5dbf6616c72a..877489fd6057b85d06ba2477020776c91bf92d3c 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/error.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/error.rs @@ -42,9 +42,9 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { macro_rules! #error_token_unique_id { { $caller:tt - frame_support = [{ $($frame_support:ident)::* }] + your_tt_return = [{ $my_tt_return:path }] } => { - $($frame_support::)*__private::tt_return! { + $my_tt_return! { $caller } }; @@ -170,9 +170,9 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { macro_rules! #error_token_unique_id { { $caller:tt - frame_support = [{ $($frame_support:ident)::* }] + your_tt_return = [{ $my_tt_return:path }] } => { - $($frame_support::)*__private::tt_return! { + $my_tt_return! { $caller error = [{ #error_ident }] } diff --git a/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs b/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs index 15ddfcf1d49d4e81c26fe96d70589c4fa431fe0c..248e83469435c96960f34ddccd55c71ebf650566 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs @@ -38,7 +38,7 @@ pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream { #[cfg(feature = "std")] impl<#type_impl_gen> #frame_support::sp_runtime::BuildStorage for #gen_cfg_ident<#gen_cfg_use_gen> #where_clause { - fn assimilate_storage(&self, storage: &mut sp_runtime::Storage) -> std::result::Result<(), std::string::String> { + fn assimilate_storage(&self, storage: &mut #frame_support::sp_runtime::Storage) -> std::result::Result<(), std::string::String> { #frame_support::__private::BasicExternalities::execute_with_storage(storage, || { self.build(); Ok(()) diff --git a/substrate/frame/support/procedural/src/pallet/expand/genesis_config.rs b/substrate/frame/support/procedural/src/pallet/expand/genesis_config.rs index b00f9bcd1a662dd592a7191a80469363f1a5acb4..31d519ef2929397293514fea96d1e21b476fc4df 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/genesis_config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/genesis_config.rs @@ -17,6 +17,7 @@ use crate::{pallet::Def, COUNTER}; use frame_support_procedural_tools::get_doc_literals; +use quote::ToTokens; use syn::{spanned::Spanned, Ident}; /// @@ -79,7 +80,7 @@ pub fn expand_genesis_config(def: &mut Def) -> proc_macro2::TokenStream { let genesis_config_item = &mut def.item.content.as_mut().expect("Checked by def parser").1[genesis_config.index]; - let serde_crate = format!("{}::__private::serde", frame_support); + let serde_crate = format!("{}::__private::serde", frame_support.to_token_stream()); match genesis_config_item { syn::Item::Enum(syn::ItemEnum { attrs, .. }) | diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 2b998227c1d841a92a2ded9f3f5b681b83d4ef65..6f32e5697512f7e87a0130ec31e69eb5201c4d89 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -34,6 +34,7 @@ mod store_trait; mod tt_default_parts; mod type_value; mod validate_unsigned; +mod warnings; use crate::pallet::Def; use quote::ToTokens; diff --git a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs index e519e34d1dfd9411d735887b4dbe0ed337772238..c2102f0284dbeeadb08fc9122e5fe824032dfb82 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -246,6 +246,14 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { implemented by the runtime") } + fn name_hash() -> [u8; 16] { + < + ::PalletInfo as #frame_support::traits::PalletInfo + >::name_hash::() + .expect("Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime") + } + fn module_name() -> &'static str { < ::PalletInfo as #frame_support::traits::PalletInfo diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index c01f0f3926a699561cb22ff3ff731a7688871c04..e7f7cf548f0ea54008c47a5e0a92a0d0b5dd93ea 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -18,7 +18,10 @@ use crate::{ counter_prefix, pallet::{ - parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics}, + parse::{ + helper::two128_str, + storage::{Metadata, QueryKind, StorageDef, StorageGenerics}, + }, Def, }, }; @@ -638,6 +641,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { Metadata::CountedMap { .. } => { let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident); let counter_prefix_struct_const = counter_prefix(&prefix_struct_const); + let storage_prefix_hash = two128_str(&counter_prefix_struct_const); quote::quote_spanned!(storage_def.attr_span => #(#cfg_attrs)* #[doc(hidden)] @@ -656,7 +660,19 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { >::name::>() .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") } + + fn pallet_prefix_hash() -> [u8; 16] { + < + ::PalletInfo + as #frame_support::traits::PalletInfo + >::name_hash::>() + .expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") + } + const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const; + fn storage_prefix_hash() -> [u8; 16] { + #storage_prefix_hash + } } #(#cfg_attrs)* impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance @@ -670,6 +686,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { Metadata::CountedNMap { .. } => { let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident); let counter_prefix_struct_const = counter_prefix(&prefix_struct_const); + let storage_prefix_hash = two128_str(&counter_prefix_struct_const); quote::quote_spanned!(storage_def.attr_span => #(#cfg_attrs)* #[doc(hidden)] @@ -688,7 +705,17 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { >::name::>() .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") } + fn pallet_prefix_hash() -> [u8; 16] { + < + ::PalletInfo + as #frame_support::traits::PalletInfo + >::name_hash::>() + .expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") + } const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const; + fn storage_prefix_hash() -> [u8; 16] { + #storage_prefix_hash + } } #(#cfg_attrs)* impl<#type_impl_gen> #frame_support::storage::types::CountedStorageNMapInstance @@ -702,6 +729,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { _ => proc_macro2::TokenStream::default(), }; + let storage_prefix_hash = two128_str(&prefix_struct_const); quote::quote_spanned!(storage_def.attr_span => #maybe_counter @@ -722,7 +750,19 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { >::name::>() .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") } + + fn pallet_prefix_hash() -> [u8; 16] { + < + ::PalletInfo + as #frame_support::traits::PalletInfo + >::name_hash::>() + .expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") + } + const STORAGE_PREFIX: &'static str = #prefix_struct_const; + fn storage_prefix_hash() -> [u8; 16] { + #storage_prefix_hash + } } ) }); 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 86db56c776dfefbdd393ae090e59ed11472456c1..c9a776ee247527b8e76508144ece3708d110194b 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 @@ -85,18 +85,16 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { // wrapped inside of braces and finally prepended with double colons, to the caller inside // of a key named `tokens`. // - // We need to accept a frame_support argument here, because this macro gets expanded on the - // crate that called the `construct_runtime!` macro, and said crate may have renamed - // frame-support, and so we need to pass in the frame-support path that said crate - // recognizes. + // We need to accept a path argument here, because this macro gets expanded on the + // crate that called the `construct_runtime!` macro, and the actual path is unknown. #[macro_export] #[doc(hidden)] macro_rules! #default_parts_unique_id { { $caller:tt - frame_support = [{ $($frame_support:ident)::* }] + your_tt_return = [{ $my_tt_return:path }] } => { - $($frame_support)*::__private::tt_return! { + $my_tt_return! { $caller tokens = [{ expanded::{ @@ -112,7 +110,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { pub use #default_parts_unique_id as tt_default_parts; - // This macro is similar to the `tt_default_parts!`. It expands the pallets thare are declared + // This macro is similar to the `tt_default_parts!`. It expands the pallets that are declared // explicitly (`System: frame_system::{Pallet, Call}`) with extra parts. // // For example, after expansion an explicit pallet would look like: @@ -124,9 +122,9 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { macro_rules! #extra_parts_unique_id { { $caller:tt - frame_support = [{ $($frame_support:ident)::* }] + your_tt_return = [{ $my_tt_return:path }] } => { - $($frame_support)*::__private::tt_return! { + $my_tt_return! { $caller tokens = [{ expanded::{ diff --git a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs new file mode 100644 index 0000000000000000000000000000000000000000..110c4fa51987a22105c9ce639770d5573642c2d0 --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -0,0 +1,100 @@ +// 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. + +//! Generates warnings for undesirable pallet code. + +use crate::pallet::parse::call::{CallVariantDef, CallWeightDef}; +use proc_macro_warning::Warning; +use syn::{ + spanned::Spanned, + visit::{self, Visit}, +}; + +/// Warn if any of the call arguments starts with a underscore and is used in a weight formula. +pub(crate) fn weight_witness_warning( + method: &CallVariantDef, + dev_mode: bool, + warnings: &mut Vec, +) { + if dev_mode { + return + } + + let CallWeightDef::Immediate(w) = &method.weight else { return }; + + let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") + .old("not check weight witness data") + .new("ensure that all witness data for weight calculation is checked before usage") + .help_link("https://github.com/paritytech/polkadot-sdk/pull/1818"); + + for (_, arg_ident, _) in method.args.iter() { + if !arg_ident.to_string().starts_with('_') || !contains_ident(w.clone(), &arg_ident) { + continue + } + + let warning = partial_warning + .clone() + .index(warnings.len()) + .span(arg_ident.span()) + .build_or_panic(); + + warnings.push(warning); + } +} + +/// Warn if the weight is a constant and the pallet not in `dev_mode`. +pub(crate) fn weight_constant_warning( + weight: &syn::Expr, + dev_mode: bool, + warnings: &mut Vec, +) { + if dev_mode { + return + } + + let syn::Expr::Lit(lit) = weight else { return }; + + let warning = Warning::new_deprecated("ConstantWeight") + .index(warnings.len()) + .old("use hard-coded constant as call weight") + .new("benchmark all calls or put the pallet into `dev` mode") + .help_link("https://github.com/paritytech/substrate/pull/13798") + .span(lit.span()) + .build_or_panic(); + + warnings.push(warning); +} + +/// Returns whether `expr` contains `ident`. +fn contains_ident(mut expr: syn::Expr, ident: &syn::Ident) -> bool { + struct ContainsIdent { + ident: syn::Ident, + found: bool, + } + + impl<'a> Visit<'a> for ContainsIdent { + fn visit_ident(&mut self, i: &syn::Ident) { + if *i == self.ident { + self.found = true; + } + } + } + + let mut visitor = ContainsIdent { ident: ident.clone(), found: false }; + visit::visit_expr(&mut visitor, &mut expr); + visitor.found +} diff --git a/substrate/frame/support/procedural/src/pallet/mod.rs b/substrate/frame/support/procedural/src/pallet/mod.rs index 3618711051d7fe5649f883a5b95708d47475e5a4..42d8272fb23edb9afc7bd1a152b5d7506fd3ba99 100644 --- a/substrate/frame/support/procedural/src/pallet/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/mod.rs @@ -26,7 +26,7 @@ //! to user defined types. And also crate new types and implement block. mod expand; -mod parse; +pub(crate) mod parse; pub use parse::{composite::keyword::CompositeKeyword, Def}; use syn::spanned::Spanned; diff --git a/substrate/frame/support/procedural/src/pallet/parse/composite.rs b/substrate/frame/support/procedural/src/pallet/parse/composite.rs index cb554a116175c1f93aa2b7f5b4da447d6efb7741..6e6ea6a795c1403b64891c00507cf0f7d8dffc25 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/composite.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/composite.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::helper; use quote::ToTokens; use syn::spanned::Spanned; @@ -91,7 +92,7 @@ impl CompositeDef { pub fn try_from( attr_span: proc_macro2::Span, index: usize, - scrate: &proc_macro2::Ident, + scrate: &syn::Path, item: &mut syn::Item, ) -> syn::Result { let item = if let syn::Item::Enum(item) = item { @@ -108,6 +109,13 @@ impl CompositeDef { return Err(syn::Error::new(item.span(), msg)) } + let has_instance = if item.generics.params.first().is_some() { + helper::check_config_def_gen(&item.generics, item.ident.span())?; + true + } else { + false + }; + let has_derive_attr = item.attrs.iter().any(|attr| { if let syn::Meta::List(syn::MetaList { path, .. }) = &attr.meta { path.get_ident().map(|ident| ident == "derive").unwrap_or(false) @@ -119,7 +127,7 @@ impl CompositeDef { if !has_derive_attr { let derive_attr: syn::Attribute = syn::parse_quote! { #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + Copy, Clone, Eq, PartialEq, #scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen, #scrate::__private::scale_info::TypeInfo, #scrate::__private::RuntimeDebug, @@ -128,6 +136,20 @@ impl CompositeDef { item.attrs.push(derive_attr); } + if has_instance { + item.attrs.push(syn::parse_quote! { + #[scale_info(skip_type_params(I))] + }); + + item.variants.push(syn::parse_quote! { + #[doc(hidden)] + #[codec(skip)] + __Ignore( + #scrate::__private::sp_std::marker::PhantomData, + ) + }); + } + let composite_keyword = syn::parse2::(item.ident.to_token_stream())?; diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index e505f8b04119bd685bb2c3dfd77521f349eb619f..fbab92db196cb33d90e88413d66e4ff75e8e3cd4 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -16,7 +16,7 @@ // limitations under the License. use super::helper; -use frame_support_procedural_tools::get_doc_literals; +use frame_support_procedural_tools::{get_doc_literals, is_using_frame_crate}; use quote::ToTokens; use syn::{spanned::Spanned, token, Token}; @@ -165,24 +165,8 @@ pub struct PalletAttr { typ: PalletAttrType, } -pub struct ConfigBoundParse(syn::Ident); - -impl syn::parse::Parse for ConfigBoundParse { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let ident = input.parse::()?; - input.parse::()?; - input.parse::()?; - - if input.peek(syn::token::Lt) { - input.parse::()?; - } - - Ok(Self(ident)) - } -} - -/// Parse for `IsType<::RuntimeEvent>` and retrieve `$ident` -pub struct IsTypeBoundEventParse(syn::Ident); +/// Parse for `IsType<::RuntimeEvent>` and retrieve `$path` +pub struct IsTypeBoundEventParse(syn::Path); impl syn::parse::Parse for IsTypeBoundEventParse { fn parse(input: syn::parse::ParseStream) -> syn::Result { @@ -191,15 +175,13 @@ impl syn::parse::Parse for IsTypeBoundEventParse { input.parse::()?; input.parse::()?; input.parse::()?; - let ident = input.parse::()?; - input.parse::()?; - input.parse::()?; + let config_path = input.parse::()?; input.parse::]>()?; input.parse::()?; input.parse::()?; input.parse::]>()?; - Ok(Self(ident)) + Ok(Self(config_path)) } } @@ -237,7 +219,7 @@ impl syn::parse::Parse for FromEventParse { /// Check if trait_item is `type RuntimeEvent`, if so checks its bounds are those expected. /// (Event type is reserved type) fn check_event_type( - frame_system: &syn::Ident, + frame_system: &syn::Path, trait_item: &syn::TraitItem, trait_has_instance: bool, ) -> syn::Result { @@ -249,19 +231,16 @@ fn check_event_type( no generics nor where_clause"; return Err(syn::Error::new(trait_item.span(), msg)) } - // Check bound contains IsType and From + // Check bound contains IsType and From let has_is_type_bound = type_.bounds.iter().any(|s| { syn::parse2::(s.to_token_stream()) - .map_or(false, |b| b.0 == *frame_system) + .map_or(false, |b| has_expected_system_config(b.0, frame_system)) }); if !has_is_type_bound { - let msg = format!( - "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ - bound: `IsType<::RuntimeEvent>`", - frame_system, - ); + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ + bound: `IsType<::RuntimeEvent>`".to_string(); return Err(syn::Error::new(type_.span(), msg)) } @@ -295,6 +274,43 @@ fn check_event_type( } } +/// Check that the path to `frame_system::Config` is valid, this is that the path is just +/// `frame_system::Config` or when using the `frame` crate it is `frame::xyz::frame_system::Config`. +fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool { + // Check if `frame_system` is actually 'frame_system'. + if path.segments.iter().all(|s| s.ident != "frame_system") { + return false + } + + let mut expected_system_config = + match (is_using_frame_crate(&path), is_using_frame_crate(&frame_system)) { + (true, false) => + // We can't use the path to `frame_system` from `frame` if `frame_system` is not being + // in scope through `frame`. + return false, + (false, true) => + // We know that the only valid frame_system path is one that is `frame_system`, as + // `frame` re-exports it as such. + syn::parse2::(quote::quote!(frame_system)).expect("is a valid path; qed"), + (_, _) => + // They are either both `frame_system` or both `frame::xyz::frame_system`. + frame_system.clone(), + }; + + expected_system_config + .segments + .push(syn::PathSegment::from(syn::Ident::new("Config", path.span()))); + + // the parse path might be something like `frame_system::Config<...>`, so we + // only compare the idents along the path. + expected_system_config + .segments + .into_iter() + .map(|ps| ps.ident) + .collect::>() == + path.segments.into_iter().map(|ps| ps.ident).collect::>() +} + /// Replace ident `Self` by `T` pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream { input @@ -311,7 +327,7 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS impl ConfigDef { pub fn try_from( - frame_system: &syn::Ident, + frame_system: &syn::Path, attr_span: proc_macro2::Span, index: usize, item: &mut syn::Item, @@ -352,8 +368,8 @@ impl ConfigDef { }; let has_frame_system_supertrait = item.supertraits.iter().any(|s| { - syn::parse2::(s.to_token_stream()) - .map_or(false, |b| b.0 == *frame_system) + syn::parse2::(s.to_token_stream()) + .map_or(false, |b| has_expected_system_config(b, frame_system)) }); let mut has_event_type = false; @@ -461,7 +477,8 @@ impl ConfigDef { (try `pub trait Config: frame_system::Config {{ ...` or \ `pub trait Config: frame_system::Config {{ ...`). \ To disable this check, use `#[pallet::disable_frame_system_supertrait_check]`", - frame_system, found, + frame_system.to_token_stream(), + found, ); return Err(syn::Error::new(item.span(), msg)) } @@ -477,3 +494,97 @@ impl ConfigDef { }) } } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn has_expected_system_config_works() { + let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); + let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_works_with_assoc_type() { + let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame_system::Config)) + .unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_works_with_frame() { + let frame_system = + syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); + let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_works_with_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_works_with_other_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame::xyz::frame_system::Config)).unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_does_not_works_with_mixed_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_does_not_works_with_other_mixed_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame::xyz::frame_system::Config)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_does_not_work_with_frame_full_path_if_not_frame_crate() { + let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_unexpected_frame_system() { + let frame_system = + syn::parse2::(quote::quote!(framez::deps::frame_system)).unwrap(); + let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_unexpected_path() { + let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); + let path = syn::parse2::(quote::quote!(frame_system::ConfigSystem)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } + + #[test] + fn has_expected_system_config_not_frame_system() { + let frame_system = syn::parse2::(quote::quote!(something)).unwrap(); + let path = syn::parse2::(quote::quote!(something::Config)).unwrap(); + assert!(!has_expected_system_config(path, &frame_system)); + } +} diff --git a/substrate/frame/support/procedural/src/pallet/parse/helper.rs b/substrate/frame/support/procedural/src/pallet/parse/helper.rs index 1e6e83d7eeba7e1b63b18693ee1fce5cce72dc76..446ec203d2ba5878304f8ee081e870cc08101a4c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/helper.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/helper.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use quote::ToTokens; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; use syn::spanned::Spanned; /// List of additional token to be used for parsing. @@ -494,7 +495,7 @@ pub fn check_type_def_gen( /// return the instance if found for `GenesisBuild` /// return None for BuildGenesisConfig pub fn check_genesis_builder_usage(type_: &syn::Path) -> syn::Result> { - let expected = "expected `GenesisBuild` or `GenesisBuild`"; + let expected = "expected `BuildGenesisConfig` (or the deprecated `GenesisBuild` or `GenesisBuild`)"; pub struct Checker(Option); impl syn::parse::Parse for Checker { fn parse(input: syn::parse::ParseStream) -> syn::Result { @@ -610,3 +611,16 @@ pub fn check_pallet_call_return_type(type_: &syn::Type) -> syn::Result<()> { syn::parse2::(type_.to_token_stream()).map(|_| ()) } + +pub(crate) fn two128_str(s: &str) -> TokenStream { + bytes_to_array(sp_core_hashing::twox_128(s.as_bytes()).into_iter()) +} + +pub(crate) fn bytes_to_array(bytes: impl IntoIterator) -> TokenStream { + let bytes = bytes.into_iter(); + + quote!( + [ #( #bytes ),* ] + ) + .into() +} diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 0f5e5f1136610e40226ba880a1b47512d2ee34a9..83a881751ef308a948e9fc69a684cd90862af145 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -37,7 +37,7 @@ pub mod type_value; pub mod validate_unsigned; use composite::{keyword::CompositeKeyword, CompositeDef}; -use frame_support_procedural_tools::generate_crate_access_2018; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use syn::spanned::Spanned; /// Parsed definition of a pallet. @@ -60,15 +60,15 @@ pub struct Def { pub extra_constants: Option, pub composites: Vec, pub type_values: Vec, - pub frame_system: syn::Ident, - pub frame_support: syn::Ident, + pub frame_system: syn::Path, + pub frame_support: syn::Path, pub dev_mode: bool, } impl Def { pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result { - let frame_system = generate_crate_access_2018("frame-system")?; - let frame_support = generate_crate_access_2018("frame-support")?; + let frame_system = generate_access_from_frame_or_crate("frame-system")?; + let frame_support = generate_access_from_frame_or_crate("frame-support")?; let item_span = item.span(); let items = &mut item diff --git a/substrate/frame/support/procedural/src/pallet_error.rs b/substrate/frame/support/procedural/src/pallet_error.rs index 7fd02240a628a23fdaee5ff84f89570aa1705fb2..693a1e9821c9728a7992a3d2d6741b855d2af867 100644 --- a/substrate/frame/support/procedural/src/pallet_error.rs +++ b/substrate/frame/support/procedural/src/pallet_error.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support_procedural_tools::generate_crate_access_2018; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use quote::ToTokens; // Derive `PalletError` @@ -25,7 +25,7 @@ pub fn derive_pallet_error(input: proc_macro::TokenStream) -> proc_macro::TokenS Err(e) => return e.to_compile_error().into(), }; - let frame_support = match generate_crate_access_2018("frame-support") { + let frame_support = match generate_access_from_frame_or_crate("frame-support") { Ok(c) => c, Err(e) => return e.into_compile_error().into(), }; @@ -111,7 +111,7 @@ pub fn derive_pallet_error(input: proc_macro::TokenStream) -> proc_macro::TokenS fn generate_field_types( field: &syn::Field, - scrate: &syn::Ident, + scrate: &syn::Path, ) -> syn::Result> { let attrs = &field.attrs; @@ -143,7 +143,7 @@ fn generate_field_types( fn generate_variant_field_types( variant: &syn::Variant, - scrate: &syn::Ident, + scrate: &syn::Path, ) -> syn::Result>> { let attrs = &variant.attrs; diff --git a/substrate/frame/support/procedural/src/storage_alias.rs b/substrate/frame/support/procedural/src/storage_alias.rs index a3f21806e18b921e07c8acdf63aa06bd51c5f2ee..c0b4089a2748f0b8be6683e591a36fb496af16a4 100644 --- a/substrate/frame/support/procedural/src/storage_alias.rs +++ b/substrate/frame/support/procedural/src/storage_alias.rs @@ -17,8 +17,8 @@ //! Implementation of the `storage_alias` attribute macro. -use crate::counter_prefix; -use frame_support_procedural_tools::generate_crate_access_2018; +use crate::{counter_prefix, pallet::parse::helper}; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use syn::{ @@ -199,7 +199,7 @@ impl StorageType { /// Generate the actual type declaration. fn generate_type_declaration( &self, - crate_: &Ident, + crate_: &syn::Path, storage_instance: &StorageInstance, storage_name: &Ident, storage_generics: Option<&SimpleGenerics>, @@ -475,7 +475,7 @@ enum PrefixType { /// Implementation of the `storage_alias` attribute macro. pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> Result { let input = syn::parse2::(input)?; - let crate_ = generate_crate_access_2018("frame-support")?; + let crate_ = generate_access_from_frame_or_crate("frame-support")?; let prefix_type = if attributes.is_empty() { PrefixType::Compatibility @@ -527,7 +527,7 @@ struct StorageInstance { /// Generate the [`StorageInstance`] for the storage alias. fn generate_storage_instance( - crate_: &Ident, + crate_: &syn::Path, storage_name: &Ident, storage_generics: Option<&SimpleGenerics>, storage_where_clause: Option<&WhereClause>, @@ -619,6 +619,7 @@ fn generate_storage_instance( let counter_code = is_counted_map.then(|| { let counter_name = Ident::new(&counter_prefix(&name_str), Span::call_site()); let counter_storage_name_str = counter_prefix(&storage_name_str); + let storage_prefix_hash = helper::two128_str(&counter_storage_name_str); quote! { #visibility struct #counter_name< #impl_generics >( @@ -633,6 +634,9 @@ fn generate_storage_instance( } const STORAGE_PREFIX: &'static str = #counter_storage_name_str; + fn storage_prefix_hash() -> [u8; 16] { + #storage_prefix_hash + } } impl<#impl_generics> #crate_::storage::types::CountedStorageMapInstance @@ -643,6 +647,8 @@ fn generate_storage_instance( } }); + let storage_prefix_hash = helper::two128_str(&storage_name_str); + // Implement `StorageInstance` trait. let code = quote! { #[allow(non_camel_case_types)] @@ -658,6 +664,9 @@ fn generate_storage_instance( } const STORAGE_PREFIX: &'static str = #storage_name_str; + fn storage_prefix_hash() -> [u8; 16] { + #storage_prefix_hash + } } #counter_code diff --git a/substrate/frame/support/procedural/src/transactional.rs b/substrate/frame/support/procedural/src/transactional.rs index 23117ffa39c4e6bbd826a885fbaecff5df7f606b..e9d4f84b797a9d7da49639040e1c2658a9cedcdf 100644 --- a/substrate/frame/support/procedural/src/transactional.rs +++ b/substrate/frame/support/procedural/src/transactional.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support_procedural_tools::generate_crate_access_2018; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro::TokenStream; use quote::quote; use syn::{ItemFn, Result}; @@ -23,7 +23,7 @@ use syn::{ItemFn, Result}; pub fn transactional(_attr: TokenStream, input: TokenStream) -> Result { let ItemFn { attrs, vis, sig, block } = syn::parse(input)?; - let crate_ = generate_crate_access_2018("frame-support")?; + let crate_ = generate_access_from_frame_or_crate("frame-support")?; let output = quote! { #(#attrs)* #vis #sig { @@ -45,7 +45,7 @@ pub fn transactional(_attr: TokenStream, input: TokenStream) -> Result Result { let ItemFn { attrs, vis, sig, block } = syn::parse(input)?; - let crate_ = generate_crate_access_2018("frame-support")?; + let crate_ = generate_access_from_frame_or_crate("frame-support")?; let output = quote! { #(#attrs)* #vis #sig { diff --git a/substrate/frame/support/procedural/src/tt_macro.rs b/substrate/frame/support/procedural/src/tt_macro.rs index 01611f5dc4a4d054de423668af2b56a1b5532035..d3712742189f8cbf78ba2fcfcd266e8e89ab4ec5 100644 --- a/substrate/frame/support/procedural/src/tt_macro.rs +++ b/substrate/frame/support/procedural/src/tt_macro.rs @@ -18,7 +18,6 @@ //! Implementation of the `create_tt_return_macro` macro use crate::COUNTER; -use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro2::{Ident, TokenStream}; use quote::format_ident; @@ -65,9 +64,9 @@ impl syn::parse::Parse for CreateTtReturnMacroDef { /// macro_rules! my_tt_macro { /// { /// $caller:tt -/// $(frame_support = [{ $($frame_support:ident)::* }])? +/// $(your_tt_return = [{ $my_tt_return:path }])? /// } => { -/// frame_support::__private::tt_return! { +/// $my_tt_return! { /// $caller /// foo = [{ bar }] /// } @@ -78,10 +77,6 @@ pub fn create_tt_return_macro(input: proc_macro::TokenStream) -> proc_macro::Tok let CreateTtReturnMacroDef { name, args } = syn::parse_macro_input!(input as CreateTtReturnMacroDef); - let frame_support = match generate_crate_access_2018("frame-support") { - Ok(i) => i, - Err(e) => return e.into_compile_error().into(), - }; let (keys, values): (Vec<_>, Vec<_>) = args.into_iter().unzip(); let count = COUNTER.with(|counter| counter.borrow_mut().inc()); let unique_name = format_ident!("{}_{}", name, count); @@ -92,9 +87,9 @@ pub fn create_tt_return_macro(input: proc_macro::TokenStream) -> proc_macro::Tok macro_rules! #unique_name { { $caller:tt - $(frame_support = [{ $($frame_support:ident)::* }])? + $(your_tt_return = [{ $my_tt_macro:path }])? } => { - #frame_support::__private::tt_return! { + $my_tt_return! { $caller #( #keys = [{ #values }] diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index fb0a1b51cbcf6dbf9df1ceeea196f97cc4d8fd8e..fd42e18180d396bb34050b5acd310ab5888fc6d7 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "visit", "extra-traits"] } +syn = { version = "2.0.38", features = ["full", "visit", "extra-traits"] } frame-support-procedural-tools-derive = { path = "derive" } diff --git a/substrate/frame/support/procedural/tools/derive/Cargo.toml b/substrate/frame/support/procedural/tools/derive/Cargo.toml index 747d3bacd42536ad81356745ff05e359debb7288..06f8e0f3d537a956f26dd873929f87bec86ce9e0 100644 --- a/substrate/frame/support/procedural/tools/derive/Cargo.toml +++ b/substrate/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.36", features = ["proc-macro", "full", "extra-traits", "parsing"] } +syn = { version = "2.0.38", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index 541accc8ab96a3520d6bf9edd03434459ca29bd5..be43961336280673524071441632bbfa7f61de61 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -39,24 +39,44 @@ fn generate_hidden_includes_mod_name(unique_id: &str) -> Ident { /// Generates the access to the `frame-support` crate. pub fn generate_crate_access(unique_id: &str, def_crate: &str) -> TokenStream { if std::env::var("CARGO_PKG_NAME").unwrap() == def_crate { - quote::quote!(frame_support) + let frame_support = match generate_access_from_frame_or_crate("frame-support") { + Ok(c) => c, + Err(e) => return e.into_compile_error().into(), + }; + quote::quote!(#frame_support) } else { let mod_name = generate_hidden_includes_mod_name(unique_id); quote::quote!( self::#mod_name::hidden_include ) } } +/// Check if a path is using the `frame` crate or not. +/// +/// This will usually check the output of [`generate_access_from_frame_or_crate`]. +/// We want to know if whatever the `path` takes us to, is exported from `frame` or not. In that +/// case `path` would start with `frame`, something like `frame::x::y:z`. +pub fn is_using_frame_crate(path: &syn::Path) -> bool { + path.segments.first().map(|s| s.ident == "frame").unwrap_or(false) +} + /// Generate the crate access for the crate using 2018 syntax. /// -/// for `frame-support` output will for example be `frame_support`. -pub fn generate_crate_access_2018(def_crate: &str) -> Result { - match crate_name(def_crate) { - Ok(FoundCrate::Itself) => { - let name = def_crate.to_string().replace("-", "_"); - Ok(syn::Ident::new(&name, Span::call_site())) - }, - Ok(FoundCrate::Name(name)) => Ok(Ident::new(&name, Span::call_site())), - Err(e) => Err(Error::new(Span::call_site(), e)), +/// If `frame` is in scope, it will use `frame::deps::`. Else, it will try and find +/// `` directly. +pub fn generate_access_from_frame_or_crate(def_crate: &str) -> Result { + if let Some(path) = get_frame_crate_path(def_crate) { + Ok(path) + } else { + let ident = match crate_name(def_crate) { + Ok(FoundCrate::Itself) => { + let name = def_crate.to_string().replace("-", "_"); + Ok(syn::Ident::new(&name, Span::call_site())) + }, + Ok(FoundCrate::Name(name)) => Ok(Ident::new(&name, Span::call_site())), + Err(e) => Err(Error::new(Span::call_site(), e)), + }?; + + Ok(syn::Path::from(ident)) } } @@ -64,21 +84,41 @@ pub fn generate_crate_access_2018(def_crate: &str) -> Result pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream { let mod_name = generate_hidden_includes_mod_name(unique_id); - match crate_name(def_crate) { - Ok(FoundCrate::Itself) => quote!(), - Ok(FoundCrate::Name(name)) => { - let name = Ident::new(&name, Span::call_site()); - quote::quote!( - #[doc(hidden)] - mod #mod_name { - pub extern crate #name as hidden_include; - } - ) - }, - Err(e) => { - let err = Error::new(Span::call_site(), e).to_compile_error(); - quote!( #err ) - }, + if let Some(path) = get_frame_crate_path(def_crate) { + quote::quote!( + #[doc(hidden)] + mod #mod_name { + pub use #path as hidden_include; + } + ) + } else { + match crate_name(def_crate) { + Ok(FoundCrate::Itself) => quote!(), + Ok(FoundCrate::Name(name)) => { + let name = Ident::new(&name, Span::call_site()); + quote::quote!( + #[doc(hidden)] + mod #mod_name { + pub use #name as hidden_include; + } + ) + }, + Err(e) => { + let err = Error::new(Span::call_site(), e).to_compile_error(); + quote!( #err ) + }, + } + } +} + +/// Generates the path to the frame crate deps. +fn get_frame_crate_path(def_crate: &str) -> Option { + // This does not work if the frame crate is renamed. + if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + let path = format!("{}::deps::{}", name, def_crate.to_string().replace("-", "_")); + Some(syn::parse_str::(&path).expect("is a valid path; qed")) + } else { + None } } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index a7106780e0215069af1d6191e5d3ad79fef7170d..f54252ff9d61de8b79c8524834d2d49c9e2dbde1 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -30,6 +30,7 @@ #![cfg_attr(not(feature = "std"), no_std)] /// Export ourself as `frame_support` to make tests happy. +#[doc(hidden)] extern crate self as frame_support; /// Private exports that are being used by macros. @@ -45,6 +46,7 @@ pub mod __private { pub use serde; pub use sp_core::{OpaqueMetadata, Void}; pub use sp_core_hashing_proc_macro; + pub use sp_inherents; pub use sp_io::{self, storage::root as storage_root}; pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] @@ -786,12 +788,6 @@ pub use serde::{Deserialize, Serialize}; #[cfg(not(no_std))] pub use macro_magic; -/// Private module re-exporting items used by frame support macros. -#[doc(hidden)] -pub mod _private { - pub use sp_inherents; -} - /// Prelude to be used for pallet testing, for ease of use. #[cfg(feature = "std")] pub mod testing_prelude { @@ -1646,8 +1642,7 @@ pub mod pallet_prelude { /// the enum: /// /// ```ignore -/// Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo, -/// RuntimeDebug +/// Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug /// ``` /// /// The inverse is also true: if there are any #[derive] attributes present for the enum, then @@ -1815,6 +1810,15 @@ pub mod pallet_prelude { /// #[pallet::origin] /// pub struct Origin(PhantomData); /// +/// // Declare a hold reason (this is optional). +/// // +/// // Creates a hold reason for this pallet that is aggregated by `construct_runtime`. +/// // A similar enum can be defined for `FreezeReason`, `LockId` or `SlashReason`. +/// #[pallet::composite_enum] +/// pub enum HoldReason { +/// SomeHoldReason +/// } +/// /// // Declare validate_unsigned implementation (this is optional). /// #[pallet::validate_unsigned] /// impl ValidateUnsigned for Pallet { @@ -1949,6 +1953,11 @@ pub mod pallet_prelude { /// #[pallet::origin] /// pub struct Origin(PhantomData<(T, I)>); /// +/// #[pallet::composite_enum] +/// pub enum HoldReason { +/// SomeHoldReason +/// } +/// /// #[pallet::validate_unsigned] /// impl, I: 'static> ValidateUnsigned for Pallet { /// type Call = Call; @@ -2188,10 +2197,80 @@ pub mod pallet_macros { pub use frame_support_procedural::{ call_index, compact, composite_enum, config, constant, disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit, - generate_store, genesis_build, genesis_config, getter, hooks, import_section, inherent, - no_default, no_default_bounds, origin, pallet_section, storage, storage_prefix, - storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, + generate_store, getter, hooks, import_section, inherent, no_default, no_default_bounds, + origin, pallet_section, storage, storage_prefix, storage_version, type_value, unbounded, + validate_unsigned, weight, whitelist_storage, }; + + /// Allows you to define the genesis configuration for the pallet. + /// + /// Item is defined as either an enum or a struct. It needs to be public and implement the + /// trait [`frame_support::traits::BuildGenesisConfig`]. + /// + /// See [`genesis_build`] for an example. + pub use frame_support_procedural::genesis_config; + + /// Allows you to define how the state of your pallet at genesis is built. This + /// takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's initial + /// state. + /// + /// The fields of the `GenesisConfig` can in turn be populated by the chain-spec. + /// + /// ## Example: + /// + /// ``` + /// #[frame_support::pallet] + /// pub mod pallet { + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::BuildGenesisConfig; + /// #[pallet::genesis_config] + /// #[derive(frame_support::DefaultNoBound)] + /// pub struct GenesisConfig { + /// foo: Vec + /// } + /// + /// #[pallet::genesis_build] + /// impl BuildGenesisConfig for GenesisConfig { + /// fn build(&self) { + /// // use &self to access fields. + /// let foo = &self.foo; + /// todo!() + /// } + /// } + /// } + /// ``` + /// + /// ## Former Usage + /// + /// Prior to , the following syntax was used. + /// This is deprecated and will soon be removed. + /// + /// ``` + /// #[frame_support::pallet] + /// pub mod pallet { + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::GenesisBuild; + /// #[pallet::genesis_config] + /// #[derive(frame_support::DefaultNoBound)] + /// pub struct GenesisConfig { + /// foo: Vec + /// } + /// + /// #[pallet::genesis_build] + /// impl GenesisBuild for GenesisConfig { + /// fn build(&self) { + /// todo!() + /// } + /// } + /// } + /// ``` + pub use frame_support_procedural::genesis_build; } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 8f490030c25b2b53b2c7ec6b3b3debdb61e7b5e8..d6ae6c6291b1e286d525289a0ece633f43977d82 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -119,7 +119,7 @@ impl< let on_chain_version = Pallet::on_chain_storage_version(); if on_chain_version == FROM { log::info!( - "Running {} VersionedOnRuntimeUpgrade: version {:?} to {:?}.", + "🚚 Pallet {:?} migrating storage version from {:?} to {:?}.", Pallet::name(), FROM, TO @@ -134,9 +134,10 @@ impl< weight.saturating_add(DbWeight::get().reads_writes(1, 1)) } else { log::warn!( - "{} VersionedOnRuntimeUpgrade for version {:?} skipped because current on-chain version is {:?}.", + "🚚 Pallet {:?} migration {}->{} can be removed; on-chain is already at {:?}.", Pallet::name(), FROM, + TO, on_chain_version ); DbWeight::get().reads(1) diff --git a/substrate/frame/support/src/storage/generator/double_map.rs b/substrate/frame/support/src/storage/generator/double_map.rs index 00a3f1bc7c1ce3d4434766e2a32fa5d523db043d..a4c1f58203e3caf0cd200d0daf5b7b7aeba36702 100644 --- a/substrate/frame/support/src/storage/generator/double_map.rs +++ b/substrate/frame/support/src/storage/generator/double_map.rs @@ -33,7 +33,7 @@ use sp_std::prelude::*; /// /// Thus value for (key1, key2) is stored at: /// ```nocompile -/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) +/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) /// ``` /// /// # Warning @@ -53,18 +53,15 @@ pub trait StorageDoubleMap { /// Hasher for the second key. type Hasher2: StorageHasher; - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; - /// The full prefix; just the hash of `module_prefix` concatenated to the hash of + /// The full prefix; just the hash of `pallet_prefix` concatenated to the hash of /// `storage_prefix`. - fn prefix_hash() -> Vec { - let result = storage_prefix(Self::module_prefix(), Self::storage_prefix()); - result.to_vec() - } + fn prefix_hash() -> [u8; 32]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option) -> Self::Query; @@ -77,7 +74,7 @@ pub trait StorageDoubleMap { where KArg1: EncodeLike, { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = k1.using_encoded(Self::Hasher1::hash); let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.as_ref().len()); @@ -94,7 +91,7 @@ pub trait StorageDoubleMap { KArg1: EncodeLike, KArg2: EncodeLike, { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key1_hashed = k1.using_encoded(Self::Hasher1::hash); let key2_hashed = k2.using_encoded(Self::Hasher2::hash); @@ -334,7 +331,7 @@ where key2: KeyArg2, ) -> Option { let old_key = { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key1_hashed = key1.using_encoded(OldHasher1::hash); let key2_hashed = key2.using_encoded(OldHasher2::hash); @@ -419,7 +416,7 @@ where } fn iter() -> Self::Iterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); Self::Iterator { prefix: prefix.clone(), previous_key: prefix, @@ -442,7 +439,7 @@ where } fn iter_keys() -> Self::FullKeyIterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); Self::FullKeyIterator { prefix: prefix.clone(), previous_key: prefix, @@ -470,7 +467,7 @@ where } fn translate Option>(mut f: F) { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); let mut previous_key = prefix.clone(); while let Some(next) = sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) @@ -561,7 +558,7 @@ mod test_iterators { type DoubleMap = self::frame_system::DoubleMap; // All map iterator - let prefix = DoubleMap::prefix_hash(); + let prefix = DoubleMap::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); @@ -621,7 +618,7 @@ mod test_iterators { assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); // Translate - let prefix = DoubleMap::prefix_hash(); + let prefix = DoubleMap::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); diff --git a/substrate/frame/support/src/storage/generator/map.rs b/substrate/frame/support/src/storage/generator/map.rs index 1d2511e324dc654dbbcbe4c37521d25511fc148c..b2919bff8d134ca39c2f9c82f509c31373e4c822 100644 --- a/substrate/frame/support/src/storage/generator/map.rs +++ b/substrate/frame/support/src/storage/generator/map.rs @@ -28,7 +28,7 @@ use sp_std::prelude::*; /// /// By default each key value is stored at: /// ```nocompile -/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key)) +/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key)) /// ``` /// /// # Warning @@ -42,18 +42,15 @@ pub trait StorageMap { /// Hasher. Used for generating final key. type Hasher: StorageHasher; - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; - /// The full prefix; just the hash of `module_prefix` concatenated to the hash of + /// The full prefix; just the hash of `pallet_prefix` concatenated to the hash of /// `storage_prefix`. - fn prefix_hash() -> Vec { - let result = storage_prefix(Self::module_prefix(), Self::storage_prefix()); - result.to_vec() - } + fn prefix_hash() -> [u8; 32]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option) -> Self::Query; @@ -66,7 +63,7 @@ pub trait StorageMap { where KeyArg: EncodeLike, { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = key.using_encoded(Self::Hasher::hash); let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.as_ref().len()); @@ -128,7 +125,7 @@ where /// Enumerate all elements in the map. fn iter() -> Self::Iterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); PrefixIterator { prefix: prefix.clone(), previous_key: prefix, @@ -150,7 +147,7 @@ where /// Enumerate all keys in the map. fn iter_keys() -> Self::KeyIterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); KeyPrefixIterator { prefix: prefix.clone(), previous_key: prefix, @@ -190,7 +187,7 @@ where previous_key: Option>, mut f: F, ) -> Option> { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); let previous_key = previous_key.unwrap_or_else(|| prefix.clone()); let current_key = @@ -339,7 +336,7 @@ impl> storage::StorageMap fn migrate_key>(key: KeyArg) -> Option { let old_key = { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = key.using_encoded(OldHasher::hash); let mut final_key = @@ -398,7 +395,7 @@ mod test_iterators { type Map = self::frame_system::Map; // All map iterator - let prefix = Map::prefix_hash(); + let prefix = Map::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); @@ -420,7 +417,7 @@ mod test_iterators { assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); // Translate - let prefix = Map::prefix_hash(); + let prefix = Map::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); diff --git a/substrate/frame/support/src/storage/generator/nmap.rs b/substrate/frame/support/src/storage/generator/nmap.rs index 5d3d689aa98a6f378666333677df77197fbc4e04..4b49ad3eb38d434a897ed2b1020156e541b02a96 100755 --- a/substrate/frame/support/src/storage/generator/nmap.rs +++ b/substrate/frame/support/src/storage/generator/nmap.rs @@ -61,18 +61,15 @@ pub trait StorageNMap { /// The type that get/take returns. type Query; - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; - /// The full prefix; just the hash of `module_prefix` concatenated to the hash of + /// The full prefix; just the hash of `pallet_prefix` concatenated to the hash of /// `storage_prefix`. - fn prefix_hash() -> Vec { - let result = storage_prefix(Self::module_prefix(), Self::storage_prefix()); - result.to_vec() - } + fn prefix_hash() -> [u8; 32]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option) -> Self::Query; @@ -85,7 +82,7 @@ pub trait StorageNMap { where K: HasKeyPrefix, { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = >::partial_key(key); let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len()); @@ -102,7 +99,7 @@ pub trait StorageNMap { KG: KeyGenerator, KArg: EncodeLikeTuple + TupleToEncodedIter, { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = KG::final_key(key); let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len()); @@ -299,7 +296,7 @@ where KArg: EncodeLikeTuple + TupleToEncodedIter, { let old_key = { - let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix()); + let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix()); let key_hashed = K::migrate_key(&key, hash_fns); let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len()); @@ -386,11 +383,11 @@ impl> } fn iter() -> Self::Iterator { - Self::iter_from(G::prefix_hash()) + Self::iter_from(G::prefix_hash().to_vec()) } fn iter_from(starting_raw_key: Vec) -> Self::Iterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); Self::Iterator { prefix, previous_key: starting_raw_key, @@ -404,11 +401,11 @@ impl> } fn iter_keys() -> Self::KeyIterator { - Self::iter_keys_from(G::prefix_hash()) + Self::iter_keys_from(G::prefix_hash().to_vec()) } fn iter_keys_from(starting_raw_key: Vec) -> Self::KeyIterator { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); Self::KeyIterator { prefix, previous_key: starting_raw_key, @@ -427,7 +424,7 @@ impl> } fn translate Option>(mut f: F) { - let prefix = G::prefix_hash(); + let prefix = G::prefix_hash().to_vec(); let mut previous_key = prefix.clone(); while let Some(next) = sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) @@ -537,7 +534,7 @@ mod test_iterators { type NMap = self::frame_system::NMap; // All map iterator - let prefix = NMap::prefix_hash(); + let prefix = NMap::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); @@ -594,7 +591,7 @@ mod test_iterators { assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); // Translate - let prefix = NMap::prefix_hash(); + let prefix = NMap::prefix_hash().to_vec(); unhashed::put(&key_before_prefix(prefix.clone()), &1u64); unhashed::put(&key_after_prefix(prefix.clone()), &1u64); diff --git a/substrate/frame/support/src/storage/generator/value.rs b/substrate/frame/support/src/storage/generator/value.rs index 4ffe40bac53ca231f10e25cf521f3f4d7df02de3..21166b39467bb2def5ea3aee089b92af6e9ecaaf 100644 --- a/substrate/frame/support/src/storage/generator/value.rs +++ b/substrate/frame/support/src/storage/generator/value.rs @@ -25,14 +25,14 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; /// /// By default value is stored at: /// ```nocompile -/// Twox128(module_prefix) ++ Twox128(storage_prefix) +/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) /// ``` pub trait StorageValue { /// The type that get/take returns. type Query; - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; @@ -44,9 +44,7 @@ pub trait StorageValue { fn from_query_to_optional_value(v: Self::Query) -> Option; /// Generate the full key used in top storage. - fn storage_value_final_key() -> [u8; 32] { - crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix()) - } + fn storage_value_final_key() -> [u8; 32]; } impl> storage::StorageValue for G { @@ -97,10 +95,6 @@ impl> storage::StorageValue for G { } } - fn kill() { - unhashed::kill(&Self::storage_value_final_key()) - } - fn mutate R>(f: F) -> R { Self::try_mutate(|v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } @@ -142,6 +136,10 @@ impl> storage::StorageValue for G { ret } + fn kill() { + unhashed::kill(&Self::storage_value_final_key()) + } + fn take() -> G::Query { let key = Self::storage_value_final_key(); let value = unhashed::get(&key); diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index d52908fa366c6cc144a4027bcafade19e50fe2dd..851b0687bd12268019f64987bbb92ac2a3231ccb 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -191,7 +191,7 @@ pub trait StorageList { /// Append a single element. /// - /// Should not be called repeatedly; use `append_many` instead. + /// Should not be called repeatedly; use `append_many` instead. /// Worst case linear `O(len)` with `len` being the number if elements in the list. fn append_one(item: EncodeLikeValue) where @@ -202,7 +202,7 @@ pub trait StorageList { /// Append many elements. /// - /// Should not be called repeatedly; use `appender` instead. + /// Should not be called repeatedly; use `appender` instead. /// Worst case linear `O(len + items.count())` with `len` beings the number if elements in the /// list. fn append_many(items: I) @@ -1273,15 +1273,15 @@ impl Iterator for ChildTriePrefixIterator { /// Trait for storage types that store all its value after a unique prefix. pub trait StoragePrefixedContainer { - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; /// Final full prefix that prefixes all keys. fn final_prefix() -> [u8; 32] { - crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix()) + crate::storage::storage_prefix(Self::pallet_prefix(), Self::storage_prefix()) } } @@ -1289,18 +1289,18 @@ pub trait StoragePrefixedContainer { /// /// By default the final prefix is: /// ```nocompile -/// Twox128(module_prefix) ++ Twox128(storage_prefix) +/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) /// ``` pub trait StoragePrefixedMap { - /// Module prefix. Used for generating final key. - fn module_prefix() -> &'static [u8]; // TODO move to StoragePrefixedContainer + /// Pallet prefix. Used for generating final key. + fn pallet_prefix() -> &'static [u8]; // TODO move to StoragePrefixedContainer /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; /// Final full prefix that prefixes all keys. fn final_prefix() -> [u8; 32] { - crate::storage::storage_prefix(Self::module_prefix(), Self::storage_prefix()) + crate::storage::storage_prefix(Self::pallet_prefix(), Self::storage_prefix()) } /// Remove all values in the overlay and up to `limit` in the backend. @@ -1624,7 +1624,7 @@ mod test { TestExternalities::default().execute_with(|| { struct MyStorage; impl StoragePrefixedMap for MyStorage { - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { b"MyModule" } @@ -1701,7 +1701,7 @@ mod test { impl generator::StorageValue for Storage { type Query = Digest; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { b"MyModule" } @@ -1716,6 +1716,10 @@ mod test { fn from_query_to_optional_value(v: Self::Query) -> Option { Some(v) } + + fn storage_value_final_key() -> [u8; 32] { + storage_prefix(Self::pallet_prefix(), Self::storage_prefix()) + } } Storage::append(DigestItem::Other(Vec::new())); @@ -1736,7 +1740,7 @@ mod test { type Query = u64; type Hasher = Twox64Concat; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { b"MyModule" } @@ -1744,6 +1748,10 @@ mod test { b"MyStorageMap" } + fn prefix_hash() -> [u8; 32] { + storage_prefix(Self::pallet_prefix(), Self::storage_prefix()) + } + fn from_optional_value_to_query(v: Option) -> Self::Query { v.unwrap_or_default() } diff --git a/substrate/frame/support/src/storage/storage_noop_guard.rs b/substrate/frame/support/src/storage/storage_noop_guard.rs index d00e6e18ecc484e3139ea27e25e3d580871c8c3c..c4d40fa99a35cef9a05d55b71f27de1717a72cee 100644 --- a/substrate/frame/support/src/storage/storage_noop_guard.rs +++ b/substrate/frame/support/src/storage/storage_noop_guard.rs @@ -37,15 +37,38 @@ /// }); /// ``` #[must_use] -pub struct StorageNoopGuard(sp_std::vec::Vec); +pub struct StorageNoopGuard<'a> { + storage_root: sp_std::vec::Vec, + error_message: &'a str, +} -impl Default for StorageNoopGuard { +impl<'a> Default for StorageNoopGuard<'a> { fn default() -> Self { - Self(sp_io::storage::root(sp_runtime::StateVersion::V1)) + Self { + storage_root: sp_io::storage::root(sp_runtime::StateVersion::V1), + error_message: "`StorageNoopGuard` detected an attempted storage change.", + } + } +} + +impl<'a> StorageNoopGuard<'a> { + /// Alias to `default()`. + pub fn new() -> Self { + Self::default() + } + + /// Creates a new [`StorageNoopGuard`] with a custom error message. + pub fn from_error_message(error_message: &'a str) -> Self { + Self { storage_root: sp_io::storage::root(sp_runtime::StateVersion::V1), error_message } + } + + /// Sets a custom error message for a [`StorageNoopGuard`]. + pub fn set_error_message(&mut self, error_message: &'a str) { + self.error_message = error_message; } } -impl Drop for StorageNoopGuard { +impl<'a> Drop for StorageNoopGuard<'a> { fn drop(&mut self) { // No need to double panic, eg. inside a test assertion failure. if sp_std::thread::panicking() { @@ -53,8 +76,9 @@ impl Drop for StorageNoopGuard { } assert_eq!( sp_io::storage::root(sp_runtime::StateVersion::V1), - self.0, - "StorageNoopGuard detected wrongful storage changes.", + self.storage_root, + "{}", + self.error_message, ); } } @@ -65,7 +89,7 @@ mod tests { use sp_io::TestExternalities; #[test] - #[should_panic(expected = "StorageNoopGuard detected wrongful storage changes.")] + #[should_panic(expected = "`StorageNoopGuard` detected an attempted storage change.")] fn storage_noop_guard_panics_on_changed() { TestExternalities::default().execute_with(|| { let _guard = StorageNoopGuard::default(); @@ -83,7 +107,7 @@ mod tests { } #[test] - #[should_panic(expected = "StorageNoopGuard detected wrongful storage changes.")] + #[should_panic(expected = "`StorageNoopGuard` detected an attempted storage change.")] fn storage_noop_guard_panics_on_early_drop() { TestExternalities::default().execute_with(|| { let guard = StorageNoopGuard::default(); @@ -111,4 +135,34 @@ mod tests { panic!("Something else"); }); } + + #[test] + #[should_panic(expected = "`StorageNoopGuard` found unexpected storage changes.")] + fn storage_noop_guard_panics_created_from_error_message() { + TestExternalities::default().execute_with(|| { + let _guard = StorageNoopGuard::from_error_message( + "`StorageNoopGuard` found unexpected storage changes.", + ); + frame_support::storage::unhashed::put(b"key", b"value"); + }); + } + + #[test] + #[should_panic(expected = "`StorageNoopGuard` found unexpected storage changes.")] + fn storage_noop_guard_panics_with_set_error_message() { + TestExternalities::default().execute_with(|| { + let mut guard = StorageNoopGuard::default(); + guard.set_error_message("`StorageNoopGuard` found unexpected storage changes."); + frame_support::storage::unhashed::put(b"key", b"value"); + }); + } + + #[test] + #[should_panic(expected = "`StorageNoopGuard` detected an attempted storage change.")] + fn storage_noop_guard_panics_new_alias() { + TestExternalities::default().execute_with(|| { + let _guard = StorageNoopGuard::new(); + frame_support::storage::unhashed::put(b"key", b"value"); + }); + } } diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 5b750a74098b8395a4234a7db562b52e254a8f63..50e2c678248c9aa34dddeaaec09b6ddeec0be348 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -107,7 +107,7 @@ where /// The prefix used to generate the key of the map. pub fn map_storage_final_prefix() -> Vec { use crate::storage::generator::StorageMap; - ::Map::prefix_hash() + ::Map::prefix_hash().to_vec() } /// Get the storage key used to fetch a value corresponding to a specific key. diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 54f8e57cf242d5fa1984817878a2c76837ade542..5da31c05922541f0cbc7c987d09fa79894c02569 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -104,7 +104,7 @@ where /// The prefix used to generate the key of the map. pub fn map_storage_final_prefix() -> Vec { use crate::storage::generator::StorageNMap; - ::Map::prefix_hash() + ::Map::prefix_hash().to_vec() } /// Get the storage key used to fetch a value corresponding to a specific key. diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index e787921841032f3f0cbada6fd0ff0d4ab665dd59..519ffcbafadee09dbfbaf4f78ea76939cf34a64b 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -117,12 +117,17 @@ where type Query = QueryKind::Query; type Hasher1 = Hasher1; type Hasher2 = Hasher2; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { Prefix::pallet_prefix().as_bytes() } + fn storage_prefix() -> &'static [u8] { Prefix::STORAGE_PREFIX.as_bytes() } + fn prefix_hash() -> [u8; 32] { + Prefix::prefix_hash() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { QueryKind::from_optional_value_to_query(v) } @@ -145,8 +150,8 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() + fn pallet_prefix() -> &'static [u8] { + >::pallet_prefix() } fn storage_prefix() -> &'static [u8] { >::storage_prefix() @@ -691,7 +696,7 @@ where { fn storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), @@ -722,7 +727,7 @@ where { fn partial_storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index 816b90162f644b88b620b218bef36e6ff952c051..7f936a8a35a61c4d8d23aa3c1d0aebe315ee6229 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -83,12 +83,15 @@ where { type Query = QueryKind::Query; type Hasher = Hasher; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { Prefix::pallet_prefix().as_bytes() } fn storage_prefix() -> &'static [u8] { Prefix::STORAGE_PREFIX.as_bytes() } + fn prefix_hash() -> [u8; 32] { + Prefix::prefix_hash() + } fn from_optional_value_to_query(v: Option) -> Self::Query { QueryKind::from_optional_value_to_query(v) } @@ -108,8 +111,8 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() + fn pallet_prefix() -> &'static [u8] { + >::pallet_prefix() } fn storage_prefix() -> &'static [u8] { >::storage_prefix() @@ -469,7 +472,7 @@ where { fn storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), @@ -497,7 +500,7 @@ where { fn partial_storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index e9a4b12dd43a16ea6713ea59a821959bbea20e51..406fd42eaf7b3773e960f4489d5ede2b090ca0a2 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -72,12 +72,15 @@ where MaxValues: Get>, { type Query = QueryKind::Query; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { Prefix::pallet_prefix().as_bytes() } fn storage_prefix() -> &'static [u8] { Prefix::STORAGE_PREFIX.as_bytes() } + fn prefix_hash() -> [u8; 32] { + Prefix::prefix_hash() + } fn from_optional_value_to_query(v: Option) -> Self::Query { QueryKind::from_optional_value_to_query(v) } @@ -96,8 +99,8 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() + fn pallet_prefix() -> &'static [u8] { + >::pallet_prefix() } fn storage_prefix() -> &'static [u8] { >::storage_prefix() @@ -581,7 +584,7 @@ where { fn storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), @@ -607,7 +610,7 @@ where { fn partial_storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::final_prefix().to_vec(), max_values: MaxValues::get(), diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 3c7f24715ac94026b3bea3c1aeb5eb7a775b41ed..3e1f2fe9551d3578678959b09b9a4c60fa962c07 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -49,7 +49,7 @@ where OnEmpty: crate::traits::Get + 'static, { type Query = QueryKind::Query; - fn module_prefix() -> &'static [u8] { + fn pallet_prefix() -> &'static [u8] { Prefix::pallet_prefix().as_bytes() } fn storage_prefix() -> &'static [u8] { @@ -61,6 +61,9 @@ where fn from_query_to_optional_value(v: Self::Query) -> Option { QueryKind::from_query_to_optional_value(v) } + fn storage_value_final_key() -> [u8; 32] { + Prefix::prefix_hash() + } } impl StorageValue @@ -251,7 +254,7 @@ where { fn storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::hashed_key().to_vec(), max_values: Some(1), @@ -271,7 +274,7 @@ where { fn partial_storage_info() -> Vec { vec![StorageInfo { - pallet_name: Self::module_prefix().to_vec(), + pallet_name: Self::pallet_prefix().to_vec(), storage_name: Self::storage_prefix().to_vec(), prefix: Self::hashed_key().to_vec(), max_values: Some(1), diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index db458880db6836eaedacd6ad44d269adca290933..3690159c5994d98d265eadf7c0a623f4630eede3 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -647,3 +647,17 @@ fn check_storage_parameter_type_works() { assert_eq!(300, StorageParameter::get()); }) } + +#[test] +fn derive_partial_eq_no_bound_core_mod() { + mod core {} + + #[derive( + crate::PartialEqNoBound, + crate::CloneNoBound, + crate::DebugNoBound, + crate::DefaultNoBound, + crate::EqNoBound, + )] + struct Test; +} diff --git a/substrate/frame/support/src/tests/storage_alias.rs b/substrate/frame/support/src/tests/storage_alias.rs index 05ea1b5f712c631bc731f9444621d7f8c20f8b81..6fc5cfefdad19722c68aba672fabcad9ad54f036 100644 --- a/substrate/frame/support/src/tests/storage_alias.rs +++ b/substrate/frame/support/src/tests/storage_alias.rs @@ -112,7 +112,7 @@ fn verbatim_attribute() { assert_eq!(1, Value::get().unwrap()); // The prefix is the one we declared above. - assert_eq!(&b"Test"[..], Value::module_prefix()); + assert_eq!(&b"Test"[..], Value::pallet_prefix()); }); } @@ -130,7 +130,7 @@ fn pallet_name_attribute() { // The prefix is the pallet name. In this case the pallet name is `System` as declared in // `construct_runtime!`. - assert_eq!(&b"System"[..], Value::::module_prefix()); + assert_eq!(&b"System"[..], Value::::pallet_prefix()); }); } @@ -154,7 +154,7 @@ fn dynamic_attribute() { assert_eq!(1, Value::::get().unwrap()); // The prefix is the one we declared above. - assert_eq!(&b"Hello"[..], Value::::module_prefix()); + assert_eq!(&b"Hello"[..], Value::::pallet_prefix()); }); } @@ -166,13 +166,13 @@ fn storage_alias_guess() { #[crate::storage_alias] pub type Value = StorageValue; - assert_eq!(&b"Test"[..], Value::module_prefix()); + assert_eq!(&b"Test"[..], Value::pallet_prefix()); // The macro will use the pallet name as prefix. #[crate::storage_alias] pub type PalletValue = StorageValue, u32>; - assert_eq!(&b"System"[..], PalletValue::::module_prefix()); + assert_eq!(&b"System"[..], PalletValue::::pallet_prefix()); }); } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 10ae5d83b5ac958fca06be636d38bb0fe4020cb4..69885b2873e3c722d0e5b8b41213ee03238cb67d 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -34,7 +34,7 @@ mod members; #[allow(deprecated)] pub use members::{AllowAll, DenyAll, Filter}; pub use members::{ - AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Everything, + AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything, EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing, RankedMembers, SortedMembers, TheseExcept, }; @@ -107,7 +107,7 @@ mod voting; pub use voting::{ClassCountOf, PollStatus, Polling, VoteTally}; mod preimages; -pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage}; +pub use preimages::{Bounded, BoundedInline, FetchResult, QueryPreimage, StorePreimage}; mod messages; pub use messages::{ diff --git a/substrate/frame/support/src/traits/members.rs b/substrate/frame/support/src/traits/members.rs index fbba742ebeb4395b4ec17ad6656956929f8fec76..d667eaa7e9d8d2b46b39254fccf5e0c6052c9751 100644 --- a/substrate/frame/support/src/traits/members.rs +++ b/substrate/frame/support/src/traits/members.rs @@ -137,6 +137,14 @@ impl, Those: ContainsPair> ContainsPair(PhantomData); +impl> Contains for Equals { + fn contains(t: &X) -> bool { + t == &T::get() + } +} + /// Create a type which implements the `Contains` trait for a particular type with syntax similar /// to `matches!`. #[macro_export] diff --git a/substrate/frame/support/src/traits/metadata.rs b/substrate/frame/support/src/traits/metadata.rs index 85d8f9a5a74e0ddfa3bf592908d0e2fb8f434e49..bd29b600916138828d7b78a4f3c4a416598c4f3b 100644 --- a/substrate/frame/support/src/traits/metadata.rs +++ b/substrate/frame/support/src/traits/metadata.rs @@ -31,6 +31,8 @@ pub trait PalletInfo { fn index() -> Option; /// Convert the given pallet `P` into its name as configured in the runtime. fn name() -> Option<&'static str>; + /// The two128 hash of name. + fn name_hash() -> Option<[u8; 16]>; /// Convert the given pallet `P` into its Rust module name as used in `construct_runtime!`. fn module_name() -> Option<&'static str>; /// Convert the given pallet `P` into its containing crate version. @@ -59,6 +61,8 @@ pub trait PalletInfoAccess { fn index() -> usize; /// Name of the pallet as configured in the runtime. fn name() -> &'static str; + /// Two128 hash of name. + fn name_hash() -> [u8; 16]; /// Name of the Rust module containing the pallet. fn module_name() -> &'static str; /// Version of the crate containing the pallet. @@ -281,6 +285,7 @@ pub trait GetStorageVersion { #[cfg(test)] mod tests { use super::*; + use sp_core::twox_128; struct Pallet1; impl PalletInfoAccess for Pallet1 { @@ -290,6 +295,9 @@ mod tests { fn name() -> &'static str { "Pallet1" } + fn name_hash() -> [u8; 16] { + twox_128(Self::name().as_bytes()) + } fn module_name() -> &'static str { "pallet1" } @@ -305,6 +313,11 @@ mod tests { fn name() -> &'static str { "Pallet2" } + + fn name_hash() -> [u8; 16] { + twox_128(Self::name().as_bytes()) + } + fn module_name() -> &'static str { "pallet2" } diff --git a/substrate/frame/support/src/traits/preimages.rs b/substrate/frame/support/src/traits/preimages.rs index bf08a286dd7cfb617e3271256e06fbb9a27e15c0..647af029c16dce07f998e34c30cb076f6a670d4c 100644 --- a/substrate/frame/support/src/traits/preimages.rs +++ b/substrate/frame/support/src/traits/preimages.rs @@ -15,16 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Stuff for dealing with 32-byte hashed preimages. +//! Stuff for dealing with hashed preimages. use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::{RuntimeDebug, H256}; -use sp_io::hashing::blake2_256; -use sp_runtime::{traits::ConstU32, DispatchError}; +use sp_core::RuntimeDebug; +use sp_runtime::{ + traits::{ConstU32, Hash}, + DispatchError, +}; use sp_std::borrow::Cow; -pub type Hash = H256; pub type BoundedInline = crate::BoundedVec>; /// The maximum we expect a single legacy hash lookup to be. @@ -32,29 +33,29 @@ const MAX_LEGACY_LEN: u32 = 1_000_000; #[derive(Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, RuntimeDebug)] #[codec(mel_bound())] -pub enum Bounded { - /// A Blake2 256 hash with no preimage length. We - /// do not support creation of this except for transitioning from legacy state. - /// In the future we will make this a pure `Dummy` item storing only the final `dummy` field. - Legacy { hash: Hash, dummy: sp_std::marker::PhantomData }, +pub enum Bounded { + /// A hash with no preimage length. We do not support creation of this except + /// for transitioning from legacy state. In the future we will make this a pure + /// `Dummy` item storing only the final `dummy` field. + Legacy { hash: H::Output, dummy: sp_std::marker::PhantomData }, /// A an bounded `Call`. Its encoding must be at most 128 bytes. Inline(BoundedInline), - /// A Blake2-256 hash of the call together with an upper limit for its size. - Lookup { hash: Hash, len: u32 }, + /// A hash of the call together with an upper limit for its size.` + Lookup { hash: H::Output, len: u32 }, } -impl Bounded { +impl Bounded { /// Casts the wrapped type into something that encodes alike. /// /// # Examples /// ``` - /// use frame_support::traits::Bounded; + /// use frame_support::{traits::Bounded, sp_runtime::traits::BlakeTwo256}; /// /// // Transmute from `String` to `&str`. - /// let x: Bounded = Bounded::Inline(Default::default()); - /// let _: Bounded<&str> = x.transmute(); + /// let x: Bounded = Bounded::Inline(Default::default()); + /// let _: Bounded<&str, BlakeTwo256> = x.transmute(); /// ``` - pub fn transmute(self) -> Bounded + pub fn transmute(self) -> Bounded where T: Encode + EncodeLike, { @@ -69,18 +70,18 @@ impl Bounded { /// Returns the hash of the preimage. /// /// The hash is re-calculated every time if the preimage is inlined. - pub fn hash(&self) -> Hash { + pub fn hash(&self) -> H::Output { use Bounded::*; match self { Lookup { hash, .. } | Legacy { hash, .. } => *hash, - Inline(x) => blake2_256(x.as_ref()).into(), + Inline(x) => ::hash(x.as_ref()), } } /// Returns the hash to lookup the preimage. /// /// If this is a `Bounded::Inline`, `None` is returned as no lookup is required. - pub fn lookup_hash(&self) -> Option { + pub fn lookup_hash(&self) -> Option { use Bounded::*; match self { Lookup { hash, .. } | Legacy { hash, .. } => Some(*hash), @@ -115,13 +116,13 @@ impl Bounded { } /// Constructs a `Lookup` bounded item. - pub fn unrequested(hash: Hash, len: u32) -> Self { + pub fn unrequested(hash: H::Output, len: u32) -> Self { Self::Lookup { hash, len } } /// Constructs a `Legacy` bounded item. #[deprecated = "This API is only for transitioning to Scheduler v3 API"] - pub fn from_legacy_hash(hash: impl Into) -> Self { + pub fn from_legacy_hash(hash: impl Into) -> Self { Self::Legacy { hash: hash.into(), dummy: sp_std::marker::PhantomData } } } @@ -130,24 +131,27 @@ pub type FetchResult = Result, DispatchError>; /// A interface for looking up preimages from their hash on chain. pub trait QueryPreimage { + /// The hasher used in the runtime. + type H: Hash; + /// Returns whether a preimage exists for a given hash and if so its length. - fn len(hash: &Hash) -> Option; + fn len(hash: &::Out) -> Option; /// Returns the preimage for a given hash. If given, `len` must be the size of the preimage. - fn fetch(hash: &Hash, len: Option) -> FetchResult; + fn fetch(hash: &::Out, len: Option) -> FetchResult; /// Returns whether a preimage request exists for a given hash. - fn is_requested(hash: &Hash) -> bool; + fn is_requested(hash: &::Out) -> bool; /// Request that someone report a preimage. Providers use this to optimise the economics for /// preimage reporting. - fn request(hash: &Hash); + fn request(hash: &::Out); /// Cancel a previous preimage request. - fn unrequest(hash: &Hash); + fn unrequest(hash: &::Out); /// Request that the data required for decoding the given `bounded` value is made available. - fn hold(bounded: &Bounded) { + fn hold(bounded: &Bounded) { use Bounded::*; match bounded { Inline(..) => {}, @@ -157,7 +161,7 @@ pub trait QueryPreimage { /// No longer request that the data required for decoding the given `bounded` value is made /// available. - fn drop(bounded: &Bounded) { + fn drop(bounded: &Bounded) { use Bounded::*; match bounded { Inline(..) => {}, @@ -167,7 +171,7 @@ pub trait QueryPreimage { /// Check to see if all data required for the given `bounded` value is available for its /// decoding. - fn have(bounded: &Bounded) -> bool { + fn have(bounded: &Bounded) -> bool { use Bounded::*; match bounded { Inline(..) => true, @@ -180,7 +184,7 @@ pub trait QueryPreimage { /// It also directly requests the given `hash` using [`Self::request`]. /// /// This may not be `peek`-able or `realize`-able. - fn pick(hash: Hash, len: u32) -> Bounded { + fn pick(hash: ::Out, len: u32) -> Bounded { Self::request(&hash); Bounded::Lookup { hash, len } } @@ -190,7 +194,7 @@ pub trait QueryPreimage { /// /// NOTE: This does not remove any data needed for realization. If you will no longer use the /// `bounded`, call `realize` instead or call `drop` afterwards. - fn peek(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + fn peek(bounded: &Bounded) -> Result<(T, Option), DispatchError> { use Bounded::*; match bounded { Inline(data) => T::decode(&mut &data[..]).ok().map(|x| (x, None)), @@ -209,7 +213,9 @@ pub trait QueryPreimage { /// Convert the given `bounded` value back into its original instance. If successful, /// `drop` any data backing it. This will not break the realisability of independently /// created instances of `Bounded` which happen to have identical data. - fn realize(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + fn realize( + bounded: &Bounded, + ) -> Result<(T, Option), DispatchError> { let r = Self::peek(bounded)?; Self::drop(bounded); Ok(r) @@ -230,11 +236,11 @@ pub trait StorePreimage: QueryPreimage { /// Request and attempt to store the bytes of a preimage on chain. /// /// May return `DispatchError::Exhausted` if the preimage is just too big. - fn note(bytes: Cow<[u8]>) -> Result; + fn note(bytes: Cow<[u8]>) -> Result<::Out, DispatchError>; /// Attempt to clear a previously noted preimage. Exactly the same as `unrequest` but is /// provided for symmetry. - fn unnote(hash: &Hash) { + fn unnote(hash: &::Out) { Self::unrequest(hash) } @@ -244,7 +250,7 @@ pub trait StorePreimage: QueryPreimage { /// /// NOTE: Once this API is used, you should use either `drop` or `realize`. /// The value is also noted using [`Self::note`]. - fn bound(t: T) -> Result, DispatchError> { + fn bound(t: T) -> Result, DispatchError> { let data = t.encode(); let len = data.len() as u32; Ok(match BoundedInline::try_from(data) { @@ -255,22 +261,24 @@ pub trait StorePreimage: QueryPreimage { } impl QueryPreimage for () { - fn len(_: &Hash) -> Option { + type H = sp_runtime::traits::BlakeTwo256; + + fn len(_: &sp_core::H256) -> Option { None } - fn fetch(_: &Hash, _: Option) -> FetchResult { + fn fetch(_: &sp_core::H256, _: Option) -> FetchResult { Err(DispatchError::Unavailable) } - fn is_requested(_: &Hash) -> bool { + fn is_requested(_: &sp_core::H256) -> bool { false } - fn request(_: &Hash) {} - fn unrequest(_: &Hash) {} + fn request(_: &sp_core::H256) {} + fn unrequest(_: &sp_core::H256) {} } impl StorePreimage for () { const MAX_LENGTH: usize = 0; - fn note(_: Cow<[u8]>) -> Result { + fn note(_: Cow<[u8]>) -> Result { Err(DispatchError::Exhausted) } } @@ -279,22 +287,22 @@ impl StorePreimage for () { mod tests { use super::*; use crate::BoundedVec; - use sp_runtime::bounded_vec; + use sp_runtime::{bounded_vec, traits::BlakeTwo256}; #[test] fn bounded_size_is_correct() { - assert_eq!(> as MaxEncodedLen>::max_encoded_len(), 131); + assert_eq!(, BlakeTwo256> as MaxEncodedLen>::max_encoded_len(), 131); } #[test] fn bounded_basic_works() { let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; let len = data.len() as u32; - let hash = blake2_256(&data).into(); + let hash = BlakeTwo256::hash(&data).into(); // Inline works { - let bound: Bounded> = Bounded::Inline(data.clone()); + let bound: Bounded, BlakeTwo256> = Bounded::Inline(data.clone()); assert_eq!(bound.hash(), hash); assert_eq!(bound.len(), Some(len)); assert!(!bound.lookup_needed()); @@ -302,7 +310,8 @@ mod tests { } // Legacy works { - let bound: Bounded> = Bounded::Legacy { hash, dummy: Default::default() }; + let bound: Bounded, BlakeTwo256> = + Bounded::Legacy { hash, dummy: Default::default() }; assert_eq!(bound.hash(), hash); assert_eq!(bound.len(), None); assert!(bound.lookup_needed()); @@ -310,7 +319,8 @@ mod tests { } // Lookup works { - let bound: Bounded> = Bounded::Lookup { hash, len: data.len() as u32 }; + let bound: Bounded, BlakeTwo256> = + Bounded::Lookup { hash, len: data.len() as u32 }; assert_eq!(bound.hash(), hash); assert_eq!(bound.len(), Some(len)); assert!(bound.lookup_needed()); @@ -323,8 +333,8 @@ mod tests { let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; // Transmute a `String` into a `&str`. - let x: Bounded = Bounded::Inline(data.clone()); - let y: Bounded<&str> = x.transmute(); + let x: Bounded = Bounded::Inline(data.clone()); + let y: Bounded<&str, BlakeTwo256> = x.transmute(); assert_eq!(y, Bounded::Inline(data)); } } diff --git a/substrate/frame/support/src/traits/schedule.rs b/substrate/frame/support/src/traits/schedule.rs index 74a5951142d522861b568e28023a791a493ac4e6..7a7d1357da1e7dba9588866d07d734f2a8fedda8 100644 --- a/substrate/frame/support/src/traits/schedule.rs +++ b/substrate/frame/support/src/traits/schedule.rs @@ -387,6 +387,8 @@ pub mod v3 { pub trait Anon { /// An address which can be used for removing a scheduled task. type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo; + /// The hasher used in the runtime. + type Hasher: sp_runtime::traits::Hash; /// Schedule a dispatch to happen at the beginning of some block in the future. /// @@ -396,7 +398,7 @@ pub mod v3 { maybe_periodic: Option>, priority: Priority, origin: Origin, - call: Bounded, + call: Bounded, ) -> Result; /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, @@ -434,6 +436,8 @@ pub mod v3 { pub trait Named { /// An address which can be used for removing a scheduled task. type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + /// The hasher used in the runtime. + type Hasher: sp_runtime::traits::Hash; /// Schedule a dispatch to happen at the beginning of some block in the future. /// @@ -446,7 +450,7 @@ pub mod v3 { maybe_periodic: Option>, priority: Priority, origin: Origin, - call: Bounded, + call: Bounded, ) -> Result; /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances diff --git a/substrate/frame/support/src/traits/storage.rs b/substrate/frame/support/src/traits/storage.rs index e0ce1c0fbd317fff284a01c43b3c25bca21ead76..fe1b9bf13bb0209be2f44d5017e2a1af8345b58d 100644 --- a/substrate/frame/support/src/traits/storage.rs +++ b/substrate/frame/support/src/traits/storage.rs @@ -61,8 +61,35 @@ pub trait StorageInstance { /// Prefix of a pallet to isolate it from other pallets. fn pallet_prefix() -> &'static str; + /// Return the prefix hash of pallet instance. + /// + /// NOTE: This hash must be `twox_128(pallet_prefix())`. + /// Should not impl this function by hand. Only use the default or macro generated impls. + fn pallet_prefix_hash() -> [u8; 16] { + sp_io::hashing::twox_128(Self::pallet_prefix().as_bytes()) + } + /// Prefix given to a storage to isolate from other storages in the pallet. const STORAGE_PREFIX: &'static str; + + /// Return the prefix hash of storage instance. + /// + /// NOTE: This hash must be `twox_128(STORAGE_PREFIX)`. + fn storage_prefix_hash() -> [u8; 16] { + sp_io::hashing::twox_128(Self::STORAGE_PREFIX.as_bytes()) + } + + /// Return the prefix hash of instance. + /// + /// NOTE: This hash must be `twox_128(pallet_prefix())++twox_128(STORAGE_PREFIX)`. + /// Should not impl this function by hand. Only use the default or macro generated impls. + fn prefix_hash() -> [u8; 32] { + let mut final_key = [0u8; 32]; + final_key[..16].copy_from_slice(&Self::pallet_prefix_hash()); + final_key[16..].copy_from_slice(&Self::storage_prefix_hash()); + + final_key + } } /// Metadata about storage from the runtime. diff --git a/substrate/frame/support/src/traits/tokens.rs b/substrate/frame/support/src/traits/tokens.rs index 253b49c6671f80fe0e05792b9095dcb3ab22032d..3635311e64357bbd2e7041d653a4268dfb65a182 100644 --- a/substrate/frame/support/src/traits/tokens.rs +++ b/substrate/frame/support/src/traits/tokens.rs @@ -31,6 +31,7 @@ pub mod pay; pub use misc::{ AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance, ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision, - Preservation, Provenance, Restriction, WithdrawConsequence, WithdrawReasons, + Preservation, Provenance, Restriction, UnityAssetBalanceConversion, WithdrawConsequence, + WithdrawReasons, }; pub use pay::{Pay, PayFromAccount, PaymentStatus}; diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index de85924a4de7c75ca0c18c262ebfb28ee6605a0f..995797bc8f66b10861a68831984302057ecfbe34 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -23,7 +23,8 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::Balance, }; -use sp_runtime::{traits::Zero, RuntimeDebug}; +use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; /// Handler for when an imbalance gets dropped. This could handle either a credit (negative) or @@ -43,7 +44,7 @@ impl HandleImbalanceDrop for () { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(RuntimeDebug, Eq, PartialEq)] +#[derive(EqNoBound, PartialEqNoBound, RuntimeDebugNoBound)] pub struct Imbalance< B: Balance, OnDrop: HandleImbalanceDrop, @@ -112,6 +113,13 @@ impl, OppositeOnDrop: HandleImbalance sp_std::mem::forget(self); (Imbalance::new(first), Imbalance::new(second)) } + + fn extract(&mut self, amount: B) -> Self { + let new = self.amount.min(amount); + self.amount = self.amount - new; + Imbalance::new(new) + } + fn merge(mut self, other: Self) -> Self { self.amount = self.amount.saturating_add(other.amount); sp_std::mem::forget(other); 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 88b9de7fdbf6461e3c89029a4d6d20734d95f9e9..a47998eb134e931e69f5131af5de79d26df4d3f5 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -354,7 +354,7 @@ impl< Balance, AssetIdType, AssetId: Get, - Handler: crate::traits::tokens::fungibles::HandleImbalanceDrop, + Handler: crate::traits::fungibles::HandleImbalanceDrop, > HandleImbalanceDrop for ConvertImbalanceDropHandler { diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 1668268ea2dcf232a4aaf3f6a7b4df3b67060542..7c0d7721a2e60908f1a5a4be8a8c876ff2bd1ae2 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -23,7 +23,8 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::{AssetId, Balance}, }; -use sp_runtime::{traits::Zero, RuntimeDebug}; +use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; /// Handler for when an imbalance gets dropped. This could handle either a credit (negative) or @@ -38,7 +39,7 @@ pub trait HandleImbalanceDrop { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(RuntimeDebug, Eq, PartialEq)] +#[derive(EqNoBound, PartialEqNoBound, RuntimeDebugNoBound)] pub struct Imbalance< A: AssetId, B: Balance, @@ -108,6 +109,15 @@ impl< sp_std::mem::forget(self); (Imbalance::new(asset.clone(), first), Imbalance::new(asset, second)) } + + /// Mutate `self` by extracting a new instance with at most `amount` value, reducing `self` + /// accordingly. + pub fn extract(&mut self, amount: B) -> Self { + let new = self.amount.min(amount); + self.amount = self.amount - new; + Imbalance::new(self.asset.clone(), new) + } + pub fn merge(mut self, other: Self) -> Result { if self.asset == other.asset { self.amount = self.amount.saturating_add(other.amount); diff --git a/substrate/frame/support/src/traits/tokens/imbalance.rs b/substrate/frame/support/src/traits/tokens/imbalance.rs index 403321725042c6899c16d90f1ba1652965a336cb..e487b8122341062ff0e4e8ed0bbf2ca23c8edbe2 100644 --- a/substrate/frame/support/src/traits/tokens/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/imbalance.rs @@ -72,6 +72,10 @@ pub trait Imbalance: Sized + TryDrop + Default { /// is guaranteed to be at most `amount` and the second will be the remainder. fn split(self, amount: Balance) -> (Self, Self); + /// Mutate `self` by extracting a new instance with at most `amount` value, reducing `self` + /// accordingly. + fn extract(&mut self, amount: Balance) -> Self; + /// Consume `self` and return two independent instances; the amounts returned will be in /// approximately the same ratio as `first`:`second`. /// @@ -190,6 +194,9 @@ impl Imbalance for () { fn split(self, _: Balance) -> (Self, Self) { ((), ()) } + fn extract(&mut self, _: Balance) -> Self { + () + } fn ration(self, _: u32, _: u32) -> (Self, Self) where Balance: From + Saturating + Div, diff --git a/substrate/frame/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index 84bbe3e8d9c838fac2d0ec81e9a283955166bfd3..fd497bc4eda6f0b66127b4fc87edacd9be76d56f 100644 --- a/substrate/frame/support/src/traits/tokens/misc.rs +++ b/substrate/frame/support/src/traits/tokens/misc.rs @@ -20,7 +20,10 @@ use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; use sp_core::RuntimeDebug; -use sp_runtime::{traits::Convert, ArithmeticError, DispatchError, TokenError}; +use sp_runtime::{ + traits::{Convert, MaybeSerializeDeserialize}, + ArithmeticError, DispatchError, TokenError, +}; use sp_std::fmt::Debug; /// The origin of funds to be used for a deposit operation. @@ -240,6 +243,7 @@ pub trait Balance: + MaxEncodedLen + Send + Sync + + MaybeSerializeDeserialize + 'static { } @@ -253,6 +257,7 @@ impl< + MaxEncodedLen + Send + Sync + + MaybeSerializeDeserialize + 'static, > Balance for T { @@ -272,6 +277,26 @@ pub trait ConversionFromAssetBalance { balance: AssetBalance, asset_id: AssetId, ) -> Result; + /// Ensures that a conversion for the `asset_id` will be successful if done immediately after + /// this call. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(asset_id: AssetId); +} + +/// Implements [`ConversionFromAssetBalance`], enabling a 1:1 conversion of the asset balance +/// value to the balance. +pub struct UnityAssetBalanceConversion; +impl + ConversionFromAssetBalance for UnityAssetBalanceConversion +where + AssetBalance: Into, +{ + type Error = (); + fn from_asset_balance(balance: AssetBalance, _: AssetId) -> Result { + Ok(balance.into()) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: AssetId) {} } /// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented diff --git a/substrate/frame/support/src/traits/tokens/pay.rs b/substrate/frame/support/src/traits/tokens/pay.rs index 78f8e7b8734803ac163a8ed767d4daf4d1a93e10..18af7e5e54838020092a2fee52fe1a78a644858a 100644 --- a/substrate/frame/support/src/traits/tokens/pay.rs +++ b/substrate/frame/support/src/traits/tokens/pay.rs @@ -23,7 +23,7 @@ use sp_core::{RuntimeDebug, TypedGet}; use sp_runtime::DispatchError; use sp_std::fmt::Debug; -use super::{fungible, Balance, Preservation::Expendable}; +use super::{fungible, fungibles, Balance, Preservation::Expendable}; /// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with /// XCM/MultiAsset and made generic over assets. @@ -107,3 +107,36 @@ impl> Pay for PayFromAccount { #[cfg(feature = "runtime-benchmarks")] fn ensure_concluded(_: Self::Id) {} } + +/// Simple implementation of `Pay` for assets which makes a payment from a "pot" - i.e. a single +/// account. +pub struct PayAssetFromAccount(sp_std::marker::PhantomData<(F, A)>); +impl frame_support::traits::tokens::Pay for PayAssetFromAccount +where + A: TypedGet, + F: fungibles::Mutate + fungibles::Create, +{ + type Balance = F::Balance; + type Beneficiary = A::Type; + type AssetKind = F::AssetId; + type Id = (); + type Error = DispatchError; + fn pay( + who: &Self::Beneficiary, + asset: Self::AssetKind, + amount: Self::Balance, + ) -> Result { + >::transfer(asset, &A::get(), who, amount, Expendable)?; + Ok(()) + } + fn check_payment(_: ()) -> PaymentStatus { + PaymentStatus::Success + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &Self::Beneficiary, asset: Self::AssetKind, amount: Self::Balance) { + >::create(asset.clone(), A::get(), true, amount).unwrap(); + >::mint_into(asset, &A::get(), amount).unwrap(); + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(_: Self::Id) {} +} diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 9c165cd03e86664cfe5be8af608bd071db26c817..167aec8a171c7773b0d4a3b10af98ff1773241d9 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } renamed-frame-support = { package = "frame-support", path = "../..", default-features = false} -frame-system = { path = "../../../system", default-features = false} +renamed-frame-system = { package = "frame-system", path = "../../../system", default-features = false} sp-core = { path = "../../../../primitives/core", default-features = false} sp-runtime = { path = "../../../../primitives/runtime", default-features = false} sp-version = { path = "../../../../primitives/version", default-features = false} @@ -24,8 +24,8 @@ sp-version = { path = "../../../../primitives/version", default-features = false default = [ "std" ] std = [ "codec/std", - "frame-system/std", "renamed-frame-support/std", + "renamed-frame-system/std", "scale-info/std", "sp-core/std", "sp-runtime/std", diff --git a/substrate/frame/support/test/compile_pass/src/lib.rs b/substrate/frame/support/test/compile_pass/src/lib.rs index bf90d73acb320a439963ec25d8379982e1338127..6ea37fb27e72f31fe0e88e1f35815675bc33660e 100644 --- a/substrate/frame/support/test/compile_pass/src/lib.rs +++ b/substrate/frame/support/test/compile_pass/src/lib.rs @@ -16,7 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Test that `construct_runtime!` also works when `frame-support` is renamed in the `Cargo.toml`. +//! Test that `construct_runtime!` also works when `frame-support` or `frame-system` are renamed in +//! the `Cargo.toml`. #![cfg_attr(not(feature = "std"), no_std)] @@ -50,7 +51,7 @@ parameter_types! { pub const Version: RuntimeVersion = VERSION; } -impl frame_system::Config for Runtime { +impl renamed_frame_system::Config for Runtime { type BaseCallFilter = Everything; type BlockWeights = (); type BlockLength = (); @@ -82,6 +83,6 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic(_); + + #[pallet::config] + // The only valid syntax here is the following or + // ``` + // pub trait Config: frame::deps::frame_system::Config {} + // ``` + pub trait Config: frame_system::Config {} + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + _config: core::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } +} + +#[cfg(test)] +// Dummy test to make sure a runtime would compile. +mod tests { + use super::{ + frame_support::{construct_runtime, derive_impl}, + frame_system, pallet, + }; + + type Block = frame_system::mocking::MockBlock; + + impl crate::pallet::Config for Runtime {} + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = Block; + } + + construct_runtime! { + pub struct Runtime + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet::{Pallet, Config}, + } + } +} diff --git a/substrate/frame/support/test/tests/construct_runtime_ui.rs b/substrate/frame/support/test/tests/construct_runtime_ui.rs index c3197c99a72bf94bbe134b89d24fced5063c15c4..0cf857e2d73c025392c96e02c3d7439690ea8c88 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui.rs @@ -32,4 +32,5 @@ fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/construct_runtime_ui/*.rs"); + t.pass("tests/construct_runtime_ui/pass/*.rs"); } 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 cc2c2e160095dc83ff5ecd13eb4983967fdbc72a..08954bb6ab5c57982b99432ca1ea888d2e70332c 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 @@ -148,7 +148,11 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_syste | ||_- in this macro invocation ... | | - = note: required because it appears within the type `Event` +note: required because it appears within the type `Event` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub enum Event { + | ^^^^^ note: required by a bound in `From` --> $RUST/core/src/convert/mod.rs | @@ -169,7 +173,11 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_syste | ||_- in this macro invocation ... | | - = note: required because it appears within the type `Event` +note: required because it appears within the type `Event` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub enum Event { + | ^^^^^ note: required by a bound in `TryInto` --> $RUST/core/src/convert/mod.rs | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/pass/composite_enum_instance.rs b/substrate/frame/support/test/tests/construct_runtime_ui/pass/composite_enum_instance.rs new file mode 100644 index 0000000000000000000000000000000000000000..ad63708747694ae5935f91efa99ae28752255e40 --- /dev/null +++ b/substrate/frame/support/test/tests/construct_runtime_ui/pass/composite_enum_instance.rs @@ -0,0 +1,80 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::derive_impl; + +pub use pallet::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::pallet_prelude::*; + + // The struct on which we build all of our Pallet logic. + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + // Your Pallet's configuration trait, representing custom external types and interfaces. + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::composite_enum] + pub enum HoldReason { + SomeHoldReason + } + + #[pallet::composite_enum] + pub enum FreezeReason { + SomeFreezeReason + } + + #[pallet::composite_enum] + pub enum SlashReason { + SomeSlashReason + } + + #[pallet::composite_enum] + pub enum LockId { + SomeLockId + } +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +pub type Header = sp_runtime::generic::Header; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type Block = sp_runtime::generic::Block; + +frame_support::construct_runtime!( + pub struct Runtime + { + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system, + Pallet1: pallet, + Pallet2: pallet::, + } +); + +impl pallet::Config for Runtime {} + +impl pallet::Config for Runtime {} + +fn main() {} diff --git a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr index 5cfbd8c88624971b205c587d70106e3e398581e4..c91226ea9c31074ca5141a121a31e4d1fe1f506d 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr @@ -1,7 +1,5 @@ -error: cannot find macro `__export_tokens_tt_tiger` in this scope - --> tests/derive_impl_ui/bad_default_impl_path.rs:59:1 +error: cannot find macro `Tiger` in this scope + --> tests/derive_impl_ui/bad_default_impl_path.rs:59:15 | 59 | #[derive_impl(Tiger as Animal)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^ diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr index 79b50a940b80246451e22096293ec723a75e19a7..f3ac6b2328110f0e2c6e95c7c6f995b3dea2d1dc 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr @@ -7,4 +7,4 @@ error[E0412]: cannot find type `RuntimeCall` in this scope 35 | #[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall; | ---------------------- in this macro invocation | - = note: this error originates in the macro `__export_tokens_tt_pallet` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `Pallet` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens_verbatim` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/debug.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/debug.stderr index d86292d71b7a1d77a27322bed069cc077f5ba101..3291f658f10e1fce9877acc69f02aa67a1c974f9 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/debug.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/debug.stderr @@ -5,4 +5,4 @@ error[E0277]: `::C` doesn't implement `std::fmt::Debug` | ^ `::C` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::C` - = note: required for the cast from `::C` to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::C` to `&dyn std::fmt::Debug` diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 1898246470c73fee4bd046d737d90580015989b1..83ae5b9253cec41fcd661ced8cd2097465c89527 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -210,12 +210,13 @@ pub mod pallet { { /// Doc comment put in metadata #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(*_foo as u64, 0))] + #[pallet::weight(Weight::from_parts(*foo as u64, 0))] pub fn foo( origin: OriginFor, - #[pallet::compact] _foo: u32, + #[pallet::compact] foo: u32, _bar: u32, ) -> DispatchResultWithPostInfo { + let _ = foo; let _ = T::AccountId::from(SomeType1); // Test for where clause let _ = T::AccountId::from(SomeType3); // Test for where clause let _ = origin; diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index 8d2d52d18852afe5eb2f5b9de059cd7d2ea25b4f..724734ec4fc9dbe7eab0c6e26fc221f165a0e8c9 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -87,12 +87,13 @@ pub mod pallet { impl, I: 'static> Pallet { /// Doc comment put in metadata #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(*_foo as u64, 0))] + #[pallet::weight(Weight::from_parts(*foo as u64, 0))] pub fn foo( origin: OriginFor, - #[pallet::compact] _foo: u32, + #[pallet::compact] foo: u32, ) -> DispatchResultWithPostInfo { let _ = origin; + let _ = foo; Self::deposit_event(Event::Something(3)); Ok(().into()) } diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index c86930f8a64e3a287a45ac15ae127982dc184d10..08ea7c0bec3a5dfca33ff497b2981e9acb17f294 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 @@ -19,7 +19,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required for `&::Bar` to implement `std::fmt::Debug` - = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&&::Bar` to `&dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound.rs:38:36 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 1b04f44c78febbf7232b26dedfd35021ea6e1981..80316fcd2489747ca34a9b030474c453e7f3d08d 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 @@ -19,7 +19,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required for `&::Bar` to implement `std::fmt::Debug` - = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&&::Bar` to `&dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 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 7429bce050c28bd0d2e9f372ed1c773646ae1acf..d45b74bad8428d57273e0cb4f0d304706dca9fd1 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 @@ -20,7 +20,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = help: the trait `std::fmt::Debug` is not implemented for `Bar` = 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 the object type `dyn std::fmt::Debug` + = note: required for the cast from `&&Bar` to `&dyn std::fmt::Debug` help: consider annotating `Bar` with `#[derive(Debug)]` | 34 + #[derive(Debug)] diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.rs b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d93638f5a51e491a51f509dc602f5c41eefbf9f --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(*_unused)] + pub fn foo(_: OriginFor, _unused: u64) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr new file mode 100644 index 0000000000000000000000000000000000000000..89fc1e0820f5ea0969b05b00efee7ca70c95e593 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr @@ -0,0 +1,12 @@ +error: use of deprecated constant `pallet::warnings::UncheckedWeightWitness_0::_w`: + It is deprecated to not check weight witness data. + Please instead ensure that all witness data for weight calculation is checked before usage. + + For more info see: + + --> tests/pallet_ui/call_weight_unchecked_warning.rs:33:31 + | +33 | pub fn foo(_: OriginFor, _unused: u64) -> DispatchResult { Ok(()) } + | ^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` 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 74ee0e4aeba5cc359174c8aa017d77c6a26a0e29..531e8bdffeb0c0f073e1775cdc0f683beb3d198d 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 @@ -30,13 +30,13 @@ error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Vec` | = help: the following other types implement trait `MaxEncodedLen`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + bool + i8 + i16 + i32 + i64 + i128 + u8 + u16 and $N others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` to implement `StorageInfoTrait` diff --git a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr index cfa0d465990a242f2c2ca2f65377b50d9e5c20bd..ea1d0ed99cd39747bfc1f94a9e3433809baa82b5 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -5,13 +5,13 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` | = help: the following other types implement trait `PalletError`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + bool + i8 + i16 + i32 + i64 + i128 + u8 + u16 and $N others = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) 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 4df6deafa0df667a4299f348eb90c12ae860ae06..fc4a33b721500a09ef03f36836f7ebea832a2547 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 @@ -18,4 +18,4 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required for `&::Bar` to implement `std::fmt::Debug` - = note: required for the cast from `&::Bar` to the object type `dyn 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/event_type_invalid_bound.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs index 665d2a984cf04801ef4c3c3712e053a075c1ae07..34b563ffb6433b6a156e5ace4abecd08b560ce49 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs @@ -41,5 +41,4 @@ mod pallet { } } -fn main() { -} +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr b/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr index e3dd0b7aa1d3434f873240154758bf73a59adf25..b54a23c91b4ee966cea5b0509de24ada95f41b1a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/genesis_invalid_generic.stderr @@ -1,4 +1,4 @@ -error: Invalid genesis builder: expected `GenesisBuild` or `GenesisBuild` +error: Invalid genesis builder: expected `BuildGenesisConfig` (or the deprecated `GenesisBuild` or `GenesisBuild`) --> tests/pallet_ui/genesis_invalid_generic.rs:36:7 | 36 | impl GenesisBuild for GenesisConfig {} diff --git a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr index 3a26d1c0495418658df96cd902f263155cc4fd45..5ea3be470a068b1468beb754b6b4caeca25d93e4 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr @@ -4,8 +4,8 @@ error[E0046]: not all trait items implemented, missing: `Call`, `Error`, `INHERE 36 | impl ProvideInherent for Pallet {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`, `is_inherent` in implementation | - = help: implement the missing item: `type Call = Type;` - = help: implement the missing item: `type Error = Type;` + = help: implement the missing item: `type Call = /* Type */;` + = help: implement the missing item: `type Error = /* Type */;` = help: implement the missing item: `const INHERENT_IDENTIFIER: [u8; 8] = value;` = help: implement the missing item: `fn create_inherent(_: &InherentData) -> std::option::Option<::Call> { todo!() }` = help: implement the missing item: `fn is_inherent(_: &::Call) -> bool { todo!() }` diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/event_type_bound_system_config_assoc_type.rs b/substrate/frame/support/test/tests/pallet_ui/pass/event_type_bound_system_config_assoc_type.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a70c4a5e68a8f67fa17f09fda2d11eb6e557efc --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/event_type_bound_system_config_assoc_type.rs @@ -0,0 +1,44 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::{Hooks, IsType}; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config { + type Bar: Clone + std::fmt::Debug + Eq; + type RuntimeEvent: IsType<::RuntimeEvent> + From>; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} + + #[pallet::event] + pub enum Event { + B { b: T::Bar }, + } +} + +fn main() {} 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 e290b22a0eaa59b02cf2af5487444cde5924c3b5..930af1d7fcb30af6f9dd4fa158fe760bea78082e 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 @@ -5,10 +5,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc + Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -20,14 +20,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: - <&&T as EncodeLike> - <&T as EncodeLike> - <&T as EncodeLike> - <&[(K, V)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[T] as EncodeLike>> + + + + + + + + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -40,14 +40,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box + bytes::bytes::Bytes Cow<'a, T> + parity_scale_codec::Ref<'a, T, U> + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + Arc Vec - bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -61,14 +61,14 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: - &T - &mut T - () - (A, B) - (A, B, C) - (A, B, C, D) - (A, B, C, D, E) - (A, B, C, D, E, F) + bool + char + i8 + i16 + i32 + i64 + i128 + u8 and $N others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -80,10 +80,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc + Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -95,14 +95,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: - <&&T as EncodeLike> - <&T as EncodeLike> - <&T as EncodeLike> - <&[(K, V)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[T] as EncodeLike>> + + + + + + + + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -115,14 +115,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box + bytes::bytes::Bytes Cow<'a, T> + parity_scale_codec::Ref<'a, T, U> + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + Arc Vec - bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 0e3a7c9f1cbfa0f7ac626eef998824a85b0673bc..79798963c8b1a5f4d44a18e6aeba93156641458d 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 @@ -5,10 +5,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc + Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -20,14 +20,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: - <&&T as EncodeLike> - <&T as EncodeLike> - <&T as EncodeLike> - <&[(K, V)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[T] as EncodeLike>> + + + + + + + + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -40,14 +40,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box + bytes::bytes::Bytes Cow<'a, T> + parity_scale_codec::Ref<'a, T, U> + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + Arc Vec - bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -61,14 +61,14 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: - &T - &mut T - () - (A, B) - (A, B, C) - (A, B, C, D) - (A, B, C, D, E) - (A, B, C, D, E, F) + bool + char + i8 + i16 + i32 + i64 + i128 + u8 and $N others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -80,10 +80,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc + Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -95,14 +95,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: - <&&T as EncodeLike> - <&T as EncodeLike> - <&T as EncodeLike> - <&[(K, V)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[(T,)] as EncodeLike>> - <&[T] as EncodeLike>> + + + + + + + + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -115,14 +115,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box + bytes::bytes::Bytes Cow<'a, T> + parity_scale_codec::Ref<'a, T, U> + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc + Arc Vec - bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 9a31e4b6bdf46eb0470e7fd90ed329a95b27ec58..e04de98800ec20fc449666f671bcd91058fb3335 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 @@ -5,13 +5,13 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = help: the following other types implement trait `MaxEncodedLen`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + bool + i8 + i16 + i32 + i64 + i128 + u8 + u16 and $N others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageInfoTrait` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index cdcd1b401f8010e3b619903fc5d11cd16fd5020e..31fe3b57338968822c8f49837c5176aa859be2cf 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 @@ -5,14 +5,14 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | = help: the following other types implement trait `MaxEncodedLen`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + bool + i8 + i16 + i32 + i64 + i128 + u8 + u16 and $N others - = note: required for `Key` to implement `KeyGeneratorMaxEncodedLen` - = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` to implement `StorageInfoTrait` + = note: required for `NMapKey` to implement `KeyGeneratorMaxEncodedLen` + = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` to implement `StorageInfoTrait` diff --git a/substrate/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index 2939fd6534c09c7e5b59816b821d781966273e81..7504a814aef13b0230e1067c0d95e0104ad74275 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -20,7 +20,7 @@ use codec::{Decode, Encode}; use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, One, SignedExtension}, + traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero}, transaction_validity::{ InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -80,6 +80,10 @@ where _len: usize, ) -> Result<(), TransactionValidityError> { let mut account = crate::Account::::get(who); + if account.providers.is_zero() && account.sufficients.is_zero() { + // Nonce storage not paid for + return Err(InvalidTransaction::Payment.into()) + } if self.0 != account.nonce { return Err(if self.0 < account.nonce { InvalidTransaction::Stale @@ -100,8 +104,11 @@ where _info: &DispatchInfoOf, _len: usize, ) -> TransactionValidity { - // check index let account = crate::Account::::get(who); + if account.providers.is_zero() && account.sufficients.is_zero() { + // Nonce storage not paid for + return InvalidTransaction::Payment.into() + } if self.0 < account.nonce { return InvalidTransaction::Stale.into() } @@ -137,7 +144,7 @@ mod tests { crate::AccountInfo { nonce: 1, consumers: 0, - providers: 0, + providers: 1, sufficients: 0, data: 0, }, @@ -164,4 +171,47 @@ mod tests { ); }) } + + #[test] + fn signed_ext_check_nonce_requires_provider() { + new_test_ext().execute_with(|| { + crate::Account::::insert( + 2, + crate::AccountInfo { + nonce: 1, + consumers: 0, + providers: 1, + sufficients: 0, + data: 0, + }, + ); + crate::Account::::insert( + 3, + crate::AccountInfo { + nonce: 1, + consumers: 0, + providers: 0, + sufficients: 1, + data: 0, + }, + ); + let info = DispatchInfo::default(); + let len = 0_usize; + // Both providers and sufficients zero + assert_noop!( + CheckNonce::(1).validate(&1, CALL, &info, len), + InvalidTransaction::Payment + ); + assert_noop!( + CheckNonce::(1).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)); + // Non-zero sufficients + assert_ok!(CheckNonce::(1).validate(&3, CALL, &info, len)); + assert_ok!(CheckNonce::(1).pre_dispatch(&3, CALL, &info, len)); + }) + } } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 84b6dc031457db67ebd9eba43b83571fb70220bf..897d3bd7ce91f6796aebccc4429e0538668cb297 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -420,8 +420,9 @@ pub mod pallet { /// /// Can be executed by every `origin`. #[pallet::call_index(0)] - #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] - pub fn remark(_origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { + #[pallet::weight(T::SystemWeightInfo::remark(remark.len() as u32))] + pub fn remark(_origin: OriginFor, remark: Vec) -> DispatchResultWithPostInfo { + let _ = remark; // No need to check the weight witness. Ok(().into()) } @@ -495,16 +496,16 @@ pub mod pallet { /// the prefix we are removing to accurately calculate the weight of this function. #[pallet::call_index(6)] #[pallet::weight(( - T::SystemWeightInfo::kill_prefix(_subkeys.saturating_add(1)), + T::SystemWeightInfo::kill_prefix(subkeys.saturating_add(1)), DispatchClass::Operational, ))] pub fn kill_prefix( origin: OriginFor, prefix: Key, - _subkeys: u32, + subkeys: u32, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - let _ = storage::unhashed::clear_prefix(&prefix, None, None); + let _ = storage::unhashed::clear_prefix(&prefix, Some(subkeys), None); Ok(().into()) } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 6759d90aaf4192ba8fab8cd4df8b9c7023cb9a13..291f6b1cf590ac0bdb751b8d5af9b6c0e22ab0e3 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -27,7 +27,7 @@ sp-std = { path = "../../primitives/std", default-features = false} sp-storage = { path = "../../primitives/storage", default-features = false} sp-timestamp = { path = "../../primitives/timestamp", default-features = false} -docify = "0.2.1" +docify = "0.2.4" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/timestamp/README.md b/substrate/frame/timestamp/README.md index 69dba60550e4b83df0719a274a31dd3be2efe6b3..55c8343187b61e391f867b55320b37b147bd4b8f 100644 --- a/substrate/frame/timestamp/README.md +++ b/substrate/frame/timestamp/README.md @@ -73,7 +73,7 @@ pub mod pallet { ### Example from the FRAME -The [Session module](https://github.com/paritytech/substrate/blob/master/frame/session/src/lib.rs) uses +The [Session module](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/session/src/lib.rs) uses the Timestamp module for session management. ## Related Modules diff --git a/substrate/frame/tips/src/lib.rs b/substrate/frame/tips/src/lib.rs index 6e8f72e0540e63bd88560fc13b778d34be740e2e..8764486d5f4fde2aafb20fa7daf919f1f1349a18 100644 --- a/substrate/frame/tips/src/lib.rs +++ b/substrate/frame/tips/src/lib.rs @@ -154,6 +154,10 @@ pub mod pallet { #[pallet::constant] type TipReportDepositBase: Get>; + /// The maximum amount for a single tip. + #[pallet::constant] + type MaxTipAmount: Get>; + /// Origin from which tippers must come. /// /// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy @@ -208,6 +212,8 @@ pub mod pallet { AlreadyKnown, /// The tip hash is unknown. UnknownTip, + /// The tip given was too generous. + MaxTipAmountExceeded, /// The account attempting to retract the tip is not the finder of the tip. NotFinder, /// The tip cannot be claimed/closed because there are not enough tippers yet. @@ -336,10 +342,13 @@ pub mod pallet { let tipper = ensure_signed(origin)?; let who = T::Lookup::lookup(who)?; ensure!(T::Tippers::contains(&tipper), BadOrigin); + + ensure!(T::MaxTipAmount::get() >= tip_value, Error::::MaxTipAmountExceeded); + let reason_hash = T::Hashing::hash(&reason[..]); ensure!(!Reasons::::contains_key(&reason_hash), Error::::AlreadyKnown); - let hash = T::Hashing::hash_of(&(&reason_hash, &who)); + let hash = T::Hashing::hash_of(&(&reason_hash, &who)); Reasons::::insert(&reason_hash, &reason); Self::deposit_event(Event::NewTip { tip_hash: hash }); let tips = vec![(tipper.clone(), tip_value)]; @@ -387,7 +396,10 @@ pub mod pallet { let tipper = ensure_signed(origin)?; ensure!(T::Tippers::contains(&tipper), BadOrigin); + ensure!(T::MaxTipAmount::get() >= tip_value, Error::::MaxTipAmountExceeded); + let mut tip = Tips::::get(hash).ok_or(Error::::UnknownTip)?; + if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) { Self::deposit_event(Event::TipClosing { tip_hash: hash }); } diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index a700892d42703f3560d1b6cabc1e1e7641cb1ddc..8fe111afc26a41386da1005924648606b34fa61f 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -29,7 +29,10 @@ use sp_storage::Storage; use frame_support::{ assert_noop, assert_ok, parameter_types, storage::StoragePrefixedMap, - traits::{ConstU32, ConstU64, SortedMembers, StorageVersion}, + traits::{ + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstU32, ConstU64, SortedMembers, StorageVersion, + }, PalletId, }; @@ -123,7 +126,10 @@ parameter_types! { pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2"); + pub TreasuryAccount: u128 = Treasury::account_id(); + pub TreasuryInstance1Account: u128 = Treasury1::account_id(); } + impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; type Currency = pallet_balances::Pallet; @@ -141,6 +147,14 @@ impl pallet_treasury::Config for Test { type SpendFunds = (); type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<10>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_treasury::Config for Test { @@ -160,6 +174,14 @@ impl pallet_treasury::Config for Test { type SpendFunds = (); type MaxApprovals = ConstU32<100>; type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type AssetKind = (); + type Beneficiary = Self::AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU64<10>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { @@ -172,6 +194,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; + type MaxTipAmount = ConstU64<10_000_000>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -183,6 +206,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; + type MaxTipAmount = ConstU64<10_000_000>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -396,6 +420,23 @@ fn tip_median_calculation_works() { }); } +#[test] +fn tip_large_should_fail() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&Treasury::account_id(), 101); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 0)); + let h = tip_hash(); + assert_noop!( + Tips::tip( + RuntimeOrigin::signed(12), + h, + <::MaxTipAmount as Get>::get() + 1 + ), + Error::::MaxTipAmountExceeded + ); + }); +} + #[test] fn tip_changing_works() { new_test_ext().execute_with(|| { @@ -470,7 +511,7 @@ fn test_last_reward_migration() { s.top = data.into_iter().collect(); sp_io::TestExternalities::new(s).execute_with(|| { - let module = pallet_tips::Tips::::module_prefix(); + let module = pallet_tips::Tips::::pallet_prefix(); let item = pallet_tips::Tips::::storage_prefix(); Tips::migrate_retract_tip_for_tip_new(module, item); diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs index c2d9ed56c7aa38867cbd988eb1fe1a486233d420..04a71e2ff4260bacade4d93420646b21b946a2c2 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs @@ -48,7 +48,7 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, traits::{ - tokens::fungibles::{Balanced, Inspect}, + fungibles::{Balanced, Inspect}, IsType, }, DefaultNoBound, diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 785564cd9888d19fce3834189a55a60107715838..f7f7a6ae89c560cf3c1c89b8255b02b0e09f3196 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } +docify = "0.2.0" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.188", features = ["derive"], optional = true } @@ -26,11 +27,12 @@ frame-system = { path = "../system", default-features = false} pallet-balances = { path = "../balances", default-features = false} sp-runtime = { path = "../../primitives/runtime", default-features = false} sp-std = { path = "../../primitives/std", default-features = false} +sp-core = { path = "../../primitives/core", default-features = false, optional = true} [dev-dependencies] -sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } pallet-utility = { path = "../utility" } +sp-core = { path = "../../primitives/core", default-features = false } [features] default = [ "std" ] @@ -43,12 +45,13 @@ std = [ "pallet-utility/std", "scale-info/std", "serde", - "sp-core/std", + "sp-core?/std", "sp-io/std", "sp-runtime/std", "sp-std/std", ] runtime-benchmarks = [ + "dep:sp-core", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 24c290ddb665e582800fdacf7838cb67dbb821f5..61fe29dafcae53b9b572243ca6b28da1c5a46bf0 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -21,12 +21,41 @@ use super::{Pallet as Treasury, *}; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; +use frame_benchmarking::{ + v1::{account, BenchmarkError}, + v2::*, +}; use frame_support::{ ensure, - traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable}, + traits::{ + tokens::{ConversionFromAssetBalance, PaymentStatus}, + EnsureOrigin, OnInitialize, + }, }; use frame_system::RawOrigin; +use sp_core::crypto::FromEntropy; + +/// Trait describing factory functions for dispatchables' parameters. +pub trait ArgumentsFactory { + /// Factory function for an asset kind. + fn create_asset_kind(seed: u32) -> AssetKind; + /// Factory function for a beneficiary. + fn create_beneficiary(seed: [u8; 32]) -> Beneficiary; +} + +/// Implementation that expects the parameters implement the [`FromEntropy`] trait. +impl ArgumentsFactory for () +where + AssetKind: FromEntropy, + Beneficiary: FromEntropy, +{ + fn create_asset_kind(seed: u32) -> AssetKind { + AssetKind::from_entropy(&mut seed.encode().as_slice()).unwrap() + } + fn create_beneficiary(seed: [u8; 32]) -> Beneficiary { + Beneficiary::from_entropy(&mut seed.as_slice()).unwrap() + } +} const SEED: u32 = 0; @@ -66,82 +95,250 @@ fn assert_last_event, I: 'static>(generic_event: >:: frame_system::Pallet::::assert_last_event(generic_event.into()); } -benchmarks_instance_pallet! { +// Create the arguments for the `spend` dispatchable. +fn create_spend_arguments, I: 'static>( + seed: u32, +) -> (T::AssetKind, AssetBalanceOf, T::Beneficiary, BeneficiaryLookupOf) { + let asset_kind = T::BenchmarkHelper::create_asset_kind(seed); + let beneficiary = T::BenchmarkHelper::create_beneficiary([seed.try_into().unwrap(); 32]); + let beneficiary_lookup = T::BeneficiaryLookup::unlookup(beneficiary.clone()); + (asset_kind, 100u32.into(), beneficiary, beneficiary_lookup) +} + +#[instance_benchmarks] +mod benchmarks { + use super::*; + // This benchmark is short-circuited if `SpendOrigin` cannot provide // a successful origin, in which case `spend` is un-callable and can use weight=0. - spend { + #[benchmark] + fn spend_local() -> Result<(), BenchmarkError> { let (_, value, beneficiary_lookup) = setup_proposal::(SEED); - let origin = T::SpendOrigin::try_successful_origin(); + let origin = + T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap(); - let call = Call::::spend { amount: value, beneficiary: beneficiary_lookup }; - }: { - if let Ok(origin) = origin.clone() { - call.dispatch_bypass_filter(origin)?; - } - } - verify { - if origin.is_ok() { - assert_last_event::(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into()) - } + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, value, beneficiary_lookup); + + assert_last_event::( + Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into(), + ); + Ok(()) } - propose_spend { + #[benchmark] + fn propose_spend() -> Result<(), BenchmarkError> { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), value, beneficiary_lookup) - reject_proposal { + #[extrinsic_call] + _(RawOrigin::Signed(caller), value, beneficiary_lookup); + + Ok(()) + } + + #[benchmark] + fn reject_proposal() -> Result<(), BenchmarkError> { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, - beneficiary_lookup + beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(reject_origin, proposal_id) - approve_proposal { - let p in 0 .. T::MaxApprovals::get() - 1; + #[extrinsic_call] + _(reject_origin as T::RuntimeOrigin, proposal_id); + + Ok(()) + } + + #[benchmark] + fn approve_proposal( + p: Linear<0, { T::MaxApprovals::get() - 1 }>, + ) -> Result<(), BenchmarkError> { create_approved_proposals::(p)?; let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, - beneficiary_lookup + beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; let approve_origin = T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(approve_origin, proposal_id) - remove_approval { + #[extrinsic_call] + _(approve_origin as T::RuntimeOrigin, proposal_id); + + Ok(()) + } + + #[benchmark] + fn remove_approval() -> Result<(), BenchmarkError> { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, - beneficiary_lookup + beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; #[allow(deprecated)] Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(reject_origin, proposal_id) - on_initialize_proposals { - let p in 0 .. T::MaxApprovals::get(); + #[extrinsic_call] + _(reject_origin as T::RuntimeOrigin, proposal_id); + + Ok(()) + } + + #[benchmark] + fn on_initialize_proposals( + p: Linear<0, { T::MaxApprovals::get() - 1 }>, + ) -> Result<(), BenchmarkError> { setup_pot_account::(); create_approved_proposals::(p)?; - }: { - Treasury::::on_initialize(frame_system::pallet_prelude::BlockNumberFor::::zero()); + + #[block] + { + Treasury::::on_initialize(0u32.into()); + } + + Ok(()) + } + + #[benchmark] + fn spend() -> Result<(), BenchmarkError> { + let origin = + T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let (asset_kind, amount, beneficiary, beneficiary_lookup) = + create_spend_arguments::(SEED); + T::BalanceConverter::ensure_successful(asset_kind.clone()); + + #[extrinsic_call] + _( + origin as T::RuntimeOrigin, + Box::new(asset_kind.clone()), + amount, + Box::new(beneficiary_lookup), + None, + ); + + let valid_from = frame_system::Pallet::::block_number(); + let expire_at = valid_from.saturating_add(T::PayoutPeriod::get()); + assert_last_event::( + Event::AssetSpendApproved { + index: 0, + asset_kind, + amount, + beneficiary, + valid_from, + expire_at, + } + .into(), + ); + Ok(()) + } + + #[benchmark] + fn payout() -> Result<(), BenchmarkError> { + let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?; + let (asset_kind, amount, beneficiary, beneficiary_lookup) = + create_spend_arguments::(SEED); + T::BalanceConverter::ensure_successful(asset_kind.clone()); + Treasury::::spend( + origin, + Box::new(asset_kind.clone()), + amount, + Box::new(beneficiary_lookup), + None, + )?; + T::Paymaster::ensure_successful(&beneficiary, asset_kind, amount); + let caller: T::AccountId = account("caller", 0, SEED); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), 0u32); + + let id = match Spends::::get(0).unwrap().status { + PaymentState::Attempted { id, .. } => { + assert_ne!(T::Paymaster::check_payment(id), PaymentStatus::Failure); + id + }, + _ => panic!("No payout attempt made"), + }; + assert_last_event::(Event::Paid { index: 0, payment_id: id }.into()); + assert!(Treasury::::payout(RawOrigin::Signed(caller).into(), 0u32).is_err()); + Ok(()) + } + + #[benchmark] + fn check_status() -> Result<(), BenchmarkError> { + let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?; + let (asset_kind, amount, beneficiary, beneficiary_lookup) = + create_spend_arguments::(SEED); + T::BalanceConverter::ensure_successful(asset_kind.clone()); + Treasury::::spend( + origin, + Box::new(asset_kind.clone()), + amount, + Box::new(beneficiary_lookup), + None, + )?; + T::Paymaster::ensure_successful(&beneficiary, asset_kind, amount); + let caller: T::AccountId = account("caller", 0, SEED); + Treasury::::payout(RawOrigin::Signed(caller.clone()).into(), 0u32)?; + match Spends::::get(0).unwrap().status { + PaymentState::Attempted { id, .. } => { + T::Paymaster::ensure_concluded(id); + }, + _ => panic!("No payout attempt made"), + }; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), 0u32); + + if let Some(s) = Spends::::get(0) { + assert!(!matches!(s.status, PaymentState::Attempted { .. })); + } + Ok(()) + } + + #[benchmark] + fn void_spend() -> Result<(), BenchmarkError> { + let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?; + let (asset_kind, amount, _, beneficiary_lookup) = create_spend_arguments::(SEED); + T::BalanceConverter::ensure_successful(asset_kind.clone()); + Treasury::::spend( + origin, + Box::new(asset_kind.clone()), + amount, + Box::new(beneficiary_lookup), + None, + )?; + assert!(Spends::::get(0).is_some()); + let origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, 0u32); + + assert!(Spends::::get(0).is_none()); + Ok(()) } - impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!( + Treasury, + crate::tests::ExtBuilder::default().build(), + crate::tests::Test + ); } diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 730fae2a4e92c9b673541d25e5fca6c759ad2c91..5e429d3914bd0c60ea24eb53825c4da4b6a07fe5 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -15,46 +15,60 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! > Made with *Substrate*, for *Polkadot*. +//! +//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) - +//! [![polkadot]](https://polkadot.network) +//! +//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! //! # Treasury Pallet //! //! The Treasury pallet provides a "pot" of funds that can be managed by stakeholders in the system //! and a structure for making spending proposals from this pot. //! -//! - [`Config`] -//! - [`Call`] -//! //! ## Overview //! //! The Treasury Pallet itself provides the pot to store funds, and a means for stakeholders to -//! propose, approve, and deny expenditures. The chain will need to provide a method (e.g. -//! inflation, fees) for collecting funds. +//! propose and claim expenditures (aka spends). The chain will need to provide a method to approve +//! spends (e.g. public referendum) and a method for collecting funds (e.g. inflation, fees). //! -//! By way of example, the Council could vote to fund the Treasury with a portion of the block +//! By way of example, stakeholders could vote to fund the Treasury with a portion of the block //! reward and use the funds to pay developers. //! -//! //! ### Terminology //! //! - **Proposal:** A suggestion to allocate funds from the pot to a beneficiary. //! - **Beneficiary:** An account who will receive the funds from a proposal iff the proposal is //! approved. -//! - **Deposit:** Funds that a proposer must lock when making a proposal. The deposit will be -//! returned or slashed if the proposal is approved or rejected respectively. //! - **Pot:** Unspent funds accumulated by the treasury pallet. +//! - **Spend** An approved proposal for transferring a specific amount of funds to a designated +//! beneficiary. +//! +//! ### Example //! -//! ## Interface +//! 1. Multiple local spends approved by spend origins and received by a beneficiary. +#![doc = docify::embed!("src/tests.rs", spend_local_origin_works)] //! -//! ### Dispatchable Functions +//! 2. Approve a spend of some asset kind and claim it. +#![doc = docify::embed!("src/tests.rs", spend_payout_works)] //! -//! General spending/proposal protocol: -//! - `propose_spend` - Make a spending proposal and stake the required deposit. -//! - `reject_proposal` - Reject a proposal, slashing the deposit. -//! - `approve_proposal` - Accept the proposal, returning the deposit. -//! - `remove_approval` - Remove an approval, the deposit will no longer be returned. +//! ## Pallet API //! -//! ## GenesisConfig +//! See the [`pallet`] module for more information about the interfaces this pallet exposes, +//! including its configuration trait, dispatchables, storage items, events and errors. //! -//! The Treasury pallet depends on the [`GenesisConfig`]. +//! ## Low Level / Implementation Details +//! +//! Spends can be initiated using either the `spend_local` or `spend` dispatchable. The +//! `spend_local` dispatchable enables the creation of spends using the native currency of the +//! chain, utilizing the funds stored in the pot. These spends are automatically paid out every +//! [`pallet::Config::SpendPeriod`]. On the other hand, the `spend` dispatchable allows spending of +//! any asset kind managed by the treasury, with payment facilitated by a designated +//! [`pallet::Config::Paymaster`]. To claim these spends, the `payout` dispatchable should be called +//! within some temporal bounds, starting from the moment they become valid and within one +//! [`pallet::Config::PayoutPeriod`]. #![cfg_attr(not(feature = "std"), no_std)] @@ -62,6 +76,8 @@ mod benchmarking; #[cfg(test)] mod tests; pub mod weights; +#[cfg(feature = "runtime-benchmarks")] +pub use benchmarking::ArgumentsFactory; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -73,9 +89,10 @@ use sp_runtime::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use frame_support::{ - print, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, + ensure, print, traits::{ - Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, + tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, ReservableCurrency, WithdrawReasons, }, weights::Weight, @@ -87,6 +104,7 @@ pub use weights::WeightInfo; pub type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; +pub type AssetBalanceOf = <>::Paymaster as Pay>::Balance; pub type PositiveImbalanceOf = <>::Currency as Currency< ::AccountId, >>::PositiveImbalance; @@ -94,6 +112,7 @@ pub type NegativeImbalanceOf = <>::Currency as Currenc ::AccountId, >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type BeneficiaryLookupOf = <>::BeneficiaryLookup as StaticLookup>::Source; /// A trait to allow the Treasury Pallet to spend it's funds for other purposes. /// There is an expectation that the implementer of this trait will correctly manage @@ -133,10 +152,47 @@ pub struct Proposal { bond: Balance, } +/// The state of the payment claim. +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)] +pub enum PaymentState { + /// Pending claim. + Pending, + /// Payment attempted with a payment identifier. + Attempted { id: Id }, + /// Payment failed. + Failed, +} + +/// Info regarding an approved treasury spend. +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)] +pub struct SpendStatus { + // The kind of asset to be spent. + asset_kind: AssetKind, + /// The asset amount of the spend. + amount: AssetBalance, + /// The beneficiary of the spend. + beneficiary: Beneficiary, + /// The block number from which the spend can be claimed. + valid_from: BlockNumber, + /// The block number by which the spend has to be claimed. + expire_at: BlockNumber, + /// The status of the payout/claim. + status: PaymentState, +} + +/// Index of an approved treasury spend. +pub type SpendIndex = u32; + #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{dispatch_context::with_context, pallet_prelude::*}; + use frame_support::{ + dispatch_context::with_context, + pallet_prelude::*, + traits::tokens::{ConversionFromAssetBalance, PaymentStatus}, + }; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -201,9 +257,38 @@ pub mod pallet { type MaxApprovals: Get; /// The origin required for approving spends from the treasury outside of the proposal - /// process. The `Success` value is the maximum amount that this origin is allowed to - /// spend at a time. + /// process. The `Success` value is the maximum amount in a native asset that this origin + /// is allowed to spend at a time. type SpendOrigin: EnsureOrigin>; + + /// Type parameter representing the asset kinds to be spent from the treasury. + type AssetKind: Parameter + MaxEncodedLen; + + /// Type parameter used to identify the beneficiaries eligible to receive treasury spends. + type Beneficiary: Parameter + MaxEncodedLen; + + /// Converting trait to take a source type and convert to [`Self::Beneficiary`]. + type BeneficiaryLookup: StaticLookup; + + /// Type for processing spends of [Self::AssetKind] in favor of [`Self::Beneficiary`]. + type Paymaster: Pay; + + /// Type for converting the balance of an [Self::AssetKind] to the balance of the native + /// asset, solely for the purpose of asserting the result against the maximum allowed spend + /// amount of the [`Self::SpendOrigin`]. + type BalanceConverter: ConversionFromAssetBalance< + ::Balance, + Self::AssetKind, + BalanceOf, + >; + + /// The period during which an approved treasury spend has to be claimed. + #[pallet::constant] + type PayoutPeriod: Get>; + + /// Helper type for benchmarks. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: ArgumentsFactory; } /// Number of proposals that have been made. @@ -233,6 +318,27 @@ pub mod pallet { pub type Approvals, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; + /// The count of spends that have been made. + #[pallet::storage] + pub(crate) type SpendCount = StorageValue<_, SpendIndex, ValueQuery>; + + /// Spends that have been approved and being processed. + // Hasher: Twox safe since `SpendIndex` is an internal count based index. + #[pallet::storage] + pub type Spends, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + SpendIndex, + SpendStatus< + T::AssetKind, + AssetBalanceOf, + T::Beneficiary, + BlockNumberFor, + ::Id, + >, + OptionQuery, + >; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig, I: 'static = ()> { @@ -277,6 +383,24 @@ pub mod pallet { }, /// The inactive funds of the pallet have been updated. UpdatedInactive { reactivated: BalanceOf, deactivated: BalanceOf }, + /// A new asset spend proposal has been approved. + AssetSpendApproved { + index: SpendIndex, + asset_kind: T::AssetKind, + amount: AssetBalanceOf, + beneficiary: T::Beneficiary, + valid_from: BlockNumberFor, + expire_at: BlockNumberFor, + }, + /// An approved spend was voided. + AssetSpendVoided { index: SpendIndex }, + /// A payment happened. + Paid { index: SpendIndex, payment_id: ::Id }, + /// A payment failed and can be retried. + PaymentFailed { index: SpendIndex, payment_id: ::Id }, + /// A spend was processed and removed from the storage. It might have been successfully + /// paid or it may have expired. + SpendProcessed { index: SpendIndex }, } /// Error for the treasury pallet. @@ -284,7 +408,7 @@ pub mod pallet { pub enum Error { /// Proposer's balance is too low. InsufficientProposersBalance, - /// No proposal or bounty at that index. + /// No proposal, bounty or spend at that index. InvalidIndex, /// Too many approvals in the queue. TooManyApprovals, @@ -293,6 +417,20 @@ pub mod pallet { InsufficientPermission, /// Proposal has not been approved. ProposalNotApproved, + /// The balance of the asset kind is not convertible to the balance of the native asset. + FailedToConvertBalance, + /// The spend has expired and cannot be claimed. + SpendExpired, + /// The spend is not yet eligible for payout. + EarlyPayout, + /// The payment has already been attempted. + AlreadyAttempted, + /// There was some issue with the mechanism of payment. + PayoutError, + /// The payout was not yet attempted/claimed. + NotAttempted, + /// The payment has neither failed nor succeeded yet. + Inconclusive, } #[pallet::hooks] @@ -319,6 +457,14 @@ pub mod pallet { Weight::zero() } } + + #[cfg(feature = "try-runtime")] + fn try_state( + _: frame_system::pallet_prelude::BlockNumberFor, + ) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state()?; + Ok(()) + } } #[derive(Default)] @@ -328,12 +474,22 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { - /// Put forward a suggestion for spending. A deposit proportional to the value - /// is reserved and slashed if the proposal is rejected. It is returned once the - /// proposal is awarded. + /// Put forward a suggestion for spending. /// - /// ## Complexity + /// ## Dispatch Origin + /// + /// Must be signed. + /// + /// ## Details + /// A deposit proportional to the value is reserved and slashed if the proposal is rejected. + /// It is returned once the proposal is awarded. + /// + /// ### Complexity /// - O(1) + /// + /// ## Events + /// + /// Emits [`Event::Proposed`] if successful. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::propose_spend())] #[allow(deprecated)] @@ -360,12 +516,21 @@ pub mod pallet { Ok(()) } - /// Reject a proposed spend. The original deposit will be slashed. + /// Reject a proposed spend. /// - /// May only be called from `T::RejectOrigin`. + /// ## Dispatch Origin /// - /// ## Complexity + /// Must be [`Config::RejectOrigin`]. + /// + /// ## Details + /// The original deposit will be slashed. + /// + /// ### Complexity /// - O(1) + /// + /// ## Events + /// + /// Emits [`Event::Rejected`] if successful. #[pallet::call_index(1)] #[pallet::weight((T::WeightInfo::reject_proposal(), DispatchClass::Operational))] #[allow(deprecated)] @@ -391,13 +556,23 @@ pub mod pallet { Ok(()) } - /// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary - /// and the original deposit will be returned. + /// Approve a proposal. /// - /// May only be called from `T::ApproveOrigin`. + /// ## Dispatch Origin /// - /// ## Complexity + /// Must be [`Config::ApproveOrigin`]. + /// + /// ## Details + /// + /// At a later time, the proposal will be allocated to the beneficiary and the original + /// deposit will be returned. + /// + /// ### Complexity /// - O(1). + /// + /// ## Events + /// + /// No events are emitted from this dispatch. #[pallet::call_index(2)] #[pallet::weight((T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational))] #[allow(deprecated)] @@ -418,15 +593,24 @@ pub mod pallet { /// Propose and approve a spend of treasury funds. /// - /// - `origin`: Must be `SpendOrigin` with the `Success` value being at least `amount`. - /// - `amount`: The amount to be transferred from the treasury to the `beneficiary`. - /// - `beneficiary`: The destination account for the transfer. + /// ## Dispatch Origin + /// + /// Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`. /// + /// ### Details /// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the /// beneficiary. + /// + /// ### Parameters + /// - `amount`: The amount to be transferred from the treasury to the `beneficiary`. + /// - `beneficiary`: The destination account for the transfer. + /// + /// ## Events + /// + /// Emits [`Event::SpendApproved`] if successful. #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::spend())] - pub fn spend( + #[pallet::weight(T::WeightInfo::spend_local())] + pub fn spend_local( origin: OriginFor, #[pallet::compact] amount: BalanceOf, beneficiary: AccountIdLookupOf, @@ -472,18 +656,26 @@ pub mod pallet { } /// Force a previously approved proposal to be removed from the approval queue. + /// + /// ## Dispatch Origin + /// + /// Must be [`Config::RejectOrigin`]. + /// + /// ## Details + /// /// The original deposit will no longer be returned. /// - /// May only be called from `T::RejectOrigin`. + /// ### Parameters /// - `proposal_id`: The index of a proposal /// - /// ## Complexity + /// ### Complexity /// - O(A) where `A` is the number of approvals /// - /// Errors: - /// - `ProposalNotApproved`: The `proposal_id` supplied was not found in the approval queue, - /// i.e., the proposal has not been approved. This could also mean the proposal does not - /// exist altogether, thus there is no way it would have been approved in the first place. + /// ### Errors + /// - [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the + /// approval queue, i.e., the proposal has not been approved. This could also mean the + /// proposal does not exist altogether, thus there is no way it would have been approved + /// in the first place. #[pallet::call_index(4)] #[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))] pub fn remove_approval( @@ -503,6 +695,229 @@ pub mod pallet { Ok(()) } + + /// Propose and approve a spend of treasury funds. + /// + /// ## Dispatch Origin + /// + /// Must be [`Config::SpendOrigin`] with the `Success` value being at least + /// `amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted + /// for assertion using the [`Config::BalanceConverter`]. + /// + /// ## Details + /// + /// Create an approved spend for transferring a specific `amount` of `asset_kind` to a + /// designated beneficiary. The spend must be claimed using the `payout` dispatchable within + /// the [`Config::PayoutPeriod`]. + /// + /// ### Parameters + /// - `asset_kind`: An indicator of the specific asset class to be spent. + /// - `amount`: The amount to be transferred from the treasury to the `beneficiary`. + /// - `beneficiary`: The beneficiary of the spend. + /// - `valid_from`: The block number from which the spend can be claimed. It can refer to + /// the past if the resulting spend has not yet expired according to the + /// [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after + /// approval. + /// + /// ## Events + /// + /// Emits [`Event::AssetSpendApproved`] if successful. + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::spend())] + pub fn spend( + origin: OriginFor, + asset_kind: Box, + #[pallet::compact] amount: AssetBalanceOf, + beneficiary: Box>, + valid_from: Option>, + ) -> DispatchResult { + let max_amount = T::SpendOrigin::ensure_origin(origin)?; + let beneficiary = T::BeneficiaryLookup::lookup(*beneficiary)?; + + let now = frame_system::Pallet::::block_number(); + let valid_from = valid_from.unwrap_or(now); + let expire_at = valid_from.saturating_add(T::PayoutPeriod::get()); + ensure!(expire_at > now, Error::::SpendExpired); + + let native_amount = + T::BalanceConverter::from_asset_balance(amount, *asset_kind.clone()) + .map_err(|_| Error::::FailedToConvertBalance)?; + + ensure!(native_amount <= max_amount, Error::::InsufficientPermission); + + with_context::>, _>(|v| { + let context = v.or_default(); + // We group based on `max_amount`, to distinguish between different kind of + // origins. (assumes that all origins have different `max_amount`) + // + // Worst case is that we reject some "valid" request. + let spend = context.spend_in_context.entry(max_amount).or_default(); + + // Ensure that we don't overflow nor use more than `max_amount` + if spend.checked_add(&native_amount).map(|s| s > max_amount).unwrap_or(true) { + Err(Error::::InsufficientPermission) + } else { + *spend = spend.saturating_add(native_amount); + Ok(()) + } + }) + .unwrap_or(Ok(()))?; + + let index = SpendCount::::get(); + Spends::::insert( + index, + SpendStatus { + asset_kind: *asset_kind.clone(), + amount, + beneficiary: beneficiary.clone(), + valid_from, + expire_at, + status: PaymentState::Pending, + }, + ); + SpendCount::::put(index + 1); + + Self::deposit_event(Event::AssetSpendApproved { + index, + asset_kind: *asset_kind, + amount, + beneficiary, + valid_from, + expire_at, + }); + Ok(()) + } + + /// Claim a spend. + /// + /// ## Dispatch Origin + /// + /// Must be signed. + /// + /// ## Details + /// + /// Spends must be claimed within some temporal bounds. A spend may be claimed within one + /// [`Config::PayoutPeriod`] from the `valid_from` block. + /// In case of a payout failure, the spend status must be updated with the `check_status` + /// dispatchable before retrying with the current function. + /// + /// ### Parameters + /// - `index`: The spend index. + /// + /// ## Events + /// + /// Emits [`Event::Paid`] if successful. + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::payout())] + pub fn payout(origin: OriginFor, index: SpendIndex) -> DispatchResult { + ensure_signed(origin)?; + let mut spend = Spends::::get(index).ok_or(Error::::InvalidIndex)?; + let now = frame_system::Pallet::::block_number(); + ensure!(now >= spend.valid_from, Error::::EarlyPayout); + ensure!(spend.expire_at > now, Error::::SpendExpired); + ensure!( + matches!(spend.status, PaymentState::Pending | PaymentState::Failed), + Error::::AlreadyAttempted + ); + + let id = T::Paymaster::pay(&spend.beneficiary, spend.asset_kind.clone(), spend.amount) + .map_err(|_| Error::::PayoutError)?; + + spend.status = PaymentState::Attempted { id }; + Spends::::insert(index, spend); + + Self::deposit_event(Event::::Paid { index, payment_id: id }); + + Ok(()) + } + + /// Check the status of the spend and remove it from the storage if processed. + /// + /// ## Dispatch Origin + /// + /// Must be signed. + /// + /// ## Details + /// + /// The status check is a prerequisite for retrying a failed payout. + /// If a spend has either succeeded or expired, it is removed from the storage by this + /// function. In such instances, transaction fees are refunded. + /// + /// ### Parameters + /// - `index`: The spend index. + /// + /// ## Events + /// + /// Emits [`Event::PaymentFailed`] if the spend payout has failed. + /// Emits [`Event::SpendProcessed`] if the spend payout has succeed. + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::check_status())] + pub fn check_status(origin: OriginFor, index: SpendIndex) -> DispatchResultWithPostInfo { + use PaymentState as State; + use PaymentStatus as Status; + + ensure_signed(origin)?; + let mut spend = Spends::::get(index).ok_or(Error::::InvalidIndex)?; + let now = frame_system::Pallet::::block_number(); + + if now > spend.expire_at && !matches!(spend.status, State::Attempted { .. }) { + // spend has expired and no further status update is expected. + Spends::::remove(index); + Self::deposit_event(Event::::SpendProcessed { index }); + return Ok(Pays::No.into()) + } + + let payment_id = match spend.status { + State::Attempted { id } => id, + _ => return Err(Error::::NotAttempted.into()), + }; + + match T::Paymaster::check_payment(payment_id) { + Status::Failure => { + spend.status = PaymentState::Failed; + Spends::::insert(index, spend); + Self::deposit_event(Event::::PaymentFailed { index, payment_id }); + }, + Status::Success | Status::Unknown => { + Spends::::remove(index); + Self::deposit_event(Event::::SpendProcessed { index }); + return Ok(Pays::No.into()) + }, + Status::InProgress => return Err(Error::::Inconclusive.into()), + } + return Ok(Pays::Yes.into()) + } + + /// Void previously approved spend. + /// + /// ## Dispatch Origin + /// + /// Must be [`Config::RejectOrigin`]. + /// + /// ## Details + /// + /// A spend void is only possible if the payout has not been attempted yet. + /// + /// ### Parameters + /// - `index`: The spend index. + /// + /// ## Events + /// + /// Emits [`Event::AssetSpendVoided`] if successful. + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::void_spend())] + pub fn void_spend(origin: OriginFor, index: SpendIndex) -> DispatchResult { + T::RejectOrigin::ensure_origin(origin)?; + let spend = Spends::::get(index).ok_or(Error::::InvalidIndex)?; + ensure!( + matches!(spend.status, PaymentState::Pending | PaymentState::Failed), + Error::::AlreadyAttempted + ); + + Spends::::remove(index); + Self::deposit_event(Event::::AssetSpendVoided { index }); + Ok(()) + } } } @@ -614,6 +1029,85 @@ impl, I: 'static> Pallet { // Must never be less than 0 but better be safe. .saturating_sub(T::Currency::minimum_balance()) } + + /// Ensure the correctness of the state of this pallet. + #[cfg(any(feature = "try-runtime", test))] + fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::try_state_proposals()?; + Self::try_state_spends()?; + + Ok(()) + } + + /// ### Invariants of proposal storage items + /// + /// 1. [`ProposalCount`] >= Number of elements in [`Proposals`]. + /// 2. Each entry in [`Proposals`] should be saved under a key stricly less than current + /// [`ProposalCount`]. + /// 3. Each [`ProposalIndex`] contained in [`Approvals`] should exist in [`Proposals`]. + /// Note, that this automatically implies [`Approvals`].count() <= [`Proposals`].count(). + #[cfg(any(feature = "try-runtime", test))] + fn try_state_proposals() -> Result<(), sp_runtime::TryRuntimeError> { + let current_proposal_count = ProposalCount::::get(); + ensure!( + current_proposal_count as usize >= Proposals::::iter().count(), + "Actual number of proposals exceeds `ProposalCount`." + ); + + Proposals::::iter_keys().try_for_each(|proposal_index| -> DispatchResult { + ensure!( + current_proposal_count as u32 > proposal_index, + "`ProposalCount` should by strictly greater than any ProposalIndex used as a key for `Proposals`." + ); + Ok(()) + })?; + + Approvals::::get() + .iter() + .try_for_each(|proposal_index| -> DispatchResult { + ensure!( + Proposals::::contains_key(proposal_index), + "Proposal indices in `Approvals` must also be contained in `Proposals`." + ); + Ok(()) + })?; + + Ok(()) + } + + /// ## Invariants of spend storage items + /// + /// 1. [`SpendCount`] >= Number of elements in [`Spends`]. + /// 2. Each entry in [`Spends`] should be saved under a key stricly less than current + /// [`SpendCount`]. + /// 3. For each spend entry contained in [`Spends`] we should have spend.expire_at + /// > spend.valid_from. + #[cfg(any(feature = "try-runtime", test))] + fn try_state_spends() -> Result<(), sp_runtime::TryRuntimeError> { + let current_spend_count = SpendCount::::get(); + ensure!( + current_spend_count as usize >= Spends::::iter().count(), + "Actual number of spends exceeds `SpendCount`." + ); + + Spends::::iter_keys().try_for_each(|spend_index| -> DispatchResult { + ensure!( + current_spend_count > spend_index, + "`SpendCount` should by strictly greater than any SpendIndex used as a key for `Spends`." + ); + Ok(()) + })?; + + Spends::::iter().try_for_each(|(_index, spend)| -> DispatchResult { + ensure!( + spend.valid_from < spend.expire_at, + "Spend cannot expire before it becomes valid." + ); + Ok(()) + })?; + + Ok(()) + } } impl, I: 'static> OnUnbalanced> for Pallet { diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index ba45d5f6ff16fb6cd40043d29e96050136ae955e..1748189723edf2ee0c95817bf211397ce6abdae6 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -19,6 +19,7 @@ #![cfg(test)] +use core::{cell::RefCell, marker::PhantomData}; use sp_core::H256; use sp_runtime::{ traits::{BadOrigin, BlakeTwo256, Dispatchable, IdentityLookup}, @@ -26,8 +27,13 @@ use sp_runtime::{ }; use frame_support::{ - assert_err_ignore_postinfo, assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, OnInitialize}, + assert_err_ignore_postinfo, assert_noop, assert_ok, + pallet_prelude::Pays, + parameter_types, + traits::{ + tokens::{ConversionFromAssetBalance, PaymentStatus}, + ConstU32, ConstU64, OnInitialize, + }, PalletId, }; @@ -96,10 +102,64 @@ impl pallet_utility::Config for Test { type WeightInfo = (); } +thread_local! { + pub static PAID: RefCell> = RefCell::new(BTreeMap::new()); + pub static STATUS: RefCell> = RefCell::new(BTreeMap::new()); + pub static LAST_ID: RefCell = RefCell::new(0u64); +} + +/// paid balance for a given account and asset ids +fn paid(who: u128, asset_id: u32) -> u64 { + PAID.with(|p| p.borrow().get(&(who, asset_id)).cloned().unwrap_or(0)) +} + +/// reduce paid balance for a given account and asset ids +fn unpay(who: u128, asset_id: u32, amount: u64) { + PAID.with(|p| p.borrow_mut().entry((who, asset_id)).or_default().saturating_reduce(amount)) +} + +/// set status for a given payment id +fn set_status(id: u64, s: PaymentStatus) { + STATUS.with(|m| m.borrow_mut().insert(id, s)); +} + +pub struct TestPay; +impl Pay for TestPay { + type Beneficiary = u128; + type Balance = u64; + type Id = u64; + type AssetKind = u32; + type Error = (); + + fn pay( + who: &Self::Beneficiary, + asset_kind: Self::AssetKind, + amount: Self::Balance, + ) -> Result { + PAID.with(|paid| *paid.borrow_mut().entry((*who, asset_kind)).or_default() += amount); + Ok(LAST_ID.with(|lid| { + let x = *lid.borrow(); + lid.replace(x + 1); + x + })) + } + fn check_payment(id: Self::Id) -> PaymentStatus { + STATUS.with(|s| s.borrow().get(&id).cloned().unwrap_or(PaymentStatus::Unknown)) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &Self::Beneficiary, _: Self::AssetKind, _: Self::Balance) {} + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(id: Self::Id) { + set_status(id, PaymentStatus::Failure) + } +} + parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: u128 = Treasury::account_id(); + pub const SpendPayoutPeriod: u64 = 5; } pub struct TestSpendOrigin; impl frame_support::traits::EnsureOrigin for TestSpendOrigin { @@ -120,6 +180,16 @@ impl frame_support::traits::EnsureOrigin for TestSpendOrigin { } } +pub struct MulBy(PhantomData); +impl> ConversionFromAssetBalance for MulBy { + type Error = (); + fn from_asset_balance(balance: u64, _asset_id: u32) -> Result { + return balance.checked_mul(N::get()).ok_or(()) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: u32) {} +} + impl Config for Test { type PalletId = TreasuryPalletId; type Currency = pallet_balances::Pallet; @@ -137,76 +207,107 @@ impl Config for Test { type SpendFunds = (); type MaxApprovals = ConstU32<100>; type SpendOrigin = TestSpendOrigin; + type AssetKind = u32; + type Beneficiary = u128; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = TestPay; + type BalanceConverter = MulBy>; + type PayoutPeriod = SpendPayoutPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { - // Total issuance will be 200 with treasury account initialized at ED. - balances: vec![(0, 100), (1, 98), (2, 1)], +pub struct ExtBuilder {} + +impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { + // Total issuance will be 200 with treasury account initialized at ED. + balances: vec![(0, 100), (1, 98), (2, 1)], + } + .assimilate_storage(&mut t) + .unwrap(); + crate::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} + +fn get_payment_id(i: SpendIndex) -> Option { + let spend = Spends::::get(i).expect("no spend"); + match spend.status { + PaymentState::Attempted { id } => Some(id), + _ => None, } - .assimilate_storage(&mut t) - .unwrap(); - crate::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); - t.into() } #[test] fn genesis_config_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Treasury::pot(), 0); assert_eq!(Treasury::proposal_count(), 0); }); } #[test] -fn spend_origin_permissioning_works() { - new_test_ext().execute_with(|| { - assert_noop!(Treasury::spend(RuntimeOrigin::signed(1), 1, 1), BadOrigin); +fn spend_local_origin_permissioning_works() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!(Treasury::spend_local(RuntimeOrigin::signed(1), 1, 1), BadOrigin); assert_noop!( - Treasury::spend(RuntimeOrigin::signed(10), 6, 1), + Treasury::spend_local(RuntimeOrigin::signed(10), 6, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(RuntimeOrigin::signed(11), 11, 1), + Treasury::spend_local(RuntimeOrigin::signed(11), 11, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(RuntimeOrigin::signed(12), 21, 1), + Treasury::spend_local(RuntimeOrigin::signed(12), 21, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(RuntimeOrigin::signed(13), 51, 1), + Treasury::spend_local(RuntimeOrigin::signed(13), 51, 1), Error::::InsufficientPermission ); }); } +#[docify::export] #[test] -fn spend_origin_works() { - new_test_ext().execute_with(|| { +fn spend_local_origin_works() { + ExtBuilder::default().build().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), 10, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), 20, 6)); - assert_ok!(Treasury::spend(RuntimeOrigin::signed(13), 50, 6)); - + // approve spend of some amount to beneficiary `6`. + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6)); + // free balance of `6` is zero, spend period has not passed. >::on_initialize(1); assert_eq!(Balances::free_balance(6), 0); - + // free balance of `6` is `100`, spend period has passed. >::on_initialize(2); assert_eq!(Balances::free_balance(6), 100); + // `100` spent, `1` burned. assert_eq!(Treasury::pot(), 0); }); } #[test] fn minting_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -215,7 +316,7 @@ fn minting_works() { #[test] fn spend_proposal_takes_min_deposit() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_ok!({ #[allow(deprecated)] Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3) @@ -227,7 +328,7 @@ fn spend_proposal_takes_min_deposit() { #[test] fn spend_proposal_takes_proportional_deposit() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_ok!({ #[allow(deprecated)] Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3) @@ -239,7 +340,7 @@ fn spend_proposal_takes_proportional_deposit() { #[test] fn spend_proposal_fails_when_proposer_poor() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_noop!( { #[allow(deprecated)] @@ -252,7 +353,7 @@ fn spend_proposal_fails_when_proposer_poor() { #[test] fn accepted_spend_proposal_ignored_outside_spend_period() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!({ @@ -272,7 +373,7 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { #[test] fn unused_pot_should_diminish() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { let init_total_issuance = Balances::total_issuance(); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::total_issuance(), init_total_issuance + 100); @@ -285,7 +386,7 @@ fn unused_pot_should_diminish() { #[test] fn rejected_spend_proposal_ignored_on_spend_period() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!({ @@ -305,7 +406,7 @@ fn rejected_spend_proposal_ignored_on_spend_period() { #[test] fn reject_already_rejected_spend_proposal_fails() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!({ @@ -328,7 +429,7 @@ fn reject_already_rejected_spend_proposal_fails() { #[test] fn reject_non_existent_spend_proposal_fails() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_noop!( { #[allow(deprecated)] @@ -341,7 +442,7 @@ fn reject_non_existent_spend_proposal_fails() { #[test] fn accept_non_existent_spend_proposal_fails() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_noop!( { #[allow(deprecated)] @@ -354,7 +455,7 @@ fn accept_non_existent_spend_proposal_fails() { #[test] fn accept_already_rejected_spend_proposal_fails() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!({ @@ -377,7 +478,7 @@ fn accept_already_rejected_spend_proposal_fails() { #[test] fn accepted_spend_proposal_enacted_on_spend_period() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -398,7 +499,7 @@ fn accepted_spend_proposal_enacted_on_spend_period() { #[test] fn pot_underflow_should_not_diminish() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -425,7 +526,7 @@ fn pot_underflow_should_not_diminish() { // i.e. pot should not include existential deposit needed for account survival. #[test] fn treasury_account_doesnt_get_deleted() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); @@ -524,7 +625,7 @@ fn genesis_funding_works() { #[test] fn max_approvals_limited() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), u64::MAX); Balances::make_free_balance_be(&0, u64::MAX); @@ -556,7 +657,7 @@ fn max_approvals_limited() { #[test] fn remove_already_removed_approval_fails() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_ok!({ @@ -578,14 +679,49 @@ fn remove_already_removed_approval_fails() { }); } +#[test] +fn spending_local_in_batch_respects_max_total() { + ExtBuilder::default().build().execute_with(|| { + // Respect the `max_total` for the given origin. + assert_ok!(RuntimeCall::from(UtilityCall::batch_all { + calls: vec![ + RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }), + RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 101 }) + ] + }) + .dispatch(RuntimeOrigin::signed(10))); + + assert_err_ignore_postinfo!( + RuntimeCall::from(UtilityCall::batch_all { + calls: vec![ + RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }), + RuntimeCall::from(TreasuryCall::spend_local { amount: 4, beneficiary: 101 }) + ] + }) + .dispatch(RuntimeOrigin::signed(10)), + Error::::InsufficientPermission + ); + }) +} + #[test] fn spending_in_batch_respects_max_total() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { // Respect the `max_total` for the given origin. assert_ok!(RuntimeCall::from(UtilityCall::batch_all { calls: vec![ - RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }), - RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 101 }) + RuntimeCall::from(TreasuryCall::spend { + asset_kind: Box::new(1), + amount: 1, + beneficiary: Box::new(100), + valid_from: None, + }), + RuntimeCall::from(TreasuryCall::spend { + asset_kind: Box::new(1), + amount: 1, + beneficiary: Box::new(101), + valid_from: None, + }) ] }) .dispatch(RuntimeOrigin::signed(10))); @@ -593,8 +729,18 @@ fn spending_in_batch_respects_max_total() { assert_err_ignore_postinfo!( RuntimeCall::from(UtilityCall::batch_all { calls: vec![ - RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }), - RuntimeCall::from(TreasuryCall::spend { amount: 4, beneficiary: 101 }) + RuntimeCall::from(TreasuryCall::spend { + asset_kind: Box::new(1), + amount: 2, + beneficiary: Box::new(100), + valid_from: None, + }), + RuntimeCall::from(TreasuryCall::spend { + asset_kind: Box::new(1), + amount: 2, + beneficiary: Box::new(101), + valid_from: None, + }) ] }) .dispatch(RuntimeOrigin::signed(10)), @@ -602,3 +748,415 @@ fn spending_in_batch_respects_max_total() { ); }) } + +#[test] +fn spend_origin_works() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 1, Box::new(6), None)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_noop!( + Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 3, Box::new(6), None), + Error::::InsufficientPermission + ); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), Box::new(1), 5, Box::new(6), None)); + assert_noop!( + Treasury::spend(RuntimeOrigin::signed(11), Box::new(1), 6, Box::new(6), None), + Error::::InsufficientPermission + ); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), Box::new(1), 10, Box::new(6), None)); + assert_noop!( + Treasury::spend(RuntimeOrigin::signed(12), Box::new(1), 11, Box::new(6), None), + Error::::InsufficientPermission + ); + + assert_eq!(SpendCount::::get(), 4); + assert_eq!(Spends::::iter().count(), 4); + }); +} + +#[test] +fn spend_works() { + ExtBuilder::default().build().execute_with(|| { + System::set_block_number(1); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + + assert_eq!(SpendCount::::get(), 1); + assert_eq!( + Spends::::get(0).unwrap(), + SpendStatus { + asset_kind: 1, + amount: 2, + beneficiary: 6, + valid_from: 1, + expire_at: 6, + status: PaymentState::Pending, + } + ); + System::assert_last_event( + Event::::AssetSpendApproved { + index: 0, + asset_kind: 1, + amount: 2, + beneficiary: 6, + valid_from: 1, + expire_at: 6, + } + .into(), + ); + }); +} + +#[test] +fn spend_expires() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(::PayoutPeriod::get(), 5); + + // spend `0` expires in 5 blocks after the creating. + System::set_block_number(1); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + System::set_block_number(6); + assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::::SpendExpired); + + // spend cannot be approved since its already expired. + assert_noop!( + Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), Some(0)), + Error::::SpendExpired + ); + }); +} + +#[docify::export] +#[test] +fn spend_payout_works() { + ExtBuilder::default().build().execute_with(|| { + System::set_block_number(1); + // approve a `2` coins spend of asset `1` to beneficiary `6`, the spend valid from now. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + // payout the spend. + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0)); + // beneficiary received `2` coins of asset `1`. + assert_eq!(paid(6, 1), 2); + assert_eq!(SpendCount::::get(), 1); + let payment_id = get_payment_id(0).expect("no payment attempt"); + System::assert_last_event(Event::::Paid { index: 0, payment_id }.into()); + set_status(payment_id, PaymentStatus::Success); + // the payment succeed. + assert_ok!(Treasury::check_status(RuntimeOrigin::signed(1), 0)); + System::assert_last_event(Event::::SpendProcessed { index: 0 }.into()); + // cannot payout the same spend twice. + assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::::InvalidIndex); + }); +} + +#[test] +fn payout_retry_works() { + ExtBuilder::default().build().execute_with(|| { + System::set_block_number(1); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0)); + assert_eq!(paid(6, 1), 2); + let payment_id = get_payment_id(0).expect("no payment attempt"); + // spend payment is failed + set_status(payment_id, PaymentStatus::Failure); + unpay(6, 1, 2); + // cannot payout a spend in the attempted state + assert_noop!( + Treasury::payout(RuntimeOrigin::signed(1), 0), + Error::::AlreadyAttempted + ); + // check status and update it to retry the payout again + assert_ok!(Treasury::check_status(RuntimeOrigin::signed(1), 0)); + System::assert_last_event(Event::::PaymentFailed { index: 0, payment_id }.into()); + // the payout can be retried now + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0)); + assert_eq!(paid(6, 1), 2); + }); +} + +#[test] +fn spend_valid_from_works() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(::PayoutPeriod::get(), 5); + System::set_block_number(1); + + // spend valid from block `2`. + assert_ok!(Treasury::spend( + RuntimeOrigin::signed(10), + Box::new(1), + 2, + Box::new(6), + Some(2) + )); + assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::::EarlyPayout); + System::set_block_number(2); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0)); + + System::set_block_number(5); + // spend approved even if `valid_from` in the past since the payout period has not passed. + assert_ok!(Treasury::spend( + RuntimeOrigin::signed(10), + Box::new(1), + 2, + Box::new(6), + Some(4) + )); + // spend paid. + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 1)); + }); +} + +#[test] +fn void_spend_works() { + ExtBuilder::default().build().execute_with(|| { + System::set_block_number(1); + // spend cannot be voided if already attempted. + assert_ok!(Treasury::spend( + RuntimeOrigin::signed(10), + Box::new(1), + 2, + Box::new(6), + Some(1) + )); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0)); + assert_noop!( + Treasury::void_spend(RuntimeOrigin::root(), 0), + Error::::AlreadyAttempted + ); + + // void spend. + assert_ok!(Treasury::spend( + RuntimeOrigin::signed(10), + Box::new(1), + 2, + Box::new(6), + Some(10) + )); + assert_ok!(Treasury::void_spend(RuntimeOrigin::root(), 1)); + assert_eq!(Spends::::get(1), None); + }); +} + +#[test] +fn check_status_works() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(::PayoutPeriod::get(), 5); + System::set_block_number(1); + + // spend `0` expired and can be removed. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + System::set_block_number(7); + let info = Treasury::check_status(RuntimeOrigin::signed(1), 0).unwrap(); + assert_eq!(info.pays_fee, Pays::No); + System::assert_last_event(Event::::SpendProcessed { index: 0 }.into()); + + // spend `1` payment failed and expired hence can be removed. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_noop!( + Treasury::check_status(RuntimeOrigin::signed(1), 1), + Error::::NotAttempted + ); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 1)); + let payment_id = get_payment_id(1).expect("no payment attempt"); + set_status(payment_id, PaymentStatus::Failure); + // spend expired. + System::set_block_number(13); + let info = Treasury::check_status(RuntimeOrigin::signed(1), 1).unwrap(); + assert_eq!(info.pays_fee, Pays::Yes); + System::assert_last_event(Event::::PaymentFailed { index: 1, payment_id }.into()); + let info = Treasury::check_status(RuntimeOrigin::signed(1), 1).unwrap(); + assert_eq!(info.pays_fee, Pays::No); + System::assert_last_event(Event::::SpendProcessed { index: 1 }.into()); + + // spend `2` payment succeed. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 2)); + let payment_id = get_payment_id(2).expect("no payment attempt"); + set_status(payment_id, PaymentStatus::Success); + let info = Treasury::check_status(RuntimeOrigin::signed(1), 2).unwrap(); + assert_eq!(info.pays_fee, Pays::No); + System::assert_last_event(Event::::SpendProcessed { index: 2 }.into()); + + // spend `3` payment in process. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 3)); + let payment_id = get_payment_id(3).expect("no payment attempt"); + set_status(payment_id, PaymentStatus::InProgress); + assert_noop!( + Treasury::check_status(RuntimeOrigin::signed(1), 3), + Error::::Inconclusive + ); + + // spend `4` removed since the payment status is unknown. + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None)); + assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 4)); + let payment_id = get_payment_id(4).expect("no payment attempt"); + set_status(payment_id, PaymentStatus::Unknown); + let info = Treasury::check_status(RuntimeOrigin::signed(1), 4).unwrap(); + assert_eq!(info.pays_fee, Pays::No); + System::assert_last_event(Event::::SpendProcessed { index: 4 }.into()); + }); +} + +#[test] +fn try_state_proposals_invariant_1_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Add a proposal using `propose_spend` + assert_ok!({ + #[allow(deprecated)] + Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3) + }); + assert_eq!(Proposals::::iter().count(), 1); + assert_eq!(ProposalCount::::get(), 1); + // Check invariant 1 holds + assert!(ProposalCount::::get() as usize >= Proposals::::iter().count()); + // Break invariant 1 by decreasing `ProposalCount` + ProposalCount::::put(0); + // Invariant 1 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("Actual number of proposals exceeds `ProposalCount`.")) + ); + }); +} + +#[test] +fn try_state_proposals_invariant_2_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Add a proposal using `propose_spend` + assert_ok!({ + #[allow(deprecated)] + Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3) + }); + assert_eq!(Proposals::::iter().count(), 1); + let current_proposal_count = ProposalCount::::get(); + assert_eq!(current_proposal_count, 1); + // Check invariant 2 holds + assert!( + Proposals::::iter_keys() + .all(|proposal_index| { + proposal_index < current_proposal_count + }) + ); + // Break invariant 2 by inserting the proposal under key = 1 + let proposal = Proposals::::take(0).unwrap(); + Proposals::::insert(1, proposal); + // Invariant 2 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("`ProposalCount` should by strictly greater than any ProposalIndex used as a key for `Proposals`.")) + ); + }); +} + +#[test] +fn try_state_proposals_invariant_3_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Add a proposal using `propose_spend` + assert_ok!({ + #[allow(deprecated)] + Treasury::propose_spend(RuntimeOrigin::signed(0), 10, 3) + }); + assert_eq!(Proposals::::iter().count(), 1); + // Approve the proposal + assert_ok!({ + #[allow(deprecated)] + Treasury::approve_proposal(RuntimeOrigin::root(), 0) + }); + assert_eq!(Approvals::::get().len(), 1); + // Check invariant 3 holds + assert!(Approvals::::get() + .iter() + .all(|proposal_index| { Proposals::::contains_key(proposal_index) })); + // Break invariant 3 by adding another key to `Approvals` + let mut approvals_modified = Approvals::::get(); + approvals_modified.try_push(2).unwrap(); + Approvals::::put(approvals_modified); + // Invariant 3 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("Proposal indices in `Approvals` must also be contained in `Proposals`.")) + ); + }); +} + +#[test] +fn try_state_spends_invariant_1_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Propose and approve a spend + assert_ok!({ + Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 1, Box::new(6), None) + }); + assert_eq!(Spends::::iter().count(), 1); + assert_eq!(SpendCount::::get(), 1); + // Check invariant 1 holds + assert!(SpendCount::::get() as usize >= Spends::::iter().count()); + // Break invariant 1 by decreasing `SpendCount` + SpendCount::::put(0); + // Invariant 1 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("Actual number of spends exceeds `SpendCount`.")) + ); + }); +} + +#[test] +fn try_state_spends_invariant_2_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Propose and approve a spend + assert_ok!({ + Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 1, Box::new(6), None) + }); + assert_eq!(Spends::::iter().count(), 1); + let current_spend_count = SpendCount::::get(); + assert_eq!(current_spend_count, 1); + // Check invariant 2 holds + assert!( + Spends::::iter_keys() + .all(|spend_index| { + spend_index < current_spend_count + }) + ); + // Break invariant 2 by inserting the spend under key = 1 + let spend = Spends::::take(0).unwrap(); + Spends::::insert(1, spend); + // Invariant 2 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("`SpendCount` should by strictly greater than any SpendIndex used as a key for `Spends`.")) + ); + }); +} + +#[test] +fn try_state_spends_invariant_3_works() { + ExtBuilder::default().build().execute_with(|| { + use frame_support::pallet_prelude::DispatchError::Other; + // Propose and approve a spend + assert_ok!({ + Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 1, Box::new(6), None) + }); + assert_eq!(Spends::::iter().count(), 1); + let current_spend_count = SpendCount::::get(); + assert_eq!(current_spend_count, 1); + // Check invariant 3 holds + assert!(Spends::::iter_values() + .all(|SpendStatus { valid_from, expire_at, .. }| { valid_from < expire_at })); + // Break invariant 3 by reversing spend.expire_at and spend.valid_from + let spend = Spends::::take(0).unwrap(); + Spends::::insert( + 0, + SpendStatus { valid_from: spend.expire_at, expire_at: spend.valid_from, ..spend }, + ); + // Invariant 3 should be violated + assert_eq!( + Treasury::do_try_state(), + Err(Other("Spend cannot expire before it becomes valid.")) + ); + }); +} diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index 8f1418f76d969056c83be8673671494992e27fef..030e18980eb54f8b16452691b884e6046878aaa2 100644 --- a/substrate/frame/treasury/src/weights.rs +++ b/substrate/frame/treasury/src/weights.rs @@ -18,28 +18,23 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-07, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// ./target/debug/substrate // benchmark // pallet // --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_treasury -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --steps=20 +// --repeat=2 +// --pallet=pallet-treasury // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/treasury/src/weights.rs -// --header=./HEADER-APACHE2 +// --output=./frame/treasury/src/._weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -52,12 +47,16 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_treasury. pub trait WeightInfo { - fn spend() -> Weight; + fn spend_local() -> Weight; fn propose_spend() -> Weight; fn reject_proposal() -> Weight; fn approve_proposal(p: u32, ) -> Weight; fn remove_approval() -> Weight; fn on_initialize_proposals(p: u32, ) -> Weight; + fn spend() -> Weight; + fn payout() -> Weight; + fn check_status() -> Weight; + fn void_spend() -> Weight; } /// Weights for pallet_treasury using the Substrate node and recommended hardware. @@ -69,12 +68,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// Storage: Treasury Proposals (r:0 w:1) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend() -> Weight { + fn spend_local() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 15_057_000 picoseconds. - Weight::from_parts(15_803_000, 1887) + // Minimum execution time: 179_000_000 picoseconds. + Weight::from_parts(190_000_000, 1887) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -86,8 +85,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 28_923_000 picoseconds. - Weight::from_parts(29_495_000, 1489) + // Minimum execution time: 349_000_000 picoseconds. + Weight::from_parts(398_000_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -99,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 30_539_000 picoseconds. - Weight::from_parts(30_986_000, 3593) + // Minimum execution time: 367_000_000 picoseconds. + Weight::from_parts(388_000_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -111,12 +110,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `504 + p * (8 ±0)` + // Measured: `483 + p * (9 ±0)` // Estimated: `3573` - // Minimum execution time: 9_320_000 picoseconds. - Weight::from_parts(12_606_599, 3573) - // Standard Error: 1_302 - .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(p.into())) + // Minimum execution time: 111_000_000 picoseconds. + Weight::from_parts(108_813_243, 3573) + // Standard Error: 147_887 + .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,8 +125,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 7_231_000 picoseconds. - Weight::from_parts(7_459_000, 1887) + // Minimum execution time: 71_000_000 picoseconds. + Weight::from_parts(78_000_000, 1887) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -135,27 +134,81 @@ impl WeightInfo for SubstrateWeight { /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Treasury Approvals (r:1 w:1) /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:100 w:100) + /// Storage: Treasury Proposals (r:99 w:99) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:200 w:200) + /// Storage: System Account (r:198 w:198) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Bounties BountyApprovals (r:1 w:1) /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. + /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `421 + p * (251 ±0)` + // Measured: `427 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 44_769_000 picoseconds. - Weight::from_parts(57_915_572, 1887) - // Standard Error: 59_484 - .saturating_add(Weight::from_parts(42_343_732, 0).saturating_mul(p.into())) + // Minimum execution time: 614_000_000 picoseconds. + Weight::from_parts(498_501_558, 1887) + // Standard Error: 1_070_260 + .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3501` + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(216_000_000, 3501) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `705` + // Estimated: `6208` + // Minimum execution time: 760_000_000 picoseconds. + Weight::from_parts(822_000_000, 6208) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(160_000_000, 3534) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(181_000_000, 3534) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -166,12 +219,12 @@ impl WeightInfo for () { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// Storage: Treasury Proposals (r:0 w:1) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend() -> Weight { + fn spend_local() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 15_057_000 picoseconds. - Weight::from_parts(15_803_000, 1887) + // Minimum execution time: 179_000_000 picoseconds. + Weight::from_parts(190_000_000, 1887) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -183,8 +236,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 28_923_000 picoseconds. - Weight::from_parts(29_495_000, 1489) + // Minimum execution time: 349_000_000 picoseconds. + Weight::from_parts(398_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -196,8 +249,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 30_539_000 picoseconds. - Weight::from_parts(30_986_000, 3593) + // Minimum execution time: 367_000_000 picoseconds. + Weight::from_parts(388_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -208,12 +261,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `504 + p * (8 ±0)` + // Measured: `483 + p * (9 ±0)` // Estimated: `3573` - // Minimum execution time: 9_320_000 picoseconds. - Weight::from_parts(12_606_599, 3573) - // Standard Error: 1_302 - .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(p.into())) + // Minimum execution time: 111_000_000 picoseconds. + Weight::from_parts(108_813_243, 3573) + // Standard Error: 147_887 + .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -223,8 +276,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 7_231_000 picoseconds. - Weight::from_parts(7_459_000, 1887) + // Minimum execution time: 71_000_000 picoseconds. + Weight::from_parts(78_000_000, 1887) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -232,25 +285,79 @@ impl WeightInfo for () { /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Treasury Approvals (r:1 w:1) /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:100 w:100) + /// Storage: Treasury Proposals (r:99 w:99) /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:200 w:200) + /// Storage: System Account (r:198 w:198) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Bounties BountyApprovals (r:1 w:1) /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// The range of component `p` is `[0, 100]`. + /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `421 + p * (251 ±0)` + // Measured: `427 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 44_769_000 picoseconds. - Weight::from_parts(57_915_572, 1887) - // Standard Error: 59_484 - .saturating_add(Weight::from_parts(42_343_732, 0).saturating_mul(p.into())) + // Minimum execution time: 614_000_000 picoseconds. + Weight::from_parts(498_501_558, 1887) + // Standard Error: 1_070_260 + .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3501` + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(216_000_000, 3501) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `705` + // Estimated: `6208` + // Minimum execution time: 760_000_000 picoseconds. + Weight::from_parts(822_000_000, 6208) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(160_000_000, 3534) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(181_000_000, 3534) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/substrate/frame/tx-pause/src/lib.rs b/substrate/frame/tx-pause/src/lib.rs index f8abf678e5a7e24646a6cb6d10c934a8d271ffcb..a3be0f50172707cc8c87b1dbe263350072c1c23d 100644 --- a/substrate/frame/tx-pause/src/lib.rs +++ b/substrate/frame/tx-pause/src/lib.rs @@ -205,7 +205,7 @@ impl Pallet { /// Ensure that this call can be paused. pub fn ensure_can_pause(full_name: &RuntimeCallNameOf) -> Result<(), Error> { // SAFETY: The `TxPause` pallet can never pause itself. - if full_name.0.as_ref() == ::name().as_bytes().to_vec() { + if full_name.0.as_slice() == ::name().as_bytes() { return Err(Error::::Unpausable) } diff --git a/substrate/frame/uniques/src/lib.rs b/substrate/frame/uniques/src/lib.rs index 1b75d0b078ba5e04e16e6ad9c5ad0f962324ec5c..8334a8d943e19a6aea1e6973955c6a4fc44a514f 100644 --- a/substrate/frame/uniques/src/lib.rs +++ b/substrate/frame/uniques/src/lib.rs @@ -69,7 +69,10 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[cfg(feature = "runtime-benchmarks")] diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index af212a31eb9713a651ac9d40c44c582ffc3c1a8e..7f963e3637d6fcb606591c46e9511280ee776879 100644 --- a/substrate/frame/utility/src/lib.rs +++ b/substrate/frame/utility/src/lib.rs @@ -479,13 +479,15 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Root_. #[pallet::call_index(5)] - #[pallet::weight((*_weight, call.get_dispatch_info().class))] + #[pallet::weight((*weight, call.get_dispatch_info().class))] pub fn with_weight( origin: OriginFor, call: Box<::RuntimeCall>, - _weight: Weight, + weight: Weight, ) -> DispatchResult { ensure_root(origin)?; + let _ = weight; // Explicitly don't check the the weight witness. + let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); res.map(|_| ()).map_err(|e| e.error) } diff --git a/substrate/frame/whitelist/src/benchmarking.rs b/substrate/frame/whitelist/src/benchmarking.rs index 1982f5eb8738e2928946ba62d066bc46a710a854..9d356f09a9d2ec411c6af5ae73940741319ab590 100644 --- a/substrate/frame/whitelist/src/benchmarking.rs +++ b/substrate/frame/whitelist/src/benchmarking.rs @@ -79,7 +79,7 @@ benchmarks! { let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); let call_encoded_len = encoded_call.len() as u32; - let call_hash = call.blake2_256().into(); + let call_hash = T::Hashing::hash_of(&call); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); @@ -106,7 +106,7 @@ benchmarks! { let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); - let call_hash = call.blake2_256().into(); + let call_hash = T::Hashing::hash_of(&call); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); diff --git a/substrate/frame/whitelist/src/lib.rs b/substrate/frame/whitelist/src/lib.rs index decf010b06757ff7ed03f101100d038078b5e67a..44551abd10715e0e4dd23d9667b2786f8ae850a1 100644 --- a/substrate/frame/whitelist/src/lib.rs +++ b/substrate/frame/whitelist/src/lib.rs @@ -44,12 +44,11 @@ use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, ensure, - traits::{Hash as PreimageHash, QueryPreimage, StorePreimage}, + traits::{QueryPreimage, StorePreimage}, weights::Weight, - Hashable, }; use scale_info::TypeInfo; -use sp_runtime::traits::Dispatchable; +use sp_runtime::traits::{Dispatchable, Hash}; use sp_std::prelude::*; pub use pallet::*; @@ -81,7 +80,7 @@ pub mod pallet { type DispatchWhitelistedOrigin: EnsureOrigin; /// The handler of pre-images. - type Preimages: QueryPreimage + StorePreimage; + type Preimages: QueryPreimage + StorePreimage; /// The weight information for this pallet. type WeightInfo: WeightInfo; @@ -93,9 +92,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - CallWhitelisted { call_hash: PreimageHash }, - WhitelistedCallRemoved { call_hash: PreimageHash }, - WhitelistedCallDispatched { call_hash: PreimageHash, result: DispatchResultWithPostInfo }, + CallWhitelisted { call_hash: T::Hash }, + WhitelistedCallRemoved { call_hash: T::Hash }, + WhitelistedCallDispatched { call_hash: T::Hash, result: DispatchResultWithPostInfo }, } #[pallet::error] @@ -113,14 +112,13 @@ pub mod pallet { } #[pallet::storage] - pub type WhitelistedCall = - StorageMap<_, Twox64Concat, PreimageHash, (), OptionQuery>; + pub type WhitelistedCall = StorageMap<_, Twox64Concat, T::Hash, (), OptionQuery>; #[pallet::call] impl Pallet { #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::whitelist_call())] - pub fn whitelist_call(origin: OriginFor, call_hash: PreimageHash) -> DispatchResult { + pub fn whitelist_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { T::WhitelistOrigin::ensure_origin(origin)?; ensure!( @@ -138,10 +136,7 @@ pub mod pallet { #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::remove_whitelisted_call())] - pub fn remove_whitelisted_call( - origin: OriginFor, - call_hash: PreimageHash, - ) -> DispatchResult { + pub fn remove_whitelisted_call(origin: OriginFor, call_hash: T::Hash) -> DispatchResult { T::WhitelistOrigin::ensure_origin(origin)?; WhitelistedCall::::take(call_hash).ok_or(Error::::CallIsNotWhitelisted)?; @@ -160,7 +155,7 @@ pub mod pallet { )] pub fn dispatch_whitelisted_call( origin: OriginFor, - call_hash: PreimageHash, + call_hash: T::Hash, call_encoded_len: u32, call_weight_witness: Weight, ) -> DispatchResultWithPostInfo { @@ -206,7 +201,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::DispatchWhitelistedOrigin::ensure_origin(origin)?; - let call_hash = call.blake2_256().into(); + let call_hash = T::Hashing::hash_of(&call).into(); ensure!( WhitelistedCall::::contains_key(call_hash), @@ -227,10 +222,7 @@ impl Pallet { /// Clean whitelisting/preimage and dispatch call. /// /// Return the call actual weight of the dispatched call if there is some. - fn clean_and_dispatch( - call_hash: PreimageHash, - call: ::RuntimeCall, - ) -> Option { + fn clean_and_dispatch(call_hash: T::Hash, call: ::RuntimeCall) -> Option { WhitelistedCall::::remove(call_hash); T::Preimages::unrequest(&call_hash); diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 71f1ff95d555c2217a341655ecaad809bc7ca01d..25c87b5d0a4dfa660786799dd4fd9beca9f3c1bf 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.38", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 74cfa0980623b0dd14c029c520093bd775f4da4d..e439a796e28d451ac47f7ed9858591b02dd50d7f 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -38,7 +38,7 @@ use syn::{ Attribute, Ident, ImplItem, ItemImpl, LitInt, LitStr, Path, Signature, Type, TypePath, }; -use std::collections::HashSet; +use std::collections::HashMap; /// The structure used for parsing the runtime api implementations. struct RuntimeApiImpls { @@ -726,7 +726,7 @@ fn populate_runtime_api_versions( fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { let mut result = Vec::::with_capacity(impls.len()); let mut sections = Vec::::with_capacity(impls.len()); - let mut processed_traits = HashSet::new(); + let mut processed_traits = HashMap::new(); let c = generate_crate_access(); @@ -746,13 +746,17 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { .ident; let span = trait_.span(); - if !processed_traits.insert(trait_) { - return Err(Error::new( + if let Some(other_span) = processed_traits.insert(trait_, span) { + let mut error = Error::new( span, "Two traits with the same name detected! \ The trait name is used to generate its ID. \ Please rename one trait at the declaration!", - )) + ); + + error.combine(Error::new(other_span, "First trait implementation.")); + + return Err(error) } let id: Path = parse_quote!( #path ID ); diff --git a/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.stderr b/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.stderr index 9e014e3ea821a192e6a6af64c45a23022c67a6f3..2197bbc99cfb1dcd4cd76c627a6280882c5517e2 100644 --- a/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_two_traits_with_same_name.stderr @@ -3,3 +3,9 @@ error: Two traits with the same name detected! The trait name is used to generat | 41 | impl second::Api for Runtime { | ^^^ + +error: First trait implementation. + --> tests/ui/impl_two_traits_with_same_name.rs:37:13 + | +37 | impl self::Api for Runtime { + | ^^^ diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index e848f280f5d8f1c7445aa6129dfc8796e48327b1..700f5160c221d7d555de74343be328f872ca7d84 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -6,7 +6,7 @@ description = "Primitives for Sassafras consensus" edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" +repository = "https://github.com/paritytech/polkadot-sdk/" documentation = "https://docs.rs/sp-consensus-sassafras" readme = "README.md" publish = false @@ -18,12 +18,12 @@ targets = ["x86_64-unknown-linux-gnu"] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.163", default-features = false, features = ["derive"], optional = true } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } -sp-application-crypto = { version = "23.0.0", default-features = false, path = "../../application-crypto", features = ["bandersnatch-experimental"] } -sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" } -sp-core = { version = "21.0.0", default-features = false, path = "../../core", features = ["bandersnatch-experimental"] } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../runtime" } -sp-std = { version = "8.0.0", default-features = false, path = "../../std" } +sp-api = { default-features = false, path = "../../api" } +sp-application-crypto = { default-features = false, path = "../../application-crypto", features = ["bandersnatch-experimental"] } +sp-consensus-slots = { default-features = false, path = "../slots" } +sp-core = { default-features = false, path = "../../core", features = ["bandersnatch-experimental"] } +sp-runtime = { default-features = false, path = "../../runtime" } +sp-std = { default-features = false, path = "../../std" } [features] default = [ "std" ] diff --git a/substrate/primitives/consensus/sassafras/README.md b/substrate/primitives/consensus/sassafras/README.md index 5024d1bf700dc7e48f55b40bc346ed76f5ed9862..b0f3685494e4e3eb8b68bf15318960f532fe22ce 100644 --- a/substrate/primitives/consensus/sassafras/README.md +++ b/substrate/primitives/consensus/sassafras/README.md @@ -7,6 +7,6 @@ to significant changes. Depends on upstream experimental feature: `bandersnatch-experimental`. -These structs were mostly extracted from the main SASSAFRAS protocol PR: https://github.com/paritytech/substrate/pull/11879. +These structs were mostly extracted from the main SASSAFRAS protocol PR: https://github.com/paritytech/polkadot-sdk/pull/1336. Tracking issue: https://github.com/paritytech/polkadot-sdk/issues/41 diff --git a/substrate/primitives/consensus/slots/src/lib.rs b/substrate/primitives/consensus/slots/src/lib.rs index 30bb42e2c7589094147f6ba2732e8c587c106302..a299ce395ea4fa79dd95bd2b9b9446e537983dd1 100644 --- a/substrate/primitives/consensus/slots/src/lib.rs +++ b/substrate/primitives/consensus/slots/src/lib.rs @@ -24,7 +24,7 @@ use scale_info::TypeInfo; use sp_timestamp::Timestamp; /// Unit type wrapper that represents a slot. -#[derive(Debug, Encode, MaxEncodedLen, Decode, Eq, Clone, Copy, Default, Ord, TypeInfo)] +#[derive(Debug, Encode, MaxEncodedLen, Decode, Eq, Clone, Copy, Default, Ord, Hash, TypeInfo)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Slot(u64); @@ -44,6 +44,26 @@ impl core::ops::Add for Slot { } } +impl core::ops::Sub for Slot { + type Output = Self; + + fn sub(self, other: Self) -> Self { + Self(self.0 - other.0) + } +} + +impl core::ops::AddAssign for Slot { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0 + } +} + +impl core::ops::SubAssign for Slot { + fn sub_assign(&mut self, rhs: Self) { + self.0 -= rhs.0 + } +} + impl core::ops::Add for Slot { type Output = Self; diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 9f1f0127d7cdcb365810c4c7351aa55fdafc2081..b9607eadb583e6b54324a8270c4770866614763d 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -57,7 +57,7 @@ sp-runtime-interface = { path = "../runtime-interface", default-features = false # bls crypto w3f-bls = { version = "0.1.3", default-features = false, optional = true} # bandersnatch crypto -bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "f4fe253", default-features = false, optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "4b09416", default-features = false, optional = true } [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index fce09b452e5d9bc31873adf69fba246819cbe51e..187b5559b931c27df9613b33232426fe77fe8bf0 100644 --- a/substrate/primitives/core/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -17,5 +17,5 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "parsing"] } +syn = { version = "2.0.38", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false} diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 832ef6c77bb3dbb71e94200e27a0e7379510769c..78b7f12f9ffd4c5ce9faacb6990f80e091994cf7 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -60,15 +60,7 @@ const PREOUT_SERIALIZED_LEN: usize = 33; // // This size is dependent on the ring domain size and the actual value // is equal to the SCALE encoded size of the `KZG` backend. -// -// Some values: -// ring_size → ~serialized_size -// 512 → 74 KB -// 1024 → 147 KB -// 2048 → 295 KB -// NOTE: This is quite big but looks like there is an upcoming fix -// in the backend. -const RING_CONTEXT_SERIALIZED_LEN: usize = 147748; +const RING_CONTEXT_SERIALIZED_LEN: usize = 147716; /// Bandersnatch public key. #[cfg_attr(feature = "full_crypto", derive(Hash))] @@ -538,10 +530,7 @@ pub mod vrf { #[cfg(feature = "full_crypto")] impl Pair { fn vrf_sign_gen(&self, data: &VrfSignData) -> VrfSignature { - let ios = core::array::from_fn(|i| { - let input = data.inputs[i].0.clone(); - self.secret.vrf_inout(input) - }); + let ios = core::array::from_fn(|i| self.secret.vrf_inout(data.inputs[i].0)); let thin_signature: ThinVrfSignature = self.secret.sign_thin_vrf(data.transcript.clone(), &ios); @@ -567,7 +556,7 @@ pub mod vrf { input: &VrfInput, ) -> [u8; N] { let transcript = Transcript::new_labeled(context); - let inout = self.secret.vrf_inout(input.0.clone()); + let inout = self.secret.vrf_inout(input.0); inout.vrf_output_bytes(transcript) } } @@ -583,7 +572,7 @@ pub mod vrf { }; let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| signature.outputs[i].0.clone()); + core::array::from_fn(|i| signature.outputs[i].0); // Deserialize only the proof, the rest has already been deserialized // This is another hack used because backend signature type is generic over @@ -596,7 +585,7 @@ pub mod vrf { }; let signature = ThinVrfSignature { proof, preouts }; - let inputs = data.inputs.iter().map(|i| i.0.clone()); + let inputs = data.inputs.iter().map(|i| i.0); public.verify_thin_vrf(data.transcript.clone(), inputs, &signature).is_ok() } @@ -610,8 +599,7 @@ pub mod vrf { input: &VrfInput, ) -> [u8; N] { let transcript = Transcript::new_labeled(context); - let inout = - bandersnatch_vrfs::VrfInOut { input: input.0.clone(), preoutput: self.0.clone() }; + let inout = bandersnatch_vrfs::VrfInOut { input: input.0, preoutput: self.0 }; inout.vrf_output_bytes(transcript) } } @@ -733,10 +721,7 @@ pub mod ring_vrf { data: &VrfSignData, prover: &RingProver, ) -> RingVrfSignature { - let ios = core::array::from_fn(|i| { - let input = data.inputs[i].0.clone(); - self.secret.vrf_inout(input) - }); + let ios = core::array::from_fn(|i| self.secret.vrf_inout(data.inputs[i].0)); let ring_signature: bandersnatch_vrfs::RingVrfSignature = bandersnatch_vrfs::RingProver { ring_prover: prover, secret: &self.secret } @@ -792,12 +777,12 @@ pub mod ring_vrf { }; let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| self.outputs[i].0.clone()); + core::array::from_fn(|i| self.outputs[i].0); let signature = bandersnatch_vrfs::RingVrfSignature { proof: vrf_signature.proof, preouts }; - let inputs = data.inputs.iter().map(|i| i.0.clone()); + let inputs = data.inputs.iter().map(|i| i.0); bandersnatch_vrfs::RingVerifier(verifier) .verify_ring_vrf(data.transcript.clone(), inputs, &signature) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 951aa1828ea5136700ca8ee91ee1693e4b6b1e0a..8ce6eb166f868b73447b922fbe3c0434e54baa86 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -17,7 +17,7 @@ //! Simple BLS (Boneh–Lynn–Shacham) Signature API. -#[cfg(feature = "std")] +#[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom}; #[cfg(feature = "full_crypto")] @@ -28,8 +28,12 @@ use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -#[cfg(feature = "std")] + +#[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(all(not(feature = "std"), feature = "serde"))] +use sp_std::alloc::{format, string::String}; + use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes, TinyBLS381}; #[cfg(feature = "full_crypto")] use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey}; @@ -39,6 +43,7 @@ use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// BLS-377 specialized types pub mod bls377 { + pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE}; use crate::crypto::CryptoTypeId; use w3f_bls::TinyBLS377; @@ -60,6 +65,7 @@ pub mod bls377 { /// BLS-381 specialized types pub mod bls381 { + pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE}; use crate::crypto::CryptoTypeId; use w3f_bls::TinyBLS381; @@ -83,17 +89,17 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl BlsBound for T {} -// Secret key serialized size +/// Secret key serialized size #[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Public key serialized size -const PUBLIC_KEY_SERIALIZED_SIZE: usize = +/// Public key serialized size +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Signature serialized size -const SIGNATURE_SERIALIZED_SIZE: usize = +/// Signature serialized size +pub const SIGNATURE_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; /// A secret seed. @@ -258,7 +264,7 @@ impl sp_std::fmt::Debug for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Public { fn serialize(&self, serializer: S) -> Result where @@ -268,7 +274,7 @@ impl Serialize for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T: BlsBound> Deserialize<'de> for Public { fn deserialize(deserializer: D) -> Result where @@ -317,6 +323,10 @@ impl sp_std::hash::Hash for Signature { } } +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} + impl TryFrom<&[u8]> for Signature { type Error = (); @@ -330,7 +340,7 @@ impl TryFrom<&[u8]> for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where @@ -340,7 +350,7 @@ impl Serialize for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where @@ -444,10 +454,9 @@ impl TraitPair for Pair { path: Iter, _seed: Option, ) -> Result<(Self, Option), DeriveError> { - let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = - self.0.secret.to_bytes().try_into().expect( - "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size", - ); + let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = self.0.secret.to_bytes().try_into().expect( + "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size; qed", + ); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -529,11 +538,10 @@ mod test { ); } - // Only passes if the seed = (seed mod ScalarField) #[test] fn seed_and_derive_should_work() { let seed = array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00", + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", ); let pair = Pair::from_seed(&seed); // we are using hash to field so this is not going to work @@ -543,7 +551,7 @@ mod test { assert_eq!( derived.to_raw_vec(), array_bytes::hex2array_unchecked::<_, 32>( - "a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d" + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" ) ); } diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 8c7d98f00cd89d3c3b65a3927bfd83d5e1136154..ccb61c12f3216fdffc657572c2489a91ce1f3a11 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -630,6 +630,13 @@ impl sp_std::str::FromStr for AccountId32 { } } +/// Creates an [`AccountId32`] from the input, which should contain at least 32 bytes. +impl FromEntropy for AccountId32 { + fn from_entropy(input: &mut impl codec::Input) -> Result { + Ok(AccountId32::new(FromEntropy::from_entropy(input)?)) + } +} + #[cfg(feature = "std")] pub use self::dummy::*; @@ -1154,6 +1161,8 @@ pub mod key_types { pub const STAKING: KeyTypeId = KeyTypeId(*b"stak"); /// A key type for signing statements pub const STATEMENT: KeyTypeId = KeyTypeId(*b"stmt"); + /// Key type for Mixnet module, used to sign key-exchange public keys. Identified as `mixn`. + pub const MIXNET: KeyTypeId = KeyTypeId(*b"mixn"); /// A key type ID useful for tests. pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } @@ -1171,6 +1180,13 @@ impl FromEntropy for bool { } } +/// Create the unit type for any given input. +impl FromEntropy for () { + fn from_entropy(_: &mut impl codec::Input) -> Result { + Ok(()) + } +} + macro_rules! impl_from_entropy { ($type:ty , $( $others:tt )*) => { impl_from_entropy!($type); @@ -1197,7 +1213,7 @@ macro_rules! impl_from_entropy_base { [$type; 17], [$type; 18], [$type; 19], [$type; 20], [$type; 21], [$type; 22], [$type; 23], [$type; 24], [$type; 25], [$type; 26], [$type; 27], [$type; 28], [$type; 29], [$type; 30], [$type; 31], [$type; 32], [$type; 36], [$type; 40], [$type; 44], [$type; 48], [$type; 56], [$type; 64], [$type; 72], [$type; 80], - [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 192], [$type; 224], [$type; 256] + [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 177], [$type; 192], [$type; 224], [$type; 256] ); } } diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 05bc679386c3dcf8741ade5221bc4b714693c138..603fa515a30e8b7cefc1093daa5905ccfac1320c 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -50,6 +50,12 @@ use sp_std::vec::Vec; /// An identifier used to match public keys against ecdsa keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); +/// The byte length of public key +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; + +/// The byte length of signature +pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; + /// A secret seed (which is bytewise essentially equivalent to a SecretKey). /// /// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. @@ -71,11 +77,11 @@ type Seed = [u8; 32]; PartialOrd, Ord, )] -pub struct Public(pub [u8; 33]); +pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); impl crate::crypto::FromEntropy for Public { fn from_entropy(input: &mut impl codec::Input) -> Result { - let mut result = Self([0u8; 33]); + let mut result = Self([0u8; PUBLIC_KEY_SERIALIZED_SIZE]); input.read(&mut result.0[..])?; Ok(result) } @@ -86,7 +92,7 @@ impl Public { /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; 33]) -> Self { + pub fn from_raw(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Self(data) } @@ -109,7 +115,7 @@ impl Public { } impl ByteArray for Public { - const LEN: usize = 33; + const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; } impl TraitPublic for Public {} @@ -148,8 +154,8 @@ impl From for Public { } } -impl UncheckedFrom<[u8; 33]> for Public { - fn unchecked_from(x: [u8; 33]) -> Self { +impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public(x) } } @@ -198,14 +204,18 @@ impl<'de> Deserialize<'de> for Public { /// A signature (a 512-bit value, plus 8 bits for recovery ID). #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] -pub struct Signature(pub [u8; 65]); +pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); + +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() == 65 { - let mut inner = [0u8; 65]; + if data.len() == SIGNATURE_SERIALIZED_SIZE { + let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); Ok(Signature(inner)) } else { @@ -239,7 +249,7 @@ impl<'de> Deserialize<'de> for Signature { impl Clone for Signature { fn clone(&self) -> Self { - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(&self.0[..]); Signature(r) } @@ -247,18 +257,18 @@ impl Clone for Signature { impl Default for Signature { fn default() -> Self { - Signature([0u8; 65]) + Signature([0u8; SIGNATURE_SERIALIZED_SIZE]) } } -impl From for [u8; 65] { - fn from(v: Signature) -> [u8; 65] { +impl From for [u8; SIGNATURE_SERIALIZED_SIZE] { + fn from(v: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { v.0 } } -impl AsRef<[u8; 65]> for Signature { - fn as_ref(&self) -> &[u8; 65] { +impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { &self.0 } } @@ -287,8 +297,8 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; 65]> for Signature { - fn unchecked_from(data: [u8; 65]) -> Signature { +impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } } @@ -298,7 +308,7 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; 65]) -> Signature { + pub fn from_raw(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } @@ -307,10 +317,10 @@ impl Signature { /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! pub fn from_slice(data: &[u8]) -> Option { - if data.len() != 65 { + if data.len() != SIGNATURE_SERIALIZED_SIZE { return None } - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(data); Some(Signature(r)) } @@ -473,7 +483,7 @@ impl Pair { pub fn verify_deprecated>(sig: &Signature, message: M, pubkey: &Public) -> bool { let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let parse_signature_overflowing = |x: [u8; 65]| { + let parse_signature_overflowing = |x: [u8; SIGNATURE_SERIALIZED_SIZE]| { let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?; let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?; Some((sig, rid)) @@ -726,7 +736,7 @@ mod test { let signature = pair.sign(&message[..]); let serialized_signature = serde_json::to_string(&signature).unwrap(); // Signature is 65 bytes, so 130 chars + 2 quote chars - assert_eq!(serialized_signature.len(), 132); + assert_eq!(serialized_signature.len(), SIGNATURE_SERIALIZED_SIZE * 2 + 2); let signature = serde_json::from_str(&serialized_signature).unwrap(); assert!(Pair::verify(&signature, &message[..], &pair.public())); } diff --git a/substrate/primitives/core/src/hexdisplay.rs b/substrate/primitives/core/src/hexdisplay.rs index 30e045dfc52acae9bbd22fecd4a2c8a4edbae979..72bb24a186e54dbfb4deecd105065dc2b63d332d 100644 --- a/substrate/primitives/core/src/hexdisplay.rs +++ b/substrate/primitives/core/src/hexdisplay.rs @@ -96,7 +96,7 @@ macro_rules! impl_non_endians { impl_non_endians!( [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], [u8; 48], [u8; 56], - [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144] + [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144], [u8; 177] ); /// Format into ASCII + # + hex, suitable for storage key preimages. diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 3a0e1f33f16c9d5fdbded144895fa1aa38bf3d73..75b84c89ae68e70cb9aac70dc23ff52d38450b37 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -66,6 +66,7 @@ pub mod hash; #[cfg(feature = "std")] mod hasher; pub mod offchain; +pub mod paired_crypto; pub mod sr25519; pub mod testing; #[cfg(feature = "std")] diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs new file mode 100644 index 0000000000000000000000000000000000000000..355fc690779f84140a47a8c6b3155d976ced531a --- /dev/null +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -0,0 +1,662 @@ +// 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. + +//! API for using a pair of crypto schemes together. + +#[cfg(feature = "serde")] +use crate::crypto::Ss58Codec; +use crate::crypto::{ByteArray, CryptoType, Derive, Public as PublicT, UncheckedFrom}; +#[cfg(feature = "full_crypto")] +use crate::crypto::{DeriveError, DeriveJunction, Pair as PairT, SecretStringError}; + +#[cfg(feature = "full_crypto")] +use sp_std::vec::Vec; + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "serde")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(all(not(feature = "std"), feature = "serde"))] +use sp_std::alloc::{format, string::String}; + +use sp_runtime_interface::pass_by::PassByInner; +use sp_std::convert::TryFrom; + +/// ECDSA and BLS12-377 paired crypto scheme +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_n_bls377 { + use crate::{bls377, crypto::CryptoTypeId, ecdsa}; + + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + const PUBLIC_KEY_LEN: usize = + ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + bls377::PUBLIC_KEY_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = + ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; + + /// (ECDSA, BLS12-377) key-pair pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; + /// (ECDSA, BLS12-377) public key pair. + pub type Public = super::Public; + /// (ECDSA, BLS12-377) signature pair. + pub type Signature = super::Signature; + + impl super::CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + impl super::CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl super::CryptoType for Pair { + type Pair = Pair; + } +} + +/// Secure seed length. +/// +/// Currently only supporting sub-schemes whose seed is a 32-bytes array. +#[cfg(feature = "full_crypto")] +const SECURE_SEED_LEN: usize = 32; + +/// A secret seed. +/// +/// It's not called a "secret key" because ring doesn't expose the secret keys +/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we +/// will need it later (such as for HDKD). +#[cfg(feature = "full_crypto")] +type Seed = [u8; SECURE_SEED_LEN]; + +/// A public key. +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +pub struct Public([u8; LEFT_PLUS_RIGHT_LEN]); + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +impl ByteArray for Public { + const LEN: usize = LEFT_PLUS_RIGHT_LEN; +} + +impl TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); + Ok(Public(inner)) + } +} + +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> + for Public +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl PassByInner for Public { + type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; + + fn into_inner(self) -> Self::Inner { + self.0 + } + + fn inner(&self) -> &Self::Inner { + &self.0 + } + + fn from_inner(inner: Self::Inner) -> Self { + Self(inner) + } +} + +#[cfg(feature = "full_crypto")] +impl< + LeftPair: PairT, + RightPair: PairT, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + const SIGNATURE_LEN: usize, + > From> + for Public +where + Pair: + PairT>, +{ + fn from(x: Pair) -> Self { + x.public() + } +} + +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> + for Public +{ + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + Public(data) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public +where + Public: CryptoType, +{ + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +impl sp_std::fmt::Debug for Public +where + Public: CryptoType, + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Public +where + Public: CryptoType, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_ss58check()) + } +} + +#[cfg(feature = "serde")] +impl<'de, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public +where + Public: CryptoType, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +impl PublicT for Public where + Public: CryptoType +{ +} + +impl Derive for Public {} + +/// Trait characterizing a signature which could be used as individual component of an +/// `paired_crypto:Signature` pair. +pub trait SignatureBound: ByteArray {} + +impl SignatureBound for T {} + +/// A pair of signatures of different types +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +pub struct Signature([u8; LEFT_PLUS_RIGHT_LEN]); + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +impl ByteArray for Signature { + const LEN: usize = LEFT_PLUS_RIGHT_LEN; +} + +impl TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); + Ok(Signature(inner)) + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +#[cfg(feature = "serde")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&array_bytes::bytes2hex("", self)) + } +} + +#[cfg(feature = "serde")] +impl<'de, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let bytes = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + Signature::::try_from(bytes.as_ref()).map_err(|e| { + de::Error::custom(format!("Error converting deserialized data into signature: {:?}", e)) + }) + } +} + +impl From> + for [u8; LEFT_PLUS_RIGHT_LEN] +{ + fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { + signature.0 + } +} + +impl sp_std::fmt::Debug for Signature +where + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +{ + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + Signature(data) + } +} + +/// A key pair. +#[cfg(feature = "full_crypto")] +#[derive(Clone)] +pub struct Pair< + LeftPair: PairT, + RightPair: PairT, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, +> { + left: LeftPair, + right: RightPair, +} + +#[cfg(feature = "full_crypto")] +impl< + LeftPair: PairT, + RightPair: PairT, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > PairT for Pair +where + Pair: CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, + Public: CryptoType, + LeftPair::Seed: From + Into, + RightPair::Seed: From + Into, +{ + type Seed = Seed; + type Public = Public; + type Signature = Signature; + + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != SECURE_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let left = LeftPair::from_seed_slice(&seed_slice)?; + let right = RightPair::from_seed_slice(&seed_slice)?; + Ok(Pair { left, right }) + } + + /// Derive a child key from a series of given junctions. + /// + /// Note: if the `LeftPair` and `RightPair` crypto schemes differ in + /// seed derivation, `derive` will drop the seed in the return. + fn derive>( + &self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), DeriveError> { + let path: Vec<_> = path.collect(); + + let left = self.left.derive(path.iter().cloned(), seed.map(|s| s.into()))?; + let right = self.right.derive(path.into_iter(), seed.map(|s| s.into()))?; + + let seed = match (left.1, right.1) { + (Some(l), Some(r)) if l.as_ref() == r.as_ref() => Some(l.into()), + _ => None, + }; + + Ok((Self { left: left.0, right: right.0 }, seed)) + } + + fn public(&self) -> Self::Public { + let mut raw = [0u8; PUBLIC_KEY_LEN]; + let left_pub = self.left.public(); + let right_pub = self.right.public(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); + raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); + Self::Public::unchecked_from(raw) + } + + fn sign(&self, message: &[u8]) -> Self::Signature { + let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + raw[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref()); + raw[LeftPair::Signature::LEN..].copy_from_slice(self.right.sign(message).as_ref()); + Self::Signature::unchecked_from(raw) + } + + fn verify>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool { + let Ok(left_pub) = public.0[..LeftPair::Public::LEN].try_into() else { return false }; + let Ok(left_sig) = sig.0[0..LeftPair::Signature::LEN].try_into() else { return false }; + if !LeftPair::verify(&left_sig, message.as_ref(), &left_pub) { + return false + } + + let Ok(right_pub) = public.0[LeftPair::Public::LEN..PUBLIC_KEY_LEN].try_into() else { + return false + }; + let Ok(right_sig) = sig.0[LeftPair::Signature::LEN..].try_into() else { return false }; + RightPair::verify(&right_sig, message.as_ref(), &right_pub) + } + + /// Get the seed/secret key for each key and then concatenate them. + fn to_raw_vec(&self) -> Vec { + let mut raw = self.left.to_raw_vec(); + raw.extend(self.right.to_raw_vec()); + raw + } +} + +// Test set exercising the (ECDSA, BLS12-377) implementation +#[cfg(all(test, feature = "bls-experimental"))] +mod test { + use super::*; + use crate::crypto::DEV_PHRASE; + use ecdsa_n_bls377::{Pair, Signature}; + + use crate::{bls377, ecdsa}; + #[test] + + fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() { + assert_eq!( + ::Public::LEN, + ::Public::LEN + ::Public::LEN + ); + assert_eq!( + ::Signature::LEN, + ::Signature::LEN + ::Signature::LEN + ); + } + + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) + .unwrap() + .public(), + ); + } + + #[test] + fn seed_and_derive_should_work() { + let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); + let pair = Pair::from_seed(&seed_for_right_and_left); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.to_raw_vec(), + [ + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61" + ), + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" + ) + ] + .concat() + ); + } + + #[test] + fn test_vector_should_work() { + let seed_left_and_right: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); + let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400"), + ), + ); + let message = b""; + let signature = + array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b" + ); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + ), + ), + ); + let message = b""; + let signature = + array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c" + ); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + #[test] + fn seeded_pair_should_work() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + array_bytes::hex2array_unchecked("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + ), + ); + let message = + array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn signature_serialization_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.0, serialized_signature); + // Signature is 177 bytes, hexify * 2 + 2 quote charsy + assert_eq!(serialized_signature.len(), 356); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } + + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } + + #[test] + fn encode_and_decode_public_key_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let encoded_public = public.encode(); + let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); + assert_eq!(public, decoded_public) + } + + #[test] + fn encode_and_decode_signature_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + let encoded_signature = signature.encode(); + let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); + assert_eq!(signature, decoded_signature) + } +} diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 15a6e85abb9675149bad87cfc769d9a8d8b89f7e..e091385071c9c3e62f77f817952d5e46dd42a1e7 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "sp-crypto-ec-utils" version = "0.4.0" authors.workspace = true -description = "Host function interface for common elliptic curve operations in Substrate runtimes" +description = "Host functions for common Arkworks elliptic curve operations" edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" @@ -12,51 +12,26 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ark-serialize = { version = "0.4.2", default-features = false } -ark-ff = { version = "0.4.2", default-features = false } ark-ec = { version = "0.4.2", default-features = false } -ark-std = { version = "0.4.0", default-features = false } ark-bls12-377 = { version = "0.4.0", features = ["curve"], default-features = false } ark-bls12-381 = { version = "0.4.0", features = ["curve"], default-features = false } ark-bw6-761 = { version = "0.4.0", default-features = false } ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false } ark-ed-on-bls12-377 = { version = "0.4.0", default-features = false } -sp-std = { path = "../../std", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -ark-scale = { version = "0.0.10", features = ["hazmat"], default-features = false } +ark-scale = { version = "0.0.11", features = ["hazmat"], default-features = false } sp-runtime-interface = { path = "../../runtime-interface", default-features = false} - -[dev-dependencies] -sp-io = { path = "../../io", default-features = false } -ark-algebra-test-templates = { version = "0.4.2", default-features = false } -sp-ark-models = { version = "0.4.1-beta", default-features = false } -sp-ark-bls12-377 = { version = "0.4.1-beta", default-features = false } -sp-ark-bls12-381 = { version = "0.4.1-beta", default-features = false } -sp-ark-bw6-761 = { version = "0.4.1-beta", default-features = false } -sp-ark-ed-on-bls12-377 = { version = "0.4.1-beta", default-features = false } -sp-ark-ed-on-bls12-381-bandersnatch = { version = "0.4.1-beta", default-features = false } +sp-std = { path = "../../std", default-features = false } [features] default = [ "std" ] std = [ - "ark-algebra-test-templates/std", "ark-bls12-377/std", "ark-bls12-381/std", "ark-bw6-761/std", "ark-ec/std", "ark-ed-on-bls12-377/std", "ark-ed-on-bls12-381-bandersnatch/std", - "ark-ff/std", "ark-scale/std", - "ark-serialize/std", - "ark-std/std", - "codec/std", - "sp-ark-bls12-377/std", - "sp-ark-bls12-381/std", - "sp-ark-bw6-761/std", - "sp-ark-ed-on-bls12-377/std", - "sp-ark-ed-on-bls12-381-bandersnatch/std", - "sp-io/std", "sp-runtime-interface/std", "sp-std/std", ] diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs deleted file mode 100644 index 78f20297299b08492c71dcedec5f3d43a695afd4..0000000000000000000000000000000000000000 --- a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs +++ /dev/null @@ -1,103 +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. - -//! Support functions for bls12_377 to improve the performance of -//! multi_miller_loop, final_exponentiation, msm's and projective -//! multiplications by host function calls - -use crate::utils::{ - final_exponentiation_generic, msm_sw_generic, mul_projective_generic, multi_miller_loop_generic, -}; -use ark_bls12_377::{g1, g2, Bls12_377}; -use sp_std::vec::Vec; - -/// Compute a multi miller loop through arkworks -pub fn multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - multi_miller_loop_generic::(a, b) -} - -/// Compute a final exponentiation through arkworks -pub fn final_exponentiation(target: Vec) -> Result, ()> { - final_exponentiation_generic::(target) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G1. -pub fn msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G2. -pub fn msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a projective scalar multiplication for short_weierstrass -/// through arkworks on G1. -pub fn mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -/// Compute a projective scalar multiplication for short_weierstrass -/// through arkworks on G2. -pub fn mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_algebra_test_templates::*; - use sp_ark_bls12_377::{ - Bls12_377 as Bls12_377Host, G1Projective as G1ProjectiveHost, - G2Projective as G2ProjectiveHost, HostFunctions, - }; - - #[derive(PartialEq, Eq)] - struct Host; - - impl HostFunctions for Host { - fn bls12_377_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_multi_miller_loop(a, b) - } - fn bls12_377_final_exponentiation(f12: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_final_exponentiation(f12) - } - fn bls12_377_msm_g1(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_msm_g1(bases, bigints) - } - fn bls12_377_msm_g2(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_msm_g2(bases, bigints) - } - fn bls12_377_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_mul_projective_g1(base, scalar) - } - fn bls12_377_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_377_mul_projective_g2(base, scalar) - } - } - - type Bls12_377 = Bls12_377Host; - type G1Projective = G1ProjectiveHost; - type G2Projective = G2ProjectiveHost; - - test_group!(g1; G1Projective; sw); - test_group!(g2; G2Projective; sw); - test_group!(pairing_output; ark_ec::pairing::PairingOutput; msm); - test_pairing!(pairing; super::Bls12_377); -} diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs deleted file mode 100644 index b2ec48a42fc53ee1b33f6ac87abce1d3df0a3a19..0000000000000000000000000000000000000000 --- a/substrate/primitives/crypto/ec-utils/src/bls12_381.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. - -//! Support functions for bls12_381 to improve the performance of -//! multi_miller_loop, final_exponentiation, msm's and projective -//! multiplications by host function calls - -use crate::utils::{ - final_exponentiation_generic, msm_sw_generic, mul_projective_generic, multi_miller_loop_generic, -}; -use ark_bls12_381::{g1, g2, Bls12_381}; -use sp_std::vec::Vec; - -/// Compute a multi miller loop through arkworks -pub fn multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - multi_miller_loop_generic::(a, b) -} - -/// Compute a final exponentiation through arkworks -pub fn final_exponentiation(target: Vec) -> Result, ()> { - final_exponentiation_generic::(target) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G1. -pub fn msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G2. -pub fn msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a projective scalar multiplication for short_weierstrass -/// through arkworks on G1. -pub fn mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -/// Compute a projective scalar multiplication for short_weierstrass -/// through arkworks on G2. -pub fn mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_algebra_test_templates::*; - use ark_ec::{AffineRepr, CurveGroup, Group}; - use ark_ff::{fields::Field, One, Zero}; - use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; - use ark_std::{rand::Rng, test_rng, vec, UniformRand}; - use sp_ark_bls12_381::{ - fq::Fq, fq2::Fq2, fr::Fr, Bls12_381 as Bls12_381Host, G1Affine as G1AffineHost, - G1Projective as G1ProjectiveHost, G2Affine as G2AffineHost, - G2Projective as G2ProjectiveHost, HostFunctions, - }; - use sp_ark_models::pairing::PairingOutput; - - #[derive(PartialEq, Eq)] - struct Host; - - impl HostFunctions for Host { - fn bls12_381_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_multi_miller_loop(a, b) - } - fn bls12_381_final_exponentiation(f12: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_final_exponentiation(f12) - } - fn bls12_381_msm_g1(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_msm_g1(bases, bigints) - } - fn bls12_381_msm_g2(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_msm_g2(bases, bigints) - } - fn bls12_381_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_mul_projective_g1(base, scalar) - } - fn bls12_381_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bls12_381_mul_projective_g2(base, scalar) - } - } - - type Bls12_381 = Bls12_381Host; - type G1Projective = G1ProjectiveHost; - type G2Projective = G2ProjectiveHost; - type G1Affine = G1AffineHost; - type G2Affine = G2AffineHost; - - test_group!(g1; G1Projective; sw); - test_group!(g2; G2Projective; sw); - test_group!(pairing_output; PairingOutput; msm); - test_pairing!(ark_pairing; super::Bls12_381); - - #[test] - fn test_g1_endomorphism_beta() { - assert!(sp_ark_bls12_381::g1::BETA.pow([3u64]).is_one()); - } - - #[test] - fn test_g1_subgroup_membership_via_endomorphism() { - let mut rng = test_rng(); - let generator = G1Projective::rand(&mut rng).into_affine(); - assert!(generator.is_in_correct_subgroup_assuming_on_curve()); - } - - #[test] - fn test_g1_subgroup_non_membership_via_endomorphism() { - let mut rng = test_rng(); - loop { - let x = Fq::rand(&mut rng); - let greatest = rng.gen(); - - if let Some(p) = G1Affine::get_point_from_x_unchecked(x, greatest) { - if !::is_zero(&p.mul_bigint(Fr::characteristic())) { - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - return - } - } - } - } - - #[test] - fn test_g2_subgroup_membership_via_endomorphism() { - let mut rng = test_rng(); - let generator = G2Projective::rand(&mut rng).into_affine(); - assert!(generator.is_in_correct_subgroup_assuming_on_curve()); - } - - #[test] - fn test_g2_subgroup_non_membership_via_endomorphism() { - let mut rng = test_rng(); - loop { - let x = Fq2::rand(&mut rng); - let greatest = rng.gen(); - - if let Some(p) = G2Affine::get_point_from_x_unchecked(x, greatest) { - if !::is_zero(&p.mul_bigint(Fr::characteristic())) { - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - return - } - } - } - } - - // Test vectors and macro adapted from https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs - macro_rules! test_vectors { - ($projective:ident, $affine:ident, $compress:expr, $expected:ident) => { - let mut e = $projective::zero(); - - let mut v = vec![]; - { - let mut expected = $expected; - for _ in 0..1000 { - let e_affine = $affine::from(e); - let mut serialized = vec![0u8; e.serialized_size($compress)]; - e_affine.serialize_with_mode(serialized.as_mut_slice(), $compress).unwrap(); - v.extend_from_slice(&serialized[..]); - - let mut decoded = serialized; - let len_of_encoding = decoded.len(); - (&mut decoded[..]).copy_from_slice(&expected[0..len_of_encoding]); - expected = &expected[len_of_encoding..]; - let decoded = - $affine::deserialize_with_mode(&decoded[..], $compress, Validate::Yes) - .unwrap(); - assert_eq!(e_affine, decoded); - - e += &$projective::generator(); - } - } - - assert_eq!(&v[..], $expected); - }; - } - - #[test] - fn g1_compressed_valid_test_vectors() { - let bytes: &'static [u8] = include_bytes!("test-data/g1_compressed_valid_test_vectors.dat"); - test_vectors!(G1Projective, G1Affine, Compress::Yes, bytes); - } - - #[test] - fn g1_uncompressed_valid_test_vectors() { - let bytes: &'static [u8] = - include_bytes!("test-data/g1_uncompressed_valid_test_vectors.dat"); - test_vectors!(G1Projective, G1Affine, Compress::No, bytes); - } - - #[test] - fn g2_compressed_valid_test_vectors() { - let bytes: &'static [u8] = include_bytes!("test-data/g2_compressed_valid_test_vectors.dat"); - test_vectors!(G2Projective, G2Affine, Compress::Yes, bytes); - } - - #[test] - fn g2_uncompressed_valid_test_vectors() { - let bytes: &'static [u8] = - include_bytes!("test-data/g2_uncompressed_valid_test_vectors.dat"); - test_vectors!(G2Projective, G2Affine, Compress::No, bytes); - } -} diff --git a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs deleted file mode 100644 index 4ad26fc54b1e0c13727f65dec83609853b9a8fce..0000000000000000000000000000000000000000 --- a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs +++ /dev/null @@ -1,103 +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. - -//! Support functions for bw6_761 to improve the performance of -//! multi_miller_loop, final_exponentiation, msm's and projective -//! multiplications by host function calls. - -use crate::utils::{ - final_exponentiation_generic, msm_sw_generic, mul_projective_generic, multi_miller_loop_generic, -}; -use ark_bw6_761::{g1, g2, BW6_761}; -use sp_std::vec::Vec; - -/// Compute a multi miller loop through arkworks -pub fn multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - multi_miller_loop_generic::(a, b) -} - -/// Compute a final exponentiation through arkworks -pub fn final_exponentiation(target: Vec) -> Result, ()> { - final_exponentiation_generic::(target) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G1. -pub fn msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks on G2. -pub fn msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a projective scalar multiplication for short_weierstrass through -/// arkworks on G1. -pub fn mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -/// Compute a projective scalar multiplication for short_weierstrass through -/// arkworks on G2. -pub fn mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_algebra_test_templates::*; - use sp_ark_bw6_761::{ - G1Projective as G1ProjectiveHost, G2Projective as G2ProjectiveHost, HostFunctions, - BW6_761 as BW6_761Host, - }; - - #[derive(PartialEq, Eq)] - struct Host; - - impl HostFunctions for Host { - fn bw6_761_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_multi_miller_loop(a, b) - } - fn bw6_761_final_exponentiation(f12: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_final_exponentiation(f12) - } - fn bw6_761_msm_g1(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_msm_g1(bases, bigints) - } - fn bw6_761_msm_g2(bases: Vec, bigints: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_msm_g2(bases, bigints) - } - fn bw6_761_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_mul_projective_g1(base, scalar) - } - fn bw6_761_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::bw6_761_mul_projective_g2(base, scalar) - } - } - - type BW6_761 = BW6_761Host; - type G1Projective = G1ProjectiveHost; - type G2Projective = G2ProjectiveHost; - - test_group!(g1; G1Projective; sw); - test_group!(g2; G2Projective; sw); - test_group!(pairing_output; ark_ec::pairing::PairingOutput; msm); - test_pairing!(pairing; super::BW6_761); -} diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs deleted file mode 100644 index e69dbd7984645918d946e48418a5c433114b5642..0000000000000000000000000000000000000000 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs +++ /dev/null @@ -1,56 +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. - -//! Support functions for ed_on_bls12_377 to improve the performance of -//! msm and projective multiplication by host function calls - -use crate::utils::{msm_te_generic, mul_projective_te_generic}; -use ark_ed_on_bls12_377::EdwardsConfig; -use sp_std::vec::Vec; - -/// Compute a multi scalar mulitplication for twisted_edwards through -/// arkworks. -pub fn msm(bases: Vec, scalars: Vec) -> Result, ()> { - msm_te_generic::(bases, scalars) -} - -/// Compute a projective scalar multiplication for twisted_edwards -/// through arkworks. -pub fn mul_projective(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_te_generic::(base, scalar) -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_algebra_test_templates::*; - use sp_ark_ed_on_bls12_377::{EdwardsProjective as EdwardsProjectiveHost, HostFunctions}; - - struct Host {} - - impl HostFunctions for Host { - fn ed_on_bls12_377_msm(bases: Vec, scalars: Vec) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_377_msm(bases, scalars) - } - fn ed_on_bls12_377_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_377_mul_projective(base, scalar) - } - } - - type EdwardsProjective = EdwardsProjectiveHost; - test_group!(te; EdwardsProjective; te); -} diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs deleted file mode 100644 index 7e9cd87e543d3731a4942f793787522c9677a9c2..0000000000000000000000000000000000000000 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs +++ /dev/null @@ -1,94 +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. - -//! Support functions for ed_on_bls12_381_bandersnatch to improve the -//! performance of msm' and projective multiplications by host function -//! calls. - -use crate::utils::{ - msm_sw_generic, msm_te_generic, mul_projective_generic, mul_projective_te_generic, -}; -use ark_ed_on_bls12_381_bandersnatch::BandersnatchConfig; -use sp_std::vec::Vec; - -/// Compute a multi scalar multiplication for short_weierstrass through -/// arkworks. -pub fn sw_msm(bases: Vec, scalars: Vec) -> Result, ()> { - msm_sw_generic::(bases, scalars) -} - -/// Compute a multi scalar mulitplication for twisted_edwards through -/// arkworks. -pub fn te_msm(bases: Vec, scalars: Vec) -> Result, ()> { - msm_te_generic::(bases, scalars) -} - -/// Compute a projective scalar multiplication for short_weierstrass -/// through arkworks. -pub fn sw_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_generic::(base, scalar) -} - -/// Compute a projective scalar multiplication for twisted_edwards -/// through arkworks. -pub fn te_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { - mul_projective_te_generic::(base, scalar) -} - -#[cfg(test)] -mod tests { - use super::*; - use ark_algebra_test_templates::*; - use sp_ark_ed_on_bls12_381_bandersnatch::{ - EdwardsProjective as EdwardsProjectiveHost, HostFunctions, SWProjective as SWProjectiveHost, - }; - - pub struct Host {} - - impl HostFunctions for Host { - fn ed_on_bls12_381_bandersnatch_te_msm( - bases: Vec, - scalars: Vec, - ) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_381_bandersnatch_te_msm(bases, scalars) - } - fn ed_on_bls12_381_bandersnatch_sw_msm( - bases: Vec, - scalars: Vec, - ) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_381_bandersnatch_sw_msm(bases, scalars) - } - fn ed_on_bls12_381_bandersnatch_te_mul_projective( - base: Vec, - scalar: Vec, - ) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_381_bandersnatch_te_mul_projective(base, scalar) - } - fn ed_on_bls12_381_bandersnatch_sw_mul_projective( - base: Vec, - scalar: Vec, - ) -> Result, ()> { - crate::elliptic_curves::ed_on_bls12_381_bandersnatch_sw_mul_projective(base, scalar) - } - } - - type EdwardsProjective = EdwardsProjectiveHost; - type SWProjective = SWProjectiveHost; - - test_group!(sw; SWProjective; sw); - test_group!(te; EdwardsProjective; te); -} diff --git a/substrate/primitives/crypto/ec-utils/src/lib.rs b/substrate/primitives/crypto/ec-utils/src/lib.rs index 22e24e61f7b357d338e4cd85f411eb8ae43e82e5..c5cc85077391c9165ef192e51ebf1e492b0cffba 100644 --- a/substrate/primitives/crypto/ec-utils/src/lib.rs +++ b/substrate/primitives/crypto/ec-utils/src/lib.rs @@ -15,251 +15,272 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The main elliptic curves trait, allowing Substrate to call into host functions -//! for operations on elliptic curves. +//! Elliptic Curves host functions which may be used to handle some of the *Arkworks* +//! computationally expensive operations. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +mod utils; + use sp_runtime_interface::runtime_interface; use sp_std::vec::Vec; +use utils::*; -pub mod bls12_377; -pub mod bls12_381; -pub mod bw6_761; -pub mod ed_on_bls12_377; -pub mod ed_on_bls12_381_bandersnatch; -mod utils; - -/// Interfaces for working with elliptic curves related types from within the runtime. -/// All type are (de-)serialized through the wrapper types from the ark-scale trait, -/// with ark_scale::{ArkScale, ArkScaleProjective}; +/// Interfaces for working with *Arkworks* elliptic curves related types from within the runtime. +/// +/// All types are (de-)serialized through the wrapper types from the `ark-scale` trait, +/// with `ark_scale::{ArkScale, ArkScaleProjective}`. +/// +/// `ArkScale`'s `Usage` generic parameter is expected to be set to `HOST_CALL`, which is +/// a shortcut for "not-validated" and "not-compressed". #[runtime_interface] pub trait EllipticCurves { - /// Compute a multi Miller loop for bls12_37 - /// Receives encoded: - /// a: ArkScale>> - /// b: ArkScale>> - /// Returns encoded: ArkScale>> + /// Pairing multi Miller loop for BLS12-377. + /// + /// - Receives encoded: + /// - `a: ArkScale>>`. + /// - `b: ArkScale>>`. + /// - Returns encoded: ArkScale>>. fn bls12_377_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - bls12_377::multi_miller_loop(a, b) + multi_miller_loop::(a, b) } - /// Compute a final exponentiation for bls12_377 - /// Receives encoded: ArkScale>> - /// Returns encoded: ArkScale>> - fn bls12_377_final_exponentiation(f12: Vec) -> Result, ()> { - bls12_377::final_exponentiation(f12) + /// Pairing final exponentiation for BLS12-377. + /// + /// - Receives encoded: `ArkScale>>`. + /// - Returns encoded: `ArkScale>>`. + fn bls12_377_final_exponentiation(f: Vec) -> Result, ()> { + final_exponentiation::(f) } - /// Compute a projective multiplication on G1 for bls12_377 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G1 for BLS12-377. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_377_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - bls12_377::mul_projective_g1(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a projective multiplication on G2 for bls12_377 - /// through arkworks on G2 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G2 for BLS12-377. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_377_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - bls12_377::mul_projective_g2(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a msm on G1 for bls12_377 - /// Receives encoded: - /// bases: ArkScale<&[ark_bls12_377::G1Affine]> - /// scalars: ArkScale<&[ark_bls12_377::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G1 for BLS12-377. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_bls12_377::G1Affine]>`. + /// - `scalars`: `ArkScale<&[ark_bls12_377::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_377_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { - bls12_377::msm_g1(bases, scalars) + msm_sw::(bases, scalars) } - /// Compute a msm on G2 for bls12_377 - /// Receives encoded: - /// bases: ArkScale<&[ark_bls12_377::G2Affine]> - /// scalars: ArkScale<&[ark_bls12_377::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G2 for BLS12-377. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_bls12_377::G2Affine]>`. + /// - `scalars`: `ArkScale<&[ark_bls12_377::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_377_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { - bls12_377::msm_g2(bases, scalars) + msm_sw::(bases, scalars) } - /// Compute a multi Miller loop on bls12_381 - /// Receives encoded: - /// a: ArkScale>> - /// b: ArkScale>> - /// Returns encoded: ArkScale>> + /// Pairing multi Miller loop for BLS12-381. + /// + /// - Receives encoded: + /// - `a`: `ArkScale>>`. + /// - `b`: `ArkScale>>`. + /// - Returns encoded: ArkScale>> fn bls12_381_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - bls12_381::multi_miller_loop(a, b) + multi_miller_loop::(a, b) } - /// Compute a final exponentiation on bls12_381 - /// Receives encoded: ArkScale>> - /// Returns encoded:ArkScale>> - fn bls12_381_final_exponentiation(f12: Vec) -> Result, ()> { - bls12_381::final_exponentiation(f12) + /// Pairing final exponentiation for BLS12-381. + /// + /// - Receives encoded: `ArkScale>>`. + /// - Returns encoded: `ArkScale>>`. + fn bls12_381_final_exponentiation(f: Vec) -> Result, ()> { + final_exponentiation::(f) } - /// Compute a projective multiplication on G1 for bls12_381 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G1 for BLS12-381. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_381_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - bls12_381::mul_projective_g1(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a projective multiplication on G2 for bls12_381 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G2 for BLS12-381. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_381_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - bls12_381::mul_projective_g2(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a msm on G1 for bls12_381 - /// Receives encoded: - /// bases: ArkScale<&[ark_bls12_381::G1Affine]> - /// scalars: ArkScale<&[ark_bls12_381::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G1 for BLS12-381. + /// + /// - Receives encoded: + /// - bases: `ArkScale<&[ark_bls12_381::G1Affine]>`. + /// - scalars: `ArkScale<&[ark_bls12_381::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_381_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { - bls12_381::msm_g1(bases, scalars) + msm_sw::(bases, scalars) } - /// Compute a msm on G2 for bls12_381 - /// Receives encoded: - /// bases: ArkScale<&[ark_bls12_381::G2Affine]> - /// scalars: ArkScale<&[ark_bls12_381::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G2 for BLS12-381. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_bls12_381::G2Affine]>`. + /// - `scalars`: `ArkScale<&[ark_bls12_381::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bls12_381_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { - bls12_381::msm_g2(bases, scalars) + msm_sw::(bases, scalars) } - /// Compute a multi Miller loop on bw6_761 - /// Receives encoded: - /// a: ArkScale>> - /// b: ArkScale>> - /// Returns encoded: ArkScale>> + /// Pairing multi Miller loop for BW6-761. + /// + /// - Receives encoded: + /// - `a`: `ArkScale>>`. + /// - `b`: `ArkScale>>`. + /// - Returns encoded: `ArkScale>>`. fn bw6_761_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { - bw6_761::multi_miller_loop(a, b) + multi_miller_loop::(a, b) } - /// Compute a final exponentiation on bw6_761 - /// Receives encoded: ArkScale>> - /// Returns encoded: ArkScale>> - fn bw6_761_final_exponentiation(f12: Vec) -> Result, ()> { - bw6_761::final_exponentiation(f12) + /// Pairing final exponentiation for BW6-761. + /// + /// - Receives encoded: `ArkScale>>`. + /// - Returns encoded: `ArkScale>>`. + fn bw6_761_final_exponentiation(f: Vec) -> Result, ()> { + final_exponentiation::(f) } - /// Compute a projective multiplication on G1 for bw6_761 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G1 for BW6-761. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bw6_761_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { - bw6_761::mul_projective_g1(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a projective multiplication on G2 for bw6_761 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Projective multiplication on G2 for BW6-761. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bw6_761_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { - bw6_761::mul_projective_g2(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute a msm on G1 for bw6_761 - /// Receives encoded: - /// bases: ArkScale<&[ark_bw6_761::G1Affine]> - /// scalars: ArkScale<&[ark_bw6_761::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G1 for BW6-761. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_bw6_761::G1Affine]>`. + /// - `scalars`: `ArkScale<&[ark_bw6_761::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bw6_761_msm_g1(bases: Vec, bigints: Vec) -> Result, ()> { - bw6_761::msm_g1(bases, bigints) + msm_sw::(bases, bigints) } - /// Compute a msm on G2 for bw6_761 - /// Receives encoded: - /// bases: ArkScale<&[ark_bw6_761::G2Affine]> - /// scalars: ArkScale<&[ark_bw6_761::Fr]> - /// Returns encoded: ArkScaleProjective + /// Multi scalar multiplication on G2 for BW6-761. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_bw6_761::G2Affine]>`. + /// - `scalars`: `ArkScale<&[ark_bw6_761::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn bw6_761_msm_g2(bases: Vec, bigints: Vec) -> Result, ()> { - bw6_761::msm_g2(bases, bigints) + msm_sw::(bases, bigints) } - /// Compute projective multiplication on ed_on_bls12_377 - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Twisted Edwards projective multiplication for Ed-on-BLS12-377. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_377_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { - ed_on_bls12_377::mul_projective(base, scalar) + mul_projective_te::(base, scalar) } - /// Compute msm on ed_on_bls12_377 - /// Receives encoded: - /// bases: ArkScale<&[ark_ed_on_bls12_377::EdwardsAffine]> - /// scalars: - /// ArkScale<&[ark_ed_on_bls12_377::Fr]> - /// Returns encoded: - /// ArkScaleProjective + /// Twisted Edwards multi scalar multiplication for Ed-on-BLS12-377. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_ed_on_bls12_377::EdwardsAffine]>`. + /// - `scalars`: `ArkScale<&[ark_ed_on_bls12_377::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_377_msm(bases: Vec, scalars: Vec) -> Result, ()> { - ed_on_bls12_377::msm(bases, scalars) + msm_te::(bases, scalars) } - /// Compute short weierstrass projective multiplication on ed_on_bls12_381_bandersnatch - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Short Weierstrass projective multiplication for Ed-on-BLS12-381-Bandersnatch. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_sw_mul_projective( base: Vec, scalar: Vec, ) -> Result, ()> { - ed_on_bls12_381_bandersnatch::sw_mul_projective(base, scalar) + mul_projective_sw::(base, scalar) } - /// Compute twisted edwards projective multiplication on ed_on_bls12_381_bandersnatch - /// Receives encoded: - /// base: ArkScaleProjective - /// scalar: ArkScale<&[u64]> - /// Returns encoded: ArkScaleProjective + /// Twisted Edwards projective multiplication for Ed-on-BLS12-381-Bandersnatch. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalar`: `ArkScale<&[u64]>`. + /// - Returns encoded: + /// `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_te_mul_projective( base: Vec, scalar: Vec, ) -> Result, ()> { - ed_on_bls12_381_bandersnatch::te_mul_projective(base, scalar) + mul_projective_te::(base, scalar) } - /// Compute short weierstrass msm on ed_on_bls12_381_bandersnatch - /// Receives encoded: - /// bases: ArkScale<&[ark_ed_on_bls12_381_bandersnatch::SWAffine]> - /// scalars: ArkScale<&[ark_ed_on_bls12_381_bandersnatch::Fr]> - /// Returns encoded: - /// ArkScaleProjective + /// Short Weierstrass multi scalar multiplication for Ed-on-BLS12-381-Bandersnatch. + /// + /// - Receives encoded: + /// - `bases`: `ArkScale<&[ark_ed_on_bls12_381_bandersnatch::SWAffine]>`. + /// - `scalars`: `ArkScale<&[ark_ed_on_bls12_381_bandersnatch::Fr]>`. + /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_sw_msm( bases: Vec, scalars: Vec, ) -> Result, ()> { - ed_on_bls12_381_bandersnatch::sw_msm(bases, scalars) + msm_sw::(bases, scalars) } - /// Compute twisted edwards msm on ed_on_bls12_381_bandersnatch - /// Receives encoded: - /// base: ArkScaleProjective - /// scalars: ArkScale<&[ark_ed_on_bls12_381_bandersnatch::Fr]> - /// Returns encoded: - /// ArkScaleProjective + /// Twisted Edwards multi scalar multiplication for Ed-on-BLS12-381-Bandersnatch. + /// + /// - Receives encoded: + /// - `base`: `ArkScaleProjective`. + /// - `scalars`: `ArkScale<&[ark_ed_on_bls12_381_bandersnatch::Fr]>`. + /// - Returns encoded: + /// `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_te_msm( bases: Vec, scalars: Vec, ) -> Result, ()> { - ed_on_bls12_381_bandersnatch::te_msm(bases, scalars) + msm_te::(bases, scalars) } } diff --git a/substrate/primitives/crypto/ec-utils/src/test-data/g1_compressed_valid_test_vectors.dat b/substrate/primitives/crypto/ec-utils/src/test-data/g1_compressed_valid_test_vectors.dat deleted file mode 100644 index ea8cd67652d133010e79df8488452450b6f5cb17..0000000000000000000000000000000000000000 Binary files a/substrate/primitives/crypto/ec-utils/src/test-data/g1_compressed_valid_test_vectors.dat and /dev/null differ diff --git a/substrate/primitives/crypto/ec-utils/src/test-data/g1_uncompressed_valid_test_vectors.dat b/substrate/primitives/crypto/ec-utils/src/test-data/g1_uncompressed_valid_test_vectors.dat deleted file mode 100644 index 86abfba945c7b701750d637bffe6701330e10e88..0000000000000000000000000000000000000000 Binary files a/substrate/primitives/crypto/ec-utils/src/test-data/g1_uncompressed_valid_test_vectors.dat and /dev/null differ diff --git a/substrate/primitives/crypto/ec-utils/src/test-data/g2_compressed_valid_test_vectors.dat b/substrate/primitives/crypto/ec-utils/src/test-data/g2_compressed_valid_test_vectors.dat deleted file mode 100644 index a40bbe251d90e576060adb7eaa2456197878804c..0000000000000000000000000000000000000000 Binary files a/substrate/primitives/crypto/ec-utils/src/test-data/g2_compressed_valid_test_vectors.dat and /dev/null differ diff --git a/substrate/primitives/crypto/ec-utils/src/test-data/g2_uncompressed_valid_test_vectors.dat b/substrate/primitives/crypto/ec-utils/src/test-data/g2_uncompressed_valid_test_vectors.dat deleted file mode 100644 index 92e4bc528e8937a311b502e4940e5e363a1f7c57..0000000000000000000000000000000000000000 Binary files a/substrate/primitives/crypto/ec-utils/src/test-data/g2_uncompressed_valid_test_vectors.dat and /dev/null differ diff --git a/substrate/primitives/crypto/ec-utils/src/utils.rs b/substrate/primitives/crypto/ec-utils/src/utils.rs index 5560d5921160509a8f2a00b28ee29331008cc780..063b8fac7ad3fbee2058480197fbc7df931c5ec4 100644 --- a/substrate/primitives/crypto/ec-utils/src/utils.rs +++ b/substrate/primitives/crypto/ec-utils/src/utils.rs @@ -15,8 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The generic executions of the operations on arkworks elliptic curves -//! which get instantiatied by the corresponding curves. +//! Generic executions of the operations for *Arkworks* elliptic curves. + use ark_ec::{ pairing::{MillerLoopOutput, Pairing, PairingOutput}, short_weierstrass, @@ -25,17 +25,18 @@ use ark_ec::{ twisted_edwards::TECurveConfig, CurveConfig, VariableBaseMSM, }; -use ark_scale::hazmat::ArkScaleProjective; -use ark_std::vec::Vec; -use codec::{Decode, Encode}; +use ark_scale::{ + hazmat::ArkScaleProjective, + scale::{Decode, Encode}, +}; +use sp_std::vec::Vec; -const HOST_CALL: ark_scale::Usage = ark_scale::HOST_CALL; -type ArkScale = ark_scale::ArkScale; +// Scale codec type which is expected to be used by the host functions. +// +// Encoding is set to `HOST_CALL` which is a shortcut for "not-validated" and "not-compressed". +type ArkScale = ark_scale::ArkScale; -pub(crate) fn multi_miller_loop_generic( - g1: Vec, - g2: Vec, -) -> Result, ()> { +pub fn multi_miller_loop(g1: Vec, g2: Vec) -> Result, ()> { let g1 = ::G1Affine>> as Decode>::decode(&mut g1.as_slice()) .map_err(|_| ())?; let g2 = ::G2Affine>> as Decode>::decode(&mut g2.as_slice()) @@ -47,7 +48,7 @@ pub(crate) fn multi_miller_loop_generic( Ok(result.encode()) } -pub(crate) fn final_exponentiation_generic(target: Vec) -> Result, ()> { +pub fn final_exponentiation(target: Vec) -> Result, ()> { let target = ::TargetField> as Decode>::decode(&mut target.as_slice()) .map_err(|_| ())?; @@ -58,10 +59,7 @@ pub(crate) fn final_exponentiation_generic(target: Vec) -> R Ok(result.encode()) } -pub(crate) fn msm_sw_generic( - bases: Vec, - scalars: Vec, -) -> Result, ()> { +pub fn msm_sw(bases: Vec, scalars: Vec) -> Result, ()> { let bases = >> as Decode>::decode(&mut bases.as_slice()) .map_err(|_| ())?; @@ -78,10 +76,7 @@ pub(crate) fn msm_sw_generic( Ok(result.encode()) } -pub(crate) fn msm_te_generic( - bases: Vec, - scalars: Vec, -) -> Result, ()> { +pub fn msm_te(bases: Vec, scalars: Vec) -> Result, ()> { let bases = >> as Decode>::decode(&mut bases.as_slice()) .map_err(|_| ())?; @@ -97,7 +92,7 @@ pub(crate) fn msm_te_generic( Ok(result.encode()) } -pub(crate) fn mul_projective_generic( +pub fn mul_projective_sw( base: Vec, scalar: Vec, ) -> Result, ()> { @@ -113,7 +108,7 @@ pub(crate) fn mul_projective_generic( Ok(result.encode()) } -pub(crate) fn mul_projective_te_generic( +pub fn mul_projective_te( base: Vec, scalar: Vec, ) -> Result, ()> { diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 689a125056949c6570ad4c97f806936d35fb792a..c97c8a0a3991e94dd5c57f067fa26f5dbc4f091c 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = "2.0.36" +syn = "2.0.38" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/externalities/src/extensions.rs b/substrate/primitives/externalities/src/extensions.rs index 8b0bbd2c5921b217aadf889adef81dc7a63be0b0..282e6ea914a84caae6a1c63af8d9ff0e125176fc 100644 --- a/substrate/primitives/externalities/src/extensions.rs +++ b/substrate/primitives/externalities/src/extensions.rs @@ -35,17 +35,24 @@ use sp_std::{ /// /// As extensions are stored as `Box`, this trait should give more confidence that the correct /// type is registered and requested. -pub trait Extension: Send + Any { +pub trait Extension: Send + 'static { /// Return the extension as `&mut dyn Any`. /// /// This is a trick to make the trait type castable into an `Any`. fn as_mut_any(&mut self) -> &mut dyn Any; + + /// Get the [`TypeId`] of this `Extension`. + fn type_id(&self) -> TypeId; } impl Extension for Box { fn as_mut_any(&mut self) -> &mut dyn Any { (**self).as_mut_any() } + + fn type_id(&self) -> TypeId { + (**self).type_id() + } } /// Macro for declaring an extension that usable with [`Extensions`]. @@ -74,6 +81,10 @@ macro_rules! decl_extension { fn as_mut_any(&mut self) -> &mut dyn std::any::Any { self } + + fn type_id(&self) -> std::any::TypeId { + std::any::Any::type_id(self) + } } impl std::ops::Deref for $ext_name { @@ -107,6 +118,10 @@ macro_rules! decl_extension { fn as_mut_any(&mut self) -> &mut dyn std::any::Any { self } + + fn type_id(&self) -> std::any::TypeId { + std::any::Any::type_id(self) + } } } } @@ -235,4 +250,25 @@ mod tests { assert_eq!(ext_ty.0, 1); } + + #[test] + fn register_box_extension() { + let mut exts = Extensions::new(); + let box1: Box = Box::new(DummyExt(1)); + let box2: Box = Box::new(DummyExt2(2)); + exts.register(box1); + exts.register(box2); + + { + let ext = exts.get_mut(TypeId::of::()).expect("Extension 1 is registered"); + let ext_ty = ext.downcast_mut::().expect("Downcasting works for Extension 1"); + assert_eq!(ext_ty.0, 1); + } + { + let ext2 = exts.get_mut(TypeId::of::()).expect("Extension 2 is registered"); + let ext_ty2 = + ext2.downcast_mut::().expect("Downcasting works for Extension 2"); + assert_eq!(ext_ty2.0, 2); + } + } } diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..3e2dcc7ec5c4c866b6254700c97b1160ed5148af --- /dev/null +++ b/substrate/primitives/mixnet/Cargo.toml @@ -0,0 +1,30 @@ +[package] +description = "Substrate mixnet types and runtime interface" +name = "sp-mixnet" +version = "0.1.0-dev" +license = "Apache-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +sp-api = { default-features = false, path = "../api" } +sp-application-crypto = { default-features = false, path = "../application-crypto" } +sp-std = { default-features = false, path = "../std" } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "scale-info/std", + "sp-api/std", + "sp-application-crypto/std", + "sp-std/std", +] diff --git a/substrate/primitives/mixnet/README.md b/substrate/primitives/mixnet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..47c109f6b57c6685750de2cc88678055c94a8a49 --- /dev/null +++ b/substrate/primitives/mixnet/README.md @@ -0,0 +1,3 @@ +Substrate mixnet types and runtime interface. + +License: Apache-2.0 diff --git a/polkadot/runtime/kusama/constants/src/weights/mod.rs b/substrate/primitives/mixnet/src/lib.rs similarity index 61% rename from polkadot/runtime/kusama/constants/src/weights/mod.rs rename to substrate/primitives/mixnet/src/lib.rs index 23812ce7ed0528c394f84042fb9842eb617a834b..58b8a10f0cd8d5d4198e6fcf7b75e09d4f639827 100644 --- a/polkadot/runtime/kusama/constants/src/weights/mod.rs +++ b/substrate/primitives/mixnet/src/lib.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -15,14 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Expose the auto generated weight files. +//! Substrate mixnet types and runtime interface. -pub mod block_weights; -pub mod extrinsic_weights; -pub mod paritydb_weights; -pub mod rocksdb_weights; +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] -pub use block_weights::BlockExecutionWeight; -pub use extrinsic_weights::ExtrinsicBaseWeight; -pub use paritydb_weights::constants::ParityDbWeight; -pub use rocksdb_weights::constants::RocksDbWeight; +pub mod runtime_api; +pub mod types; diff --git a/substrate/primitives/mixnet/src/runtime_api.rs b/substrate/primitives/mixnet/src/runtime_api.rs new file mode 100644 index 0000000000000000000000000000000000000000..28ab40e633787545c4710043d746a9de3295d232 --- /dev/null +++ b/substrate/primitives/mixnet/src/runtime_api.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API for querying mixnet configuration and registering mixnodes. + +use super::types::{Mixnode, MixnodesErr, SessionIndex, SessionStatus}; +use sp_std::vec::Vec; + +sp_api::decl_runtime_apis! { + /// API to query the mixnet session status and mixnode sets, and to register mixnodes. + pub trait MixnetApi { + /// Get the index and phase of the current session. + fn session_status() -> SessionStatus; + + /// Get the mixnode set for the previous session. + fn prev_mixnodes() -> Result, MixnodesErr>; + + /// Get the mixnode set for the current session. + fn current_mixnodes() -> Result, MixnodesErr>; + + /// Try to register a mixnode for the next session. + /// + /// If a registration extrinsic is submitted, `true` is returned. The caller should avoid + /// calling `maybe_register` again for a few blocks, to give the submitted extrinsic a + /// chance to get included. + /// + /// With the above exception, `maybe_register` is designed to be called every block. Most + /// of the time it will not do anything, for example: + /// + /// - If it is not an appropriate time to submit a registration extrinsic. + /// - If the local node has already registered a mixnode for the next session. + /// - If the local node is not permitted to register a mixnode for the next session. + /// + /// `session_index` should match `session_status().current_index`; if it does not, `false` + /// is returned immediately. + fn maybe_register(session_index: SessionIndex, mixnode: Mixnode) -> bool; + } +} diff --git a/substrate/primitives/mixnet/src/types.rs b/substrate/primitives/mixnet/src/types.rs new file mode 100644 index 0000000000000000000000000000000000000000..fc214f94d1cbf2e4063efdf09dcdbc1e0aceb258 --- /dev/null +++ b/substrate/primitives/mixnet/src/types.rs @@ -0,0 +1,100 @@ +// 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. + +//! Mixnet types used by both host and runtime. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_std::vec::Vec; + +mod app { + use sp_application_crypto::{app_crypto, key_types::MIXNET, sr25519}; + app_crypto!(sr25519, MIXNET); +} + +/// Authority public session key, used to verify registration signatures. +pub type AuthorityId = app::Public; +/// Authority signature, attached to mixnode registrations. +pub type AuthoritySignature = app::Signature; + +/// Absolute session index. +pub type SessionIndex = u32; + +/// Each session should progress through these phases in order. +#[derive(Decode, Encode, TypeInfo, PartialEq, Eq)] +pub enum SessionPhase { + /// Generate cover traffic to the current session's mixnode set. + CoverToCurrent, + /// Build requests using the current session's mixnode set. + RequestsToCurrent, + /// Only send cover (and forwarded) traffic to the previous session's mixnode set. + CoverToPrev, + /// Disconnect the previous session's mixnode set. + DisconnectFromPrev, +} + +/// The index and phase of the current session. +#[derive(Decode, Encode, TypeInfo)] +pub struct SessionStatus { + /// Index of the current session. + pub current_index: SessionIndex, + /// Current session phase. + pub phase: SessionPhase, +} + +/// Size in bytes of a [`KxPublic`]. +pub const KX_PUBLIC_SIZE: usize = 32; + +/// X25519 public key, used in key exchange between message senders and mixnodes. Mixnode public +/// keys are published on-chain and change every session. Message senders generate a new key for +/// every message they send. +pub type KxPublic = [u8; KX_PUBLIC_SIZE]; + +/// Ed25519 public key of a libp2p peer. +pub type PeerId = [u8; 32]; + +/// Information published on-chain for each mixnode every session. +#[derive(Decode, Encode, TypeInfo)] +pub struct Mixnode { + /// Key-exchange public key for the mixnode. + pub kx_public: KxPublic, + /// libp2p peer ID of the mixnode. + pub peer_id: PeerId, + /// External addresses for the mixnode, in multiaddr format, UTF-8 encoded. + pub external_addresses: Vec>, +} + +/// Error querying the runtime for a session's mixnode set. +#[derive(Decode, Encode, TypeInfo)] +pub enum MixnodesErr { + /// Insufficient mixnodes were registered for the session. + InsufficientRegistrations { + /// The number of mixnodes that were registered for the session. + num: u32, + /// The minimum number of mixnodes that must be registered for the mixnet to operate. + min: u32, + }, +} + +impl sp_std::fmt::Display for MixnodesErr { + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + match self { + MixnodesErr::InsufficientRegistrations { num, min } => + write!(fmt, "{num} mixnode(s) registered; {min} is the minimum"), + } + } +} diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 1e9f0517df1296d7a2853027398b1d01ce588a50..5e75f926f87cae29e7ed69621d3222ce3862680a 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 0afe1ec5bb692346fdebbc0cd046b4238b806842..62ae0502114823c3e701c39f727d1ce8aca39e16 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -19,7 +19,7 @@ //! - [`seq_phragmen`]: Implements the Phragmén Sequential Method. An un-ranked, relatively fast //! election method that ensures PJR, but does not provide a constant factor approximation of the //! maximin problem. -//! - [`phragmms`](phragmms::phragmms): Implements a hybrid approach inspired by Phragmén which is +//! - [`ghragmms`](phragmms::phragmms()): Implements a hybrid approach inspired by Phragmén which is //! executed faster but it can achieve a constant factor approximation of the maximin problem, //! similar to that of the MMS algorithm. //! - [`balance`](balancing::balance): Implements the star balancing algorithm. This iterative diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index fe06c56d5a1550e3571fa0ae42574beded7ae397..fbc49785ae97008e66fcc4b84a7111e998b8dc61 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -20,4 +20,4 @@ Inflector = "0.11.4" proc-macro-crate = "1.1.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "visit", "fold", "extra-traits"] } +syn = { version = "2.0.38", features = ["full", "visit", "fold", "extra-traits"] } diff --git a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr index 23e671f6ce3f3e93ef8e49aba332b86e2c029473..10012ede793dee015a10279257a9d640096de0c8 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr @@ -3,3 +3,15 @@ error[E0425]: cannot find function `bar` in module `test` | 33 | test::bar(); | ^^^ not found in `test` + | +note: found an item that was configured out + --> tests/ui/no_feature_gated_method.rs:25:5 + | +25 | fn bar() {} + | ^^^ + = note: the item is gated behind the `bar-feature` feature +note: found an item that was configured out + --> tests/ui/no_feature_gated_method.rs:25:5 + | +25 | fn bar() {} + | ^^^ diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 1621af164b375cfec231777e08af83b839b45892..dfc18987d152582ecf4301798200fa52df53af25 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -37,6 +37,23 @@ pub type SessionIndex = u32; /// Counter for the number of eras that have passed. pub type EraIndex = u32; +/// Representation of a staking account, which may be a stash or controller account. +/// +/// Note: once the controller is completely deprecated, this enum can also be deprecated in favor of +/// the stash account. Tracking issue: . +#[derive(Clone, Debug)] +pub enum StakingAccount { + Stash(AccountId), + Controller(AccountId), +} + +#[cfg(feature = "std")] +impl From for StakingAccount { + fn from(account: AccountId) -> Self { + StakingAccount::Stash(account) + } +} + /// Representation of the status of a staker. #[derive(RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone))] @@ -121,10 +138,12 @@ pub trait OnStakingUpdate { /// * `slashed_active` - The new bonded balance of the staker after the slash was applied. /// * `slashed_unlocking` - A map of slashed eras, and the balance of that unlocking chunk after /// the slash is applied. Any era not present in the map is not affected at all. + /// * `slashed_total` - The aggregated balance that was lost due to the slash. fn on_slash( _stash: &AccountId, _slashed_active: Balance, _slashed_unlocking: &BTreeMap, + _slashed_total: Balance, ) { } } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 3cd1b7a3a76d36319345d6270cfe5e7504f77324..7fce559e3ed633aac290d5e7b550f47fe0d196ba 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive" ] } proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.36", features = ["full", "fold", "extra-traits", "visit"] } +syn = { version = "2.0.38", features = ["full", "fold", "extra-traits", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/scripts/ci/deny.toml b/substrate/scripts/ci/deny.toml index 5297d07143c225b65290b22ff4728be87a0261cb..ca059e384a358b242f7ba0e524f9b534df91d74f 100644 --- a/substrate/scripts/ci/deny.toml +++ b/substrate/scripts/ci/deny.toml @@ -68,6 +68,7 @@ exceptions = [ { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-wasmtime" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-informant" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-keystore" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-mixnet" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-bitswap" }, { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-common" }, diff --git a/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml b/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml index 4171f92f68feff11d2f10cbeeea63be64f80f546..ac89c58bfc3e223831795fb160d5d51816c7f6f4 100644 --- a/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml +++ b/substrate/scripts/ci/monitoring/alerting-rules/alerting-rules.yaml @@ -146,11 +146,7 @@ groups: hours.' - alert: UnboundedChannelPersistentlyLarge - expr: '( - (substrate_unbounded_channel_len{action = "send"} - - ignoring(action) substrate_unbounded_channel_len{action = "received"}) - or on(instance) substrate_unbounded_channel_len{action = "send"} - ) >= 200' + expr: 'substrate_unbounded_channel_size >= 200' for: 5m labels: severity: warning diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 63611ae8da6b2b306f0311ea0ac79297ae4cc068..73ffce8645b868a07b2cc77f1f00e47d0339ae79 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -11,7 +11,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/src/lib.rs b/substrate/src/lib.rs index 16a606778965792fcfa5e9f1639ef960e47a7fe2..409515ea505bfb8bcc2f32d63d3db9b3d210c992 100644 --- a/substrate/src/lib.rs +++ b/substrate/src/lib.rs @@ -21,7 +21,7 @@ //! Substrate is a Rust framework for building blockchains in a modular and extensible way. While in //! itself un-opinionated, it is the main engine behind the Polkadot ecosystem. //! -//! [![github]](https://github.com/paritytech/substrate/) - [![polkadot]](https://polkadot.network) +//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/) - [![polkadot]](https://polkadot.network) //! //! This crate in itself does not contain any code and is just meant ot be a documentation hub for //! substrate-based crates. @@ -157,7 +157,7 @@ //! through which Polkadot can be utilized is by building "parachains", blockchains that are //! connected to Polkadot's shared security. //! -//! To build a parachain, one could use [`Cumulus`](https://github.com/paritytech/cumulus/), the +//! To build a parachain, one could use [`Cumulus`](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus), the //! library on top of Substrate, empowering any substrate-based chain to be a Polkadot parachain. //! //! ## Where To Go Next? diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 727d46cb8f53de54ab14704580614e2b41a34ec5..4d279c7b703dd44977287b41f8451400a768d073 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -107,6 +107,3 @@ std = [ ] # Special feature to disable logging disable-logging = [ "sp-api/disable-logging" ] - -#Enabling this flag will disable GenesisBuilder API implementation in runtime. -disable-genesis-builder = [] diff --git a/substrate/test-utils/runtime/build.rs b/substrate/test-utils/runtime/build.rs index 230606635f7dc5a4fa452dc7f5dfd021747a6002..dd79ce2c5ae842ad7fc1c759a14fa8dedd200a1a 100644 --- a/substrate/test-utils/runtime/build.rs +++ b/substrate/test-utils/runtime/build.rs @@ -15,8 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -const BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV: &str = "BUILD_NO_GENESIS_BUILDER_SUPPORT"; - fn main() { #[cfg(feature = "std")] { @@ -31,19 +29,6 @@ fn main() { .build(); } - #[cfg(feature = "std")] - if std::env::var(BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV).is_ok() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .append_to_rust_flags("-Clink-arg=-zstack-size=1048576") - .set_file_name("wasm_binary_no_genesis_builder") - .import_memory() - .enable_feature("disable-genesis-builder") - .build(); - } - println!("cargo:rerun-if-env-changed={}", BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV); - #[cfg(feature = "std")] { substrate_wasm_builder::WasmBuilder::new() diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index b116c8556815f3eef73e08252faab9d9f586ff24..687790f2ffaf8bfe13a4bb58075efc3da750114a 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -26,11 +26,10 @@ pub mod genesismap; pub mod substrate_test_pallet; use codec::{Decode, Encode}; -#[cfg(not(feature = "disable-genesis-builder"))] -use frame_support::genesis_builder_helper::{build_config, create_default_config}; use frame_support::{ construct_runtime, dispatch::DispatchClass, + genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstU32, ConstU64}, weights::{ @@ -722,7 +721,6 @@ impl_runtime_apis! { } } - #[cfg(not(feature = "disable-genesis-builder"))] impl sp_genesis_builder::GenesisBuilder for Runtime { fn create_default_config() -> Vec { create_default_config::() @@ -1203,7 +1201,6 @@ mod tests { }) } - #[cfg(not(feature = "disable-genesis-builder"))] mod genesis_builder_tests { use super::*; use crate::genesismap::GenesisStorageBuilder; diff --git a/substrate/test-utils/runtime/transaction-pool/src/lib.rs b/substrate/test-utils/runtime/transaction-pool/src/lib.rs index 7b529200440279a59a74bdb9d3dbf315a21d9261..8c8345b06bd32e4efbe2f721ddebe2cc2f2f9c4e 100644 --- a/substrate/test-utils/runtime/transaction-pool/src/lib.rs +++ b/substrate/test-utils/runtime/transaction-pool/src/lib.rs @@ -22,6 +22,7 @@ use codec::Encode; use futures::future::ready; use parking_lot::RwLock; +use sc_transaction_pool::ChainApi; use sp_blockchain::{CachedHeaderMetadata, TreeRoute}; use sp_runtime::{ generic::{self, BlockId}, @@ -237,9 +238,14 @@ impl TestApi { ) -> Result, Error> { sp_blockchain::tree_route(self, from, to) } + + /// Helper function for mapping block number to hash. Use if mapping shall not fail. + pub fn expect_hash_from_number(&self, n: BlockNumber) -> Hash { + self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap() + } } -impl sc_transaction_pool::ChainApi for TestApi { +impl ChainApi for TestApi { type Block = Block; type Error = Error; type ValidationFuture = futures::future::Ready>; @@ -247,13 +253,13 @@ impl sc_transaction_pool::ChainApi for TestApi { fn validate_transaction( &self, - at: &BlockId, + at: ::Hash, _source: TransactionSource, uxt: ::Extrinsic, ) -> Self::ValidationFuture { self.validation_requests.write().push(uxt.clone()); - match self.block_id_to_number(at) { + match self.block_id_to_number(&BlockId::Hash(at)) { Ok(Some(number)) => { let found_best = self .chain diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 017e4b4d5034913d1747a546a2e10cc582e4da37..e32fe47b729712368d4803e7d756dffd18a52476 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.0.1", default-features = false } handlebars = "4.2.2" diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs index 69c95d13c098530a0b1c09ef569c5ff976bf02e3..9493a693bbed321785bf0d23326d0f68b3efd534 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -779,6 +779,7 @@ fn worst_case_pov( /// A simple match statement which outputs the log 16 of some value. fn easy_log_16(i: u32) -> u32 { + #[allow(clippy::redundant_guards)] match i { i if i == 0 => 0, i if i <= 16 => 1, diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 89aef53386505b22000f065df5098f38dfc1f04a..24c04f47391e8157a45f830986a7e3f6585ebb1b 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index b06674a62cb34803e7ee416d362a274820c3ec6b..13e61138356231a4c0c56da19bc61abbbf7286cc 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ kitchensink-runtime = { path = "../../../../bin/node/runtime" } generate-bags = { path = ".." } # third-party -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index ad6ab006da1dcd0c69c3ffa1b24a2a00128c6d34..7067aed238aca08b5b03ae99f568ad1777751911 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -23,7 +23,6 @@ sp-runtime = { path = "../../../primitives/runtime" } tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } futures = "0.3" -async-recursion = "1.0.4" indicatif = "0.17.3" spinners = "4.1.0" tokio-retry = "0.3.0" diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 072ea6ef5e5970a6fe377e742e04d623f0c34607..71e9320ebeeb272faa156d758dd6571c9cb148a9 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -20,7 +20,6 @@ //! An equivalent of `sp_io::TestExternalities` that can load its state from a remote substrate //! based chain, or a local state snapshot file. -use async_recursion::async_recursion; use codec::{Compact, Decode, Encode}; use indicatif::{ProgressBar, ProgressStyle}; use jsonrpsee::{ @@ -44,7 +43,7 @@ use sp_runtime::{ use sp_state_machine::TestExternalities; use spinners::{Spinner, Spinners}; use std::{ - cmp::max, + cmp::{max, min}, fs, ops::{Deref, DerefMut}, path::{Path, PathBuf}, @@ -353,10 +352,11 @@ where const PARALLEL_REQUESTS: usize = 4; const BATCH_SIZE_INCREASE_FACTOR: f32 = 1.10; const BATCH_SIZE_DECREASE_FACTOR: f32 = 0.50; - const INITIAL_BATCH_SIZE: usize = 5000; + const REQUEST_DURATION_TARGET: Duration = Duration::from_secs(15); + const INITIAL_BATCH_SIZE: usize = 10; // nodes by default will not return more than 1000 keys per request const DEFAULT_KEY_DOWNLOAD_PAGE: u32 = 1000; - const KEYS_PAGE_MAX_RETRIES: usize = 12; + const MAX_RETRIES: usize = 12; const KEYS_PAGE_RETRY_INTERVAL: Duration = Duration::from_secs(5); async fn rpc_get_storage( @@ -411,8 +411,8 @@ where let keys = loop { // This loop can hit the node with very rapid requests, occasionally causing it to // error out in CI (https://github.com/paritytech/substrate/issues/14129), so we retry. - let retry_strategy = FixedInterval::new(Self::KEYS_PAGE_RETRY_INTERVAL) - .take(Self::KEYS_PAGE_MAX_RETRIES); + let retry_strategy = + FixedInterval::new(Self::KEYS_PAGE_RETRY_INTERVAL).take(Self::MAX_RETRIES); let get_page_closure = || self.get_keys_single_page(Some(prefix.clone()), last_key.clone(), at); let page = Retry::spawn(retry_strategy, get_page_closure).await?; @@ -448,8 +448,6 @@ where /// /// * `client` - An `Arc` wrapped `HttpClient` used for making the requests. /// * `payloads` - A vector of tuples containing a JSONRPC method name and `ArrayParams` - /// * `batch_size` - The initial batch size to use for the request. The batch size will be - /// adjusted dynamically in case of failure. /// /// # Returns /// @@ -485,80 +483,107 @@ where /// } /// } /// ``` - #[async_recursion] async fn get_storage_data_dynamic_batch_size( client: &HttpClient, payloads: Vec<(String, ArrayParams)>, - batch_size: usize, bar: &ProgressBar, ) -> Result>, String> { - // All payloads have been processed - if payloads.is_empty() { - return Ok(vec![]) - }; - - log::debug!( - target: LOG_TARGET, - "Remaining payloads: {} Batch request size: {}", - payloads.len(), - batch_size, - ); + let mut all_data: Vec> = vec![]; + let mut start_index = 0; + let mut retries = 0usize; + let mut batch_size = Self::INITIAL_BATCH_SIZE; + let total_payloads = payloads.len(); + + while start_index < total_payloads { + log::debug!( + target: LOG_TARGET, + "Remaining payloads: {} Batch request size: {}", + total_payloads - start_index, + batch_size, + ); - // Payloads to attempt to process this batch - let page = payloads.iter().take(batch_size).cloned().collect::>(); + let end_index = usize::min(start_index + batch_size, total_payloads); + let page = &payloads[start_index..end_index]; - // Build the batch request - let mut batch = BatchRequestBuilder::new(); - for (method, params) in page.iter() { - batch - .insert(method, params.clone()) - .map_err(|_| "Invalid batch method and/or params")? - } - let batch_response = match client.batch_request::>(batch).await { - Ok(batch_response) => batch_response, - Err(e) => { - if batch_size < 2 { - return Err(e.to_string()) - } + // Build the batch request + let mut batch = BatchRequestBuilder::new(); + for (method, params) in page.iter() { + batch + .insert(method, params.clone()) + .map_err(|_| "Invalid batch method and/or params")?; + } - log::debug!( - target: LOG_TARGET, - "Batch request failed, trying again with smaller batch size. {}", - e.to_string() - ); + let request_started = Instant::now(); + let batch_response = match client.batch_request::>(batch).await { + Ok(batch_response) => { + retries = 0; + batch_response + }, + Err(e) => { + if retries > Self::MAX_RETRIES { + return Err(e.to_string()) + } + + retries += 1; + let failure_log = format!( + "Batch request failed ({}/{} retries). Error: {}", + retries, + Self::MAX_RETRIES, + e.to_string() + ); + // after 2 subsequent failures something very wrong is happening. log a warning + // and reset the batch size down to 1. + if retries >= 2 { + log::warn!("{}", failure_log); + batch_size = 1; + } else { + log::debug!("{}", failure_log); + // Decrease batch size by DECREASE_FACTOR + batch_size = + (batch_size as f32 * Self::BATCH_SIZE_DECREASE_FACTOR) as usize; + } + continue + }, + }; - return Self::get_storage_data_dynamic_batch_size( - client, - payloads, - max(1, (batch_size as f32 * Self::BATCH_SIZE_DECREASE_FACTOR) as usize), - bar, + let request_duration = request_started.elapsed(); + batch_size = if request_duration > Self::REQUEST_DURATION_TARGET { + // Decrease batch size + max(1, (batch_size as f32 * Self::BATCH_SIZE_DECREASE_FACTOR) as usize) + } else { + // Increase batch size, but not more than the remaining total payloads to process + min( + total_payloads - start_index, + max( + batch_size + 1, + (batch_size as f32 * Self::BATCH_SIZE_INCREASE_FACTOR) as usize, + ), ) - .await - }, - }; + }; + + log::debug!( + target: LOG_TARGET, + "Request duration: {:?} Target duration: {:?} Last batch size: {} Next batch size: {}", + request_duration, + Self::REQUEST_DURATION_TARGET, + end_index - start_index, + batch_size + ); - // Collect the data from this batch - let mut data: Vec> = vec![]; - let batch_response_len = batch_response.len(); - for item in batch_response.into_iter() { - match item { - Ok(x) => data.push(x), - Err(e) => return Err(e.message().to_string()), + let batch_response_len = batch_response.len(); + for item in batch_response.into_iter() { + match item { + Ok(x) => all_data.push(x), + Err(e) => return Err(e.message().to_string()), + } } + bar.inc(batch_response_len as u64); + + // Update the start index for the next iteration + start_index = end_index; } - bar.inc(batch_response_len as u64); - // Return this data joined with the remaining keys - let remaining_payloads = payloads.iter().skip(batch_size).cloned().collect::>(); - let mut rest = Self::get_storage_data_dynamic_batch_size( - client, - remaining_payloads, - max(batch_size + 1, (batch_size as f32 * Self::BATCH_SIZE_INCREASE_FACTOR) as usize), - bar, - ) - .await?; - data.append(&mut rest); - Ok(data) + Ok(all_data) } /// Synonym of `getPairs` that uses paged queries to first get the keys, and then @@ -605,12 +630,7 @@ where ); let payloads_chunked = payloads.chunks((&payloads.len() / Self::PARALLEL_REQUESTS).max(1)); let requests = payloads_chunked.map(|payload_chunk| { - Self::get_storage_data_dynamic_batch_size( - &client, - payload_chunk.to_vec(), - Self::INITIAL_BATCH_SIZE, - &bar, - ) + Self::get_storage_data_dynamic_batch_size(&client, payload_chunk.to_vec(), &bar) }); // Execute the requests and move the Result outside. let storage_data_result: Result, _> = @@ -683,20 +703,14 @@ where .collect::>(); let bar = ProgressBar::new(payloads.len() as u64); - let storage_data = match Self::get_storage_data_dynamic_batch_size( - client, - payloads, - Self::INITIAL_BATCH_SIZE, - &bar, - ) - .await - { - Ok(storage_data) => storage_data, - Err(e) => { - log::error!(target: LOG_TARGET, "batch processing failed: {:?}", e); - return Err("batch processing failed") - }, - }; + let storage_data = + match Self::get_storage_data_dynamic_batch_size(client, payloads, &bar).await { + Ok(storage_data) => storage_data, + Err(e) => { + log::error!(target: LOG_TARGET, "batch processing failed: {:?}", e); + return Err("batch processing failed") + }, + }; assert_eq!(child_keys_len, storage_data.len()); diff --git a/substrate/utils/frame/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index 1eff71e3390a38af2f1cd0d2ba417783a86ee5a2..f467a87989048d9cca418ba04c57d363cc05162d 100644 --- a/substrate/utils/frame/rpc/system/src/lib.rs +++ b/substrate/utils/frame/rpc/system/src/lib.rs @@ -219,7 +219,6 @@ mod tests { use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_transaction_pool::BasicPool; use sp_runtime::{ - generic::BlockId, transaction_validity::{InvalidTransaction, TransactionValidityError}, ApplyExtrinsicResult, }; @@ -245,11 +244,12 @@ mod tests { }; t.into_unchecked_extrinsic() }; + let hash_of_block0 = client.info().genesis_hash; // Populate the pool let ext0 = new_transaction(0); - block_on(pool.submit_one(&BlockId::number(0), source, ext0)).unwrap(); + block_on(pool.submit_one(hash_of_block0, source, ext0)).unwrap(); let ext1 = new_transaction(1); - block_on(pool.submit_one(&BlockId::number(0), source, ext1)).unwrap(); + block_on(pool.submit_one(hash_of_block0, source, ext1)).unwrap(); let accounts = System::new(client, pool, DenyUnsafe::Yes); diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index c736c3f6cc569bf37126b702b3f983d074c59bbd..65380a22ce6e0adc95b837b1a7b340764c3ad775 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -35,7 +35,7 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true} substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.57" -clap = { version = "4.4.3", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" diff --git a/substrate/utils/prometheus/src/lib.rs b/substrate/utils/prometheus/src/lib.rs index 581666635ab54698d0426bc80007e245ee8568fe..ed1f9137aec4efad97218b2340e49436a05fd577 100644 --- a/substrate/utils/prometheus/src/lib.rs +++ b/substrate/utils/prometheus/src/lib.rs @@ -111,10 +111,16 @@ async fn init_prometheus_with_listener( } }); - let server = Server::builder(listener).serve(service); + let (signal, on_exit) = tokio::sync::oneshot::channel::<()>(); + let server = Server::builder(listener).serve(service).with_graceful_shutdown(async { + let _ = on_exit.await; + }); let result = server.await.map_err(Into::into); + // Gracefully shutdown server, otherwise the server does not stop if it has open connections + let _ = signal.send(()); + result }